Coverage for /usr/lib/python3/dist-packages/sympy/geometry/curve.py: 39%
83 statements
« prev ^ index » next coverage.py v7.9.1, created at 2025-06-14 15:55 +0200
« prev ^ index » next coverage.py v7.9.1, created at 2025-06-14 15:55 +0200
1"""Curves in 2-dimensional Euclidean space.
3Contains
4========
5Curve
7"""
9from sympy.functions.elementary.miscellaneous import sqrt
10from sympy.core import diff
11from sympy.core.containers import Tuple
12from sympy.core.symbol import _symbol
13from sympy.geometry.entity import GeometryEntity, GeometrySet
14from sympy.geometry.point import Point
15from sympy.integrals import integrate
16from sympy.matrices import Matrix, rot_axis3
17from sympy.utilities.iterables import is_sequence
19from mpmath.libmp.libmpf import prec_to_dps
22class Curve(GeometrySet):
23 """A curve in space.
25 A curve is defined by parametric functions for the coordinates, a
26 parameter and the lower and upper bounds for the parameter value.
28 Parameters
29 ==========
31 function : list of functions
32 limits : 3-tuple
33 Function parameter and lower and upper bounds.
35 Attributes
36 ==========
38 functions
39 parameter
40 limits
42 Raises
43 ======
45 ValueError
46 When `functions` are specified incorrectly.
47 When `limits` are specified incorrectly.
49 Examples
50 ========
52 >>> from sympy import Curve, sin, cos, interpolate
53 >>> from sympy.abc import t, a
54 >>> C = Curve((sin(t), cos(t)), (t, 0, 2))
55 >>> C.functions
56 (sin(t), cos(t))
57 >>> C.limits
58 (t, 0, 2)
59 >>> C.parameter
60 t
61 >>> C = Curve((t, interpolate([1, 4, 9, 16], t)), (t, 0, 1)); C
62 Curve((t, t**2), (t, 0, 1))
63 >>> C.subs(t, 4)
64 Point2D(4, 16)
65 >>> C.arbitrary_point(a)
66 Point2D(a, a**2)
68 See Also
69 ========
71 sympy.core.function.Function
72 sympy.polys.polyfuncs.interpolate
74 """
76 def __new__(cls, function, limits):
77 if not is_sequence(function) or len(function) != 2:
78 raise ValueError("Function argument should be (x(t), y(t)) "
79 "but got %s" % str(function))
80 if not is_sequence(limits) or len(limits) != 3:
81 raise ValueError("Limit argument should be (t, tmin, tmax) "
82 "but got %s" % str(limits))
84 return GeometryEntity.__new__(cls, Tuple(*function), Tuple(*limits))
86 def __call__(self, f):
87 return self.subs(self.parameter, f)
89 def _eval_subs(self, old, new):
90 if old == self.parameter:
91 return Point(*[f.subs(old, new) for f in self.functions])
93 def _eval_evalf(self, prec=15, **options):
94 f, (t, a, b) = self.args
95 dps = prec_to_dps(prec)
96 f = tuple([i.evalf(n=dps, **options) for i in f])
97 a, b = [i.evalf(n=dps, **options) for i in (a, b)]
98 return self.func(f, (t, a, b))
100 def arbitrary_point(self, parameter='t'):
101 """A parameterized point on the curve.
103 Parameters
104 ==========
106 parameter : str or Symbol, optional
107 Default value is 't'.
108 The Curve's parameter is selected with None or self.parameter
109 otherwise the provided symbol is used.
111 Returns
112 =======
114 Point :
115 Returns a point in parametric form.
117 Raises
118 ======
120 ValueError
121 When `parameter` already appears in the functions.
123 Examples
124 ========
126 >>> from sympy import Curve, Symbol
127 >>> from sympy.abc import s
128 >>> C = Curve([2*s, s**2], (s, 0, 2))
129 >>> C.arbitrary_point()
130 Point2D(2*t, t**2)
131 >>> C.arbitrary_point(C.parameter)
132 Point2D(2*s, s**2)
133 >>> C.arbitrary_point(None)
134 Point2D(2*s, s**2)
135 >>> C.arbitrary_point(Symbol('a'))
136 Point2D(2*a, a**2)
138 See Also
139 ========
141 sympy.geometry.point.Point
143 """
144 if parameter is None:
145 return Point(*self.functions)
147 tnew = _symbol(parameter, self.parameter, real=True)
148 t = self.parameter
149 if (tnew.name != t.name and
150 tnew.name in (f.name for f in self.free_symbols)):
151 raise ValueError('Symbol %s already appears in object '
152 'and cannot be used as a parameter.' % tnew.name)
153 return Point(*[w.subs(t, tnew) for w in self.functions])
155 @property
156 def free_symbols(self):
157 """Return a set of symbols other than the bound symbols used to
158 parametrically define the Curve.
160 Returns
161 =======
163 set :
164 Set of all non-parameterized symbols.
166 Examples
167 ========
169 >>> from sympy.abc import t, a
170 >>> from sympy import Curve
171 >>> Curve((t, t**2), (t, 0, 2)).free_symbols
172 set()
173 >>> Curve((t, t**2), (t, a, 2)).free_symbols
174 {a}
176 """
177 free = set()
178 for a in self.functions + self.limits[1:]:
179 free |= a.free_symbols
180 free = free.difference({self.parameter})
181 return free
183 @property
184 def ambient_dimension(self):
185 """The dimension of the curve.
187 Returns
188 =======
190 int :
191 the dimension of curve.
193 Examples
194 ========
196 >>> from sympy.abc import t
197 >>> from sympy import Curve
198 >>> C = Curve((t, t**2), (t, 0, 2))
199 >>> C.ambient_dimension
200 2
202 """
204 return len(self.args[0])
206 @property
207 def functions(self):
208 """The functions specifying the curve.
210 Returns
211 =======
213 functions :
214 list of parameterized coordinate functions.
216 Examples
217 ========
219 >>> from sympy.abc import t
220 >>> from sympy import Curve
221 >>> C = Curve((t, t**2), (t, 0, 2))
222 >>> C.functions
223 (t, t**2)
225 See Also
226 ========
228 parameter
230 """
231 return self.args[0]
233 @property
234 def limits(self):
235 """The limits for the curve.
237 Returns
238 =======
240 limits : tuple
241 Contains parameter and lower and upper limits.
243 Examples
244 ========
246 >>> from sympy.abc import t
247 >>> from sympy import Curve
248 >>> C = Curve([t, t**3], (t, -2, 2))
249 >>> C.limits
250 (t, -2, 2)
252 See Also
253 ========
255 plot_interval
257 """
258 return self.args[1]
260 @property
261 def parameter(self):
262 """The curve function variable.
264 Returns
265 =======
267 Symbol :
268 returns a bound symbol.
270 Examples
271 ========
273 >>> from sympy.abc import t
274 >>> from sympy import Curve
275 >>> C = Curve([t, t**2], (t, 0, 2))
276 >>> C.parameter
277 t
279 See Also
280 ========
282 functions
284 """
285 return self.args[1][0]
287 @property
288 def length(self):
289 """The curve length.
291 Examples
292 ========
294 >>> from sympy import Curve
295 >>> from sympy.abc import t
296 >>> Curve((t, t), (t, 0, 1)).length
297 sqrt(2)
299 """
300 integrand = sqrt(sum(diff(func, self.limits[0])**2 for func in self.functions))
301 return integrate(integrand, self.limits)
303 def plot_interval(self, parameter='t'):
304 """The plot interval for the default geometric plot of the curve.
306 Parameters
307 ==========
309 parameter : str or Symbol, optional
310 Default value is 't';
311 otherwise the provided symbol is used.
313 Returns
314 =======
316 List :
317 the plot interval as below:
318 [parameter, lower_bound, upper_bound]
320 Examples
321 ========
323 >>> from sympy import Curve, sin
324 >>> from sympy.abc import x, s
325 >>> Curve((x, sin(x)), (x, 1, 2)).plot_interval()
326 [t, 1, 2]
327 >>> Curve((x, sin(x)), (x, 1, 2)).plot_interval(s)
328 [s, 1, 2]
330 See Also
331 ========
333 limits : Returns limits of the parameter interval
335 """
336 t = _symbol(parameter, self.parameter, real=True)
337 return [t] + list(self.limits[1:])
339 def rotate(self, angle=0, pt=None):
340 """This function is used to rotate a curve along given point ``pt`` at given angle(in radian).
342 Parameters
343 ==========
345 angle :
346 the angle at which the curve will be rotated(in radian) in counterclockwise direction.
347 default value of angle is 0.
349 pt : Point
350 the point along which the curve will be rotated.
351 If no point given, the curve will be rotated around origin.
353 Returns
354 =======
356 Curve :
357 returns a curve rotated at given angle along given point.
359 Examples
360 ========
362 >>> from sympy import Curve, pi
363 >>> from sympy.abc import x
364 >>> Curve((x, x), (x, 0, 1)).rotate(pi/2)
365 Curve((-x, x), (x, 0, 1))
367 """
368 if pt:
369 pt = -Point(pt, dim=2)
370 else:
371 pt = Point(0,0)
372 rv = self.translate(*pt.args)
373 f = list(rv.functions)
374 f.append(0)
375 f = Matrix(1, 3, f)
376 f *= rot_axis3(angle)
377 rv = self.func(f[0, :2].tolist()[0], self.limits)
378 pt = -pt
379 return rv.translate(*pt.args)
381 def scale(self, x=1, y=1, pt=None):
382 """Override GeometryEntity.scale since Curve is not made up of Points.
384 Returns
385 =======
387 Curve :
388 returns scaled curve.
390 Examples
391 ========
393 >>> from sympy import Curve
394 >>> from sympy.abc import x
395 >>> Curve((x, x), (x, 0, 1)).scale(2)
396 Curve((2*x, x), (x, 0, 1))
398 """
399 if pt:
400 pt = Point(pt, dim=2)
401 return self.translate(*(-pt).args).scale(x, y).translate(*pt.args)
402 fx, fy = self.functions
403 return self.func((fx*x, fy*y), self.limits)
405 def translate(self, x=0, y=0):
406 """Translate the Curve by (x, y).
408 Returns
409 =======
411 Curve :
412 returns a translated curve.
414 Examples
415 ========
417 >>> from sympy import Curve
418 >>> from sympy.abc import x
419 >>> Curve((x, x), (x, 0, 1)).translate(1, 2)
420 Curve((x + 1, x + 2), (x, 0, 1))
422 """
423 fx, fy = self.functions
424 return self.func((fx + x, fy + y), self.limits)