วาดเส้นหยักเป็นลอนใน QGIS?


21

มีฟังก์ชั่นหรือปลั๊กอิน QGIS เพื่อวาดเส้น wiggly หรือไม่?

ฉันใช้เครื่องมือ Spline เพื่อวาดคลื่นด้วยตนเอง แต่ใช้เวลานาน ถ้าเป็นไปได้ฉันต้องการวาดสิ่งที่ชอบ:

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

Inkscape Function Plotter ( sin(x)เส้นโค้ง)


คำถามที่น่าสนใจจริงๆ! คุณกำลังคิดเกี่ยวกับเครื่องมือสำหรับการวาดเส้นทันที (เช่นเมื่อคุณวาดคุณสมบัติเส้นอย่างง่าย ๆ โดยใช้เมาส์) หรืออาจเป็นวิธีที่จะได้รับผลลัพธ์นี้เริ่มต้นจากพิกัดเป็นอินพุต (ในที่สุดจากจุดเส้นหรือรูปหลายเหลี่ยม)
mgri

1
@ mgri ขอบคุณสำหรับความคิดเห็นของคุณ ฉันคาดว่าจะใช้บรรทัดนี้เพื่อทำเครื่องหมายขอบเขตด้วยความไม่แน่นอนบางอย่าง (เช่นแนวชายฝั่งที่ผันผวน) ดังนั้นแนวคิดหลักคือการแปลงโพลีไลน์ (ผ่านพิกัดที่กำหนดไว้ล่วงหน้า) เป็น wiggles แต่แนวคิดของการวาดเส้นประเภทนี้ในทันทีก็น่าดึงดูดเช่นกัน
Kazuhito

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

คำตอบ:


18

ฉันเสนอวิธีแก้ปัญหาโดยใช้ PyQGIS ควรทำงานได้ทั้งกับเลเยอร์ Linestring และ MultiLineString

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

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

คุณจะต้องเรียกใช้รหัสนี้จาก Python Console เท่านั้น:

from math import sin, cos, radians

step = 3 # choose the proper value (e.g. meters or degrees) with reference to the CRS used
crv_angle = 45 # degrees

def segment(polyline):
    for x in range(0, len(polyline) - 1):
        first_point = polyline[x]
        second_point = polyline[x +1]
        seg = QgsGeometry.fromPolyline([first_point, second_point])
        tmp_azim = first_point.azimuth(second_point)
        len_feat = seg.length()
        parts = int(len_feat/step)
        real_step = len_feat/parts # this is the real step applied

        points = []
        current = 0
        up = True

        while current < len_feat:
            if up:
                round_angle = radians(90 - (tmp_azim - crv_angle))
                up = False
            else:
                round_angle = radians(90 - (tmp_azim + crv_angle))
                up = True
            first = seg.interpolate(current)
            coord_x, coord_y = (first.asPoint().x(), first.asPoint().y())
            p1=QgsPointV2(coord_x, coord_y)
            dist_x, dist_y = ((real_step*sin(rad_crv_angle))* cos(round_angle), (real_step*sin(rad_crv_angle)) * sin(round_angle))
            p2 = QgsPointV2(coord_x + dist_x, coord_y + dist_y)
            points.extend([p1, p2])
            current += real_step

        second = seg.interpolate(current + real_step)
        p3=QgsPointV2(second.asPoint().x(), second.asPoint().y())
        points.append(p3)

        circularRing = QgsCircularStringV2()
        circularRing.setPoints(points) # set points for circular rings
        fet = QgsFeature()
        fet.setGeometry(QgsGeometry(circularRing))
        prov.addFeatures([fet])

layer = iface.activeLayer() # load the input layer as you want
crs = layer.crs().toWkt()
rad_crv_angle = radians(crv_angle)

# Create the output layer
outLayer = QgsVectorLayer('Linestring?crs='+ crs, 'wiggly_line' , 'memory')
prov = outLayer.dataProvider()
fields = layer.pendingFields()
prov.addAttributes(fields)
outLayer.updateFields()

for feat in layer.getFeatures():
    geom = feat.geometry()
    polyline = geom.asPolyline()
    segment(polyline)

# Add the layer to the Layers panel
QgsMapLayerRegistry.instance().addMapLayer(outLayer)

และมันจะสร้างเลเยอร์หน่วยความจำบรรทัดใหม่พร้อมผลลัพธ์ที่ต้องการ:

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


ว้าว! ฉันไม่สามารถหยุดเล่นกับสิ่งนี้ได้งดงามมาก ด้านบนของมันเอาท์พุทตัวเองสามารถใช้สำหรับการดำเนินงานเพิ่มเติมเช่นบัฟเฟอร์ ขอบคุณ @mgri สิ่งสุดท้ายที่ฉันเห็นบางครั้งวงกลมเล็ก ๆ ปรากฏขึ้นที่หรือใกล้จุดยอด สิ่งนี้สามารถหลีกเลี่ยงได้หรือไม่? ฉันสามารถลบออกได้โดยการลบโหนดกลางของวงกลมดังกล่าวโดย Node Tool (ดังนั้นจึงไม่ใช่เรื่องใหญ่)
Kazuhito

1
@Kazuhito โปรดดูรหัสที่แก้ไขของฉัน ดูเหมือนว่ามีบางอย่างผิดปกติกับ discretization และฉันหวังว่าจะได้รับการแก้ไขในขณะนี้ ฉันทำการทดสอบหลายครั้งและดูเหมือนว่าใช้งานได้ดี (รหัสนี้ยังสามารถอ่านได้มากขึ้น)
mgri

