def equation(self, x='x', y='y'): """The equation of the line: ax + by + c. Parameters ---------- x : str, optional The name to use for the x-axis, default value is 'x'. y : str, optional The name to use for the y-axis, default value is 'y'. Returns ------- equation : sympy expression Examples -------- >>> from sympy import Point, Line >>> p1, p2 = Point(1, 0), Point(5, 3) >>> l1 = Line(p1, p2) >>> l1.equation() -3*x + 4*y + 3 """ x, y = _symbol(x), _symbol(y) p1, p2 = self.points if p1[0] == p2[0]: return x - p1[0] elif p1[1] == p2[1]: return y - p1[1] a, b, c = self.coefficients return simplify(a*x + b*y + c)
def equation(self, x='x', y='y'): """The equation of the circle. Parameters ========== x : str or Symbol, optional Default value is 'x'. y : str or Symbol, optional Default value is 'y'. Returns ======= equation : SymPy expression Examples ======== >>> from sympy import Point, Circle >>> c1 = Circle(Point(0, 0), 5) >>> c1.equation() x**2 + y**2 - 25 """ x = _symbol(x) y = _symbol(y) t1 = (x - self.center.x)**2 t2 = (y - self.center.y)**2 return t1 + t2 - self.major**2
def equation(self, x='x', y='y'): """The equation of the ellipse. Parameters ========== x : str, optional Label for the x-axis. Default value is 'x'. y : str, optional Label for the y-axis. Default value is 'y'. Returns ======= equation : sympy expression See Also ======== arbitrary_point : Returns parameterized point on ellipse Examples ======== >>> from sympy import Point, Ellipse >>> e1 = Ellipse(Point(1, 0), 3, 2) >>> e1.equation() y**2/4 + (x/3 - 1/3)**2 - 1 """ x = _symbol(x) y = _symbol(y) t1 = ((x - self.center.x) / self.hradius)**2 t2 = ((y - self.center.y) / self.vradius)**2 return t1 + t2 - 1
def equation(self, x="x", y="y"): """The equation of the ellipse. Parameters ---------- x : str, optional Label for the x-axis. Default value is 'x'. y : str, optional Label for the y-axis. Default value is 'y'. Returns ------- equation : sympy expression Examples -------- >>> from sympy import Point, Ellipse >>> e1 = Ellipse(Point(1, 0), 3, 2) >>> e1.equation() y**2/4 + (x/3 - 1/3)**2 - 1 """ x = _symbol(x) y = _symbol(y) t1 = ((x - self.center[0]) / self.hradius) ** 2 t2 = ((y - self.center[1]) / self.vradius) ** 2 return t1 + t2 - 1
def equation(self, x="x", y="y"): """The equation of the circle. Parameters ---------- x : str or Symbol, optional Default value is 'x'. y : str or Symbol, optional Default value is 'y'. Returns ------- equation : sympy expression Examples -------- >>> from sympy import Point, Circle >>> c1 = Circle(Point(0, 0), 5) >>> c1.equation() x**2 + y**2 - 25 """ x = _symbol(x) y = _symbol(y) t1 = (x - self.center[0]) ** 2 t2 = (y - self.center[1]) ** 2 return t1 + t2 - self.major ** 2
def plot_interval(self, parameter='t'): """The plot interval for the default geometric plot of the Ray. Gives values that will produce a ray that is 10 units long (where a unit is the distance between the two points that define the ray). Parameters ========== parameter : str, optional Default value is 't'. Returns ======= plot_interval : list [parameter, lower_bound, upper_bound] Examples ======== >>> from sympy import Point, Ray, pi >>> r = Ray((0, 0), angle=pi/4) >>> r.plot_interval() [t, 0, 10] """ t = _symbol(parameter) return [t, 0, 10]
def plot_interval(self, parameter='t'): """The plot interval for the default geometric plot of the curve. Parameters ---------- parameter : str or Symbol, optional Default value is 't'; otherwise the provided symbol is used. Returns ------- plot_interval : list (plot interval) [parameter, lower_bound, upper_bound] Examples -------- >>> from sympy import Curve, sin >>> from sympy.abc import x, t, s >>> Curve((x, sin(x)), (x, 1, 2)).plot_interval() [t, 1, 2] >>> Curve((x, sin(x)), (x, 1, 2)).plot_interval(s) [s, 1, 2] """ t = _symbol(parameter, self.parameter) return [t] + list(self.limits[1:])
def plot_interval(self, parameter='t'): """The plot interval for the default geometric plot of line. Parameters ========== parameter : str, optional Default value is 't'. Returns ======= plot_interval : list (plot interval) [parameter, lower_bound, upper_bound] Examples ======== >>> from sympy import Point, Line >>> p1, p2 = Point(0, 0), Point(5, 3) >>> l1 = Line(p1, p2) >>> l1.plot_interval() [t, -5, 5] """ t = _symbol(parameter) return [t, -5, 5]
def plot_interval(self, parameter='t'): """The plot interval for the default geometric plot of the Segment. Parameters ========== parameter : str, optional Default value is 't'. Returns ======= plot_interval : list [parameter, lower_bound, upper_bound] Examples ======== >>> from sympy import Point, Segment >>> p1, p2 = Point(0, 0), Point(5, 3) >>> s1 = Segment(p1, p2) >>> s1.plot_interval() [t, 0, 1] """ t = _symbol(parameter) return [t, 0, 1]
def plot_interval(self, parameter='t'): """The plot interval for the default geometric plot of the Ellipse. Parameters ========== parameter : str, optional Default value is 't'. Returns ======= plot_interval : list [parameter, lower_bound, upper_bound] Examples ======== >>> from sympy import Point, Ellipse >>> e1 = Ellipse(Point(0, 0), 3, 2) >>> e1.plot_interval() [t, -pi, pi] """ t = _symbol(parameter) return [t, -S.Pi, S.Pi]
def arbitrary_point(self, parameter="t"): """A parameterized point on the ellipse. Parameters ---------- parameter : str, optional Default value is 't'. Returns ------- arbitrary_point : Point Raises ------ ValueError When `parameter` already appears in the functions. See Also -------- Point Examples -------- >>> from sympy import Point, Ellipse >>> e1 = Ellipse(Point(0, 0), 3, 2) >>> e1.arbitrary_point() Point(3*cos(t), 2*sin(t)) """ t = _symbol(parameter) if t.name in (f.name for f in self.free_symbols): raise ValueError("Symbol %s already appears in object and cannot be used as a parameter." % t.name) return Point(self.center[0] + self.hradius * C.cos(t), self.center[1] + self.vradius * C.sin(t))
def plot_interval(self, parameter='t'): """The plot interval for the default geometric plot of the Ray. Parameters ========== parameter : str, optional Default value is 't'. Returns ======= plot_interval : list [parameter, lower_bound, upper_bound] Examples ======== >>> from sympy import Point, Ray, pi >>> r = Ray((0, 0), angle=pi/4) >>> r.plot_interval() [t, 0, 5*sqrt(2)/(1 + 5*sqrt(2))] """ t = _symbol(parameter) p = self.arbitrary_point(t) # get a t corresponding to length of 10 want = 10 u = Segment(self.p1, p.subs(t, S.Half)).length # gives unit length t_need = want/u return [t, 0, t_need/(1 + t_need)]
def plot_interval(self, parameter='t'): """The plot interval for the default geometric plot of line. Gives values that will produce a line that is +/- 5 units long (where a unit is the distance between the two points that define the line). Parameters ========== parameter : str, optional Default value is 't'. Returns ======= plot_interval : list (plot interval) [parameter, lower_bound, upper_bound] Examples ======== >>> from sympy import Point, Line >>> p1, p2 = Point(0, 0), Point(5, 3) >>> l1 = Line(p1, p2) >>> l1.plot_interval() [t, -5, 5] """ t = _symbol(parameter) return [t, -5, 5]
def arbitrary_point(self, parameter='t'): """A parameterized point on the Segment. Parameters ========== parameter : str, optional The name of the parameter which will be used for the parametric point. The default value is 't'. Returns ======= point : Point Parameters ========== parameter : str, optional The name of the parameter which will be used for the parametric point. The default value is 't'. Returns ======= point : Point Raises ====== ValueError When ``parameter`` already appears in the Segment's definition. See Also ======== sympy.geometry.point.Point Examples ======== >>> from sympy import Point, Segment >>> p1, p2 = Point(1, 0), Point(5, 3) >>> s1 = Segment(p1, p2) >>> s1.arbitrary_point() Point(4*t + 1, 3*t) """ t = _symbol(parameter) if t.name in (f.name for f in self.free_symbols): raise ValueError('Symbol %s already appears in object and cannot be used as a parameter.' % t.name) x = simplify(self.p1.x + t*(self.p2.x - self.p1.x)) y = simplify(self.p1.y + t*(self.p2.y - self.p1.y)) return Point(x, y)
def arbitrary_point(self, parameter='t'): """ A parameterized point on the curve. Parameters ========== parameter : str or Symbol, optional Default value is 't'; the Curve's parameter is selected with None or self.parameter otherwise the provided symbol is used. Returns ======= arbitrary_point : Point Raises ====== ValueError When `parameter` already appears in the functions. See Also ======== sympy.geometry.point.Point Examples ======== >>> from sympy import Symbol >>> from sympy.abc import s >>> from sympy.geometry import Curve >>> C = Curve([2*s, s**2], (s, 0, 2)) >>> C.arbitrary_point() Point(2*t, t**2) >>> C.arbitrary_point(C.parameter) Point(2*s, s**2) >>> C.arbitrary_point(None) Point(2*s, s**2) >>> C.arbitrary_point(Symbol('a')) Point(2*a, a**2) """ if parameter is None: return Point(*self.functions) tnew = _symbol(parameter, self.parameter) t = self.parameter if (tnew.name != t.name and tnew.name in (f.name for f in self.free_symbols)): raise ValueError('Symbol %s already appears in object ' 'and cannot be used as a parameter.' % tnew.name) return Point(*[w.subs(t, tnew) for w in self.functions])
def equation(self, x='x', y='y'): """The equation of the line: ax + by + c. Parameters ========== x : str, optional The name to use for the x-axis, default value is 'x'. y : str, optional The name to use for the y-axis, default value is 'y'. Returns ======= equation : sympy expression See Also ======== LinearEntity.coefficients Examples ======== >>> from sympy import Point, Line >>> p1, p2 = Point(1, 0), Point(5, 3) >>> l1 = Line(p1, p2) >>> l1.equation() -3*x + 4*y + 3 """ x, y = _symbol(x), _symbol(y) p1, p2 = self.points if p1.x == p2.x: return x - p1.x elif p1.y == p2.y: return y - p1.y a, b, c = self.coefficients return simplify(a*x + b*y + c)
def arbitrary_point(self, parameter='t'): """A parameterized point on the polygon. The parameter, varying from 0 to 1, assigns points to the position on the perimeter that is that fraction of the total perimeter. So the point evaluated at t=1/2 would return the point from the first vertex that is 1/2 way around the polygon. Parameters ---------- parameter : str, optional Default value is 't'. Returns ------- arbitrary_point : Point Raises ------ ValueError When `parameter` already appears in the Polygon's definition. See Also -------- Point Examples -------- >>> from sympy import Polygon, S, Symbol >>> t = Symbol('t', real=True) >>> tri = Polygon((0, 0), (1, 0), (1, 1)) >>> p = tri.arbitrary_point('t') >>> perimeter = tri.perimeter >>> s1, s2 = [s.length for s in tri.sides[:2]] >>> p.subs(t, (s1 + s2/2)/perimeter) Point(1, 1/2) """ t = _symbol(parameter) if t.name in (f.name for f in self.free_symbols): raise ValueError('Symbol %s already appears in object and cannot be used as a parameter.' % t.name) sides = [] perimeter = self.perimeter perim_fraction_start = 0 for s in self.sides: side_perim_fraction = s.length/perimeter perim_fraction_end = perim_fraction_start + side_perim_fraction pt = s.arbitrary_point(parameter).subs( t, (t - perim_fraction_start)/side_perim_fraction) sides.append((pt, (perim_fraction_start <= t < perim_fraction_end))) perim_fraction_start = perim_fraction_end return Piecewise(*sides)
def arbitrary_point(self, parameter='t'): """A parameterized point on the Segment. Parameters ---------- parameter : str, optional The name of the parameter which will be used for the parametric point. The default value is 't'. Returns ------- point : Point Parameters ---------- parameter : str, optional The name of the parameter which will be used for the parametric point. The default value is 't'. Returns ------- point : Point Raises ------ ValueError When `parameter` already appears in the Segment's definition. See Also -------- Point Examples -------- >>> from sympy import Point, Segment >>> p1, p2 = Point(1, 0), Point(5, 3) >>> s1 = Segment(p1, p2) >>> s1.arbitrary_point() Point(1 + 4*t, 3*t) """ t = _symbol(parameter) if t.name in (f.name for f in self.free_symbols): raise ValueError('Symbol %s already appears in object and cannot be used as a parameter.' % t.name) x = simplify(self.p1[0] + t*(self.p2[0] - self.p1[0])) y = simplify(self.p1[1] + t*(self.p2[1] - self.p1[1])) return Point(x, y)
def arbitrary_point(self, parameter='t'): """A parameterized point on the Line. Parameters ========== parameter : str, optional The name of the parameter which will be used for the parametric point. The default value is 't'. When this parameter is 0, the first point used to define the line will be returned, and when it is 1 the second point will be returned. Returns ======= point : Point Raises ====== ValueError When ``parameter`` already appears in the Line's definition. See Also ======== sympy.geometry.point.Point Examples ======== >>> from sympy import Point, Line >>> p1, p2 = Point(1, 0), Point(5, 3) >>> l1 = Line(p1, p2) >>> l1.arbitrary_point() Point(4*t + 1, 3*t) """ t = _symbol(parameter) if t.name in (f.name for f in self.free_symbols): raise ValueError('Symbol %s already appears in object ' 'and cannot be used as a parameter.' % t.name) x = simplify(self.p1.x + t*(self.p2.x - self.p1.x)) y = simplify(self.p1.y + t*(self.p2.y - self.p1.y)) return Point(x, y)
def random_point(self): """A random point on the ellipse. Returns ======= point : Point See Also ======== sympy.geometry.point.Point arbitrary_point : Returns parameterized point on ellipse Notes ----- A random point may not appear to be on the ellipse, ie, `p in e` may return False. This is because the coordinates of the point will be floating point values, and when these values are substituted into the equation for the ellipse the result may not be zero because of floating point rounding error. Examples ======== >>> from sympy import Point, Ellipse >>> e1 = Ellipse(Point(0, 0), 3, 2) >>> p1 = e1.random_point() >>> # a random point may not appear to be on the ellipse because of >>> # floating point rounding error >>> p1 in e1 # doctest: +SKIP True >>> p1 # doctest +ELLIPSIS Point(...) """ from random import random t = _symbol("t") x, y = self.arbitrary_point(t).args # get a random value in [-pi, pi) subs_val = float(S.Pi) * (2 * random() - 1) return Point(x.subs(t, subs_val), y.subs(t, subs_val))
def plot_interval(self, parameter='t'): """The plot interval for the default geometric plot of line. Parameters ---------- parameter : str, optional Default value is 't'. Returns ------- plot_interval : list (plot interval) [parameter, lower_bound, upper_bound] Examples -------- >>> from sympy import Point, Line >>> p1, p2 = Point(0, 0), Point(5, 3) >>> l1 = Line(p1, p2) >>> l1.plot_interval() [t, -5, 5] """ t = _symbol(parameter) return [t, -5, 5]
def arbitrary_point(self, parameter='t'): """A parameterized point on the ellipse. Parameters ========== parameter : str, optional Default value is 't'. Returns ======= arbitrary_point : Point Raises ====== ValueError When `parameter` already appears in the functions. See Also ======== sympy.geometry.point.Point Examples ======== >>> from sympy import Point, Ellipse >>> e1 = Ellipse(Point(0, 0), 3, 2) >>> e1.arbitrary_point() Point(3*cos(t), 2*sin(t)) """ t = _symbol(parameter) if t.name in (f.name for f in self.free_symbols): raise ValueError( 'Symbol %s already appears in object and cannot be used as a parameter.' % t.name) return Point(self.center[0] + self.hradius * C.cos(t), self.center[1] + self.vradius * C.sin(t))
def __new__(cls, *args, **kwargs): if kwargs.get('n', 0): n = kwargs.pop('n') args = list(args) # return a virtual polygon with n sides if len(args) == 2: # center, radius args.append(n) elif len(args) == 3: # center, radius, rotation args.insert(2, n) return RegularPolygon(*args, **kwargs) vertices = [Point(a) for a in args] # remove consecutive duplicates nodup = [] for p in vertices: if nodup and p == nodup[-1]: continue nodup.append(p) if len(nodup) > 1 and nodup[-1] == nodup[0]: nodup.pop() # last point was same as first # remove collinear points unless they are shared points got = set() shared = set() for p in nodup: if p in got: shared.add(p) else: got.add(p) i = -3 while i < len(nodup) - 3 and len(nodup) > 2: a, b, c = sorted([nodup[i], nodup[i + 1], nodup[i + 2]]) if b not in shared and Point.is_collinear(a, b, c): nodup[i] = a nodup[i + 1] = None nodup.pop(i + 1) i += 1 vertices = filter(lambda x: x is not None, nodup) if len(vertices) > 3: rv = GeometryEntity.__new__(cls, *vertices, **kwargs) elif len(vertices) == 3: return Triangle(*vertices, **kwargs) elif len(vertices) == 2: return Segment(*vertices, **kwargs) else: return Point(*vertices, **kwargs) # reject polygons that have intersecting sides unless the # intersection is a shared point or a generalized intersection. # A self-intersecting polygon is easier to detect than a # random set of segments since only those sides that are not # part of the convex hull can possibly intersect with other # sides of the polygon...but for now we use the n**2 algorithm # and check all sides with intersection with any preceding sides hit = _symbol('hit') if not rv.is_convex: sides = rv.sides for i, si in enumerate(sides): pts = si[0], si[1] ai = si.arbitrary_point(hit) for j in xrange(i): sj = sides[j] if sj[0] not in pts and sj[1] not in pts: aj = si.arbitrary_point(hit) tx = (solve(ai[0] - aj[0]) or [S.Zero])[0] if tx.is_number and 0 <= tx <= 1: ty = (solve(ai[1] - aj[1]) or [S.Zero])[0] if (tx or ty) and ty.is_number and 0 <= ty <= 1: print ai, aj raise GeometryError("Polygon has intersecting sides.") return rv
def random_point(self, seed=None): """A random point on the ellipse. Returns ======= point : Point See Also ======== sympy.geometry.point.Point arbitrary_point : Returns parameterized point on ellipse Notes ----- A random point may not appear to be on the ellipse, ie, `p in e` may return False. This is because the coordinates of the point will be floating point values, and when these values are substituted into the equation for the ellipse the result may not be zero because of floating point rounding error. Examples ======== >>> from sympy import Point, Ellipse, Segment >>> e1 = Ellipse(Point(0, 0), 3, 2) >>> e1.random_point() # gives some random point Point(...) >>> p1 = e1.random_point(seed=0); p1.n(2) Point(2.1, 1.4) The random_point method assures that the point will test as being in the ellipse: >>> p1 in e1 True Notes ===== An arbitrary_point with a random value of t substituted into it may not test as being on the ellipse because the expression tested that a point is on the ellipse doesn't simplify to zero and doesn't evaluate exactly to zero: >>> from sympy.abc import t >>> e1.arbitrary_point(t) Point(3*cos(t), 2*sin(t)) >>> p2 = _.subs(t, 0.1) >>> p2 in e1 False Note that arbitrary_point routine does not take this approach. A value for cos(t) and sin(t) (not t) is substituted into the arbitrary point. There is a small chance that this will give a point that will not test as being in the ellipse, so the process is repeated (up to 10 times) until a valid point is obtained. """ from sympy import sin, cos, Rational t = _symbol('t') x, y = self.arbitrary_point(t).args # get a random value in [-1, 1) corresponding to cos(t) # and confirm that it will test as being in the ellipse if seed is not None: rng = random.Random(seed) else: rng = random for i in range(10): # should be enough? # simplify this now or else the Float will turn s into a Float c = 2*Rational(rng.random()) - 1 s = sqrt(1 - c**2) p1 = Point(x.subs(cos(t), c), y.subs(sin(t), s)) if p1 in self: return p1 raise GeometryError( 'Having problems generating a point in the ellipse.')
def random_point(self, seed=None): """A random point on the ellipse. Returns ======= point : Point See Also ======== sympy.geometry.point.Point arbitrary_point : Returns parameterized point on ellipse Notes ----- A random point may not appear to be on the ellipse, ie, `p in e` may return False. This is because the coordinates of the point will be floating point values, and when these values are substituted into the equation for the ellipse the result may not be zero because of floating point rounding error. Examples ======== >>> from sympy import Point, Ellipse, Segment >>> e1 = Ellipse(Point(0, 0), 3, 2) >>> e1.random_point() # gives some random point Point(...) >>> p1 = e1.random_point(seed=0); p1.n(2) Point(2.1, 1.4) The random_point method assures that the point will test as being in the ellipse: >>> p1 in e1 True Notes ===== An arbitrary_point with a random value of t substituted into it may not test as being on the ellipse because the expression tested that a point is on the ellipse doesn't simplify to zero and doesn't evaluate exactly to zero: >>> from sympy.abc import t >>> e1.arbitrary_point(t) Point(3*cos(t), 2*sin(t)) >>> p2 = _.subs(t, 0.1) >>> p2 in e1 False Note that arbitrary_point routine does not take this approach. A value for cos(t) and sin(t) (not t) is substituted into the arbitrary point. There is a small chance that this will give a point that will not test as being in the ellipse, so the process is repeated (up to 10 times) until a valid point is obtained. """ from sympy import sin, cos, Rational t = _symbol('t') x, y = self.arbitrary_point(t).args # get a random value in [-1, 1) corresponding to cos(t) # and confirm that it will test as being in the ellipse if seed is not None: rng = random.Random(seed) else: rng = random for i in range(10): # should be enough? # simplify this now or else the Float will turn s into a Float c = 2 * Rational(rng.random()) - 1 s = sqrt(1 - c**2) p1 = Point(x.subs(cos(t), c), y.subs(sin(t), s)) if p1 in self: return p1 raise GeometryError( 'Having problems generating a point in the ellipse.')
def __new__(cls, *args, **kwargs): if kwargs.get('n', 0): n = kwargs.pop('n') args = list(args) # return a virtual polygon with n sides if len(args) == 2: # center, radius args.append(n) elif len(args) == 3: # center, radius, rotation args.insert(2, n) return RegularPolygon(*args, **kwargs) vertices = [Point(a) for a in args] # remove consecutive duplicates nodup = [] for p in vertices: if nodup and p == nodup[-1]: continue nodup.append(p) if len(nodup) > 1 and nodup[-1] == nodup[0]: nodup.pop() # last point was same as first # remove collinear points unless they are shared points got = set() shared = set() for p in nodup: if p in got: shared.add(p) else: got.add(p) i = -3 while i < len(nodup) - 3 and len(nodup) > 2: a, b, c = sorted([nodup[i], nodup[i + 1], nodup[i + 2]]) if b not in shared and Point.is_collinear(a, b, c): nodup[i] = a nodup[i + 1] = None nodup.pop(i + 1) i += 1 vertices = filter(lambda x: x is not None, nodup) if len(vertices) > 3: rv = GeometryEntity.__new__(cls, *vertices, **kwargs) elif len(vertices) == 3: return Triangle(*vertices, **kwargs) elif len(vertices) == 2: return Segment(*vertices, **kwargs) else: return Point(*vertices, **kwargs) # reject polygons that have intersecting sides unless the # intersection is a shared point or a generalized intersection. # A self-intersecting polygon is easier to detect than a # random set of segments since only those sides that are not # part of the convex hull can possibly intersect with other # sides of the polygon...but for now we use the n**2 algorithm # and check all sides with intersection with any preceding sides hit = _symbol('hit') if not rv.is_convex: sides = rv.sides for i, si in enumerate(sides): pts = si[0], si[1] ai = si.arbitrary_point(hit) for j in xrange(i): sj = sides[j] if sj[0] not in pts and sj[1] not in pts: aj = si.arbitrary_point(hit) tx = (solve(ai[0] - aj[0]) or [S.Zero])[0] if tx.is_number and 0 <= tx <= 1: ty = (solve(ai[1] - aj[1]) or [S.Zero])[0] if (tx or ty) and ty.is_number and 0 <= ty <= 1: print ai, aj raise GeometryError( "Polygon has intersecting sides.") return rv
def arbitrary_point(self, parameter='t'): """A parameterized point on the Ray. Parameters ---------- parameter : str, optional The name of the parameter which will be used for the parametric point. The default value is 't'. Returns ------- point : Point Raises ------ ValueError When `parameter` already appears in the Ray's definition. See Also -------- Point Examples -------- >>> from sympy import Ray, Point, Segment, S, simplify, solve >>> from sympy.abc import t >>> r = Ray(Point(0, 0), Point(2, 3)) >>> p = r.arbitrary_point(t) The parameter `t` used in the arbitrary point maps 0 to the origin of the ray and 1 to the end of the ray at infinity (which will show up as NaN). >>> p.subs(t, 0), p.subs(t, 1) (Point(0, 0), Point(oo, oo)) The unit that `t` moves you is based on the spacing of the points used to define the ray. >>> p.subs(t, 1/(S(1) + 1)) # one unit Point(2, 3) >>> p.subs(t, 2/(S(1) + 2)) # two units out Point(4, 6) >>> p.subs(t, S.Half/(S(1) + S.Half)) # half a unit out Point(1, 3/2) If you want to be located a distance of 1 from the origin of the ray, what value of `t` is needed? a) find the unit length and pick t accordingly >>> u = Segment(r[0], p.subs(t, S.Half)).length # S.Half = 1/(1 + 1) >>> want = 1 >>> t_need = want/u >>> p_want = p.subs(t, t_need/(1 + t_need)) >>> simplify(Segment(r[0], p_want).length) 1 b) find the t that makes the length from origin to p equal to 1 >>> l = Segment(r[0], p).length >>> t_need = solve(l**2 - want**2, t) # use the square to remove abs() if it is there >>> t_need = [w for w in t_need if w.n() > 0][0] # take positive t >>> p_want = p.subs(t, t_need) >>> simplify(Segment(r[0], p_want).length) 1 """ t = _symbol(parameter) if t.name in (f.name for f in self.free_symbols): raise ValueError( 'Symbol %s already appears in object and cannot be used as a parameter.' % t.name) m = self.slope x = simplify(self.p1[0] + t / (1 - t) * (self.p2[0] - self.p1[0])) y = simplify(self.p1[1] + t / (1 - t) * (self.p2[1] - self.p1[1])) return Point(x, y)
def arbitrary_point(self, parameter='t'): """A parameterized point on the Ray. Parameters ========== parameter : str, optional The name of the parameter which will be used for the parametric point. The default value is 't'. Returns ======= point : Point Raises ====== ValueError When ``parameter`` already appears in the Ray's definition. See Also ======== sympy.geometry.point.Point Examples ======== >>> from sympy import Ray, Point, Segment, S, simplify, solve >>> from sympy.abc import t >>> r = Ray(Point(0, 0), Point(2, 3)) >>> p = r.arbitrary_point(t) The parameter `t` used in the arbitrary point maps 0 to the origin of the ray and 1 to the end of the ray at infinity (which will show up as NaN). >>> p.subs(t, 0), p.subs(t, 1) (Point(0, 0), Point(oo, oo)) The unit that `t` moves you is based on the spacing of the points used to define the ray. >>> p.subs(t, 1/(S(1) + 1)) # one unit Point(2, 3) >>> p.subs(t, 2/(S(1) + 2)) # two units out Point(4, 6) >>> p.subs(t, S.Half/(S(1) + S.Half)) # half a unit out Point(1, 3/2) If you want to be located a distance of 1 from the origin of the ray, what value of `t` is needed? a) Find the unit length and pick `t` accordingly. >>> u = Segment(r.p1, p.subs(t, S.Half)).length # S.Half = 1/(1 + 1) >>> want = 1 >>> t_need = want/u >>> p_want = p.subs(t, t_need/(1 + t_need)) >>> simplify(Segment(r.p1, p_want).length) 1 b) Find the `t` that makes the length from origin to `p` equal to 1. >>> l = Segment(r.p1, p).length >>> t_need = solve(l**2 - want**2, t) # use the square to remove abs() if it is there >>> t_need = [w for w in t_need if w.n() > 0][0] # take positive t >>> p_want = p.subs(t, t_need) >>> simplify(Segment(r.p1, p_want).length) 1 """ t = _symbol(parameter) if t.name in (f.name for f in self.free_symbols): raise ValueError('Symbol %s already appears in object and cannot be used as a parameter.' % t.name) x = simplify(self.p1.x + t/(1 - t)*(self.p2.x - self.p1.x)) y = simplify(self.p1.y + t/(1 - t)*(self.p2.y - self.p1.y)) return Point(x, y)