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.
Solved! Go to Solution.
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()
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: