Creating new point on existing line

Hello,

My question is: Is there a way to define a new point on an existing line, based on the distance from one of the two points defining the line, preferably in percentages?
The situation: I want to crop a model in a standardized way by using cut planes. For my model, there are only a limited number of landmarks available, so I would like to create new points to create the plane. I found two good landmarks/points to use and placed a line in between these points. Now I would like to create a new point on this line. This point should be placed on 80% of the distance between the points, starting from one of the points defining this line. E.g. if the line (defined by points A and B) is 10 cm long, I would like a point C on this line that is 8 cm away from A and 2 from B.
I realize that this can probably be done by defining a sphere with a defined radius (e.g. 8 cm) and point A as the center and by then trying to intersect this sphere and the line to create the point. Although this seems like a long process to me. Is there any other way to obtain this point?

Thanks in advance!

This is doable with a few lines of python code. First off though, line tool in slicer is restricted to two control points. So you can’t really add a third one to it. But you can do what you describe with the open curve tool, which will allow you do what you described. The rest is geometry.

Take a look at the python script repository to see how you can interact markups programmatically.

https://slicer.readthedocs.io/en/latest/developer_guide/script_repository.html#adding-control-points-programmatically

Do you mean a markups line node ? As @muratmaga said, there can be only 2 points.

We may conclude that you are interested in a point coordinate only, is it so ?

Yes, I only need the point coordinate. I just wondered if there was any tool that allows to slide a point along a line (markups line node). This would allow me to see how the position of this point affects my plane. Does there exist anything like that (or is it easy to code)?

Right now, I fixed it with this script, but it still requires to define the desired distance between the two points. (I’m new to coding in python, so my apologies if the code is not so elegant).

pointListNode = slicer.util.getNode(“F”)
data =
for fidIndex in range(pointListNode.GetNumberOfControlPoints()):
coords=[0,0,0]
pointListNode.GetNthControlPointPosition(fidIndex,coords)
data.append(coords)

distance_between_points = [data[0][0]-data[1][0], data[0][1]-data[1][1], data[0][2]-data[1][2]]
percentage = float(input("What percentage do you want to use? "))
added_value = [i * percentage for i in distance_between_points]
new_coord = [data[0][0]-added_value[0], data[0][1]-added_value[1], data[0][2]-added_value[2]]
slicer.modules.markups.logic().AddControlPoint(new_coord[0], new_coord[1], new_coord[2])

You may use this function to get a coordinate along a line (p1, p2) at a specified distance relative to p2.

def findLinearCoordinateByDistance(p1, p2, difference):
    rp2 = [ p2[0] - p1[0], p2[1] - p1[1], p2[2] - p1[2]]
    lineLength = math.sqrt(vtk.vtkMath().Distance2BetweenPoints(p1, p2))
    factor = (1.0 + (difference / lineLength))
    result = [ p1[0] + (rp2[0] * factor), p1[1] + (rp2[1] * factor), p1[2] + (rp2[2] * factor) ]
    return result

If you have a Fiducial node with 2 points, and you want a third point at 80% distance from p1 :

import math

# Paste the above function

f = slicer.util.getNode("F")
p1 = [ 0.0 ] * 3
p2 = [ 0.0 ] * 3
f.GetNthControlPointPositionWorld(0, p1)
f.GetNthControlPointPositionWorld(1, p2)
lineLength = math.sqrt(vtk.vtkMath().Distance2BetweenPoints(p1, p2))
newCoordinate = findLinearCoordinateByDistance(p1, p2, -lineLength * 0.2)
f.AddControlPointWorld(newCoordinate)

You may check ‘Stenosis measurement : 1D’ module in SlicerVMTK extension, that you may install using the ‘Extensions manager’.

The input is a Markups open curve. In your case, use a curve with 3 points and slide the second point. You may experiment with more points also.

Please note that this module was written for a specific use case, hence its name. I suppose it could fit your purpose AFAIU.