rational-linkages 2.1.0__cp313-cp313-win_amd64.whl → 2.2.0__cp313-cp313-win_amd64.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.
- rational_linkages/CollisionAnalyser.py +12 -7
- rational_linkages/CollisionFreeOptimization.py +4 -1
- rational_linkages/DualQuaternion.py +5 -2
- rational_linkages/FactorizationProvider.py +6 -5
- rational_linkages/MiniBall.py +8 -1
- rational_linkages/MotionApproximation.py +5 -1
- rational_linkages/MotionDesigner.py +32 -28
- rational_linkages/MotionFactorization.py +6 -5
- rational_linkages/MotionInterpolation.py +1 -1
- rational_linkages/PlotterMatplotlib.py +16 -4
- rational_linkages/PlotterPyqtgraph.py +17 -4
- rational_linkages/RationalBezier.py +2 -3
- rational_linkages/RationalCurve.py +12 -3
- rational_linkages/RationalDualQuaternion.py +5 -4
- rational_linkages/RationalMechanism.py +4 -4
- rational_linkages/SingularityAnalysis.py +2 -3
- rational_linkages/utils.py +60 -3
- rational_linkages/utils_rust.cp313-win_amd64.pyd +0 -0
- {rational_linkages-2.1.0.dist-info → rational_linkages-2.2.0.dist-info}/METADATA +32 -18
- rational_linkages-2.2.0.dist-info/RECORD +40 -0
- rational_linkages-2.1.0.dist-info/RECORD +0 -40
- {rational_linkages-2.1.0.dist-info → rational_linkages-2.2.0.dist-info}/WHEEL +0 -0
- {rational_linkages-2.1.0.dist-info → rational_linkages-2.2.0.dist-info}/licenses/LICENSE +0 -0
- {rational_linkages-2.1.0.dist-info → rational_linkages-2.2.0.dist-info}/top_level.txt +0 -0
@@ -1,8 +1,8 @@
|
|
1
1
|
import numpy
|
2
|
-
import sympy
|
3
|
-
from scipy.optimize import minimize
|
4
2
|
|
5
|
-
from
|
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 =
|
50
|
+
t = symbols('t')
|
51
51
|
|
52
52
|
motions = []
|
53
53
|
for motion in relative_motions:
|
54
|
-
motions.append(RationalCurve([
|
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 =
|
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([
|
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
|
-
|
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
|
229
|
+
from sympy import Rational
|
230
230
|
|
231
231
|
if study_parameters is not None:
|
232
|
-
rational_numbers = [
|
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
|
-
|
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 =
|
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],
|
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 =
|
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 =
|
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)
|
rational_linkages/MiniBall.py
CHANGED
@@ -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
|
-
|
8
|
-
from
|
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
|
"""
|
@@ -29,14 +40,16 @@ class MotionDesigner:
|
|
29
40
|
|
30
41
|
:examples:
|
31
42
|
|
32
|
-
|
43
|
+
Run motion designer without initial points or poses:
|
44
|
+
|
45
|
+
.. testcode:: [motiondesigner_ex1]
|
33
46
|
|
34
47
|
from rational_linkages import MotionDesigner
|
35
48
|
|
36
49
|
d = MotionDesigner(method='quadratic_from_poses')
|
37
50
|
d.show()
|
38
51
|
|
39
|
-
.. testoutput:: [
|
52
|
+
.. testoutput:: [motiondesigner_ex1]
|
40
53
|
:hide:
|
41
54
|
|
42
55
|
Closing the window... generated points for interpolation:
|
@@ -44,11 +57,15 @@ class MotionDesigner:
|
|
44
57
|
[ 1. , -0.207522406 , -0.0333866662, -0.0691741237, -0.0625113682, -0.141265791 , -0.4478576802, -0.2637268902]
|
45
58
|
[ 1. , 0.2333739522, -0.0427838517, 0.0777914503, -0.0839342318, 0.2991396249, 0.2980046603, 0.345444421 ]
|
46
59
|
|
47
|
-
.. testcleanup:: [
|
60
|
+
.. testcleanup:: [motiondesigner_ex1]
|
48
61
|
|
49
62
|
del d, MotionDesigner
|
50
63
|
|
51
|
-
|
64
|
+
Run motion designer with initial points:
|
65
|
+
|
66
|
+
.. code-block:: python
|
67
|
+
|
68
|
+
# NOT TESTED
|
52
69
|
|
53
70
|
from rational_linkages import MotionDesigner, PointHomogeneous
|
54
71
|
|
@@ -65,19 +82,6 @@ class MotionDesigner:
|
|
65
82
|
d = MotionDesigner(method='quadratic_from_points', initial_points_or_poses=chosen_points)
|
66
83
|
d.show()
|
67
84
|
|
68
|
-
.. testoutput:: [motiondesigner_example2]
|
69
|
-
:hide:
|
70
|
-
|
71
|
-
Closing the window... generated points for interpolation:
|
72
|
-
[ 1. , -0.2 , 0. , 1.76]
|
73
|
-
[1., 1., 1., 2.]
|
74
|
-
[ 1., 3., -3., 1.]
|
75
|
-
[ 1., 2., -4., 1.]
|
76
|
-
[ 1., -2., -2., 2.]
|
77
|
-
|
78
|
-
.. testcleanup:: [motiondesigner_example2]
|
79
|
-
|
80
|
-
del d, MotionDesigner, PointHomogeneous, chosen_points
|
81
85
|
|
82
86
|
"""
|
83
87
|
def __init__(self,
|
@@ -1,7 +1,8 @@
|
|
1
1
|
from typing import Union
|
2
2
|
|
3
3
|
import numpy as np
|
4
|
-
|
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)[
|
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 =
|
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 [
|
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 =
|
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 #
|
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 #
|
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
|
-
|
5
|
-
from
|
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 #
|
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 #
|
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 #
|
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 #
|
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
|
-
|
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[
|
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) ->
|
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:
|
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 #
|
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 #
|
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 #
|
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 #
|
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
|
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
|
|
rational_linkages/utils.py
CHANGED
@@ -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 #
|
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 #
|
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)
|
Binary file
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: rational-linkages
|
3
|
-
Version: 2.
|
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:
|
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:
|
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
|
125
|
-
|
126
|
-
|
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
|
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
|
-
|
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
|
-
|
170
|
+
* MSVC v143 - VS 2022 C++ x64/x86 build tools (latest)
|
171
|
+
* Windows 11 SDK
|
172
|
+
* C++ CMake tools for Windows
|
158
173
|
|
159
|
-
|
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=5tT2fw_3s8ZNDQbxMwUnFPdzyXfq8QhcH28ri-ZRsyE,6650
|
2
|
+
rational_linkages/CollisionAnalyser.py,sha256=JQYjJFtrNeEUuLB1lv6HMHX3PL1PP4pw6YzELHQw6ZU,21607
|
3
|
+
rational_linkages/CollisionFreeOptimization.py,sha256=Il5KRl9XxyGLwRGNbLHJ7C8JvXpumDm0LXtSDNfW5W8,12628
|
4
|
+
rational_linkages/DualQuaternion.py,sha256=LFM_g2d7hyHaxNPgAueL1dt6qlPA4tSMpWRyv5-15MI,25430
|
5
|
+
rational_linkages/DualQuaternionAction.py,sha256=EgwULVtLSenGlUYXXXdshbt2PeoiJ32ZeTyssMBdKIs,4530
|
6
|
+
rational_linkages/ExudynAnalysis.py,sha256=OuW-k9yzgstN6id9Fa_CW4SdAYPbDliQXHVsVni1sf8,6283
|
7
|
+
rational_linkages/FactorizationProvider.py,sha256=Khq5pz_iXmyw6WHqapyzPEUOfLVge3uwsr4EFn6FshE,6802
|
8
|
+
rational_linkages/Linkage.py,sha256=X56Hn46R0F8OXHIj5PpVzEtCMwZu_9OaxX_OgRvIyHA,10380
|
9
|
+
rational_linkages/MiniBall.py,sha256=tjnVtOMfiSih_qnCa5HfQNbW_6A694XY_xzLikA1kG8,10423
|
10
|
+
rational_linkages/MotionApproximation.py,sha256=YtLx9ShEedsUaBVMzNzfWj0G_Ueuamx8xX4QU2V_xWU,10237
|
11
|
+
rational_linkages/MotionDesigner.py,sha256=SrIm_EcI5W0hSF9KWmG7a6gw0X95XQH422S--OD3zyY,29580
|
12
|
+
rational_linkages/MotionFactorization.py,sha256=Fvt6BHvMu8N1g4KVZU-5GMxP3uy-HBzuG7otdhdmp_A,17246
|
13
|
+
rational_linkages/MotionInterpolation.py,sha256=CnD72edjR9_StW9J31Vjif2JCpFq2ZdLw9UF4mBubgQ,35934
|
14
|
+
rational_linkages/NormalizedLine.py,sha256=J41UnSQg6jS23uW_oKYzse_MLRqEMgC-RQ0jNzpfP_A,15646
|
15
|
+
rational_linkages/NormalizedPlane.py,sha256=KlsV2Bems4onD_TTDj9SaPa57hVjZHiTt4tqZ5jpRZw,6032
|
16
|
+
rational_linkages/Plotter.py,sha256=g-DI3kKh6-Y1Q5uvGde-exDeFkifia7MIQDVK3FQsvo,4456
|
17
|
+
rational_linkages/PlotterMatplotlib.py,sha256=H53nc147fgw8iTP2xeiphIaHdW9URTTX7zyAucsHHhw,37734
|
18
|
+
rational_linkages/PlotterPyqtgraph.py,sha256=jZAvJTbof4rUUzGMYRY23raKaYafskylPR0AV8vLIpg,52541
|
19
|
+
rational_linkages/PointHomogeneous.py,sha256=PFOUriVm-kRvV2PzlyyZcrw2wlCK3uGDB3ZEgfXP5v4,13784
|
20
|
+
rational_linkages/Quaternion.py,sha256=RDRRczv10hLehnsJepwYXXBQeum9-tfstJATdsDCssE,5285
|
21
|
+
rational_linkages/RationalBezier.py,sha256=sPoWuVcjm_EiaRDMHPEUaeFO8MMWZUSSq4MSUrznPrs,15243
|
22
|
+
rational_linkages/RationalCurve.py,sha256=MGg4_sBMDukBI2kO8NahW6BWNcJ8_A_JMHbgVGtO71M,29066
|
23
|
+
rational_linkages/RationalDualQuaternion.py,sha256=Os3kcLE9qdXyh0EwVxtsPn-MCeEqXS6LTROpYt-spjc,1494
|
24
|
+
rational_linkages/RationalMechanism.py,sha256=7xJVQigyu8HP2r0Mh9RQ5P090VDVe4GYMc5ENDIJxdc,64658
|
25
|
+
rational_linkages/SingularityAnalysis.py,sha256=Dv7giyGFty53BqbIXJfJR_C5zkJOc3mbSIuU8I-MN68,1903
|
26
|
+
rational_linkages/StaticMechanism.py,sha256=gWheI8nz4lrQLs9lLKasxuxupVuyjim610W-F8-d0SY,12795
|
27
|
+
rational_linkages/TransfMatrix.py,sha256=UuPw5z6wBgqxYwNczxgYJfvjyYl_rxk5Bhax-pRTBiE,16810
|
28
|
+
rational_linkages/__init__.py,sha256=j51yV2-UG2vDFIUmV0sg0TDb5RmbhJ6LBaalrZspisQ,1050
|
29
|
+
rational_linkages/models.py,sha256=aMdyKBeLDi3XtXebW84K1w8VL8g3eqlMXVCG6OJqrb4,7246
|
30
|
+
rational_linkages/utils.py,sha256=yWALKgkgTcYobZVCWuyAspe0DFdmagBTVyH16rdxqmk,5246
|
31
|
+
rational_linkages/utils_rust.cp313-win_amd64.pyd,sha256=Loyyz0vjIRLx8_ADqSpqa4jKMxZ3g3OKzJI1hF1D3F4,244736
|
32
|
+
rational_linkages/utils_rust.pyi,sha256=iTaedylbvDNplOzrd1RZ0PPJzCvh20w52ewbLiuAgnU,140
|
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/licenses/LICENSE,sha256=SrpxAZ1vJi81S4VF9EBjgxz9qrVj9acCyQPSAk3JgOo,35784
|
37
|
+
rational_linkages-2.2.0.dist-info/METADATA,sha256=QrSr-JP9QWjHcRwiqENcXv1_aKxdGqel8tqhxdTaNF8,9904
|
38
|
+
rational_linkages-2.2.0.dist-info/WHEEL,sha256=qV0EIPljj1XC_vuSatRWjn02nZIz3N1t8jsZz7HBr2U,101
|
39
|
+
rational_linkages-2.2.0.dist-info/top_level.txt,sha256=IxRIuCa6RJFZKK15jamktxgS0abg1PV2WqXo1Z-MalI,18
|
40
|
+
rational_linkages-2.2.0.dist-info/RECORD,,
|
@@ -1,40 +0,0 @@
|
|
1
|
-
rational_linkages/AffineMetric.py,sha256=5tT2fw_3s8ZNDQbxMwUnFPdzyXfq8QhcH28ri-ZRsyE,6650
|
2
|
-
rational_linkages/CollisionAnalyser.py,sha256=0Y3ld_Km9WyrHy-nQDD0doXbR0aTEXbjfOUxYDhRJcY,21451
|
3
|
-
rational_linkages/CollisionFreeOptimization.py,sha256=-Vl5KE0KkXwc18Xgbjqvin2ExV302onfO6DK0LTf63U,12486
|
4
|
-
rational_linkages/DualQuaternion.py,sha256=J6gTgQxO1piIA615jBX4ubqwwicUFkr49FDsiRN1sdI,25290
|
5
|
-
rational_linkages/DualQuaternionAction.py,sha256=EgwULVtLSenGlUYXXXdshbt2PeoiJ32ZeTyssMBdKIs,4530
|
6
|
-
rational_linkages/ExudynAnalysis.py,sha256=OuW-k9yzgstN6id9Fa_CW4SdAYPbDliQXHVsVni1sf8,6283
|
7
|
-
rational_linkages/FactorizationProvider.py,sha256=Faqxv15MAzNJh6zzGgvXULfzGRkl_6Ciy22usM2kDJs,6796
|
8
|
-
rational_linkages/Linkage.py,sha256=X56Hn46R0F8OXHIj5PpVzEtCMwZu_9OaxX_OgRvIyHA,10380
|
9
|
-
rational_linkages/MiniBall.py,sha256=dyjHkjsYVHBiw4uT2tpY1kV3-aC6VGQbsLHmgsTUF20,10158
|
10
|
-
rational_linkages/MotionApproximation.py,sha256=C01okbvF5AP49jgKyKysc7CCF8Z0iyNO18sN_FY4hyc,10147
|
11
|
-
rational_linkages/MotionDesigner.py,sha256=lWGsn4bffD4WBq9p2dshGUv9QBPULI0FEU_HgxdhHNw,29563
|
12
|
-
rational_linkages/MotionFactorization.py,sha256=5jsMc15pxzAouiQ1_63ppmgV-SgDhyZgjCGexyUisnM,17244
|
13
|
-
rational_linkages/MotionInterpolation.py,sha256=FZg6tTSJO5xkhV42JwFbwKeCUQsVfLGHmRu8RMQ2iJg,35935
|
14
|
-
rational_linkages/NormalizedLine.py,sha256=J41UnSQg6jS23uW_oKYzse_MLRqEMgC-RQ0jNzpfP_A,15646
|
15
|
-
rational_linkages/NormalizedPlane.py,sha256=KlsV2Bems4onD_TTDj9SaPa57hVjZHiTt4tqZ5jpRZw,6032
|
16
|
-
rational_linkages/Plotter.py,sha256=g-DI3kKh6-Y1Q5uvGde-exDeFkifia7MIQDVK3FQsvo,4456
|
17
|
-
rational_linkages/PlotterMatplotlib.py,sha256=WfH-hPo1aclSBH9vmApMmUota0Cz9gnHGWWEedKK6R0,37468
|
18
|
-
rational_linkages/PlotterPyqtgraph.py,sha256=T2iAgU39Sxu9Sjt4yIgida7IaTPqRe4jnQIqkcZnEuA,52191
|
19
|
-
rational_linkages/PointHomogeneous.py,sha256=PFOUriVm-kRvV2PzlyyZcrw2wlCK3uGDB3ZEgfXP5v4,13784
|
20
|
-
rational_linkages/Quaternion.py,sha256=RDRRczv10hLehnsJepwYXXBQeum9-tfstJATdsDCssE,5285
|
21
|
-
rational_linkages/RationalBezier.py,sha256=omC5XczOGzZ62BGmBNBSwlpKKTEYX7K87BG5nD17ppo,15300
|
22
|
-
rational_linkages/RationalCurve.py,sha256=CtD9h52SxzIUBC_KGvd7JOFLXIlPks1KRK2PzAIoq14,28714
|
23
|
-
rational_linkages/RationalDualQuaternion.py,sha256=_g87ZCk6Z4mN1_IKBqbR-N0-GWQ7xSrnPXZb7dxkj1M,1487
|
24
|
-
rational_linkages/RationalMechanism.py,sha256=mnJv3UVbSZAVEohPeDWXCdhIMGA3kW5wGNfmQddSxK8,64662
|
25
|
-
rational_linkages/SingularityAnalysis.py,sha256=2_BoJy4v3_EwJ84e3-2qW6vjtZd263gDjGzfABI8s2g,1899
|
26
|
-
rational_linkages/StaticMechanism.py,sha256=gWheI8nz4lrQLs9lLKasxuxupVuyjim610W-F8-d0SY,12795
|
27
|
-
rational_linkages/TransfMatrix.py,sha256=UuPw5z6wBgqxYwNczxgYJfvjyYl_rxk5Bhax-pRTBiE,16810
|
28
|
-
rational_linkages/__init__.py,sha256=j51yV2-UG2vDFIUmV0sg0TDb5RmbhJ6LBaalrZspisQ,1050
|
29
|
-
rational_linkages/models.py,sha256=aMdyKBeLDi3XtXebW84K1w8VL8g3eqlMXVCG6OJqrb4,7246
|
30
|
-
rational_linkages/utils.py,sha256=2W9XJJX73oyRQjAhGrHpc2moNoAGkJawVuCxYeHRTfo,3152
|
31
|
-
rational_linkages/utils_rust.cp313-win_amd64.pyd,sha256=6vDIyP6s9sbwypepI59nrpjQkX7Jhd4NlFB1JO9_iZE,244736
|
32
|
-
rational_linkages/utils_rust.pyi,sha256=iTaedylbvDNplOzrd1RZ0PPJzCvh20w52ewbLiuAgnU,140
|
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/licenses/LICENSE,sha256=SrpxAZ1vJi81S4VF9EBjgxz9qrVj9acCyQPSAk3JgOo,35784
|
37
|
-
rational_linkages-2.1.0.dist-info/METADATA,sha256=vhD8crkMbXmXGm9-SNfwZ8rEiEG65GcXBjSM2SqA8jQ,9154
|
38
|
-
rational_linkages-2.1.0.dist-info/WHEEL,sha256=qV0EIPljj1XC_vuSatRWjn02nZIz3N1t8jsZz7HBr2U,101
|
39
|
-
rational_linkages-2.1.0.dist-info/top_level.txt,sha256=IxRIuCa6RJFZKK15jamktxgS0abg1PV2WqXo1Z-MalI,18
|
40
|
-
rational_linkages-2.1.0.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|