1
ขอบคุณ @mgri มาก มีแวดวงเล็ก ๆ ซึ่งฉันขอโทษที่ฉันไม่สามารถอธิบายได้อย่างชัดเจนว่าสิ่งเหล่านี้จะปรากฏขึ้นได้อย่างไร จุดยอดส่วนใหญ่ตอนนี้เป็น "วงกลมฟรี" ความแตกต่างเพียงอย่างเดียวที่ฉันสังเกตเห็นคือโหนดดังกล่าว (พร้อมวงกลม) แสดง "r-value" ที่เล็กลงบนตารางตัวแก้ไขจุดยอดของเครื่องมือโหนด สิ่งนี้จัดการได้ง่ายและดีกว่าที่ฉันคาดไว้มาก ขอขอบคุณอีกครั้ง. ให้ฉันยอมรับคำตอบของคุณเป็นทางออก
Kazuhito

1
ขอบคุณ @Kazuhito ฉันขอโทษที่ไม่ได้สร้างโซลูชั่นที่สมบูรณ์แบบ อย่างไรก็ตามฉันหวังว่าคุณจะสนุกไปกับมัน (ไม่เช่นนั้นคุณอาจส่งไฟล์ตัวอย่างตัวอย่างมาให้ฉันและฉันจะพยายามแก้ไขปัญหานี้) หากฉันพบวิธีที่มีประสิทธิภาพมากขึ้นฉันจะโพสต์มัน!
mgri

1
ขอบคุณมาก @ มนตรี หากฉันพบรูปแบบที่โดดเด่นใด ๆ ในลักษณะของแวดวงฉันจะอัปเดตคุณด้วยตัวอย่างที่ทำซ้ำได้ มันสนุกมาก (และเอาต์พุตมันสวยงาม)!
Kazuhito

20

คำตอบสั้น ๆ : คุณสามารถขอรับได้โดยใช้ SVG ที่กำหนดเอง ดูด้านล่างของโพสต์นี้เพื่อหนึ่ง

คำตอบยาว:

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

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

ในการรับสิ่งนี้คุณจะจัดรูปแบบบรรทัดด้วยสองบรรทัดมาร์กเกอร์ แต่ละเส้นมาร์กเกอร์ทำจากเครื่องหมายแบบง่ายครึ่งวงกลม อันที่หนึ่งหมุน 180 โดยทั้งคู่ถูกตั้งค่าเป็นแบบโปร่งใส

บนบรรทัดของตัวทำเครื่องหมายคุณแนะนำให้หนึ่งในนั้นถูกออฟเซ็ตเพื่อไม่ให้วาดสัญลักษณ์สองตัวต่อหน้ากัน แต่จะอยู่เคียงข้างกัน หากคุณใช้ offest = 1/2 * ขนาดช่วงเอาต์พุตจะเป็นเส้นโค้งไซน์ ฉันขอแนะนำให้คุณเล่นด้วยขนาดช่วงเวลาออฟเซ็ตและขนาดสัญลักษณ์

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

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

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

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

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

** แก้ไข **

ตัวเลือกอื่นในการกำจัดเส้นกลางคือการสร้างสัญลักษณ์ SVG ใหม่ ฉันดัดแปลงเส้นโค้งครึ่งโดยอาศัยส่วนที่โค้งมนเท่านั้น มันใช้งานได้แม้ว่า 1/2 วงรีอาจน่าสนใจมากกว่า สกรีนช็อตทำได้โดยใช้สัญลักษณ์ขนาด 10 ช่วงเวลา 4 ออฟเซ็ต 2

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

บันทึกรหัสด้านล่างในไฟล์ half_circle_line.svg และตรวจสอบให้แน่ใจว่ามีการตั้งค่าพา ธ ไปยัง svg QGIS // Settings / Options / System / SVG Paths

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg width="11.2889mm" height="11.2889mm"
 viewBox="0 0 32 32"
 xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"  version="1.2" baseProfile="tiny">
<title>Qt Svg Document</title>
<desc>Generated with Qt</desc>
<defs>
</defs>
<g fill="none" stroke="black" stroke-width="1" fill-rule="evenodd" stroke-linecap="square" stroke-linejoin="bevel" >

<g fill="#ffffff" fill-opacity="0" stroke="#000000" stroke-opacity="1" stroke-width="1" stroke-linecap="square" stroke-linejoin="bevel" transform="matrix(1,0,0,1,0,0)"
font-family="MS Shell Dlg 2" font-size="8.25" font-weight="400" font-style="normal" 
>
<path vector-effect="non-scaling-stroke" fill-rule="evenodd" d="M19.1181,16 C19.1181,16 19.1181,14.2779 17.7221,12.8819 16,12.8819 C14.2779,12.8819 12.8819,14.2779 12.8819,16"/>
</g>
</g>
</svg>

ความคิดดี. ขณะนี้ดิ้นรนกับ "เส้นกลาง" ถาวร: ...
Kazuhito

+1 จากฉันด้วย ในขณะเดียวกันฉันกำลังพยายามคิดถึงวิธีแก้ไขปัญหา PyQGIS @ Kazuhito โปรดแจ้งให้เราทราบหากนี่จะเพียงพอสำหรับคุณหรือหากคุณต้องการทางออกทางกายภาพ
mgri

@ mgri ด้วยคำตอบนี้ฉันมี "chain" ไม่ใช่ "wave" ตอนนี้ (พยายามแก้ไข) ขอขอบคุณที่มีทางออกทางกายภาพ
Kazuhito

JGH คุณมีความคิดที่จะลบ "เส้นกลาง" ออกไปหรือไม่โดยการปิดบังด้วยเส้นสีขาว ดูเหมือนว่ามันจะมีการแยกส่วน
Kazuhito

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