বহুভুজ সহ "লোভী" ক্লিপিং লাইন


9

আমি বহুভুজের বাইরের সীমানায় পোলাইনের একটি সেট (নীচে চিত্রের কালো লাইনগুলি) ক্লিপ করতে চাই। বহুভুজের মধ্যে যে কোনও voids উপেক্ষা করা উচিত। আমার আদর্শ আউটপুট হ'ল ড্যাশযুক্ত হলুদ লাইন। প্রাথমিক লাইনগুলি সোজা নাও হতে পারে। চিত্রটি সরলীকৃত উদাহরণ, বাস্তবে বহুভুজ অনেক বেশি জটিল এবং এখানে কয়েকশ লাইন রয়েছে। আমি মনে করি না যে উত্তল হলের কাজ করবে (তবে আমি ভুল হতে পারি)। আমি আরকিস, কিগিস, আরকি, সুদৃশ্য ইত্যাদির সমাধানগুলির জন্য খোলা আছি, কোডিংটি অজুহাতে থাকতে চাইলে আমি প্রয়োজনে অন্যান্য বিকল্পগুলিতেও খোলাম। আমার সহকর্মীদের পক্ষে সরঞ্জামটি ভাগ করে নেওয়া সহজ করে দেওয়া আর্কগিসও পছন্দনীয় তবে এটি কোনও প্রয়োজন নয়।

বহুক্ষেত্রের ছেদগুলিতে পয়েন্টগুলির একটি সেট তৈরি করে বহুভুজ দিয়ে পৃথক রেখাকে ছেদ করা এখনই আমি সবচেয়ে ভালভাবে ভাবতে পারি। লাইনের শুরুতে পয়েন্টগুলি দূরত্বে বাছাই করুন। দূরতম এবং নিকটতম (এফএসি) পয়েন্টগুলি বহুভুজের বাইরের সীমানা হবে। তারপরে এফএসি পয়েন্টগুলি ব্যবহার করে মূল লাইনটি থেকে যথাযথ শীর্ষকে বেছে নিতে এবং উপযুক্ত পয়েন্টগুলি থেকে হলুদ ড্যাশযুক্ত লাইন তৈরি করুন। এটি কাজ করা উচিত তবে প্রয়োজনের চেয়ে জটিল বলে মনে হচ্ছে।

কয়েকটি অতিরিক্ত চিন্তা:

  • লাইনগুলি লিনিয়ার "পর্যাপ্ত" যে পয়েন্টগুলির মধ্যে একটি সাধারণ দূরত্বের গণনাটি কাজ করা উচিত, লিনিয়ার রেফারেন্সিং প্রয়োজন হবে না।
  • আরকি-তে এটি সহজ হবে যদি কোনও বিন্দুতে একটি লাইন বিভক্ত করার কোনও সরঞ্জাম ছিল তবে আমি এটির সন্ধান করতে পারি না।

কেউ ভাবেন?

উদাহরণ


+1, আকর্ষণীয় সমস্যা! আমি কী কী সমাধানগুলি উপলভ্য তা দেখতে আগ্রহী =)
জোসেফ

কেবলমাত্র আপনার মাঝের লাইনটি অর্জন করা শক্ত - উপরে এবং নীচে কেবল কোনও ভয়েড পূরণ করার পরে একটি ক্লিপ থেকে আসে। ফলস্বরূপ, আমি মনে করি আপনার নিজের প্রশ্নটি সেটির দিকে ফোকাস করা উচিত এবং যদি এটি আপনার পছন্দসই সরঞ্জাম হয় তবে এটির সুযোগটি কেবল আর্কপাইয়ের সাথে সংকীর্ণ করা উচিত। আপনি সর্বদা অন্য সরঞ্জাম সম্পর্কে জিজ্ঞাসা করতে পারেন, যদি এটির কোনও সমাধান আসে না।
পলিজিও

