วิธี snap เครือข่ายถนนไปยังตารางหกเหลี่ยมใน QGIS?


13

ฉันพยายามใช้ QGIS 2.14 เพื่อจับเครือข่ายถนนไปยังตารางหกเหลี่ยม แต่ฉันได้รับสิ่งประดิษฐ์แปลก ๆ

ฉันได้สร้างกริดหกเหลี่ยมด้วยMMQGISเซลล์มีขนาดประมาณ 20 x 23 เมตร ฉันบัฟเฟอร์เครือข่ายถนน 1 ม. และเพิ่มความหนาแน่นจึงมีโหนดทุกสองสามเมตร คุณสามารถเห็นสิ่งที่ฉันพยายามบรรลุด้านล่าง อย่างที่คุณเห็นฉันสามารถทำให้มันทำงานได้ในบางกรณี: -

  • สีน้ำเงินคือถนนหนาแน่น (เส้นบัฟเฟอร์)
  • สีแดงเป็นรุ่น 'hexified' - นี่คือสิ่งที่ฉันต้องการค้นหา
  • สีเทาคือตารางฐานสิบหก

ป้อนคำอธิบายรูปภาพที่นี่

จากนั้นฉันใช้คุณสมบัติรูปทรงใหม่ของSnapเพื่อจัดเรียงโหนดไปยังมุมหกเหลี่ยมที่ใกล้เคียงที่สุด ผลลัพธ์มีแนวโน้ม แต่ดูเหมือนจะมีบางกรณีขอบที่เส้นขยายออกเพื่อเติมหกเหลี่ยม (หรือส่วนหนึ่งของมัน): -

ป้อนคำอธิบายรูปภาพที่นี่

เหตุผลของบัฟเฟอร์คือรูปทรงเรขาคณิตของ Snapไม่อนุญาตให้คุณไปยังชั้นที่มีรูปทรงเรขาคณิตที่แตกต่างกัน ตัวอย่างเช่นคุณไม่สามารถจัดเรียงโหนดบนเลเยอร์ LINE เพื่อให้คะแนนในเลเยอร์ POINT) ดูเหมือนว่า POLYGON จะมีความสุขมากที่สุดในการถ่าย POLYGON

ฉันสงสัยว่าถนนจะขยายออกไปเมื่อด้านหนึ่งของถนนสายบัฟเฟอร์ที่กระโดดไปด้านหนึ่งของเซลล์ฐานสิบหกและอีกฝั่งหนึ่งกระโดดไปด้านอื่น ๆ ของเซลล์ฐานสิบหก ในตัวอย่างของฉันถนนที่ข้ามไปทางทิศตะวันตกทิศตะวันออกในมุมที่รุนแรงดูเหมือนจะเลวร้ายที่สุด

สิ่งที่ฉันพยายามไม่ประสบความสำเร็จ: -

  • บัฟเฟอร์เครือข่ายถนนด้วยจำนวนเล็กน้อยดังนั้นมันจึงยังคงเป็นรูปหลายเหลี่ยม แต่บางมาก
  • ทำให้เซลล์หกเหลี่ยมมีความหนาแน่นเพิ่มขึ้น (ดังนั้นจึงมีโหนตามขอบไม่ใช่ที่มุม)
  • การเปลี่ยนแปลงระยะการหักมุมสูงสุด (นี่มีเอฟเฟกต์มากที่สุด แต่ฉันไม่สามารถหาค่าในอุดมคติได้)
  • ใช้เลเยอร์ LINE ไม่ใช่ POLYGON

ฉันพบว่าถ้าฉันเปลี่ยนไปใช้เลเยอร์เพียงแค่ LINE มันใช้งานได้ชั่วขณะหนึ่งแล้วเกิดปัญหา ดูเหมือนว่าจะบันทึกงานตามที่ไป - บางบรรทัดได้รับการประมวลผลบางส่วน

ป้อนคำอธิบายรูปภาพที่นี่

ไม่มีใครรู้วิธีอื่น ๆ ที่จะ snap คะแนนในบรรทัดไปยังจุดที่ใกล้ที่สุดในอีกชั้น / รูปหลายเหลี่ยมชั้นนึกคิดโดยไม่จำเป็นต้องใช้ postgres / postgis (แม้ว่าการแก้ปัญหาด้วย postgis จะยินดีด้วย)

แก้ไข

