Efficient way of finding points for a curve

I have a couple of plugins where I create either an arc or a circle to use as a path, collect the vertices, and then abort the operation…

it’s fine when only needed once, but I now only need three points, recalculated many times,

given points A, B, what is the best formula to find C and D?

I also know the distance between C, B, D…

A and B could be anywhere in 3D space…


My first thoughts…

clone pointB as pointC
make a rotation transformation [tr] about pointA using the Z_AXIS and the desired angle

repeat for pointD with a negative rotation angle.

If you want an ‘offset’ dimension rather than an angle, you can get the flat-radius using Pythag.
Using the flat-radius and desired ‘offset’ you can get the angle for the transformation rotation, OR calculate the new point directly…


Although you could try some basic 2D trigonometry, I would recommend using 3D transformations instead. Point A can be projected onto the X-Y plane as point E. Since it is the main X-Y plane through the origin, its coordinates would be <A.x, B.y, and zero>. Given A and B as Point3d variables “point_A” and “point_B”, expanding upon what @TIG said:

point_E = Geom::Point3d.new( point_A.x, point_A.y, 0.0)
angle = 360.0 / 24.0
rotation_EZ = Geom::Transformation.rotation( point_E, Z_AXIS, angle.degrees)

point_C = point_B.transform( rotation_EZ )
point_D = point_B.transform( rotation_EZ.inverse )

I don’t know how to determine the angle from the default circle segment, but I hard coded it to 360/24. You will want to come up with your own value.

I don’t think you need to project point_A onto the ground.
So then you don’t need point_E, because the rotation is around a vector [Z_AXIS] and any point sets the rotation’s transformation around itself using that vector - so point_A works fine as it is.

Otherwise your code is fine…

Since the OP didn’t specify the actual angle through which to rotate the new two points [or how else we might determine the two points’ locations], your idea to take the default circle segmentation at 360/24.0 seems OK for now…

But if the ‘offset’ of the points is a fixed distance from point_B then your earlier approach to project point_A onto the ‘ground’ could be adjusted to take account of point_B’s z value:

point_E = Geom::Point3d.new( point_A.x, point_A.y, point_B.z)

Then the radius of the ‘circle of rotation’ is:

radius = point_E.distance(point_B)

That can then be used to calculate a perpendicular offset from point_B for point_C & D

cheers both for the input…

I did use rotation of the cloned point in the end…

the segment length is a variable that I calculate based on the view and model widths…

angle = (360/segments).degrees rescue 1.degrees

also as it may not be at z == 0 I used [point_A.x, point_A,y, point_B.z] as my second point for the radius…

I also needed to calculate the vector as Z_axis failed in some scenario’s…

I’ll add a gif when I advance it a bit more…

You also do not need the flattened point_E in this scenario as Array has been extended with an API #distance method.

radius = [ point_A.x, point_A.y, point_B.z ].distance(point_B)

For the angles, this is simple trigo geometry. If dBC and dBD are equal, you can use the transformation to build the whole arc.

#Given <ptA>, <ptB> and the chord distances <dBC> and <dBD>
normal = Z_AXIS
center = ptA.project_to_plane([ptB, normal])
radius = center.distance(ptB)
angleBC = 2 * Math.asin(0.5 * dBC / radius)    #isocele triangle
angleBD = 2 * Math.asin(0.5 * dBD / radius)    #isocele triangle
ptC = Geom::Transformation.rotation(center, normal, angleBC) * ptB
ptD = Geom::Transformation.rotation(center, normal, -angleBD) * ptB
1 Like