লাইন একাধিক বহুভুজ পার?
এমিল ব্রুন্ডেজ

এমিল, ধরে নিই যে লাইনগুলি একাধিক বহুভুজ পেরিয়ে যেতে পারে। তবে জ্যামিতি ব্যতীত বহুভুজগুলির মধ্যে কোনও পার্থক্য নেই তাই এগুলিকে দ্রবীভূত করা যায়, বহুগুণিত বৈশিষ্ট্যে মার্জ করা যায় ইত্যাদি ইত্যাদি যদি এটি অ্যালগরিদমকে সহজ করে তোলে। একাধিক বহুভুজের উপর দিয়ে একটি লাইন ক্রসিং সম্ভবত বিরল হবে এবং এটি যদি প্রয়োজন হয় তবে হাত দিয়ে মোকাবেলা করা একটি পতাকাযুক্ত মামলা হতে পারে।
মাইক

আপনার লাইসেন্স স্তরটি কী?
এমিল ব্রুন্ডেজ

উত্তর:


4

আমি আমার পাইকিজিআইএস দ্রবণে ফেলে দিতে চাই, অন্য কিছু নয়।

from PyQt4.QtCore import QVariant
from qgis.analysis import QgsGeometryAnalyzer

# get layers
lines = QgsMapLayerRegistry.instance().mapLayersByName('lines')[0]
clipper = QgsMapLayerRegistry.instance().mapLayersByName('clipper')[0]

# prepare result layer
clipped = QgsVectorLayer('LineString?crs=epsg:4326', 'clipped', 'memory')
clipped.startEditing()
clipped.addAttribute(QgsField('fid', QVariant.Int))
fni = clipped.fieldNameIndex('fid')
clipped.commitChanges()

prov = clipped.dataProvider()
fields = prov.fields()

for line in lines.getFeatures():
    # to increase performance filter possible clippers 
    clippers = clipper.getFeatures(QgsFeatureRequest().setFilterRect(line.geometry().boundingBox()))
    for clip in clippers:
            # split the line
            line1 = line.geometry().splitGeometry(clip.geometry().asPolygon()[0], True)
            feats = []
            # get the split points
            vertices = [QgsPoint(vert[0], vert[1]) for vert in line1[2]]
            for part in line1[1]:
                # for each split part check, if first AND last vertex equal to split points
                if part.vertexAt(0) in vertices and part.vertexAt(len(part.asPolyline())-1) in vertices:
                    # if so create feature and set fid to original line's id
                    feat = QgsFeature(fields)
                    feat.setAttributes([line.id()])
                    feat.setGeometry(part)
                    feats.append(feat)

            prov.addFeatures(feats)

# expose layer
clipped.updateExtents()
QgsMapLayerRegistry.instance().addMapLayers([clipped])

# now dissolve lines having the same value in field fni: here original line's id
diss = QgsGeometryAnalyzer()
diss.dissolve(clipped, 'E:\\clipped.shp', uniqueIdField=fni)

আমার পরীক্ষার কেস - ক্লিপিংয়ের আগে: ক্লিপ আগে

ক্লিপিং পরে:

পরে

মূল লাইনের বৈশিষ্ট্যগুলির পুরো সেটটি পেতে আমি মনে করি ফলাফলের সাথে তাদের যুক্ত হওয়া ভাল হবে। অন্যথায় প্রস্তুতি বিভাগে তৈরি করতে হবে এবং সবচেয়ে অভ্যন্তরীণ লুপে সেট করতে হবে। তবে আমি পরীক্ষা করে দেখিনি যদি তারা দ্রবীভূত প্রক্রিয়াটি পাস করে বা তারা হারিয়ে যায় তবে নীতিগতভাবে তাদের আলাদা আলাদা মান থাকতে পারে।


খুব সংক্ষিপ্ত উত্তর। কিউজিআইএস স্ক্রিন শটগুলি কীভাবে সর্বদা কিউজিআইএস-এর মতো দেখাচ্ছে?
মাইক বানিস্টার

