I am trying to convert the measured 3D points data into 3D lines. The data is underground vertical well data. When I am converting from points to line the conversion process is failing to capture the Z values and the lines are being drawn on the surface horizontally. I can understand the issue but I am not sure how to solve it. Any suggestions would be helpful.
Thank you.
This is the code that you could use to convert the csv into a 3D polyline:
def main(): import csv import arcpy # input csv csv_path = r"C:\Forum\3Dpnts_3Dlines\SampleData_well.csv" fld_x = 'bh_long' fld_y = 'bh_lat' fld_z = 'Z' fld_order = 'measdpth' fld_lineid = 'api_wellno' # settings sr = arcpy.SpatialReference(4326) # WGS_1984 arcpy.env.overwriteOutput = True feetinmeter = 0.3048 # output featureclass (could also point to fc in fgdb) fc = r"C:\Forum\3Dpnts_3Dlines\shp\test01.shp" lineids = [] dct = {} # read csv with open(csv_path, 'rb') as f: reader = csv.reader(f) cnt = 0 for row in reader: cnt += 1 if cnt == 1: # header header = row else: # read fields from data lineid = row[header.index(fld_lineid)] x = float(row[header.index(fld_x)]) y = float(row[header.index(fld_y)]) z = float(row[header.index(fld_z)]) * feetinmeter # create point object with XYZ pnt = arcpy.Point(x, y, z) # read order and create string to sort on (lineid + order) order = row[header.index(fld_order)] srt = "{0}_{1}".format("%04d" % (int(lineid),), "{0}".format(round(float(order), 1)).zfill(8)) # create nested dictionary with points per line if lineid in dct: dct[lineid][srt] = pnt else: dct[lineid] = {} dct[lineid][srt] = pnt # create polylines lst_polylines = [] for lineid, dct2 in dct.items(): lst_pnt = [] for srt, pnt in sorted(dct2.items()): lst_pnt.append(pnt) polyline = arcpy.Polyline(arcpy.Array(lst_pnt), sr, True, False) lst_polylines.append(polyline) # write polylines to output featureclass arcpy.CopyFeatures_management(lst_polylines, fc) if __name__ == '__main__': main()
If the standard tool is not working, you could always use some Python code to create the 3D lines. The thread below shows a snippet to convert a 2D polygon into a 3D polygon (and later into a PolylineZM). Re: M for a XYZ polyline
I guess the code can be adjusted to read a 3D point featureclass and create 3D lines.
If you are willing to share some sample data I can adjust the code.
Howdy Bakker,
Thank you for your direction. I will first try to develop the python code based on your link. If I am unable to solve the issue, I am willing to share a sample dataset with you. Is there any way I can send the dataset directly ?
Thank you once again.
Raghuveer
If your data is classified, and you can't share it, then don't share it. No problem. It will help in order to determine if there is a field that identifies which points below to which line, the order of the points and if other attributes should be considered (also if the geometry is 3D or the Z is stored as attribute).
In case you need further assistance please specify those details and the version of ArcGIS you have installed.
If you run into problems while coding, you can post back what you have done so far and me and/or other users can provide help in fixing the code.
The data is collected at various depths vertically and we have Z value attribute and other attributes as well.
I am using ArcGIS 10.3
The code below seems to be working...
def main(): import arcpy import os arcpy.env.overwriteOutput = True fc_pnt = r"D:\Xander\GeoNet\3Dpoints_3Dlines\gdb\test.gdb\points3D_v02" fc_z = r"D:\Xander\GeoNet\3Dpoints_3Dlines\gdb\test.gdb\polylineZ" fld_lineid = "LineID" fld_order = "Elevation" # create a new fc Z enabled, but no M values fc_ws, fc_name = os.path.split(fc_z) arcpy.CreateFeatureclass_management(fc_ws, fc_name, "POLYLINE", fc_pnt, "DISABLED", "ENABLED", fc_pnt) # write the geometries to the new fc sr = arcpy.Describe(fc_pnt).spatialReference # flds_in = ("SHAPE@", fld_lineid, fld_order) fld_shp_in = arcpy.Describe(fc_pnt).shapeFieldName sort_flds = "{0} A; {1} A".format(fld_lineid, fld_order) flds_in = "{0}; {1}; {2}".format(fld_shp_in, fld_lineid, fld_order) flds_out = ("SHAPE@", fld_lineid) lineid = "NotSet" lst_poly_z = [] with arcpy.da.InsertCursor(fc_z, flds_out) as curs_out: curs = arcpy.SearchCursor(fc_pnt, fields=flds_in, sort_fields=sort_flds) for row in curs: pnt = row.getValue(fld_shp_in) prev_lineid = lineid lineid = row.getValue(fld_lineid) if prev_lineid == lineid: # add point to line lst_poly_z.append(pnt.firstPoint) else: # write previous line and start new one if len(lst_poly_z) > 1: polyline_z = arcpy.Polyline(arcpy.Array(lst_poly_z), sr, True, False) row_out = [polyline_z, prev_lineid] curs_out.insertRow(tuple(row_out)) lst_poly_z = [] lst_poly_z.append(pnt.firstPoint) # write last polyline if len(lst_poly_z) > 1: polyline_z = arcpy.Polyline(arcpy.Array(lst_poly_z), sr, True, False) row_out = [polyline_z, lineid] curs_out.insertRow(tuple(row_out)) del curs, row if __name__ == '__main__': main()
Bakker,
Finally I got permission to share some sample dataset
Hi Naga Raghuveer Modala ,
I will have a look at it and come back to you as soon as possible. If I have any questions I will post them here.
BTW, my first name is Xander. You can call me Xander.
Kind regards, Xander
Some assumptions and questions:
Xander,
A small explanation of what is going on, on line 44 and 45:
srt = "{0}_{1}".format("%04d" % (int(lineid),), "{0}".format(round(float(order), 1)).zfill(8))
It creates a string combining the lineid (e.g. 102) and the order (e.g. 5482.0) into a string that will be used as key for the dictionary. The dictionary is sorted on key (see line 58) and the string "srt" will have a value like: "0102_005482.0". This allows to sort on line and per line on order.
See also: Some Python Snippets
I am trying understand this code. When i apply the same code with slight modifications to different set of data. It isn't working correctly. The new data has a lineID of 14 characters and the order varying from 3 to 5 characters.
if the lineid is always 14 characters, or if it is not numerical you could simply do this:
srt = "{0}_{1}".format(lineid, "{0}".format(round(float(order), 1)).zfill(8))
It is probably not important in which order the lines are processed. What is important is the order of the points per line being processed.
Whoop! Its not the code I had problem with. its the format of my CSV columns. After fixing that issue everything looks great. Thank you very much Xander for all your help.
Les membres connectés peuvent publier, suivre les mises à jour, et plus encore. Nouveau ici ? Inscrivez-vous gratuitement.
Find useful guides, FAQs, and documents to help you navigate and make the most of Esri Community.