สำหรับทุกคนที่ต้องการที่จะมีการเดินทางที่ผมได้วางโครงการเริ่มต้น QGIS ที่นี่ใน Dropbox ซึ่งรวมถึงชั้น Hex Grid และ Densified line lines (เครือข่ายถนนมาจาก OSM ดังนั้นสามารถดาวน์โหลดได้โดยใช้ QuickOSM เช่นหากคุณต้องการรับต้นฉบับเพื่อลดขนาดถนน)

โปรดทราบว่ามันอยู่ใน OSGB (epsg: 27700) ซึ่งเป็น UTM ที่แปลเป็นภาษาอังกฤษสำหรับสหราชอาณาจักรโดยมีหน่วยเป็นเมตร


3
คุณกรุณาแบ่งปันชุดข้อมูลตัวอย่างได้ไหม ฉันต้องการทดลองใช้ แต่ไม่ต้องการดำเนินการสร้างข้อมูลตัวอย่างตั้งแต่เริ่มต้น
Germán Carrillo

@ GermánCarrillo - ขอบคุณ ฉันได้เพิ่มลิงก์ไปยังโครงการตัวอย่างในคำถาม
Steven Kay

คำตอบ:


14

วิธีการแก้ปัญหาของฉันเกี่ยวข้องกับสคริปต์ PyQGIS ที่เร็วขึ้นและมีประสิทธิภาพมากกว่าเวิร์กโฟลว์ที่เกี่ยวข้องกับการหักมุม (ฉันก็ลองด้วย) ใช้อัลกอริทึมของฉันฉันได้รับผลลัพธ์เหล่านี้:

ป้อนคำอธิบายรูปภาพที่นี่

ป้อนคำอธิบายรูปภาพที่นี่

คุณสามารถเรียกใช้ข้อมูลโค้ดต่อไปนี้ตามลำดับจากภายใน QGIS (ในคอนโซล QGIS Python) ในตอนท้ายคุณจะได้รับเลเยอร์หน่วยความจำที่มีการจัดเส้นทางที่โหลดไว้ใน QGIS

ข้อกำหนดเบื้องต้นเท่านั้นคือการสร้าง Shapefile ถนนหลายส่วน (ใช้Processing->Singleparts to multipartฉันใช้เขตข้อมูลfictitiuosเป็นUnique ID fieldพารามิเตอร์) สิ่งนี้จะทำให้เรามีroads_multipart.shpไฟล์ที่มีคุณสมบัติเดียว