3

আরকি-তে এটি সহজ হবে যদি কোনও বিন্দুতে একটি লাইন বিভক্ত করার কোনও সরঞ্জাম ছিল তবে আমি এটির সন্ধান করতে পারি না।

যদি আপনি বহুভুজ এবং লাইনগুলিকে ইনপুট হিসাবে ইন্টিগ্রেট পরিচালনা করেন তবে এটি প্রতিটি যেখানে ছেদ করে সেখানে এটি একটি খণ্ড যুক্ত করবে। (সাবধানী, যেমন ইন্টিগ্রেট নতুন আউটপুট উত্পাদন না করে ইনপুটগুলিকে পরিবর্তন করে))

একবার আপনি নিশ্চিত হয়ে উঠলেন যে কাকতালীয় শিখরগুলি রয়েছে, আপনি লাইনটির শীর্ষ প্রান্তগুলিকে পুনরাবৃত্তি করতে পারবেন এবং প্রতিটি অন্যান্য বৈশিষ্ট্য স্পর্শ করে কিনা তা পরীক্ষা করে দেখতে পারেন। স্পর্শ করে এমন শিখুনের আদেশ তালিকা থেকে, সর্বনিম্ন এবং সেট থেকে সর্বোচ্চটি নিন। তারপরে, প্রতিটি বৈশিষ্ট্য থেকে দুটি লাইন তৈরি করুন: এ: (শুরু, ..., মিনিট) এবং বি: (সর্বোচ্চ, ..., শেষ)।

আর একটি অপশন, যদিও আমি নিশ্চিত নই যে আরকিপিসি ইনপুট অবজেক্টে উল্লম্ব ক্রমের ভিত্তিতে ফিচার পার্ট অর্ডারিং সংরক্ষণ করে কিনা, ক্লিপটি যেমন হয় তেমন চালানো হবে। আপনার উদাহরণের মাঝের লাইনের জন্য, এর তিনটি অংশ সহ একাধিক বৈশিষ্ট্য হওয়া উচিত। অর্ডারের উপর নির্ভর করে, আপনি ক্লিপ দ্বারা উত্পাদিত প্রতিটি মাল্টিপার্ট লাইনটি পুনরাবৃত্তি করতে এবং আউট মাল্টিপার্ট বৈশিষ্ট্যের প্রথম এবং শেষ অংশ বাদে সমস্ত সরিয়ে ফেলতে পারেন।


3

এই ক্ষেত্রে তিনটি সমস্যা নিয়ে লড়াই করতে হবে:

  • গর্ত
  • বহুভুজ মধ্যে লাইন
  • শেষ লাইন

এখানে চিত্র বর্ণনা লিখুন

গর্ত

যেহেতু কোনও গর্তের মধ্যে যে কোনও লাইন বজায় থাকবে, তাই বহুভুজগুলি থেকে গর্তগুলি সরিয়ে দিন। নীচের স্ক্রিপ্টে আমি কার্সার এবং জ্যামিতির ব্যবহার করে এটি করি।

বহুভুজ মধ্যে লাইন

দুটি বহুভুজের স্পর্শযুক্ত লাইনগুলি সরানো দরকার। নীচের স্ক্রিপ্টে আমি একটি one to manyইনপুট বৈশিষ্ট্য শ্রেণি হিসাবে আমার লাইন এবং আমার যোগদান বৈশিষ্ট্য শ্রেণীর হিসাবে বহুভুজগুলি দিয়ে একটি স্থানিক যোগদানের মাধ্যমে এটি করি। যে দুটি লাইন দু'বার উত্পন্ন হয় দুটি বহুভুজকে স্পর্শ করে এবং সরানো হয়।

শেষ লাইন

