I'm trying to use Sympy to calculate a point along an extended line segment.
So first I'm setting up a line Segment
between point_a and point_b:
from sympy import Point, Segment
point_a = (4, 1)
point_b = (10, 3)
p1, p2 = Point(point_a), Point(point_b)
seg = Segment(p1, p2)
In this example the length of the segment is approx 6.32455532034
I want to be able to keep point_a
where it is but extend point_b
out so that the length of the segment is 20
(instead of 6.32
)
seg.length = 20
new_end_point = seg.points[1]
However it does not allow the length of the line to be changed like this. Is there a simple way I can do this?
Note 1: that I'm trying to use Sympy for this in order to keep the code readable for non-math people (such as myself)
Note 2: 20
is an arbrary length not related to the starting distance between p1 and p2
Thanks to @smichr for the answer, I have added a simplified version of what he said:
from sympy import Point, Ray, Circle
point_a = (4, 1)
point_b = (10, 3)
extend = 20
p1, p2 = Point(point_a), Point(point_b)
ray = Ray(p1, p2)
c = Circle(p1, extend).intersection(ray)
# The resulting point
result = c[0].evalf().coordinates
Take a segment defined by points
>>> p1=(0,0)
>>> p2=(1,0)
>>> s=Segment(p1,p2)
Cast it to a Ray and see where it intersects the Circle of desired radius, centered on p1. It will only intersect at one point, so use that point for your new segment:
>>> from sympy.abc import t
>>> from sympy import Ray, Circle
>>> Circle(p1, 20).intersection(Ray(*s.args))[0]
Point(20, 0)
>>> new_segment = Segment(p1, _)
You could wrap this into a function like this:
>>> def directed_segment(line, length):
... from sympy import Circle, Ray
... p3 = Ray(*line.args).intersection(Circle(line.p1, length))[0]
... return line.func(line.p1, p3)
...
>>> directed_segment(s,20)
Segment2D(Point2D(0, 0), Point2D(20, 0))
The simplest approach is to just scale the segment in both directions wrt the desired point (first arg, in your case). The scale factor will be your desired length, l
, divided by the current length. A helper function named new_seg
is defined below and used to lengthen a 3,4,5 hypotenuse to a length of 10 while maintaining the initial point of the segment:
new_seg=lambda s,l : s.scale(*[l/s.length]*2, s.args[0])
>>> new_seg(Segment((1,2),(4,6)), 10)
Segment2D(Point2D(1, 2), Point2D(7, 10))
>>> assert _.length == 10
If you used s.midpoint
instead of s.args[0]
then the midpoint of the segment would remain the same. For example, to double the length while maintaining the midpoint,
>>> t=s.scale(2,2,s.midpoint)
>>> assert t.length = 2*s.length and t.midpoint == s.midpoint