นี่คืออัลกอริทึมที่อธิบาย:

  1. รับด้านหกเหลี่ยมที่ใกล้ที่สุดซึ่งมีเส้นทางตัดกัน สำหรับแต่ละหกเหลี่ยมเราสร้างสามเหลี่ยม 6 รูปแบบระหว่างจุดยอดของเพื่อนบ้านแต่ละคู่กับเซนทรอยด์ที่เกี่ยวข้อง หากถนนใดตัดกันรูปสามเหลี่ยมส่วนที่แบ่งปันโดยรูปหกเหลี่ยมและรูปสามเหลี่ยมจะถูกเพิ่มเข้าไปในเส้นทางสุดท้ายที่มีการจัดชิดซ้าย นี่คือส่วนที่หนักกว่าของอัลกอริธึมทั้งหมดใช้เวลา 35 วินาทีในการทำงานบนเครื่องของฉัน ในสองบรรทัดแรกมี 2 พา ธ Shapefile คุณควรปรับให้เหมาะสมกับพา ธ ไฟล์ของคุณเอง

    hexgrid = QgsVectorLayer("/docs/borrar/hex_grid_question/layers/normal-hexgrid.shp", "hexgrid", "ogr")
    roads = QgsVectorLayer("/docs/borrar/hex_grid_question/layers/roads_multipart.shp", "roads", "ogr")  # Must be multipart!
    
    roadFeat = roads.getFeatures().next() # We just have 1 geometry
    road = roadFeat.geometry() 
    indicesHexSides = ((0,1), (1,2), (2,3), (3,4), (4,5), (5,0))
    
    epsilon = 0.01
    # Function to compare whether 2 segments are equal (even if inverted)
    def isSegmentAlreadySaved(v1, v2):
        for segment in listSegments:        
            p1 = QgsPoint(segment[0][0], segment[0][1])
            p2 = QgsPoint(segment[1][0], segment[1][1])
            if v1.compare(p1, epsilon) and v2.compare(p2, epsilon) \
                or v1.compare(p2, epsilon) and v2.compare(p1, epsilon):
                return True
        return False
    
    # Let's find the nearest sides of hexagons where routes cross
    listSegments = []
    for hexFeat in hexgrid.getFeatures():
        hex = hexFeat.geometry()
        if hex.intersects( road ):
            for side in indicesHexSides:
                triangle = QgsGeometry.fromPolyline([hex.centroid().asPoint(), hex.vertexAt(side[0]), hex.vertexAt(side[1])])
                if triangle.intersects( road ):
                    # Only append new lines, we don't want duplicates!!!
                    if not isSegmentAlreadySaved(hex.vertexAt(side[0]), hex.vertexAt(side[1])): 
                        listSegments.append( [[hex.vertexAt(side[0]).x(), hex.vertexAt(side[0]).y()], [hex.vertexAt(side[1]).x(),hex.vertexAt(side[1]).y()]] )  
  2. กำจัดตัดการเชื่อมต่อ (หรือ 'เปิด') กลุ่มโดยใช้รายการหลาม tuples และพจนานุกรม ณ จุดนี้มีส่วนที่ไม่ได้เชื่อมต่ออยู่เหลืออยู่กล่าวคือส่วนที่มีจุดยอดหนึ่งถูกตัดการเชื่อมต่อ แต่อีกส่วนหนึ่งเชื่อมต่อกับอย่างน้อย 2 ส่วนอื่น ๆ (ดูส่วนสีแดงในรูปถัดไป) เราจำเป็นต้องกำจัดพวกเขา

    ป้อนคำอธิบายรูปภาพที่นี่

    # Let's remove disconnected/open segments
    lstVertices = [tuple(point) for segment in listSegments for point in segment]
    dictConnectionsPerVertex = dict((tuple(x),lstVertices.count(x)-1) for x in set(lstVertices))
    
    # A vertex is not connected and the other one is connected to 2 segments
    def segmentIsOpen(segment):
        return dictConnectionsPerVertex[tuple(segment[0])] == 0 and dictConnectionsPerVertex[tuple(segment[1])] >= 2 \
            or dictConnectionsPerVertex[tuple(segment[1])] == 0 and dictConnectionsPerVertex[tuple(segment[0])] >= 2
    
    # Remove open segments
    segmentsToDelete = [segment for segment in listSegments if segmentIsOpen(segment)]        
    for toBeDeleted in segmentsToDelete:
        listSegments.remove( toBeDeleted )
  3. ตอนนี้เราสามารถสร้างเลเยอร์เวกเตอร์จากรายการพิกัดและโหลดไปยังแผนที่ QGIS :

    # Create a memory layer and load it to QGIS map canvas
    vl = QgsVectorLayer("LineString", "Snapped Routes", "memory")
    pr = vl.dataProvider()
    features = []
    for segment in listSegments:
        fet = QgsFeature()
        fet.setGeometry( QgsGeometry.fromPolyline( [QgsPoint(segment[0][0], segment[0][1]), QgsPoint(segment[1][0], segment[1][1])] ) )
        features.append(fet)
    
    pr.addFeatures( features )
    vl.updateExtents()
    QgsMapLayerRegistry.instance().addMapLayer(vl)

อีกส่วนหนึ่งของผลลัพธ์:

ป้อนคำอธิบายรูปภาพที่นี่