কেবল এক প্রান্তে বহুভুজকে স্পর্শ করা লাইনগুলি সরাতে, আমি লাইনগুলি শেষ বিন্দুতে রূপান্তর করি। আমি এর পরে কোন শেষ পয়েন্টগুলি ফ্লাটার তা নির্ধারণ করতে বৈশিষ্ট্য স্তর এবং নির্বাচনগুলি ব্যবহার করি। বহুভুজকে ছেদ করে এমন শেষ পয়েন্টগুলি নির্বাচন করি। আমি তারপরে আমার নির্বাচনটি স্যুইচ করি। এটি শেষের পয়েন্টগুলি নির্বাচন করে যা বহুভুজকে ছেদ করে না। আমি এই নির্বাচিত পয়েন্টগুলিকে ছেদ করে যে কোনও লাইন নির্বাচন করি এবং সেগুলি মুছি।

ফলাফল

এখানে চিত্র বর্ণনা লিখুন

অনুমিতি

  • ইনপুটগুলি ফাইল জিওডাটাবেস বৈশিষ্ট্য ক্লাস
  • আর্কজিআইএস অ্যাডভান্সড লাইসেন্স উপলব্ধ (এক eraseএবং এ কারণে feature vertices to points)
  • অবিচ্ছিন্ন, সংযুক্ত লাইনগুলি একটি একক বৈশিষ্ট্য
  • বহুভুজ কোনও ওভারল্যাপ করে না
  • কোনও মাল্টিপার্ট বহুভুজ নেই

লিপি

নীচের স্ক্রিপ্টটি আপনার লাইন বৈশিষ্ট্য বর্গের _GreedyClipএকই জিওডাটাবেজে আপনার লাইন বৈশিষ্ট্য বর্গের প্লাসের নামের সাথে একটি বৈশিষ্ট্য শ্রেণিকে আউটপুট করে । একটি কর্মক্ষেত্রের অবস্থানও প্রয়োজন।

#input polygon feature class
polyFc = r"C:\Users\e1b8\Desktop\E1B8\Workspace\Workspace.gdb\testPolygon2"
#input line feature class
lineFc = r"C:\Users\e1b8\Desktop\E1B8\Workspace\Workspace.gdb\testLine"
#workspace
workspace = r"in_memory"

print "importing"
import arcpy
import os

#generate a unique ArcGIS file name
def UniqueFileName(location = "in_memory", name = "file", extension = ""):
    if extension:
        outName = os.path.join (location, name + "." + extension)
    else:
        outName = os.path.join (location, name)
    i = 0
    while arcpy.Exists (outName):
        i += 1
        if extension:
            outName = os.path.join (location, "{0}_{1}.{2}".format (name, i, extension))
        else:
            outName = os.path.join (location, "{0}_{1}".format (name, i))
    return outName

#remove holes from polygons
def RemoveHoles (inFc, workspace):
    outFc = UniqueFileName (workspace)
    array = arcpy.Array ()
    sr = arcpy.Describe (inFc).spatialReference
    outPath, outName = os.path.split (outFc)
    arcpy.CreateFeatureclass_management (outPath, outName, "POLYGON", spatial_reference = sr)
    with arcpy.da.InsertCursor (outFc, "SHAPE@") as iCurs:
        with arcpy.da.SearchCursor (inFc, "SHAPE@") as sCurs:
            for geom, in sCurs:
                try:
                    part = geom.getPart (0)
                except:
                    continue
                for pnt in part:
                    if not pnt:
                        break
                    array.add (pnt)
                polygon = arcpy.Polygon (array)
                array.removeAll ()
                row = (polygon,)
                iCurs.insertRow (row)
    del iCurs
    del sCurs
    return outFc

