123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425 |
- """Curves in 2-dimensional Euclidean space.
- Contains
- ========
- Curve
- """
- from sympy.functions.elementary.miscellaneous import sqrt
- from sympy.core import sympify, diff
- from sympy.core.containers import Tuple
- from sympy.core.symbol import _symbol
- from sympy.geometry.entity import GeometryEntity, GeometrySet
- from sympy.geometry.point import Point
- from sympy.integrals import integrate
- from sympy.utilities.iterables import is_sequence
- from mpmath.libmp.libmpf import prec_to_dps
- class Curve(GeometrySet):
- """A curve in space.
- A curve is defined by parametric functions for the coordinates, a
- parameter and the lower and upper bounds for the parameter value.
- Parameters
- ==========
- function : list of functions
- limits : 3-tuple
- Function parameter and lower and upper bounds.
- Attributes
- ==========
- functions
- parameter
- limits
- Raises
- ======
- ValueError
- When `functions` are specified incorrectly.
- When `limits` are specified incorrectly.
- Examples
- ========
- >>> from sympy import Curve, sin, cos, interpolate
- >>> from sympy.abc import t, a
- >>> C = Curve((sin(t), cos(t)), (t, 0, 2))
- >>> C.functions
- (sin(t), cos(t))
- >>> C.limits
- (t, 0, 2)
- >>> C.parameter
- t
- >>> C = Curve((t, interpolate([1, 4, 9, 16], t)), (t, 0, 1)); C
- Curve((t, t**2), (t, 0, 1))
- >>> C.subs(t, 4)
- Point2D(4, 16)
- >>> C.arbitrary_point(a)
- Point2D(a, a**2)
- See Also
- ========
- sympy.core.function.Function
- sympy.polys.polyfuncs.interpolate
- """
- def __new__(cls, function, limits):
- fun = sympify(function)
- if not is_sequence(fun) or len(fun) != 2:
- raise ValueError("Function argument should be (x(t), y(t)) "
- "but got %s" % str(function))
- if not is_sequence(limits) or len(limits) != 3:
- raise ValueError("Limit argument should be (t, tmin, tmax) "
- "but got %s" % str(limits))
- return GeometryEntity.__new__(cls, Tuple(*fun), Tuple(*limits))
- def __call__(self, f):
- return self.subs(self.parameter, f)
- def _eval_subs(self, old, new):
- if old == self.parameter:
- return Point(*[f.subs(old, new) for f in self.functions])
- def _eval_evalf(self, prec=15, **options):
- f, (t, a, b) = self.args
- dps = prec_to_dps(prec)
- f = tuple([i.evalf(n=dps, **options) for i in f])
- a, b = [i.evalf(n=dps, **options) for i in (a, b)]
- return self.func(f, (t, a, b))
- 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
- =======
- Point :
- Returns a point in parametric form.
- Raises
- ======
- ValueError
- When `parameter` already appears in the functions.
- Examples
- ========
- >>> from sympy import Curve, Symbol
- >>> from sympy.abc import s
- >>> C = Curve([2*s, s**2], (s, 0, 2))
- >>> C.arbitrary_point()
- Point2D(2*t, t**2)
- >>> C.arbitrary_point(C.parameter)
- Point2D(2*s, s**2)
- >>> C.arbitrary_point(None)
- Point2D(2*s, s**2)
- >>> C.arbitrary_point(Symbol('a'))
- Point2D(2*a, a**2)
- See Also
- ========
- sympy.geometry.point.Point
- """
- if parameter is None:
- return Point(*self.functions)
- tnew = _symbol(parameter, self.parameter, real=True)
- 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])
- @property
- def free_symbols(self):
- """Return a set of symbols other than the bound symbols used to
- parametrically define the Curve.
- Returns
- =======
- set :
- Set of all non-parameterized symbols.
- Examples
- ========
- >>> from sympy.abc import t, a
- >>> from sympy import Curve
- >>> Curve((t, t**2), (t, 0, 2)).free_symbols
- set()
- >>> Curve((t, t**2), (t, a, 2)).free_symbols
- {a}
- """
- free = set()
- for a in self.functions + self.limits[1:]:
- free |= a.free_symbols
- free = free.difference({self.parameter})
- return free
- @property
- def ambient_dimension(self):
- """The dimension of the curve.
- Returns
- =======
- int :
- the dimension of curve.
- Examples
- ========
- >>> from sympy.abc import t
- >>> from sympy import Curve
- >>> C = Curve((t, t**2), (t, 0, 2))
- >>> C.ambient_dimension
- 2
- """
- return len(self.args[0])
- @property
- def functions(self):
- """The functions specifying the curve.
- Returns
- =======
- functions :
- list of parameterized coordinate functions.
- Examples
- ========
- >>> from sympy.abc import t
- >>> from sympy import Curve
- >>> C = Curve((t, t**2), (t, 0, 2))
- >>> C.functions
- (t, t**2)
- See Also
- ========
- parameter
- """
- return self.args[0]
- @property
- def limits(self):
- """The limits for the curve.
- Returns
- =======
- limits : tuple
- Contains parameter and lower and upper limits.
- Examples
- ========
- >>> from sympy.abc import t
- >>> from sympy import Curve
- >>> C = Curve([t, t**3], (t, -2, 2))
- >>> C.limits
- (t, -2, 2)
- See Also
- ========
- plot_interval
- """
- return self.args[1]
- @property
- def parameter(self):
- """The curve function variable.
- Returns
- =======
- Symbol :
- returns a bound symbol.
- Examples
- ========
- >>> from sympy.abc import t
- >>> from sympy import Curve
- >>> C = Curve([t, t**2], (t, 0, 2))
- >>> C.parameter
- t
- See Also
- ========
- functions
- """
- return self.args[1][0]
- @property
- def length(self):
- """The curve length.
- Examples
- ========
- >>> from sympy import Curve
- >>> from sympy.abc import t
- >>> Curve((t, t), (t, 0, 1)).length
- sqrt(2)
- """
- integrand = sqrt(sum(diff(func, self.limits[0])**2 for func in self.functions))
- return integrate(integrand, self.limits)
- 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
- =======
- List :
- the plot interval as below:
- [parameter, lower_bound, upper_bound]
- Examples
- ========
- >>> from sympy import Curve, sin
- >>> from sympy.abc import x, 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]
- See Also
- ========
- limits : Returns limits of the parameter interval
- """
- t = _symbol(parameter, self.parameter, real=True)
- return [t] + list(self.limits[1:])
- def rotate(self, angle=0, pt=None):
- """This function is used to rotate a curve along given point ``pt`` at given angle(in radian).
- Parameters
- ==========
- angle :
- the angle at which the curve will be rotated(in radian) in counterclockwise direction.
- default value of angle is 0.
- pt : Point
- the point along which the curve will be rotated.
- If no point given, the curve will be rotated around origin.
- Returns
- =======
- Curve :
- returns a curve rotated at given angle along given point.
- Examples
- ========
- >>> from sympy import Curve, pi
- >>> from sympy.abc import x
- >>> Curve((x, x), (x, 0, 1)).rotate(pi/2)
- Curve((-x, x), (x, 0, 1))
- """
- from sympy.matrices import Matrix, rot_axis3
- if pt:
- pt = -Point(pt, dim=2)
- else:
- pt = Point(0,0)
- rv = self.translate(*pt.args)
- f = list(rv.functions)
- f.append(0)
- f = Matrix(1, 3, f)
- f *= rot_axis3(angle)
- rv = self.func(f[0, :2].tolist()[0], self.limits)
- pt = -pt
- return rv.translate(*pt.args)
- def scale(self, x=1, y=1, pt=None):
- """Override GeometryEntity.scale since Curve is not made up of Points.
- Returns
- =======
- Curve :
- returns scaled curve.
- Examples
- ========
- >>> from sympy import Curve
- >>> from sympy.abc import x
- >>> Curve((x, x), (x, 0, 1)).scale(2)
- Curve((2*x, x), (x, 0, 1))
- """
- if pt:
- pt = Point(pt, dim=2)
- return self.translate(*(-pt).args).scale(x, y).translate(*pt.args)
- fx, fy = self.functions
- return self.func((fx*x, fy*y), self.limits)
- def translate(self, x=0, y=0):
- """Translate the Curve by (x, y).
- Returns
- =======
- Curve :
- returns a translated curve.
- Examples
- ========
- >>> from sympy import Curve
- >>> from sympy.abc import x
- >>> Curve((x, x), (x, 0, 1)).translate(1, 2)
- Curve((x + 1, x + 2), (x, 0, 1))
- """
- fx, fy = self.functions
- return self.func((fx + x, fy + y), self.limits)
|