curve.py 10.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425
  1. """Curves in 2-dimensional Euclidean space.
  2. Contains
  3. ========
  4. Curve
  5. """
  6. from sympy.functions.elementary.miscellaneous import sqrt
  7. from sympy.core import sympify, diff
  8. from sympy.core.containers import Tuple
  9. from sympy.core.symbol import _symbol
  10. from sympy.geometry.entity import GeometryEntity, GeometrySet
  11. from sympy.geometry.point import Point
  12. from sympy.integrals import integrate
  13. from sympy.utilities.iterables import is_sequence
  14. from mpmath.libmp.libmpf import prec_to_dps
  15. class Curve(GeometrySet):
  16. """A curve in space.
  17. A curve is defined by parametric functions for the coordinates, a
  18. parameter and the lower and upper bounds for the parameter value.
  19. Parameters
  20. ==========
  21. function : list of functions
  22. limits : 3-tuple
  23. Function parameter and lower and upper bounds.
  24. Attributes
  25. ==========
  26. functions
  27. parameter
  28. limits
  29. Raises
  30. ======
  31. ValueError
  32. When `functions` are specified incorrectly.
  33. When `limits` are specified incorrectly.
  34. Examples
  35. ========
  36. >>> from sympy import Curve, sin, cos, interpolate
  37. >>> from sympy.abc import t, a
  38. >>> C = Curve((sin(t), cos(t)), (t, 0, 2))
  39. >>> C.functions
  40. (sin(t), cos(t))
  41. >>> C.limits
  42. (t, 0, 2)
  43. >>> C.parameter
  44. t
  45. >>> C = Curve((t, interpolate([1, 4, 9, 16], t)), (t, 0, 1)); C
  46. Curve((t, t**2), (t, 0, 1))
  47. >>> C.subs(t, 4)
  48. Point2D(4, 16)
  49. >>> C.arbitrary_point(a)
  50. Point2D(a, a**2)
  51. See Also
  52. ========
  53. sympy.core.function.Function
  54. sympy.polys.polyfuncs.interpolate
  55. """
  56. def __new__(cls, function, limits):
  57. fun = sympify(function)
  58. if not is_sequence(fun) or len(fun) != 2:
  59. raise ValueError("Function argument should be (x(t), y(t)) "
  60. "but got %s" % str(function))
  61. if not is_sequence(limits) or len(limits) != 3:
  62. raise ValueError("Limit argument should be (t, tmin, tmax) "
  63. "but got %s" % str(limits))
  64. return GeometryEntity.__new__(cls, Tuple(*fun), Tuple(*limits))
  65. def __call__(self, f):
  66. return self.subs(self.parameter, f)
  67. def _eval_subs(self, old, new):
  68. if old == self.parameter:
  69. return Point(*[f.subs(old, new) for f in self.functions])
  70. def _eval_evalf(self, prec=15, **options):
  71. f, (t, a, b) = self.args
  72. dps = prec_to_dps(prec)
  73. f = tuple([i.evalf(n=dps, **options) for i in f])
  74. a, b = [i.evalf(n=dps, **options) for i in (a, b)]
  75. return self.func(f, (t, a, b))
  76. def arbitrary_point(self, parameter='t'):
  77. """A parameterized point on the curve.
  78. Parameters
  79. ==========
  80. parameter : str or Symbol, optional
  81. Default value is 't'.
  82. The Curve's parameter is selected with None or self.parameter
  83. otherwise the provided symbol is used.
  84. Returns
  85. =======
  86. Point :
  87. Returns a point in parametric form.
  88. Raises
  89. ======
  90. ValueError
  91. When `parameter` already appears in the functions.
  92. Examples
  93. ========
  94. >>> from sympy import Curve, Symbol
  95. >>> from sympy.abc import s
  96. >>> C = Curve([2*s, s**2], (s, 0, 2))
  97. >>> C.arbitrary_point()
  98. Point2D(2*t, t**2)
  99. >>> C.arbitrary_point(C.parameter)
  100. Point2D(2*s, s**2)
  101. >>> C.arbitrary_point(None)
  102. Point2D(2*s, s**2)
  103. >>> C.arbitrary_point(Symbol('a'))
  104. Point2D(2*a, a**2)
  105. See Also
  106. ========
  107. sympy.geometry.point.Point
  108. """
  109. if parameter is None:
  110. return Point(*self.functions)
  111. tnew = _symbol(parameter, self.parameter, real=True)
  112. t = self.parameter
  113. if (tnew.name != t.name and
  114. tnew.name in (f.name for f in self.free_symbols)):
  115. raise ValueError('Symbol %s already appears in object '
  116. 'and cannot be used as a parameter.' % tnew.name)
  117. return Point(*[w.subs(t, tnew) for w in self.functions])
  118. @property
  119. def free_symbols(self):
  120. """Return a set of symbols other than the bound symbols used to
  121. parametrically define the Curve.
  122. Returns
  123. =======
  124. set :
  125. Set of all non-parameterized symbols.
  126. Examples
  127. ========
  128. >>> from sympy.abc import t, a
  129. >>> from sympy import Curve
  130. >>> Curve((t, t**2), (t, 0, 2)).free_symbols
  131. set()
  132. >>> Curve((t, t**2), (t, a, 2)).free_symbols
  133. {a}
  134. """
  135. free = set()
  136. for a in self.functions + self.limits[1:]:
  137. free |= a.free_symbols
  138. free = free.difference({self.parameter})
  139. return free
  140. @property
  141. def ambient_dimension(self):
  142. """The dimension of the curve.
  143. Returns
  144. =======
  145. int :
  146. the dimension of curve.
  147. Examples
  148. ========
  149. >>> from sympy.abc import t
  150. >>> from sympy import Curve
  151. >>> C = Curve((t, t**2), (t, 0, 2))
  152. >>> C.ambient_dimension
  153. 2
  154. """
  155. return len(self.args[0])
  156. @property
  157. def functions(self):
  158. """The functions specifying the curve.
  159. Returns
  160. =======
  161. functions :
  162. list of parameterized coordinate functions.
  163. Examples
  164. ========
  165. >>> from sympy.abc import t
  166. >>> from sympy import Curve
  167. >>> C = Curve((t, t**2), (t, 0, 2))
  168. >>> C.functions
  169. (t, t**2)
  170. See Also
  171. ========
  172. parameter
  173. """
  174. return self.args[0]
  175. @property
  176. def limits(self):
  177. """The limits for the curve.
  178. Returns
  179. =======
  180. limits : tuple
  181. Contains parameter and lower and upper limits.
  182. Examples
  183. ========
  184. >>> from sympy.abc import t
  185. >>> from sympy import Curve
  186. >>> C = Curve([t, t**3], (t, -2, 2))
  187. >>> C.limits
  188. (t, -2, 2)
  189. See Also
  190. ========
  191. plot_interval
  192. """
  193. return self.args[1]
  194. @property
  195. def parameter(self):
  196. """The curve function variable.
  197. Returns
  198. =======
  199. Symbol :
  200. returns a bound symbol.
  201. Examples
  202. ========
  203. >>> from sympy.abc import t
  204. >>> from sympy import Curve
  205. >>> C = Curve([t, t**2], (t, 0, 2))
  206. >>> C.parameter
  207. t
  208. See Also
  209. ========
  210. functions
  211. """
  212. return self.args[1][0]
  213. @property
  214. def length(self):
  215. """The curve length.
  216. Examples
  217. ========
  218. >>> from sympy import Curve
  219. >>> from sympy.abc import t
  220. >>> Curve((t, t), (t, 0, 1)).length
  221. sqrt(2)
  222. """
  223. integrand = sqrt(sum(diff(func, self.limits[0])**2 for func in self.functions))
  224. return integrate(integrand, self.limits)
  225. def plot_interval(self, parameter='t'):
  226. """The plot interval for the default geometric plot of the curve.
  227. Parameters
  228. ==========
  229. parameter : str or Symbol, optional
  230. Default value is 't';
  231. otherwise the provided symbol is used.
  232. Returns
  233. =======
  234. List :
  235. the plot interval as below:
  236. [parameter, lower_bound, upper_bound]
  237. Examples
  238. ========
  239. >>> from sympy import Curve, sin
  240. >>> from sympy.abc import x, s
  241. >>> Curve((x, sin(x)), (x, 1, 2)).plot_interval()
  242. [t, 1, 2]
  243. >>> Curve((x, sin(x)), (x, 1, 2)).plot_interval(s)
  244. [s, 1, 2]
  245. See Also
  246. ========
  247. limits : Returns limits of the parameter interval
  248. """
  249. t = _symbol(parameter, self.parameter, real=True)
  250. return [t] + list(self.limits[1:])
  251. def rotate(self, angle=0, pt=None):
  252. """This function is used to rotate a curve along given point ``pt`` at given angle(in radian).
  253. Parameters
  254. ==========
  255. angle :
  256. the angle at which the curve will be rotated(in radian) in counterclockwise direction.
  257. default value of angle is 0.
  258. pt : Point
  259. the point along which the curve will be rotated.
  260. If no point given, the curve will be rotated around origin.
  261. Returns
  262. =======
  263. Curve :
  264. returns a curve rotated at given angle along given point.
  265. Examples
  266. ========
  267. >>> from sympy import Curve, pi
  268. >>> from sympy.abc import x
  269. >>> Curve((x, x), (x, 0, 1)).rotate(pi/2)
  270. Curve((-x, x), (x, 0, 1))
  271. """
  272. from sympy.matrices import Matrix, rot_axis3
  273. if pt:
  274. pt = -Point(pt, dim=2)
  275. else:
  276. pt = Point(0,0)
  277. rv = self.translate(*pt.args)
  278. f = list(rv.functions)
  279. f.append(0)
  280. f = Matrix(1, 3, f)
  281. f *= rot_axis3(angle)
  282. rv = self.func(f[0, :2].tolist()[0], self.limits)
  283. pt = -pt
  284. return rv.translate(*pt.args)
  285. def scale(self, x=1, y=1, pt=None):
  286. """Override GeometryEntity.scale since Curve is not made up of Points.
  287. Returns
  288. =======
  289. Curve :
  290. returns scaled curve.
  291. Examples
  292. ========
  293. >>> from sympy import Curve
  294. >>> from sympy.abc import x
  295. >>> Curve((x, x), (x, 0, 1)).scale(2)
  296. Curve((2*x, x), (x, 0, 1))
  297. """
  298. if pt:
  299. pt = Point(pt, dim=2)
  300. return self.translate(*(-pt).args).scale(x, y).translate(*pt.args)
  301. fx, fy = self.functions
  302. return self.func((fx*x, fy*y), self.limits)
  303. def translate(self, x=0, y=0):
  304. """Translate the Curve by (x, y).
  305. Returns
  306. =======
  307. Curve :
  308. returns a translated curve.
  309. Examples
  310. ========
  311. >>> from sympy import Curve
  312. >>> from sympy.abc import x
  313. >>> Curve((x, x), (x, 0, 1)).translate(1, 2)
  314. Curve((x + 1, x + 2), (x, 0, 1))
  315. """
  316. fx, fy = self.functions
  317. return self.func((fx + x, fy + y), self.limits)