개발자 이야기

[pyqgis] split hole polyline 본문

GIS/QGIS

[pyqgis] split hole polyline

프란5 2019. 11. 26. 21:36
반응형

from itertools import combinations,chain
import math

class CheckTest():
    def __init__(self):
        
        self.str_key_name = 'gid'
        self.str_gen_id = "nextval('id_seq'::regclass)"
        self.layer = iface.activeLayer()
        self.fldnames = []
        self.idx_key = -1
        self.maxvalue = 0
        
        flds = self.layer.fields()
        
        for idx in range(0, len(flds)):
            fld = flds[idx]
            name = fld.name()
            self.fldnames.append(name)
        
            if name == self.str_key_name:
                self.idx_key = idx
                self.maxvalue = self.layer.maximumValue(idx)
        
        print(self.fldnames)
        print('key: {} == maxvalue: {}'.format(self.idx_key, self.maxvalue))
        
        
        
    def step(self):
        cnt = 0
        for ft in self.layer.getFeatures():
            geom = ft.geometry()
            total_dist = geom.length()
            
            mpolylines = geom.asMultiPolyline()
            ptlist = list(chain(*chain(*mpolylines)))
            
            #attrs= ft.attributes()
            #print(attrs)
            
            b = self.check_hole(ptlist)
            if b:
                list1, list2 = self.get_splits(ptlist, total_dist)
                #print(list1)
                #print(list2)
                pts1 = []
                pts2 = []
                for idx in range(0, len(list1), 2):
                    pts1.append(QgsPointXY(list1[idx], list1[idx+1]))
                
                for idx in range(0, len(list2), 2):
                    pts2.append(QgsPointXY(list2[idx], list2[idx+1]))
            
                geom1 = QgsGeometry.fromPolylineXY(pts1)
                geom2 = QgsGeometry.fromPolylineXY(pts2)
            
                ft.setGeometry(geom1)
                self.layer.updateFeature(ft)
                
                #print('{} == {}'.format(list1, list2))
             
                attrs= ft.attributes()
                
                attrs[0] = self.str_gen_id
                if self.idx_key >=0:
                    self.maxvalue +=1
                    attrs[self.idx_key] = self.maxvalue
               
                print(attrs)
                
                new_feat = QgsFeature(self.layer.fields())
                new_feat.setAttributes(attrs)
                new_feat.setGeometry(geom2)
                
                self.layer.addFeature(new_feat)
            
            cnt+=1
            
            if cnt> 200:
                break
                
            
    def get_splits(self, ptlist, total_dist):
        
        half = total_dist/2
        
        size = len(ptlist)
        
        x1 = ptlist[0]
        y1 = ptlist[1]
        
        sum =0
        
        list1 = []
        list2 = []
        
        for idx in range(2, size, 2):
            x2 = ptlist[idx]
            y2 = ptlist[idx+1]
        
            dist = self.get_distance(x1, y1, x2, y2)
            sum += dist
            
            if sum > half:
                
                over = sum - half
                
                cx = (x2 - x1)*(dist - over)/dist
                cy = (y2 - y1)*(dist - over)/dist
                
                list1 = ptlist[:idx]
                list1.append(x1 + cx)
                list1.append(y1 + cy)
                list2 = ptlist[idx:]
                list2.insert(0, y1 +cy)
                list2.insert(0, x1 +cx)
                break
            
            
            x1 = x2
            y1 = y2
        
        
        return list1, list2
        
        
        
    def get_distance(self, x1, y1, x2, y2):
        dist = math.sqrt((x2 - x1)**2 + (y2 - y1)**2)
        return dist
        
        
    
    def check_hole(self, ptlist):
        size = len(ptlist)
        x1 = ptlist[0]
        y1 = ptlist[1]
        x2 = ptlist[size-2]
        y2 = ptlist[size-1]
        
        if x1 == x2 and y1 == y2:
            return True
    
        return False
        
        
    
    
     
tt = CheckTest()
tt.step()

반응형