rational-linkages 2.1.0__cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl → 2.2.0__cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,8 +1,8 @@
1
1
  import numpy
2
- import sympy
3
- from scipy.optimize import minimize
4
2
 
5
- from . import LineSegment
3
+ from sympy import symbols, Poly
4
+
5
+ from .Linkage import LineSegment
6
6
  from .DualQuaternion import DualQuaternion
7
7
  from .NormalizedLine import NormalizedLine
8
8
  from .PointHomogeneous import PointHomogeneous, PointOrbit
@@ -47,11 +47,11 @@ class CollisionAnalyser:
47
47
 
48
48
  relative_motions = branch0 + branch1[::-1]
49
49
 
50
- t = sympy.symbols('t')
50
+ t = symbols('t')
51
51
 
52
52
  motions = []
53
53
  for motion in relative_motions:
54
- motions.append(RationalCurve([sympy.Poly(c, t, greedy=False)
54
+ motions.append(RationalCurve([Poly(c, t, greedy=False)
55
55
  for c in motion],
56
56
  metric=self.metric))
57
57
  return motions
@@ -296,6 +296,11 @@ class CollisionAnalyser:
296
296
  """
297
297
  Optimize the link control points to avoid collisions with the bounding orbits.
298
298
  """
299
+ try:
300
+ from scipy.optimize import minimize # lazy import
301
+ except ImportError:
302
+ raise RuntimeError("Scipy import failed. Check its installation.")
303
+
299
304
  def flatten_cps(cps):
300
305
  return numpy.array([cp.normalized_in_3d() for cp in cps]).flatten()
301
306
 
@@ -348,11 +353,11 @@ class CollisionAnalyser:
348
353
  :param min_splits: Minimum number of splits for the bezier curves.
349
354
  """
350
355
 
351
- t = sympy.symbols('t')
356
+ t = symbols('t')
352
357
  motions = []
353
358
  for i, idx in enumerate(reduced_indices):
354
359
  rel_motion = self.mechanism.relative_motion(segment_id_number, idx)
355
- motions.append(RationalCurve([sympy.Poly(c, t, greedy=False)
360
+ motions.append(RationalCurve([Poly(c, t, greedy=False)
356
361
  for c in rel_motion],
357
362
  metric=self.metric))
358
363
 
@@ -30,7 +30,10 @@ class CollisionFreeOptimization:
30
30
  parameters of the points, result of the optimization
31
31
  :rtype: tuple
32
32
  """
33
- from scipy.optimize import minimize
33
+ try:
34
+ from scipy.optimize import minimize # lazy import
35
+ except ImportError:
36
+ raise RuntimeError("Scipy import failed. Check its installation.")
34
37
 
35
38
  # get the axes represented as normalized lines
36
39
  if len(self.mechanism.factorizations) == 1:
@@ -226,10 +226,13 @@ class DualQuaternion:
226
226
  :return: DualQuaternion with rational elements
227
227
  :rtype: DualQuaternion
228
228
  """
229
- from sympy import Rational, nsimplify
229
+ from sympy import Rational
230
230
 
231
231
  if study_parameters is not None:
232
- rational_numbers = [nsimplify(x, tolerance=1*(-10)) for x in study_parameters]
232
+ rational_numbers = [x if isinstance(x, Expr)
233
+ else Rational(*x) if isinstance(x, tuple)
234
+ else Rational(x)
235
+ for x in study_parameters]
233
236
  else:
234
237
  rational_numbers = [Rational(1), Rational(0), Rational(0), Rational(0),
235
238
  Rational(0), Rational(0), Rational(0), Rational(0)]
@@ -3,7 +3,8 @@ from warnings import warn
3
3
 
4
4
  import biquaternion_py
5
5
  import numpy as np
6
- import sympy as sp
6
+
7
+ from sympy import Symbol, Rational
7
8
 
8
9
  from .DualQuaternion import DualQuaternion
9
10
  from .MotionFactorization import MotionFactorization
@@ -45,7 +46,7 @@ class FactorizationProvider:
45
46
 
46
47
  :warning: If the given curve has not only rational numbers as input.
47
48
  """
48
- t = sp.Symbol("t")
49
+ t = Symbol("t")
49
50
 
50
51
  if isinstance(curve, RationalCurve):
51
52
  bi_quat = biquaternion_py.BiQuaternion(curve.extract_expressions())
@@ -58,7 +59,7 @@ class FactorizationProvider:
58
59
  poly_coeffs = bi_poly.all_coeffs()
59
60
  for i in range(len(poly_coeffs)):
60
61
  for j in range(len(poly_coeffs[i].args)):
61
- if not isinstance(poly_coeffs[i].args[j], sp.Rational):
62
+ if not isinstance(poly_coeffs[i].args[j], Rational):
62
63
  warn('The given curve has not only rational numbers as input. The factorization will be performed with floating point numbers, but may be instable.')
63
64
  break
64
65
 
@@ -92,7 +93,7 @@ class FactorizationProvider:
92
93
  'as input. The factorization will be performed with floating '
93
94
  'point numbers, but may be instable.')
94
95
 
95
- t = sp.Symbol("t")
96
+ t = Symbol("t")
96
97
 
97
98
  bi_poly = t - biquaternion_py.BiQuaternion(factorization.dq_axes[0].array())
98
99
  for i in range(1, factorization.number_of_factors):
@@ -147,7 +148,7 @@ class FactorizationProvider:
147
148
  :return: The rotation axis of the factor.
148
149
  :rtype: DualQuaternion
149
150
  """
150
- t = sp.Symbol("t")
151
+ t = Symbol("t")
151
152
  t_dq = DualQuaternion([t, 0, 0, 0, 0, 0, 0, 0])
152
153
 
153
154
  factor_dq = DualQuaternion(factor.poly.coeffs)
@@ -1,5 +1,4 @@
1
1
  import numpy as np
2
- from scipy.optimize import minimize
3
2
 
4
3
  from .AffineMetric import AffineMetric
5
4
  from .PointHomogeneous import PointHomogeneous
@@ -55,6 +54,14 @@ class MiniBall:
55
54
  return PointHomogeneous(center), radius_squared
56
55
 
57
56
  def get_ball_minimize(self):
57
+ """
58
+ Find the smallest ball containing all given points using optimization
59
+ """
60
+ try:
61
+ from scipy.optimize import minimize # lazy import
62
+ except ImportError:
63
+ raise RuntimeError("Scipy import failed. Check the package installation.")
64
+
58
65
  def objective_function(x):
59
66
  """
60
67
  Objective function to minimize the squared radius r^2 of the ball
@@ -1,13 +1,17 @@
1
1
  from typing import Union
2
2
 
3
3
  import numpy as np
4
- from scipy.optimize import minimize
5
4
 
6
5
  from .AffineMetric import AffineMetric
7
6
  from .DualQuaternion import DualQuaternion
8
7
  from .PointHomogeneous import PointHomogeneous
9
8
  from .RationalCurve import RationalCurve
10
9
 
10
+ try:
11
+ from scipy.optimize import minimize # lazy import, optional dependency
12
+ except ImportError:
13
+ minimize = None
14
+
11
15
  ### NOT YET in the documentation ### TODO: add to docs
12
16
 
13
17
 
@@ -1,25 +1,36 @@
1
1
  import sys
2
- from typing import Union
3
-
4
2
  import numpy as np
5
- import pyqtgraph.opengl as gl
6
3
 
7
- # PyQt and Pyqtgraph imports
8
- from PyQt6 import QtCore, QtWidgets
4
+ from typing import Union
5
+ from warnings import warn
9
6
 
10
- # Import your custom classes (adjust the import paths as needed)
11
7
  from .DualQuaternion import DualQuaternion
12
8
  from .MotionInterpolation import MotionInterpolation
13
- from .PlotterPyqtgraph import (
14
- FramePlotHelper,
15
- InteractivePlotterWidget,
16
- PlotterPyqtgraph,
17
- )
18
9
  from .PointHomogeneous import PointHomogeneous
19
10
  from .RationalCurve import RationalCurve
20
11
  from .RationalMechanism import RationalMechanism
21
12
  from .TransfMatrix import TransfMatrix
22
13
 
14
+ # Try importing GUI components
15
+ try:
16
+ import pyqtgraph.opengl as gl
17
+ from PyQt6 import QtCore, QtWidgets
18
+ from .PlotterPyqtgraph import (
19
+ FramePlotHelper,
20
+ InteractivePlotterWidget,
21
+ PlotterPyqtgraph,
22
+ )
23
+ except (ImportError, OSError):
24
+ warn("Failed to import OpenGL or PyQt6. If you expect interactive GUI to work, "
25
+ "please check the package installation.")
26
+
27
+ gl = None
28
+ QtCore = None
29
+ QtWidgets = None
30
+ FramePlotHelper = None
31
+ InteractivePlotterWidget = None
32
+ PlotterPyqtgraph = None
33
+
23
34
 
24
35
  class MotionDesigner:
25
36
  """
@@ -1,7 +1,8 @@
1
1
  from typing import Union
2
2
 
3
3
  import numpy as np
4
- import sympy as sp
4
+
5
+ from sympy import Symbol, Poly
5
6
 
6
7
  from .DualQuaternion import DualQuaternion
7
8
  from .Linkage import Linkage
@@ -81,7 +82,7 @@ class MotionFactorization(RationalCurve):
81
82
 
82
83
  @staticmethod
83
84
  def get_polynomials_from_factorization(factors: list[DualQuaternion]) -> (
84
- list)[sp.Poly]:
85
+ list)[Poly]:
85
86
  """
86
87
  Construct rational curve from Dual Quaternions equation factors
87
88
 
@@ -91,14 +92,14 @@ class MotionFactorization(RationalCurve):
91
92
  :return: motion curve using Sympy polynomials
92
93
  :rtype: RationalCurve
93
94
  """
94
- t = sp.Symbol("t")
95
+ t = Symbol("t")
95
96
 
96
97
  polynomial_t = DualQuaternion([t, 0, 0, 0, 0, 0, 0, 0])
97
98
  polynomials_dq = DualQuaternion()
98
99
  for i in range(len(factors)):
99
100
  polynomials_dq = polynomials_dq * (polynomial_t - factors[i])
100
101
 
101
- return [sp.Poly(polynom, t)
102
+ return [Poly(polynom, t)
102
103
  for i, polynom in enumerate(polynomials_dq.array())]
103
104
 
104
105
  def get_symbolic_factors(self) -> list[DualQuaternion]:
@@ -108,7 +109,7 @@ class MotionFactorization(RationalCurve):
108
109
  :return: list of DualQuaternions representing the curve
109
110
  :rtype: list[DualQuaternion]
110
111
  """
111
- t = sp.Symbol("t")
112
+ t = Symbol("t")
112
113
  polynomial_t = DualQuaternion([t, 0, 0, 0, 0, 0, 0, 0])
113
114
  return [polynomial_t - self.dq_axes[i] for i in range(len(self.dq_axes))]
114
115
 
@@ -367,7 +367,7 @@ class MotionInterpolation:
367
367
  :return: Polynomials of rational motion curve.
368
368
  :rtype: list[sp.Poly]
369
369
  """
370
- from scipy.optimize import minimize # inner import
370
+ from scipy.optimize import minimize # lazy import
371
371
 
372
372
  mid_pose = DualQuaternion.random_on_study_quadric()
373
373
  mid_pose_tr = TransfMatrix(mid_pose.dq2matrix())
@@ -2,11 +2,9 @@ from functools import wraps
2
2
  from itertools import cycle
3
3
  from os import makedirs
4
4
  from os.path import isdir, join
5
+ from warnings import warn
5
6
 
6
- import matplotlib
7
- import matplotlib.pyplot as plt
8
7
  import numpy as np
9
- from matplotlib.widgets import Slider, TextBox
10
8
 
11
9
  from .DualQuaternion import DualQuaternion
12
10
  from .Linkage import LineSegment
@@ -19,6 +17,20 @@ from .RationalCurve import RationalCurve
19
17
  from .RationalMechanism import RationalMechanism
20
18
  from .TransfMatrix import TransfMatrix
21
19
 
20
+ # Try importing GUI components
21
+ try:
22
+ import matplotlib
23
+ import matplotlib.pyplot as plt
24
+ from matplotlib.widgets import Slider, TextBox
25
+
26
+ except (ImportError, OSError):
27
+ warn("Failed to import Matplotlib. Check the package installation.")
28
+
29
+ matplotlib = None
30
+ plt = None
31
+ Slider = None
32
+ TextBox = None
33
+
22
34
 
23
35
  class PlotterMatplotlib:
24
36
  def __init__(self,
@@ -932,7 +944,7 @@ class PlotterMatplotlib:
932
944
  :param list list_of_angles: list of joint angles
933
945
  :param float sleep_time: time to wait between each frame
934
946
  """
935
- from time import sleep # inner import
947
+ from time import sleep # lazy import
936
948
 
937
949
  t_angle = list_of_angles
938
950
 
@@ -1,9 +1,7 @@
1
1
  import sys
2
-
3
2
  import numpy as np
4
- import pyqtgraph.opengl as gl
5
- from PyQt6 import QtCore, QtGui, QtWidgets
6
- from PyQt6.QtWidgets import QApplication
3
+
4
+ from warnings import warn
7
5
 
8
6
  from .DualQuaternion import DualQuaternion
9
7
  from .Linkage import LineSegment
@@ -17,6 +15,21 @@ from .RationalCurve import RationalCurve
17
15
  from .RationalMechanism import RationalMechanism
18
16
  from .TransfMatrix import TransfMatrix
19
17
 
18
+ # Try importing GUI components
19
+ try:
20
+ import pyqtgraph.opengl as gl
21
+ from PyQt6 import QtCore, QtGui, QtWidgets
22
+ from PyQt6.QtWidgets import QApplication
23
+ except (ImportError, OSError):
24
+ warn("Failed to import OpenGL or PyQt6. If you expect interactive GUI to work, "
25
+ "please check the package installation.")
26
+
27
+ gl = None
28
+ QtCore = None
29
+ QtGui = None
30
+ QtWidgets = None
31
+ QApplication = None
32
+
20
33
 
21
34
  class PlotterPyqtgraph:
22
35
  """
@@ -2,7 +2,6 @@ from copy import deepcopy
2
2
 
3
3
  import numpy as np
4
4
  import sympy as sp
5
- from sympy.integrals.quadrature import gauss_legendre
6
5
 
7
6
  from .DualQuaternion import DualQuaternion
8
7
  from .MiniBall import MiniBall
@@ -93,7 +92,7 @@ class RationalBezier(RationalCurve):
93
92
  """
94
93
  Get the numerical coefficients of the Bezier curve
95
94
  """
96
- from scipy.special import comb # INNER IMPORT
95
+ from scipy.special import comb # lazy import
97
96
 
98
97
  control_pts = np.array([point.array() for point in control_points])
99
98
  degree = len(control_points) - 1
@@ -210,7 +209,7 @@ class BezierSegment:
210
209
 
211
210
  @metric.setter
212
211
  def metric(self, metric: "AffineMetric"):
213
- from .AffineMetric import AffineMetric # inner import
212
+ from .AffineMetric import AffineMetric # lazy import
214
213
 
215
214
  if isinstance(metric, AffineMetric):
216
215
  self._metric = metric
@@ -3,7 +3,6 @@ from typing import Union
3
3
 
4
4
  import numpy as np
5
5
  import sympy as sp
6
- from scipy.integrate import quad
7
6
 
8
7
  from .DualQuaternion import DualQuaternion
9
8
  from .PointHomogeneous import PointHomogeneous
@@ -136,7 +135,7 @@ class RationalCurve:
136
135
 
137
136
  @metric.setter
138
137
  def metric(self, metric: "AffineMetric"):
139
- from .AffineMetric import AffineMetric # inner import
138
+ from .AffineMetric import AffineMetric # lazy import
140
139
 
141
140
  if isinstance(metric, AffineMetric):
142
141
  self._metric = metric
@@ -573,7 +572,7 @@ class RationalCurve:
573
572
  if not self.is_motion:
574
573
  raise ValueError("Not a motion curve, cannot split into Bezier curves.")
575
574
 
576
- from .RationalBezier import BezierSegment # inner import
575
+ from .RationalBezier import BezierSegment # lazy import
577
576
 
578
577
  curve = self.get_curve_in_pr12()
579
578
 
@@ -657,6 +656,11 @@ class RationalCurve:
657
656
  :raises ValueError: if the interval values are identical
658
657
  :raises ValueError: if the number of segments is less than 1
659
658
  """
659
+ try:
660
+ from scipy.integrate import quad # lazy import
661
+ except ImportError:
662
+ raise RuntimeError("Scipy import failed. Check the package installation.")
663
+
660
664
  if interval[0] > interval[1]:
661
665
  raise ValueError("The interval must be in the form [a, b] where a < b")
662
666
  elif interval[0] == interval[1]:
@@ -708,6 +712,11 @@ class RationalCurve:
708
712
  :return: t value that splits the curve into given segment length
709
713
  :rtype: float
710
714
  """
715
+ try:
716
+ from scipy.integrate import quad # lazy import
717
+ except ImportError:
718
+ raise RuntimeError("Scipy import failed. Check the package installation.")
719
+
711
720
  # initial lower and upper bounds
712
721
  low = section_start
713
722
  high = curve_interval[1] # start with the upper bound
@@ -1,5 +1,6 @@
1
1
  import numpy as np
2
- import sympy as sp
2
+
3
+ from sympy import Rational
3
4
 
4
5
  from .DualQuaternion import DualQuaternion
5
6
 
@@ -12,7 +13,7 @@ class RationalDualQuaternion(DualQuaternion):
12
13
  """
13
14
  RationalDualQuaternion class representing a 8-dimensional dual quaternion.
14
15
  """
15
- def __init__(self, study_parameters: list[sp.Rational]):
16
+ def __init__(self, study_parameters: list[Rational]):
16
17
  """
17
18
  RationalDualQuaternion class
18
19
 
@@ -34,7 +35,7 @@ class RationalDualQuaternion(DualQuaternion):
34
35
  """
35
36
  return f"{self.rational_numbers}"
36
37
 
37
- def __getitem__(self, idx) -> sp.Rational:
38
+ def __getitem__(self, idx) -> Rational:
38
39
  """
39
40
  Get an element of DualQuaternion
40
41
 
@@ -50,6 +51,6 @@ class RationalDualQuaternion(DualQuaternion):
50
51
  Get the array of the rational numbers
51
52
 
52
53
  :return: Rational numbers
53
- :rtype: sp.Matrix
54
+ :rtype: sympy.Matrix
54
55
  """
55
56
  return np.array(self.rational_numbers)
@@ -110,7 +110,7 @@ class RationalMechanism(RationalCurve):
110
110
  This metric is used for collision detection.
111
111
  """
112
112
  if self._metric is None:
113
- from .AffineMetric import AffineMetric # inner import
113
+ from .AffineMetric import AffineMetric # lazy import
114
114
  mechanism_points = self.points_at_parameter(0,
115
115
  inverted_part=True,
116
116
  only_links=False)
@@ -400,7 +400,7 @@ class RationalMechanism(RationalCurve):
400
400
  :return: list of TransfMatrix objects
401
401
  :rtype: list[TransfMatrix]
402
402
  """
403
- from .TransfMatrix import TransfMatrix # inner import
403
+ from .TransfMatrix import TransfMatrix # lazy import
404
404
 
405
405
  screws = deepcopy(self.get_screw_axes())
406
406
 
@@ -942,7 +942,7 @@ class RationalMechanism(RationalCurve):
942
942
  """
943
943
  Perform singularity check of the mechanism.
944
944
  """
945
- from .SingularityAnalysis import SingularityAnalysis # inner import
945
+ from .SingularityAnalysis import SingularityAnalysis # lazy import
946
946
 
947
947
  sa = SingularityAnalysis()
948
948
  return sa.check_singularity(self)
@@ -957,7 +957,7 @@ class RationalMechanism(RationalCurve):
957
957
  result of the optimization
958
958
  :rtype: list, list, float
959
959
  """
960
- from .CollisionFreeOptimization import CollisionFreeOptimization # inner import
960
+ from .CollisionFreeOptimization import CollisionFreeOptimization # lazy import
961
961
 
962
962
  # get smallest polyline
963
963
  pts, points_params, res = CollisionFreeOptimization(self).smallest_polyline()
@@ -1,4 +1,4 @@
1
- import sympy
1
+ from sympy import Matrix
2
2
 
3
3
  from .Linkage import LineSegment
4
4
  from .RationalMechanism import RationalMechanism
@@ -49,8 +49,7 @@ class SingularityAnalysis:
49
49
  # normalization
50
50
 
51
51
 
52
-
53
- jacobian = sympy.Matrix.zeros(6, len(algebraic_plucker_coords))
52
+ jacobian = Matrix.zeros(6, len(algebraic_plucker_coords))
54
53
  for i, plucker_line in enumerate(algebraic_plucker_coords):
55
54
  jacobian[:, i] = plucker_line.screw
56
55
 
@@ -13,7 +13,7 @@ def dq_algebraic2vector(ugly_expression: list) -> list:
13
13
  :return: 8-vector representation of the algebraic equation
14
14
  :rtype: list
15
15
  """
16
- from sympy import expand, symbols # inner import
16
+ from sympy import expand, symbols # lazy import
17
17
  i, j, k, epsilon = symbols('i j k epsilon')
18
18
 
19
19
  expr = expand(ugly_expression)
@@ -41,7 +41,7 @@ def extract_coeffs(expr, var, deg: int, expand: bool = True):
41
41
  :rtype: list
42
42
  """
43
43
  if expand:
44
- from sympy import expand # inner import
44
+ from sympy import expand # lazy import
45
45
  expr = expand(expr)
46
46
  return [expr.coeff(var, i) for i in range(deg, -1, -1)]
47
47
 
@@ -97,10 +97,67 @@ def is_package_installed(package_name: str) -> bool:
97
97
  """
98
98
  Check if a package is installed.
99
99
  """
100
- from importlib.metadata import distribution
100
+ from importlib.metadata import distribution # lazy import
101
101
 
102
102
  try:
103
103
  distribution(package_name)
104
104
  return True
105
105
  except ImportError:
106
106
  return False
107
+
108
+
109
+ def tr_from_dh_rationally(t_theta, di, ai, t_alpha):
110
+ """
111
+ Create transformation matrix from DH parameters using Sympy in rational form.
112
+
113
+ The input shall be rational numbers, including the angles which are expected
114
+ to be parameters of tangent half-angle substitution, i.e., t_theta = tan(theta/2)
115
+ and t_alpha = tan(alpha/2).
116
+
117
+ :param sp.Rational t_theta: DH parameter theta in tangent half-angle form
118
+ :param sp.Rational di: DH parameter d, the offset along Z axis
119
+ :param sp.Rational ai: DH parameter a, the length along X axis
120
+ :param sp.Rational t_alpha: DH parameter alpha in tangent half-angle form
121
+
122
+ :return: 4x4 transformation matrix
123
+ :rtype: sp.Matrix
124
+ """
125
+ from sympy import Matrix, eye, Expr # lazy import
126
+
127
+ if not all(isinstance(param, Expr) for param in [t_theta, di, ai, t_alpha]):
128
+ raise ValueError("All parameters must be of type sympy objects (Expr).")
129
+
130
+ s_th = 2*t_theta / (1 + t_theta**2)
131
+ c_th = (1 - t_theta**2) / (1 + t_theta**2)
132
+ s_al = 2*t_alpha / (1 + t_alpha**2)
133
+ c_al = (1 - t_alpha**2) / (1 + t_alpha**2)
134
+
135
+ mat = eye(4)
136
+ mat[1:4, 0] = Matrix([ai * c_th, ai * s_th, di])
137
+ mat[1, 1:4] = Matrix([[c_th, -s_th * c_al, s_th * s_al]])
138
+ mat[2, 1:4] = Matrix([[s_th, c_th * c_al, -c_th * s_al]])
139
+ mat[3, 1:4] = Matrix([[0, s_al, c_al]])
140
+ return mat
141
+
142
+
143
+ def normalized_line_rationally(point, direction):
144
+ """
145
+ Create a normalized Plücker line from a point and a direction using Sympy.
146
+
147
+ The input shall be rational numbers, i.e. Sympy objects.
148
+
149
+ :param sp.Rational point:
150
+ :param sp.Rational direction:
151
+
152
+ :return: 6-vector representing the Plücker line
153
+ :rtype: sp.Matrix
154
+ """
155
+ from sympy import Matrix, Expr # lazy import
156
+
157
+ if not all(isinstance(param, Expr) for param in point + direction):
158
+ raise ValueError("All parameters must be of type sympy objects (Expr).")
159
+
160
+ dir = Matrix(direction)
161
+ pt = Matrix(point)
162
+ mom = (-1 * dir).cross(pt)
163
+ return Matrix.vstack(dir, mom)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: rational-linkages
3
- Version: 2.1.0
3
+ Version: 2.2.0
4
4
  Summary: Rational Linkages
5
5
  Author-email: Daniel Huczala <daniel.huczala@uibk.ac.at>
6
6
  License-Expression: GPL-3.0-or-later
@@ -14,15 +14,18 @@ Requires-Python: >=3.10
14
14
  Description-Content-Type: text/markdown
15
15
  License-File: LICENSE
16
16
  Requires-Dist: biquaternion-py>=1.2.0
17
- Requires-Dist: scipy>=1.10.0
17
+ Requires-Dist: numpy>=1.10.0
18
18
  Requires-Dist: sympy>=1.10.0
19
19
  Requires-Dist: PyQt6>=6.2.0
20
20
  Requires-Dist: pyqtgraph>=0.12.4
21
21
  Requires-Dist: PyOpenGL>=3.0.0
22
+ Requires-Dist: matplotlib>=3.9.0; platform_system == "Linux"
23
+ Requires-Dist: matplotlib>=3.9.0; platform_system == "Windows" and platform_machine == "ARM64"
22
24
  Provides-Extra: opt
23
25
  Requires-Dist: ipython>=8.0.0; extra == "opt"
24
- Requires-Dist: gmpy2>=2.2.0; extra == "opt"
26
+ Requires-Dist: scipy>=1.10.0; extra == "opt"
25
27
  Requires-Dist: matplotlib>=3.9.0; extra == "opt"
28
+ Requires-Dist: gmpy2>=2.2.0; (platform_system != "Windows" and platform_machine != "ARM64") and extra == "opt"
26
29
  Provides-Extra: exu
27
30
  Requires-Dist: exudyn>=1.9.0; extra == "exu"
28
31
  Requires-Dist: numpy-stl>=3.0.0; extra == "exu"
@@ -113,17 +116,28 @@ Using pip:
113
116
 
114
117
  <code>pip install rational-linkages</code>
115
118
 
116
- or
119
+ or with optional dependencies:
117
120
 
118
- <code>pip install rational-linkages[opt]</code>
121
+ <code>pip install rational-linkages[opt,exu]</code>
119
122
 
120
- Mac users might need to use backslashes to escape the brackets, e.g.:
123
+ Mac/linux users might need to use backslashes to escape the brackets, e.g.:
121
124
 
122
- <code>pip install rational-linkages\\[opt\\]</code>
125
+ <code>pip install rational-linkages\\[opt,exu\\]</code>
123
126
 
124
- for installing also optional dependencies (ipython - inline plotting, gmpy2 - faster
125
- symbolic computations, exudyn - multibody simulations, numpy-stl -
126
- work with meshes in exudyn).
127
+ for installing also **opt**ional dependencies (scipy - optimization problems solving, ipython - inline plotting,
128
+ matplotlib - alternative engine for 3D plotting, gmpy2 - optimized symbolic computations)
129
+ and **exu**dyn dependencies (exudyn - multibody simulations,
130
+ numpy-stl + ngsolve - work with meshes in exudyn).
131
+
132
+ On **Linux systems**, to run GUI interactive plotting,
133
+ some additional libraries are required for plotting with PyQt6. For example,
134
+ on Ubuntu, it can be installed as follows:
135
+
136
+ <code>sudo apt install libgl1-mesa-glx libxkbcommon-x11-0 libegl1 libdbus-1-3</code>
137
+
138
+ or on Ubuntu 24.04 and higher:
139
+
140
+ <code>sudo apt install libgl1 libxkbcommon-x11-0 libegl1 libdbus-1-3</code>
127
141
 
128
142
  ### Install from source
129
143
 
@@ -143,21 +157,21 @@ work with meshes in exudyn).
143
157
 
144
158
  <code>pip install -e .[opt,dev,doc]</code> including the development and documentation dependencies.
145
159
 
146
- Mac or Linux users might need to use backslashes to escape the brackets, e.g.:
160
+ Mac/linux users might need to use backslashes to escape the brackets, e.g.:
147
161
 
148
162
  <code>pip install -e .\\[opt\\]</code>
149
163
 
150
- Additionally, on Linux systems, some additional libraries are required for plotting with PyQt6. For example,
151
- on Ubuntu, it can be installed as follows:
152
164
 
153
- <code>sudo apt install libgl1-mesa-glx libxkbcommon-x11-0 libegl1 libdbus-1-3</code>
154
165
 
155
- or on Ubuntu 24.04 and higher:
166
+ To run the Rust functions, you need to install the [Rust toolchain](https://www.rust-lang.org) and
167
+ build the Rust code yourself. On top of that, on Windows, you need to install a
168
+ C++ build toolchain. In `Visual Studio Installer`, select:
156
169
 
157
- <code>sudo apt install libgl1 libxkbcommon-x11-0 libegl1 libdbus-1-3</code>
170
+ * MSVC v143 - VS 2022 C++ x64/x86 build tools (latest)
171
+ * Windows 11 SDK
172
+ * C++ CMake tools for Windows
158
173
 
159
- To run the Rust functions, you need to install the [Rust toolchain](https://www.rust-lang.org) and
160
- build the Rust code yourself, for example:
174
+ Then, navigate to the `rational_linkages/rust` folder and run:
161
175
 
162
176
  <code>cargo build --release</code>
163
177
 
@@ -0,0 +1,40 @@
1
+ rational_linkages/AffineMetric.py,sha256=ky_DdcPx91k3USU-J4x9854wtnLHfQwjOFAfO_AV-dw,6451
2
+ rational_linkages/CollisionAnalyser.py,sha256=oVUidgAmVaGybayCmbJxlzSO-ZW8k4EkkKtbehbVL74,21091
3
+ rational_linkages/CollisionFreeOptimization.py,sha256=JPqwcV3A38TQou9MLRN1OwJwrM5rEXxwCb0QzP-dCy4,12328
4
+ rational_linkages/DualQuaternion.py,sha256=FPeUPLhT4xNi7rtvbPtCXuSXNLaGKHXaxdIDj8VphQw,24688
5
+ rational_linkages/DualQuaternionAction.py,sha256=CB05xGXkhd_2Is8iMnLn7XQd4bLszqkWk8TM85rxx1g,4394
6
+ rational_linkages/ExudynAnalysis.py,sha256=Z3TsLZfs89KCgY5njqQ_NpTiZXYDo2CvEy5SVZa1BG0,6106
7
+ rational_linkages/FactorizationProvider.py,sha256=WB_eBFbH28Pyt141qfxzlpRdraLSl1-YbgQl5inoydg,6636
8
+ rational_linkages/Linkage.py,sha256=7EfFhI0As_h17BWhimxHlEszewwipVuMf-toXuAmVwU,10095
9
+ rational_linkages/MiniBall.py,sha256=dqCV53avb1Z4ucipTng4NypsGlGYEMGSKsrqmZX7YKM,10170
10
+ rational_linkages/MotionApproximation.py,sha256=XkotKnIg8pRdIJy6cja-AmXMV7tvgp8_dCa4kjgVCzU,9964
11
+ rational_linkages/MotionDesigner.py,sha256=E59hkSAHWh0_uezTZeY2MGOz07JxHFJMb04rhAT-EwE,29203
12
+ rational_linkages/MotionFactorization.py,sha256=ecO6IEh6QVk_toNXDNiP5Py-dGC6jpdCU8SNGOy0GTA,16803
13
+ rational_linkages/MotionInterpolation.py,sha256=fji0E2UDhHNJ3YatCNTajQAgWe-e2MunZjH4kpkSyGY,35037
14
+ rational_linkages/NormalizedLine.py,sha256=XbQYVJsmACRHWauaxpdMtuesUCwCpgrJ0_8Yqa6gPk0,15219
15
+ rational_linkages/NormalizedPlane.py,sha256=3Wxknual_h8gGQLWcKOdJRhhzO04syvdH3eHkJl0Mb0,5853
16
+ rational_linkages/Plotter.py,sha256=JWZH2crPwE77ExwC8C5sZT2z7Mz7ZRGNFIp7f82pTM0,4352
17
+ rational_linkages/PlotterMatplotlib.py,sha256=EH0dXjvt1vN7RC0vs6nx4NCM3uWlxbyJYzvHx_rr12w,36756
18
+ rational_linkages/PlotterPyqtgraph.py,sha256=1N3w4ONeBPkiBquWC8hViTwLAfRBdGzUdtGXjRbNHpY,51306
19
+ rational_linkages/PointHomogeneous.py,sha256=3CKh1jmcGNqUfY2aA0ca7Kg5LIzOaiAAhfAbzU_omEM,13355
20
+ rational_linkages/Quaternion.py,sha256=j9EyUOqJHNMNB5k3hIh0MjK52R2ES_UA2MhetpB9VZg,5083
21
+ rational_linkages/RationalBezier.py,sha256=irpwzO6pN-32OS3EBMRX6WKcYOMb1OnPtNeJlILHFeE,14822
22
+ rational_linkages/RationalCurve.py,sha256=mPTtroMrAXION-924TT6ATDlgLaF8nxeuLDhcndugdE,28296
23
+ rational_linkages/RationalDualQuaternion.py,sha256=2gogaelV4j4nFLkPQRxqHH0jMHY20XIQY_SNKsPAaDw,1438
24
+ rational_linkages/RationalMechanism.py,sha256=NT6YrXEy9reZz0wKD96NkihfrY9sSVBzOcvCpoHQjFA,63115
25
+ rational_linkages/SingularityAnalysis.py,sha256=hxCfjDQafH4luPCO5cATCATz13-YssWynGqhqCQ9Bqk,1847
26
+ rational_linkages/StaticMechanism.py,sha256=Slh6-9ml6p9jX-krvJ7_sJ8fRropBG-nsUboDyVJJSY,12476
27
+ rational_linkages/TransfMatrix.py,sha256=9Hx-jxV_hgvOsmVgedMlTss-E4D40TaN6zCSR0n_5Yc,16355
28
+ rational_linkages/__init__.py,sha256=EOM1Nu9cecOyNFIb2nVaYE3X9Va_SzDMXa_L0Jj61uo,1023
29
+ rational_linkages/models.py,sha256=J3mJahJIJ_1MgY018iNG0MYwc47Gvh9gQShbLMBX94c,7105
30
+ rational_linkages/utils.py,sha256=lUxWCwcQvnd_rATeIdotvkHqFYdKjwjOeZWrImxFomo,5084
31
+ rational_linkages/utils_rust.cpython-312-aarch64-linux-gnu.so,sha256=ykLpLe1OjQbyeaio43NpONyvsdTXMCrZimtyEiY63kw,566376
32
+ rational_linkages/utils_rust.pyi,sha256=d0jxgYhwPQRbGY21dsXAXaWJb0OQWIEkUH3R4pP3sYs,137
33
+ rational_linkages/data/bennett_ark24.pkl,sha256=Eh7S5PHOi0ENg8-FS7KjQsc6BBeMXT984Yz5VKiqwNM,39216
34
+ rational_linkages/data/collisions_free_6r.pkl,sha256=XZFvnt8jEUfDY3JacLlS1kE-EQvtgmb7Un07DovmUmg,73101
35
+ rational_linkages/data/plane_fold_6r.pkl,sha256=lbrnqFksdJ6QW4LJqyVv-ujjhP25kkUWdGY7bjR6Hbo,48752
36
+ rational_linkages-2.2.0.dist-info/METADATA,sha256=zROC8j1g98a1OFznPBq4acFJxUIeTG6AKMB82uqdLrE,9692
37
+ rational_linkages-2.2.0.dist-info/WHEEL,sha256=29GglsfgOKni3MnvXwDNoeBjBZY4LOjl_HH3QTWETk4,153
38
+ rational_linkages-2.2.0.dist-info/top_level.txt,sha256=IxRIuCa6RJFZKK15jamktxgS0abg1PV2WqXo1Z-MalI,18
39
+ rational_linkages-2.2.0.dist-info/RECORD,,
40
+ rational_linkages-2.2.0.dist-info/licenses/LICENSE,sha256=L6gckgyu1UWPusHTuO7e5Lz62VaOlvh-I1kPZ4cGycQ,35110
@@ -1,40 +0,0 @@
1
- rational_linkages/AffineMetric.py,sha256=ky_DdcPx91k3USU-J4x9854wtnLHfQwjOFAfO_AV-dw,6451
2
- rational_linkages/CollisionAnalyser.py,sha256=YrR9EJZmOMvZyLcRdrCnjZd1V6wBlT62-1q3xeLWLOA,20940
3
- rational_linkages/CollisionFreeOptimization.py,sha256=BEAZxOUjC2JOgBOKgO_T02_s_3Q74zrD1KWMkJyJU_w,12189
4
- rational_linkages/DualQuaternion.py,sha256=Y5_vpNE2D6Yr0LG9EpZ3tXKdgw9L1pCEnMToonMmPWw,24551
5
- rational_linkages/DualQuaternionAction.py,sha256=CB05xGXkhd_2Is8iMnLn7XQd4bLszqkWk8TM85rxx1g,4394
6
- rational_linkages/ExudynAnalysis.py,sha256=Z3TsLZfs89KCgY5njqQ_NpTiZXYDo2CvEy5SVZa1BG0,6106
7
- rational_linkages/FactorizationProvider.py,sha256=P10xj6GfDKX2lw9Ou-aE0W0_5RWNnyh6FbQhTQyV-YE,6631
8
- rational_linkages/Linkage.py,sha256=7EfFhI0As_h17BWhimxHlEszewwipVuMf-toXuAmVwU,10095
9
- rational_linkages/MiniBall.py,sha256=bbW-vRlWuxZibqdJdC2sXIrJpVchxcAuYD0TP6hRY8w,9912
10
- rational_linkages/MotionApproximation.py,sha256=znmJf3hQMxvLbX4MCSOqodNCgSV25Gb8XRQwmnEMWrI,9878
11
- rational_linkages/MotionDesigner.py,sha256=ofQvpD4iFzGkO58VlJAaODRKld6mHDOaCoFTYb-U-0Y,28895
12
- rational_linkages/MotionFactorization.py,sha256=25YCv69a9bs88bkYKWO_Y9yJecbSjkwRGNub-geGreQ,16802
13
- rational_linkages/MotionInterpolation.py,sha256=foZjh-snmgO6rj9ZhCH-Lu39l4OL8szp51gxzXATiGU,35038
14
- rational_linkages/NormalizedLine.py,sha256=XbQYVJsmACRHWauaxpdMtuesUCwCpgrJ0_8Yqa6gPk0,15219
15
- rational_linkages/NormalizedPlane.py,sha256=3Wxknual_h8gGQLWcKOdJRhhzO04syvdH3eHkJl0Mb0,5853
16
- rational_linkages/Plotter.py,sha256=JWZH2crPwE77ExwC8C5sZT2z7Mz7ZRGNFIp7f82pTM0,4352
17
- rational_linkages/PlotterMatplotlib.py,sha256=h2iRIhfN17R4NIv9IsaDzL3ltTJN0sOs_y5PODXL4Tc,36502
18
- rational_linkages/PlotterPyqtgraph.py,sha256=0zD89MBRudywpr_hw743RvGg31BqJse9Q_BUmLYwfuw,50969
19
- rational_linkages/PointHomogeneous.py,sha256=3CKh1jmcGNqUfY2aA0ca7Kg5LIzOaiAAhfAbzU_omEM,13355
20
- rational_linkages/Quaternion.py,sha256=j9EyUOqJHNMNB5k3hIh0MjK52R2ES_UA2MhetpB9VZg,5083
21
- rational_linkages/RationalBezier.py,sha256=xzOnu5r_W1CZIGQCsTEQcVuADX9WifsZdYNg_5yGPUg,14878
22
- rational_linkages/RationalCurve.py,sha256=53Sd-lHwhvjzUakvAQMkMNtu9MNv299oyC-FfdHMeJc,27953
23
- rational_linkages/RationalDualQuaternion.py,sha256=_JTXjmDY2RbX71GIRYCyO9ko6jiLUtiDzNbtbsuWfXU,1432
24
- rational_linkages/RationalMechanism.py,sha256=pIhRmrIwfF1Ha3TGhFwUJgtoT1j0sPfviuCYycETrwc,63119
25
- rational_linkages/SingularityAnalysis.py,sha256=kVLm6Nz1IE6pPJLk1DUXGnlyMlByo_Fk2hEkpdF3iRc,1842
26
- rational_linkages/StaticMechanism.py,sha256=Slh6-9ml6p9jX-krvJ7_sJ8fRropBG-nsUboDyVJJSY,12476
27
- rational_linkages/TransfMatrix.py,sha256=9Hx-jxV_hgvOsmVgedMlTss-E4D40TaN6zCSR0n_5Yc,16355
28
- rational_linkages/__init__.py,sha256=EOM1Nu9cecOyNFIb2nVaYE3X9Va_SzDMXa_L0Jj61uo,1023
29
- rational_linkages/models.py,sha256=J3mJahJIJ_1MgY018iNG0MYwc47Gvh9gQShbLMBX94c,7105
30
- rational_linkages/utils.py,sha256=XKvukpwLPmu1khL63molq2sa0KpvUAH2LaX-bnsU-bE,3046
31
- rational_linkages/utils_rust.cpython-312-aarch64-linux-gnu.so,sha256=-4Iqdi_KJYtlK0tBHhAP_Kbe8n8zoSJBLd2pfINKHi8,566376
32
- rational_linkages/utils_rust.pyi,sha256=d0jxgYhwPQRbGY21dsXAXaWJb0OQWIEkUH3R4pP3sYs,137
33
- rational_linkages/data/bennett_ark24.pkl,sha256=Eh7S5PHOi0ENg8-FS7KjQsc6BBeMXT984Yz5VKiqwNM,39216
34
- rational_linkages/data/collisions_free_6r.pkl,sha256=XZFvnt8jEUfDY3JacLlS1kE-EQvtgmb7Un07DovmUmg,73101
35
- rational_linkages/data/plane_fold_6r.pkl,sha256=lbrnqFksdJ6QW4LJqyVv-ujjhP25kkUWdGY7bjR6Hbo,48752
36
- rational_linkages-2.1.0.dist-info/METADATA,sha256=IlVBpmnUUL3KbWqgVA-kyXCEws5ADWTUN4ym19JktqI,8956
37
- rational_linkages-2.1.0.dist-info/WHEEL,sha256=29GglsfgOKni3MnvXwDNoeBjBZY4LOjl_HH3QTWETk4,153
38
- rational_linkages-2.1.0.dist-info/top_level.txt,sha256=IxRIuCa6RJFZKK15jamktxgS0abg1PV2WqXo1Z-MalI,18
39
- rational_linkages-2.1.0.dist-info/RECORD,,
40
- rational_linkages-2.1.0.dist-info/licenses/LICENSE,sha256=L6gckgyu1UWPusHTuO7e5Lz62VaOlvh-I1kPZ4cGycQ,35110