Locating a Depth in Polyline Z

3339
9
Jump to solution
06-07-2013 08:47 AM
AdamGuo
New Contributor II
Hi,
I am stumped. I am trying to locate a point on a 3D line with a measured depth 10170 feet. I am having difficulties of trying to locate the point only using a measured depth number.

The 3D line was created from XYZs points.

Any help would be appreciated.

I have attached the sample line file.

Thank you.
Tags (1)
0 Kudos
1 Solution

Accepted Solutions
T__WayneWhitley
Frequent Contributor
Sorry, the upload didn't work -- here it is, see the attachment.  I don't have 3D analyst so maybe someone who does will help....I am assuming that ext can easily solve this problem.  ...maybe network analyst can as well?  I am surprised I couldn't get linear referencing tools to do it, but maybe I'm missing something.

Enjoy,
Wayne

View solution in original post

0 Kudos
9 Replies
T__WayneWhitley
Frequent Contributor
Adam, I posted at the other thread -- I don't think it is too impractical to use the workflow:

1- calculate the xyz midpoint geom property of the line or lines...
2- use Make XY event layer to produce the points (don't forget your computed Z coord).
3- use split line at point:

Split Line At Point (Data Management)
Desktop » Geoprocessing » Tool reference » Data Management toolbox
http://resources.arcgis.com/en/help/main/10.1/index.html#//00170000003w000000


Maybe that'll work?  I'd be interested to know.


-Wayne
0 Kudos
AdamGuo
New Contributor II
Wayne thank you for your quick reply.

The problem with this is not finding the midpoint unfortunately. What I am trying to find is the point location on a 3d line with the 3d length of 10170 ft (without using XYZ coordinates). The 3d line itself is 16108.6 ft long.

I have tried converting the line into a polyline zm and used linear referencing, but that didn't give me a correct 3d length.
0 Kudos
T__WayneWhitley
Frequent Contributor
Hmmm, I think I see what you mean about the Linear Referencing, Create Routes seems to only create a route that is about 7034 ft long... probably there's a better way with the 3D analyst ext, or some related tool - I'm a little out of my depth here (pardon the pun).

Interesting problem though, and I did notice this - your linework in the XY extent really gets narrowly focused before a depth of about 8840 ft and the general XY extent in this region is 2059589, 254120; 2059602, 254140 (xy min; xy max).  602 -589 = 13 and 140 - 120 = 20, so in an approx 13' x 20' area.  I don't know if this fits your 'real' world situation...

This I got from Feature Vertices to Points to get PointZM points from which the Z value was calculated with Calculate Geometry...

Don't know if that'll make sense to you, but I'll attach that point shp here.  Sorry I don't have a solution...


-Wayne
0 Kudos
T__WayneWhitley
Frequent Contributor
Sorry, the upload didn't work -- here it is, see the attachment.  I don't have 3D analyst so maybe someone who does will help....I am assuming that ext can easily solve this problem.  ...maybe network analyst can as well?  I am surprised I couldn't get linear referencing tools to do it, but maybe I'm missing something.

Enjoy,
Wayne
0 Kudos
AdamGuo
New Contributor II
Hi Wayne,

Thank you for your help. I finally figured out the steps to get this to work correctly about 80% of the time now. Instead of create route using the single line, I found that I needed to split the line at the vertices to get the individual segments and calc their 3d length in the attribute table using calc geometry. After that, use linear referencing to create route and then go into edit session and use the split tool to split by measured distance.

The reason for working only 80% of time is because now I am working with a different line and the created route distance just doesn't match up with the 3d length for some reason (I tried the above steps for 5 different lines now and it worked like a charm.).

Do you have much experience in linear referencing by chance, I am having a hard time trying to figure where to post this new error I have in the forum.

I think the error is caused by how the tool calculates the route, but I am not sure.
0 Kudos
AdamGuo
New Contributor II
I've been tinkering with this all morning now. To get the most accuracy out of linear referencing, I needed to create the "From" and "To" columns based off the 3d lengths of individual line segments instead of letting Arc generalize the distances.

Thanks for your help again.
0 Kudos
T__WayneWhitley
Frequent Contributor
I was intrigued by this problem and thought you'd be interested to know I was able to precisely locate your point along the 3d line using some simple Python scripting... 3D Analyst would have been useful particularly if the line contained curves; it did not (shapefiles do not support true curve geometry), so I was able to proceed with a very straightforward technique:

- Use the distance formula (sqrt of the total sum of squares of the delta X,Y, and Z components) to cumulatively add segment distances between vertices until exceeding your target 3D distance on the line.  Exiting at that point identifies the target segment 'range'.

- Since dealing with a straight line segment (and the segment has been found in preceding step), the distance along the segment can be interpolated, i.e., it is the same proportion for each X, Y, Z component.

- Once the point coordinates was calculated, I created a new point object using the calculated XYZ values and loaded it into your point layer via an insertcursor, which I then proceeded to use in 'breaking' the line at your 10170' distance (for verification).

That last step I used so that the Calculate Geometry result for the 3d distance would be shown, see the attached.

Again, note that if you had a fc with true curves, this interpolation method would not directly apply.  I realize too this is not the Python forum, but thought this particular problem was very well suited for this approach.  I 'cleaned' the below edited code from an IDLE session I was using, but didn't do a final test, so use at your discretion.  I wrote this in a bit of a hurry to move on to something else, so just let me know if something doesn't make sense or I made an omission.

No error trapping was used - for demo purposes only.

Enjoy,
Wayne

import arcpy, time

# Define a function to 'handle' 2 input point XYZ coords, computing the distance between.
def Dist3d(x1,y1,z1,x2,y2,z2):
 deltaX = x1 - x2
 deltaY = y1 - y2
 deltaZ = z1-z2
 distance = (deltaX**2 + deltaY**2 + deltaZ**2)**0.5
 return distance

# Your shapefile (change the pathname accordingly).
shp = r'F:\Well_Bore\Well_Bore.shp'

# The point distance of interest, in this case, 10170.0
ptDistOfInterest = 10170.0

# Open a cursor, fetching the 1st row feature geometry.
rows = arcpy.SearchCursor(shp)
row = rows.next()
feat = row.Shape

# Listing a few properties, just curious...
# For the line feat in this thread:
print feat.type   # prints 'polyline'
print feat.isMultipart   # prints 'False'
print feat.partCount   # prints '1'
print feat.length   # prints '7034.13303256'
print feat.length3D   # prints '16108.56262561997'

pointBgn = feat.firstPoint
print pointBgn.Z   # prints '0.0'

pointEnd = feat.lastPoint
print pointEnd.Z   # prints '-9381.4961999999941'

# The 'getPart' method returns an array of points.
theGeomPtArray = feat.getPart(0)
print theGeomPtArray.count   # prints '197'

# Initializing a cumulative distance variable.
cumulativeD = 0.0

# Looping on the array, computing the distances, breaking at 10170.0...
for i in range(theGeomPtArray.count - 1):
 pt1 = theGeomPtArray.getObject(i)
 pt2 = theGeomPtArray.getObject(i + 1)
 x1,x2 = pt1.X, pt2.X
 y1,y2 = pt1.Y, pt2.Y
 z1,z2 = pt1.Z, pt2.Z
 cumulativeD += Dist3d(x1, y1, z1, x2, y2, z2)
 if cumulativeD > ptDistOfInterest:
  k = i
  break

 
# Need to know the break point:
print k   # prints '124'

# Need to know the current cumulative distance:
print cumulativeD   # prints '10193.8322556'

# Need to fetch the 2 point objects from the array.
# The point distance specified is on this segment.
ptBrk = theGeomPtArray.getObject(k)
print ptBrk.X, ptBrk.Y, ptBrk.Z
# (2059018.4176586419, 254935.63821481168, -9491.9726999999984)

ptBrkNext = theGeomPtArray.getObject(k+1)
print ptBrkNext.X, ptBrkNext.Y, ptBrkNext.Z
# (2059003.0216920525, 254967.06695772707, -9491.7893999999942)

# Assign to vars to pass to the dist function...
x1,y1,z1 = ptBrkNext.X, ptBrkNext.Y, ptBrkNext.Z
x2,y2,z2 = ptBrk.X, ptBrk.Y, ptBrk.Z

segDistance = Dist3d(x1, y1, z1, x2, y2, z2)
print segDistance   # prints '34.9976465974'

# The break in the loop exit value for cumulativeD included the segment.
# ...so the current segment has to be 'backed off' (subtracted).
priorDist = cumulativeD - segDistance
print priorDist   # prints '10158.834609'

# Then, the distance to add from prior point:
addDist = 10170.0 - priorDist
print addDist   # prints '11.1653910146'

# And with that, we compute the proportion for interpolation...
proportion = addDist/segDistance
print proportion   # prints '0.319032623624'

# Proceed with the interpolation - X, Y, and Z:
Xonseg = proportion*(x1 - x2) + x2
Yonseg = proportion*(y1 - y2) + y2
Zonseg = proportion*(z1 - z2) + z2

# This is your point of interest, the coordinates:
print Xonseg   # prints '2059013.5058430277'
print Yonseg   # prints '254945.66500912118'
print Zonseg   # prints '-9491.91422132'

# Pause in order to read the output.
time.sleep(10)


The output simply prints point coordinates to the screen, but say you wanted to see the point- for example, appended to the 'feature vertices to points' output shapefile (I did this as well), then that's easy using this (careful with schema-locking):
#  Additional code, append the result to WellPointZM,
#  for visual inspection purposes of the above code.
WellPointZM = r'F:\Well_Bore\WellPointZM.shp'

# First create a pt obj, using coordinates.
# This uses coords computed in previous code above...
pnt = arcpy.Point(Xonseg, Yonseg, Zonseg)

insertPt = arcpy.InsertCursor(WellPointZM)
addPT = insertPt.newRow()
addPT.Shape = pnt
insertPt.insertRow(addPT)
del insertPt    # the cursor to 'unlock'
0 Kudos
T__WayneWhitley
Frequent Contributor
I had time to look at the Linear Referencing again...

What I did to make the Linear Referencing work was to use Calibrate Routes after Create Routes...

I calculated the POINT_M field in the attached point layer, much like I did in the Python script (except with Python did not store the distances in an attribute table), then used this point layer field to 'Calibrate Routes' on the initially created route (the output from 'Create Routes').

When I used 'Make Route Event Layer', using a 'dummy' spreadsheet table with the specified value as part of a single record, I got the desired point, same as the script result.

The 'corrected' or calibrated route shapefile is also attached.  I don't know why the initial Create Routes execution didn't do the job, but nice to know the Calibrate Routes can override the result.

Enjoy,
Wayne
0 Kudos
thelishier
New Contributor

I wonder if we have an easier solution on this topic since it's 10 years later and Arc Pro is here.

0 Kudos