หากคุณต้องการแอททริบิวต์ในเส้นทางที่ snapped เราสามารถใช้ดัชนีอวกาศเพื่อประเมินการแยกได้อย่างรวดเร็ว (เช่นใน/gis//a/130440/4972 ) แต่นั่นเป็นอีกเรื่องหนึ่ง

หวังว่านี่จะช่วยได้!


1
ขอบคุณที่ทำงานได้อย่างสมบูรณ์แบบ! มีปัญหาในการวางลงในคอนโซลหลาม ... ฉันบันทึกเป็นไฟล์. py ในเอดิเตอร์ qgis python และทำงานได้ดีจากที่นั่น ขั้นตอนหลายส่วนจะลบแอตทริบิวต์ แต่การเข้าร่วมของบัฟเฟอร์ / อวกาศจะแก้ไขได้!
Steven Kay

1
ที่ดี! ในที่สุดมันก็ช่วยแก้ปัญหาที่คุณเผชิญอยู่ ฉันสนใจที่จะรู้ว่ากรณีการใช้งานที่คุณกำลังเผชิญอยู่ คุณคิดว่าเราสามารถใช้สิ่งนี้เพื่อเป็นปลั๊กอิน QGIS หรืออาจเป็นสคริปต์ที่รวมอยู่ในสคริปต์การประมวลผลหรือไม่?
Germán Carrillo

1
กรณีการใช้งานที่ฉันมีอยู่ในใจคือแผนที่การขนส่งมวลชนเช่น Tube Map ที่คุณจะต้องสอดสายไปที่กริด tesselatedหรือมุมที่ จำกัด สิ่งนี้สามารถทำได้ด้วยตนเองโดยการแปลงเป็นดิจิทัล แต่ฉันสนใจที่จะดูว่ามันอาจเป็นไปโดยอัตโนมัติ ฉันใช้ hexes เพราะมันสร้างง่ายน่าสนใจและมีมุมซึ่งไม่ใช่มุมฉาก ฉันคิดว่านี่เป็นสิ่งที่ควรค่าแก่การพิจารณาในรายละเอียดมากขึ้นโดยเฉพาะอย่างยิ่งถ้าเป็นเรื่องทั่วไปที่จะทำงานร่วมกับ tesselations อื่น ๆ ...
สตีเวนเคย์

1
แนวคิดเบื้องหลังสคริปต์จะทำงานบนกริดสามเหลี่ยม, เพนตากอน, รูปหกเหลี่ยมและอื่น ๆ
Germán Carrillo

6

ฉันทำมันใน ArcGIS แน่นอนสามารถนำมาใช้โดยใช้ QGIS หรือเพียงแค่หลามกับแพคเกจที่มีความสามารถในการอ่านรูปทรงเรขาคณิต ตรวจสอบให้แน่ใจว่าถนนเป็นตัวแทนของเครือข่ายเช่นตัดกันที่ปลายถนนเท่านั้น คุณกำลังจัดการกับ OSM ฉันคิดว่ามันเป็นกรณี

  • แปลงรูปหลายเหลี่ยมความใกล้เคียงเป็นเส้นตรงและระนาบพวกมันดังนั้นพวกเขาจึงกลายเป็นเครือข่ายทางเรขาคณิตเช่นกัน
  • วางคะแนนที่จุดสิ้นสุด - คะแนน Voronoi: ป้อนคำอธิบายรูปภาพที่นี่
  • วางจุดบนถนนในช่วงเวลาปกติ 5 ม. ให้แน่ใจว่าถนนในเครือข่ายมีชื่อที่ไม่ซ้ำกัน:

ป้อนคำอธิบายรูปภาพที่นี่ ป้อนคำอธิบายรูปภาพที่นี่

  • สำหรับ Road Point ทุกจุดหาพิกัดของ Voronoi Point ที่ใกล้ที่สุด: ป้อนคำอธิบายรูปภาพที่นี่
  • สร้าง "ถนน" โดยเชื่อมต่อจุดที่ใกล้ที่สุดในลำดับเดียวกัน: ป้อนคำอธิบายรูปภาพที่นี่

หากคุณไม่ต้องการเห็นสิ่งนี้: ป้อนคำอธิบายรูปภาพที่นี่

อย่าพยายามใช้คะแนน chainage บนเส้น Voronoi ฉันกลัวว่ามันจะทำให้แย่ลงเท่านั้น ดังนั้นตัวเลือกเดียวของคุณคือการสร้างเครือข่ายจากเส้น Voronoi และค้นหาเส้นทางระหว่างจุดสิ้นสุดของถนนนั่นก็ไม่ใช่เรื่องใหญ่อะไรเช่นกัน


นี่มันเยี่ยมมากขอบคุณ! คุณพูดถึงการใช้เส้น voronoi ไม่คุ้นเคยกับมันมาก (Voronois จากจุดฉันเข้าใจได้) คุณหมายถึงแต่ละบรรทัดล้อมรอบด้วยรูปหลายเหลี่ยมของจุดทั้งหมดที่อยู่ใกล้กับบรรทัดนั้นหรือไม่ (ฉันไม่ทราบวิธีการทำเช่นนั้นใน QGIS) หรือคุณหมายถึงเส้นเขตแดนจาก voronoi mesh ธรรมดาตามคะแนน?
Steven Kay

เส้นเขตแดนของรูปหลายเหลี่ยมความใกล้เคียง Btw ฉันหยุดเร็วเกินไป ในการทำงานให้เสร็จก็เพียงพอที่จะแยกผลลัพธ์ที่ 1 ที่จุดสุดยอดเพิ่มจุดที่ตรงกลางและทำซ้ำกระบวนการ
FelixIP

4

ฉันรู้ว่าคุณกำลังขอวิธี QGIS แต่อดทนกับฉันสำหรับคำตอบ arcpy:

roads = 'clipped roads' # roads layer
hexgrid = 'normal-hexgrid' # hex grid layer
sr = arcpy.Describe('roads').spatialReference # spatial reference
outlines = [] # final output lines
points = [] # participating grid vertices
vert_dict = {} # vertex dictionary
hex_dict = {} # grid dictionary
with arcpy.da.SearchCursor(roads,["SHAPE@","OID@"], spatial_reference=sr) as r_cursor: # loop through roads
    for r_row in r_cursor:
        with arcpy.da.SearchCursor(hexgrid,["SHAPE@","OID@"], spatial_reference=sr) as h_cursor: # loop through hex grid
            for h_row in h_cursor:
                if not r_row[0].disjoint(h_row[0]): # check if the shapes overlap
                    hex_verts = []
                    for part in h_row[0]:
                        for pnt in part:
                            hex_verts.append(pnt) # add grid vertices to list
                    int_pts = r_row[0].intersect(h_row[0],1) # find all intersection points between road and grid
                    hex_bnd = h_row[0].boundary() # convert grid to line
                    hex_dict[h_row[1]] = hex_bnd # add grid geometry to dictionary
                    for int_pt in int_pts: # loop through intersection points
                        near_dist = 1000 # arbitrary large number
                        int_pt = arcpy.PointGeometry(int_pt,sr)
                        for hex_vert in hex_verts: # loop through hex vertices
                            if int_pt.distanceTo(hex_vert) < near_dist: # find shortest distance between intersection point and grid vertex
                                near_vert = hex_vert # remember geometry
                                near_dist = int_pt.distanceTo(hex_vert) # remember distance
                        vert_dict.setdefault(h_row[1],[]).append(arcpy.PointGeometry(near_vert,sr)) # store geometry in dictionary
                        points.append(arcpy.PointGeometry(near_vert,sr)) # add to points list
for k,v in vert_dict.iteritems(): # loop through participating vertices
    if len(v) < 2: # skip if there was only one vertex
        continue
    hex = hex_dict[k] # get hex grid geometry
    best_path = hex # longest line possible is hex grid boundary
    for part in hex:
        for int_vert in v: # loop through participating vertices
            for i,pnt in enumerate(part): # loop through hex grid vertices
                if pnt.equals(int_vert): # find vertex index on hex grid corresponding to current point
                    start_i = i
                    if start_i == 6:
                        start_i = 0
                    for dir in [[0,6,1],[5,-1,-1]]: # going to loop once clockwise, once counter-clockwise
                        past_pts = 0 # keep track of number of passed participating vertices
                        cur_line_arr = arcpy.Array() # polyline coordinate holder
                        cur_line_arr.add(part[start_i]) # add starting vertex to growing polyline
                        for j in range(dir[0],dir[1],dir[2]): # loop through hex grid vertices
                            if past_pts < len(v): # only make polyline until all participating vertices have been visited
                                if dir[2] == 1: # hex grid vertex index bookkeeping
                                    if start_i + j < 6:
                                        index = start_i + j
                                    else:
                                        index = (start_i - 6) + j
                                else:
                                    index = j - (5 - start_i)
                                    if index < 0:
                                        index += 6
                                cur_line_arr.add(part[index]) # add current vertex to growing polyline
                                for cur_pnt in v:
                                    if part[index].equals(cur_pnt): # check if the current vertex is a participating vertex
                                        past_pts += 1 # add to counter
                        if cur_line_arr.count > 1:
                            cur_line = arcpy.Polyline(cur_line_arr,sr)
                            if cur_line.length < best_path.length: # see if current polyline is shorter than any previous candidate
                                best_path = cur_line # if so, store polyline
    outlines.append(best_path) # add best polyline to list
arcpy.CopyFeatures_management(outlines, r'in_memory\outlines') # write list
arcpy.CopyFeatures_management(points, r'in_memory\mypoints') # write points, if you want

ป้อนคำอธิบายรูปภาพที่นี่

หมายเหตุ:

  • สคริปต์นี้มีลูปจำนวนมากภายในลูปและเคอร์เซอร์ซ้อนกัน มีห้องสำหรับเพิ่มประสิทธิภาพแน่นอน ฉันวิ่งผ่านชุดข้อมูลของคุณในไม่กี่นาที แต่คุณสมบัติอื่น ๆ จะรวมปัญหา

ขอบคุณสำหรับสิ่งนี้ชื่นชมมาก นี่แสดงให้เห็นว่าเอฟเฟกต์ที่ฉันกำลังมองเห็น ความคิดเห็นมากมายหมายความว่าฉันสามารถรับส่วนสำคัญของสิ่งที่คุณทำแม้ว่าฉันจะไม่สามารถเรียกใช้รหัส แม้ว่ามันจะเป็นอาร์คี แต่ฉันแน่ใจว่านี่จะสามารถใช้ได้ใน pyqgis แนวคิดของอัลกอริทึมในที่นี่น่าสนใจ (โดยเฉพาะอย่างยิ่งการดูทั้งตามเข็มนาฬิกาและทวนเข็มนาฬิกาแต่ละรอบฐานสิบหกและเลือกทางลัดที่สั้นที่สุด)
Steven Kay

2

หากคุณต้องแบ่งเส้นถนนออกเป็นส่วน ๆ ซึ่งแต่ละส่วนนั้นมีหกเหลี่ยมอยู่การตัดสินใจของคุณว่ากลุ่มเส้นหกเหลี่ยมที่ใช้นั้นจะเป็นอย่างไรระยะทางจากเซนทรอยด์ของส่วนถนนแยกไปยังจุดกึ่งกลางของแต่ละเหลี่ยมหกเหลี่ยมนั้นน้อยกว่าครึ่ง เส้นผ่าศูนย์กลางของรูปหกเหลี่ยม (หรือน้อยกว่ารัศมีของวงกลมที่พอดีภายในหกเหลี่ยม)

ดังนั้นหากคุณไปที่ (หนึ่งส่วนต่อครั้ง) เลือกส่วนของเส้นหกเหลี่ยม (โดยที่แต่ละส่วนนั้นเป็นด้านของรูปหกเหลี่ยม) ที่อยู่ในระยะทางรัศมีของรูปหกเหลี่ยมคุณสามารถคัดลอกรูปทรงเรขาคณิตของเส้นเหล่านั้นและรวมเข้าด้วยกัน ตัวระบุเฉพาะที่คุณใช้สำหรับชุดข้อมูลถนนของคุณ

หากคุณมีปัญหาในการรวมตัวระบุที่ไม่ซ้ำกันคุณสามารถใช้บัฟเฟอร์และเลือกตามสถานที่ในกลุ่มเหล่านั้นเท่านั้นที่จะใช้คุณสมบัติของชุดข้อมูลถนนของคุณ ด้วยวิธีนี้คุณไม่ต้องกังวลกับการจับคู่เท็จกับบัฟเฟอร์ที่มีขนาดใหญ่เกินไป

ปัญหาเกี่ยวกับเครื่องมือ snap คือมันเก็บจุดโดยไม่เลือกปฏิบัติ มันยากที่จะค้นหาความอดทนที่สมบูรณ์แบบที่จะใช้ ด้วยวิธีการนี้คุณจะสามารถระบุส่วนของเส้นหกเหลี่ยมได้อย่างถูกต้องจากนั้นเปลี่ยนรูปทรงเรขาคณิตของข้อมูลถนนของคุณ (หรือแทรกรูปทรงเรขาคณิตลงในชุดข้อมูลอื่น)

นอกจากนี้หากคุณยังคงมีปัญหากับส่วนของเส้นตรงที่กระโดดจากด้านหนึ่งของรูปหกเหลี่ยมไปที่อีกด้านหนึ่งคุณสามารถแบ่งบรรทัดออกเป็นส่วน ๆ ตามจุดยอดคำนวณความยาวของแต่ละบรรทัดแล้วลบส่วนของเส้นที่มีขนาดใหญ่กว่า ความยาวเฉลี่ยของด้านหนึ่งของรูปหกเหลี่ยม


1

ปลากะพงรูปทรงเรขาคณิตใน qgis 3.0 ได้รับการทำใหม่และตอนนี้อนุญาตให้มีการสลับระหว่างประเภทเรขาคณิตที่แตกต่างกัน นอกจากนี้ยังมีการแก้ไขมากมาย คุณสามารถลองรุ่น "สแนปชอตรายวัน" เพื่อเข้าถึงปลากะพงที่ได้รับการปรับปรุงก่อนปล่อย 3.0 อย่างเป็นทางการ

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.