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

1"""Curves in 2-dimensional Euclidean space. 

2 

3Contains 

4======== 

5Curve 

6 

7""" 

8 

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 

18 

19from mpmath.libmp.libmpf import prec_to_dps 

20 

21 

22class Curve(GeometrySet): 

23 """A curve in space. 

24 

25 A curve is defined by parametric functions for the coordinates, a 

26 parameter and the lower and upper bounds for the parameter value. 

27 

28 Parameters 

29 ========== 

30 

31 function : list of functions 

32 limits : 3-tuple 

33 Function parameter and lower and upper bounds. 

34 

35 Attributes 

36 ========== 

37 

38 functions 

39 parameter 

40 limits 

41 

42 Raises 

43 ====== 

44 

45 ValueError 

46 When `functions` are specified incorrectly. 

47 When `limits` are specified incorrectly. 

48 

49 Examples 

50 ======== 

51 

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) 

67 

68 See Also 

69 ======== 

70 

71 sympy.core.function.Function 

72 sympy.polys.polyfuncs.interpolate 

73 

74 """ 

75 

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)) 

83 

84 return GeometryEntity.__new__(cls, Tuple(*function), Tuple(*limits)) 

85 

86 def __call__(self, f): 

87 return self.subs(self.parameter, f) 

88 

89 def _eval_subs(self, old, new): 

90 if old == self.parameter: 

91 return Point(*[f.subs(old, new) for f in self.functions]) 

92 

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)) 

99 

100 def arbitrary_point(self, parameter='t'): 

101 """A parameterized point on the curve. 

102 

103 Parameters 

104 ========== 

105 

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. 

110 

111 Returns 

112 ======= 

113 

114 Point : 

115 Returns a point in parametric form. 

116 

117 Raises 

118 ====== 

119 

120 ValueError 

121 When `parameter` already appears in the functions. 

122 

123 Examples 

124 ======== 

125 

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) 

137 

138 See Also 

139 ======== 

140 

141 sympy.geometry.point.Point 

142 

143 """ 

144 if parameter is None: 

145 return Point(*self.functions) 

146 

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]) 

154 

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. 

159 

160 Returns 

161 ======= 

162 

163 set : 

164 Set of all non-parameterized symbols. 

165 

166 Examples 

167 ======== 

168 

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} 

175 

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 

182 

183 @property 

184 def ambient_dimension(self): 

185 """The dimension of the curve. 

186 

187 Returns 

188 ======= 

189 

190 int : 

191 the dimension of curve. 

192 

193 Examples 

194 ======== 

195 

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 

201 

202 """ 

203 

204 return len(self.args[0]) 

205 

206 @property 

207 def functions(self): 

208 """The functions specifying the curve. 

209 

210 Returns 

211 ======= 

212 

213 functions : 

214 list of parameterized coordinate functions. 

215 

216 Examples 

217 ======== 

218 

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) 

224 

225 See Also 

226 ======== 

227 

228 parameter 

229 

230 """ 

231 return self.args[0] 

232 

233 @property 

234 def limits(self): 

235 """The limits for the curve. 

236 

237 Returns 

238 ======= 

239 

240 limits : tuple 

241 Contains parameter and lower and upper limits. 

242 

243 Examples 

244 ======== 

245 

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) 

251 

252 See Also 

253 ======== 

254 

255 plot_interval 

256 

257 """ 

258 return self.args[1] 

259 

260 @property 

261 def parameter(self): 

262 """The curve function variable. 

263 

264 Returns 

265 ======= 

266 

267 Symbol : 

268 returns a bound symbol. 

269 

270 Examples 

271 ======== 

272 

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 

278 

279 See Also 

280 ======== 

281 

282 functions 

283 

284 """ 

285 return self.args[1][0] 

286 

287 @property 

288 def length(self): 

289 """The curve length. 

290 

291 Examples 

292 ======== 

293 

294 >>> from sympy import Curve 

295 >>> from sympy.abc import t 

296 >>> Curve((t, t), (t, 0, 1)).length 

297 sqrt(2) 

298 

299 """ 

300 integrand = sqrt(sum(diff(func, self.limits[0])**2 for func in self.functions)) 

301 return integrate(integrand, self.limits) 

302 

303 def plot_interval(self, parameter='t'): 

304 """The plot interval for the default geometric plot of the curve. 

305 

306 Parameters 

307 ========== 

308 

309 parameter : str or Symbol, optional 

310 Default value is 't'; 

311 otherwise the provided symbol is used. 

312 

313 Returns 

314 ======= 

315 

316 List : 

317 the plot interval as below: 

318 [parameter, lower_bound, upper_bound] 

319 

320 Examples 

321 ======== 

322 

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] 

329 

330 See Also 

331 ======== 

332 

333 limits : Returns limits of the parameter interval 

334 

335 """ 

336 t = _symbol(parameter, self.parameter, real=True) 

337 return [t] + list(self.limits[1:]) 

338 

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). 

341 

342 Parameters 

343 ========== 

344 

345 angle : 

346 the angle at which the curve will be rotated(in radian) in counterclockwise direction. 

347 default value of angle is 0. 

348 

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. 

352 

353 Returns 

354 ======= 

355 

356 Curve : 

357 returns a curve rotated at given angle along given point. 

358 

359 Examples 

360 ======== 

361 

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)) 

366 

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) 

380 

381 def scale(self, x=1, y=1, pt=None): 

382 """Override GeometryEntity.scale since Curve is not made up of Points. 

383 

384 Returns 

385 ======= 

386 

387 Curve : 

388 returns scaled curve. 

389 

390 Examples 

391 ======== 

392 

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)) 

397 

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) 

404 

405 def translate(self, x=0, y=0): 

406 """Translate the Curve by (x, y). 

407 

408 Returns 

409 ======= 

410 

411 Curve : 

412 returns a translated curve. 

413 

414 Examples 

415 ======== 

416 

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)) 

421 

422 """ 

423 fx, fy = self.functions 

424 return self.func((fx + x, fy + y), self.limits)