#split line fc by polygon fc
def SplitLinesByPolygon (lineFc, polygonFc, workspace):
    #clip
    clipFc = UniqueFileName(workspace)
    arcpy.Clip_analysis (lineFc, polygonFc, clipFc)
    #erase
    eraseFc = UniqueFileName(workspace)
    arcpy.Erase_analysis (lineFc, polygonFc, eraseFc)
    #merge
    mergeFc = UniqueFileName(workspace)
    arcpy.Merge_management ([clipFc, eraseFc], mergeFc)
    #multipart to singlepart
    outFc = UniqueFileName(workspace)
    arcpy.MultipartToSinglepart_management (mergeFc, outFc)
    #delete intermediate data
    for trash in [clipFc, eraseFc, mergeFc]:
        arcpy.Delete_management (trash)
    return outFc

#remove lines between two polygons and end lines
def RemoveLines (inFc, polygonFc, workspace):
    #check if "TARGET_FID" is in fields
    flds = [f.name for f in arcpy.ListFields (inFc)]
    if "TARGET_FID" in flds:
        #delete "TARGET_FID" field
        arcpy.DeleteField_management (inFc, "TARGET_FID")
    #spatial join
    sjFc = UniqueFileName(workspace)
    arcpy.SpatialJoin_analysis (inFc, polygonFc, sjFc, "JOIN_ONE_TO_MANY")
    #list of TARGET_FIDs
    targetFids = [fid for fid, in arcpy.da.SearchCursor (sjFc, "TARGET_FID")]
    #target FIDs with multiple occurances
    deleteFids = [dFid for dFid in targetFids if targetFids.count (dFid) > 1]
    if deleteFids:
        #delete rows with update cursor
        with arcpy.da.UpdateCursor (inFc, "OID@") as cursor:
            for oid, in cursor:
                if oid in deleteFids:
                    cursor.deleteRow ()
        del cursor
    #feature vertices to points
    vertFc = UniqueFileName(workspace)
    arcpy.FeatureVerticesToPoints_management (inFc, vertFc, "BOTH_ENDS")
    #select points intersecting polygons
    arcpy.MakeFeatureLayer_management (vertFc, "vertLyr")
    arcpy.SelectLayerByLocation_management ("vertLyr", "", polygonFc, "1 FEET")
    #switch selection
    arcpy.SelectLayerByAttribute_management ("vertLyr", "SWITCH_SELECTION")
    arcpy.MakeFeatureLayer_management (inFc, "lineLyr")
    #check for selection
    if arcpy.Describe ("vertLyr").FIDSet:
        #select lines by selected points
        arcpy.SelectLayerByLocation_management ("lineLyr", "", "vertLyr", "1 FEET")
        #double check selection (should always have selection)
        if arcpy.Describe ("lineLyr").FIDSet:
            #delete selected rows
            arcpy.DeleteFeatures_management ("lineLyr")

    #delete intermediate data
    for trash in [sjFc, "vertLyr", "lineLyr"]:
        arcpy.Delete_management (trash)

#main script
def main (polyFc, lineFc, workspace):

    #remove holes
    print "removing holes"
    holelessPolyFc = RemoveHoles (polyFc, workspace)

    #split line at polygons
    print "splitting lines at polygons"
    splitFc = SplitLinesByPolygon (lineFc, holelessPolyFc, workspace)

    #delete unwanted lines
    print "removing unwanted lines"
    RemoveLines (splitFc, polyFc, workspace)

    #create output feature class
    outFc = lineFc + "_GreedyClip"
    outFcPath, outFcName = os.path.split (outFc)
    outFc = UniqueFileName (outFcPath, outFcName)
    arcpy.CopyFeatures_management (splitFc, outFc)
    print "created:"
    print outFc
    print
    print "cleaning up"
    #delete intermediate data
    for trash in [holelessPolyFc, splitFc]:
        arcpy.Delete_management (trash)

    print "done"                    

if __name__ == "__main__":
    main (polyFc, lineFc, workspace)  

ভাল সমাধান এমিল। এটি আমার সাথে শেষ হওয়ার চেয়ে কম কোড।
মাইক বেনিস্টার
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.