patme 0.4.4__py3-none-any.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.
Potentially problematic release.
This version of patme might be problematic. Click here for more details.
- patme/__init__.py +52 -0
- patme/buildtools/__init__.py +7 -0
- patme/buildtools/rce_releasecreator.py +336 -0
- patme/buildtools/release.py +26 -0
- patme/femtools/__init__.py +5 -0
- patme/femtools/abqmsgfilechecker.py +137 -0
- patme/femtools/fecall.py +1092 -0
- patme/geometry/__init__.py +0 -0
- patme/geometry/area.py +124 -0
- patme/geometry/coordinatesystem.py +635 -0
- patme/geometry/intersect.py +284 -0
- patme/geometry/line.py +183 -0
- patme/geometry/misc.py +420 -0
- patme/geometry/plane.py +464 -0
- patme/geometry/rotate.py +244 -0
- patme/geometry/scale.py +152 -0
- patme/geometry/shape2d.py +50 -0
- patme/geometry/transformations.py +1831 -0
- patme/geometry/translate.py +139 -0
- patme/mechanics/__init__.py +4 -0
- patme/mechanics/loads.py +435 -0
- patme/mechanics/material.py +1260 -0
- patme/service/__init__.py +7 -0
- patme/service/decorators.py +85 -0
- patme/service/duration.py +96 -0
- patme/service/exceptionhook.py +104 -0
- patme/service/exceptions.py +36 -0
- patme/service/io/__init__.py +3 -0
- patme/service/io/basewriter.py +122 -0
- patme/service/logger.py +375 -0
- patme/service/mathutils.py +108 -0
- patme/service/misc.py +71 -0
- patme/service/moveimports.py +217 -0
- patme/service/stringutils.py +419 -0
- patme/service/systemutils.py +290 -0
- patme/sshtools/__init__.py +3 -0
- patme/sshtools/cara.py +435 -0
- patme/sshtools/clustercaller.py +420 -0
- patme/sshtools/facluster.py +350 -0
- patme/sshtools/sshcall.py +168 -0
- patme-0.4.4.dist-info/LICENSE +21 -0
- patme-0.4.4.dist-info/LICENSES/MIT.txt +9 -0
- patme-0.4.4.dist-info/METADATA +168 -0
- patme-0.4.4.dist-info/RECORD +46 -0
- patme-0.4.4.dist-info/WHEEL +4 -0
- patme-0.4.4.dist-info/entry_points.txt +3 -0
patme/geometry/plane.py
ADDED
|
@@ -0,0 +1,464 @@
|
|
|
1
|
+
# Copyright (C) 2020 Deutsches Zentrum fuer Luft- und Raumfahrt(DLR, German Aerospace Center) <www.dlr.de>
|
|
2
|
+
# SPDX-FileCopyrightText: 2022 German Aerospace Center (DLR)
|
|
3
|
+
#
|
|
4
|
+
# SPDX-License-Identifier: MIT
|
|
5
|
+
"""
|
|
6
|
+
documentation
|
|
7
|
+
"""
|
|
8
|
+
import numpy as np
|
|
9
|
+
|
|
10
|
+
from patme import epsilon
|
|
11
|
+
from patme.geometry.intersect import Intersection
|
|
12
|
+
from patme.geometry.line import Line
|
|
13
|
+
from patme.geometry.rotate import Rotation
|
|
14
|
+
from patme.geometry.translate import Translation
|
|
15
|
+
from patme.service.exceptions import GeometryError, ImproperParameterError, InternalError
|
|
16
|
+
from patme.service.logger import log
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class Plane:
|
|
20
|
+
"""this class represents the mathematical description of a plane.
|
|
21
|
+
|
|
22
|
+
It provides necessary methods for calculating intersection points and other stuff.
|
|
23
|
+
A positioning point and the plane normal vector is necessary to establish the plane.
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
>>> plane = Plane()
|
|
27
|
+
>>> plane = plane.generatePlane([3,0,0], planeNormalVector = [0,0,1])
|
|
28
|
+
>>> plane.planeNormalVector
|
|
29
|
+
Translation([0., 0., 1.])
|
|
30
|
+
>>> plane.planePositioningVector
|
|
31
|
+
Translation([3, 0, 0])
|
|
32
|
+
>>> plane.getProjectedPoints([[2,0,0]])
|
|
33
|
+
array([[2., 0., 0.]])
|
|
34
|
+
"""
|
|
35
|
+
|
|
36
|
+
def __init__(self, *args, **kwargs):
|
|
37
|
+
"""
|
|
38
|
+
:param refPlane: string, optional if a standard projection plane is to be used ('xy', 'xz' and 'yz' possible)
|
|
39
|
+
:param planeID: string, specifying the id of the projection plane
|
|
40
|
+
|
|
41
|
+
"""
|
|
42
|
+
self._n = None
|
|
43
|
+
self._position = None
|
|
44
|
+
self._planeOrientationVector1 = None
|
|
45
|
+
self._planeOrientationVector2 = None
|
|
46
|
+
|
|
47
|
+
refPlane = kwargs.pop("refPlane", None)
|
|
48
|
+
|
|
49
|
+
if refPlane:
|
|
50
|
+
|
|
51
|
+
allowedRefPlanes = ["xy", "xz", "yz"]
|
|
52
|
+
if refPlane not in allowedRefPlanes:
|
|
53
|
+
raise ImproperParameterError(
|
|
54
|
+
f'Parameter "refPlane" is "{refPlane}" but must be one of {allowedRefPlanes}'
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
self.planePositioningVector = np.zeros(3)
|
|
58
|
+
|
|
59
|
+
baseVector = np.eye(3)
|
|
60
|
+
self._planeOrientationVector1, self._planeOrientationVector2 = (
|
|
61
|
+
baseVector["xyz".index(axis), :] for axis in refPlane
|
|
62
|
+
)
|
|
63
|
+
|
|
64
|
+
self.generatePlane(self._position, self._planeOrientationVector1, self._planeOrientationVector2)
|
|
65
|
+
|
|
66
|
+
self.planeID = kwargs.pop("planeID", None)
|
|
67
|
+
|
|
68
|
+
if not self.planeID and refPlane:
|
|
69
|
+
self.planeID = f"Plane_{refPlane}"
|
|
70
|
+
|
|
71
|
+
for key in kwargs:
|
|
72
|
+
if not hasattr(self, key):
|
|
73
|
+
log.warning(f'Setting unknown key "{key}" in class {self.__class__} with name "{str(self)}"')
|
|
74
|
+
setattr(self, key, kwargs[key])
|
|
75
|
+
|
|
76
|
+
def copy(self):
|
|
77
|
+
"""doc"""
|
|
78
|
+
return Plane(
|
|
79
|
+
planeID=f"{self.planeID}_copy",
|
|
80
|
+
_planeOrientationVector1=self.planeOrientationVector1,
|
|
81
|
+
_planeOrientationVector2=self.planeOrientationVector2,
|
|
82
|
+
_position=self._position,
|
|
83
|
+
_n=self._n,
|
|
84
|
+
)
|
|
85
|
+
|
|
86
|
+
def to_occ(self):
|
|
87
|
+
"""doc"""
|
|
88
|
+
try:
|
|
89
|
+
from OCC.gp import gp_Ax3, gp_Dir, gp_Pln, gp_Pnt
|
|
90
|
+
except ImportError:
|
|
91
|
+
from OCC.Core.gp import gp_Ax3, gp_Dir, gp_Pln, gp_Pnt
|
|
92
|
+
|
|
93
|
+
origPos = gp_Pnt(*self._position)
|
|
94
|
+
normal = gp_Dir(*self.planeNormalVector)
|
|
95
|
+
Vx = gp_Dir(*self.planeOrientationVector1)
|
|
96
|
+
ax = gp_Ax3(origPos, normal, Vx)
|
|
97
|
+
return gp_Pln(ax)
|
|
98
|
+
|
|
99
|
+
def getDistanceToPoint(self, point):
|
|
100
|
+
"""
|
|
101
|
+
this function is intended to calculate the distance from this plane to the given point p
|
|
102
|
+
d(P,E)=abs(n*p-d)/abs(n) with E: n*x = n*a = d
|
|
103
|
+
|
|
104
|
+
>>> plane = Plane()
|
|
105
|
+
>>> plane = plane.generatePlane([0,0,0], planeNormalVector = [0,0,1])
|
|
106
|
+
>>> plane.getDistanceToPoint([0,0,10])
|
|
107
|
+
10.0
|
|
108
|
+
>>> plane = Plane()
|
|
109
|
+
>>> plane = plane.generatePlane([0,0,0], planeNormalVector = [1,1,1])
|
|
110
|
+
>>> '{:03.1f}'.format(plane.getDistanceToPoint([1,1,1])**2)
|
|
111
|
+
'3.0'
|
|
112
|
+
|
|
113
|
+
:param point: instance of type Translation(), specifying the point, from which the distance to the plane shall be calculated
|
|
114
|
+
"""
|
|
115
|
+
distanceNominator = abs(
|
|
116
|
+
np.dot(point, self.planeNormalVector) - np.dot(self.planeNormalVector, self.planePositioningVector)
|
|
117
|
+
)
|
|
118
|
+
return distanceNominator / np.linalg.norm(self.planeNormalVector)
|
|
119
|
+
|
|
120
|
+
@staticmethod
|
|
121
|
+
def fromPointCloud(points):
|
|
122
|
+
from patme.geometry.misc import PCA
|
|
123
|
+
|
|
124
|
+
_, v = PCA(points)
|
|
125
|
+
point = np.mean(points, axis=0)
|
|
126
|
+
return Plane().generatePlane(point, planeNormalVector=v[:, 2])
|
|
127
|
+
|
|
128
|
+
def generatePlane(
|
|
129
|
+
self, positioningPoint=None, orientationPoint1=None, orientationPoint2=None, planeNormalVector=None
|
|
130
|
+
):
|
|
131
|
+
"""
|
|
132
|
+
:param positioningPoint: instance of type Translation(), specifying a point within the projection plane
|
|
133
|
+
:param orientationPoint1: instance of type Translation(), specifying an orientation vector within the projection plane
|
|
134
|
+
:param orientationPoint2: instance of type Translation(), specifying an orientation vector within the projection perpendicular to orientationPoint1
|
|
135
|
+
"""
|
|
136
|
+
|
|
137
|
+
if positioningPoint is not None and orientationPoint1 is not None and orientationPoint2 is not None:
|
|
138
|
+
self.planePositioningVector = Translation(positioningPoint)
|
|
139
|
+
self._planeOrientationVector1 = np.asarray(orientationPoint1) - self.planePositioningVector
|
|
140
|
+
self._planeOrientationVector2 = np.asarray(orientationPoint2) - self.planePositioningVector
|
|
141
|
+
|
|
142
|
+
# Ebenennormalenvektor bestimmen
|
|
143
|
+
# n = planeOrientationVector1 x planeOrientationVector2
|
|
144
|
+
# n*(x-planePositionVector) = 0
|
|
145
|
+
self.planeNormalVector = np.cross(self._planeOrientationVector1, self._planeOrientationVector2)
|
|
146
|
+
|
|
147
|
+
elif positioningPoint is not None and planeNormalVector is not None:
|
|
148
|
+
self.planePositioningVector = Translation(positioningPoint)
|
|
149
|
+
self.planeNormalVector = planeNormalVector
|
|
150
|
+
|
|
151
|
+
self.setPlaneOrientationVectors()
|
|
152
|
+
|
|
153
|
+
else:
|
|
154
|
+
raise InternalError("At least one point for a proper plane definition is missing.")
|
|
155
|
+
|
|
156
|
+
self.normalizeVectors()
|
|
157
|
+
|
|
158
|
+
return self
|
|
159
|
+
|
|
160
|
+
def getIntersection(self, lines=None, areas=None):
|
|
161
|
+
"""This method is intended to return the intersection of the provided input with itself.
|
|
162
|
+
Depending on the input this method returns an instance of Translation or an
|
|
163
|
+
instance of Line
|
|
164
|
+
|
|
165
|
+
>>> plane = Plane()
|
|
166
|
+
>>> plane = plane.generatePlane([0,0,0], planeNormalVector = [0,0,1])
|
|
167
|
+
>>> plane.getIntersection(lines = [Line(Translation([0,0,0]),Translation([0,0,1]))])
|
|
168
|
+
Translation([0., 0., 0.])
|
|
169
|
+
"""
|
|
170
|
+
if lines is None:
|
|
171
|
+
lines = []
|
|
172
|
+
if areas is None:
|
|
173
|
+
areas = []
|
|
174
|
+
|
|
175
|
+
if lines:
|
|
176
|
+
return Intersection.getIntersection(lines=lines, areas=[self])
|
|
177
|
+
elif areas:
|
|
178
|
+
areas.insert(0, self)
|
|
179
|
+
return Intersection.getIntersection(areas=areas)
|
|
180
|
+
else:
|
|
181
|
+
raise ImproperParameterError("No line or area specified for intersection.")
|
|
182
|
+
|
|
183
|
+
def getIntersectionPointOfVetor(self, vectorPoint, vectorOrienation):
|
|
184
|
+
"""Calculates the intersection point of a vector with this plane. The vector must not be parallel to the plane
|
|
185
|
+
|
|
186
|
+
:return: Translation defining the intersection point
|
|
187
|
+
:raises GeometryError: in case vector is parallel to plane
|
|
188
|
+
|
|
189
|
+
>>> plane = Plane()
|
|
190
|
+
>>> plane = plane.generatePlane([0,0,0], planeNormalVector = [0,0,1])
|
|
191
|
+
>>> plane.getIntersectionPointOfVetor([0,0,0],[0,0,1])
|
|
192
|
+
Translation([0., 0., 0.])
|
|
193
|
+
"""
|
|
194
|
+
line = Line(Translation(vectorPoint), Translation(vectorPoint) + vectorOrienation)
|
|
195
|
+
result = Intersection.getIntersection(lines=[line], areas=[self])
|
|
196
|
+
|
|
197
|
+
if result is None:
|
|
198
|
+
raise GeometryError("Line is parallel to plane and not coincident")
|
|
199
|
+
if result is line:
|
|
200
|
+
raise GeometryError("Line is parallel and coincident to plane")
|
|
201
|
+
|
|
202
|
+
return Translation(result)
|
|
203
|
+
|
|
204
|
+
def getProjectedPoints(self, points=None, transformIntoPlaneCoordinates=False):
|
|
205
|
+
"""This method is intended to provide the functionality of orthogonal projection of points and lines onto a plane.
|
|
206
|
+
|
|
207
|
+
:param points: list of points to be projected
|
|
208
|
+
:param transformIntoPlaneCoordinates: Flag, if the resulting points should be absolute or in the plane
|
|
209
|
+
coordinate system including the plane's rotation
|
|
210
|
+
|
|
211
|
+
>>> plane = Plane()
|
|
212
|
+
>>> plane = plane.generatePlane([0,0,1], planeNormalVector = [0,0,1])
|
|
213
|
+
>>> plane.getProjectedPoints([[1,0,3],[0,1,3]])
|
|
214
|
+
array([[1., 0., 1.],
|
|
215
|
+
[0., 1., 1.]])
|
|
216
|
+
>>> plane = plane.generatePlane([0,0,1], planeNormalVector = [0,0,1])
|
|
217
|
+
>>> plane.getProjectedPoints([[1,0,3],[0,1,3]], transformIntoPlaneCoordinates=True)
|
|
218
|
+
array([[1., 0., 0.],
|
|
219
|
+
[0., 1., 0.]])
|
|
220
|
+
|
|
221
|
+
.. figure:: ../../bilder/reference/IMG7254.PNG
|
|
222
|
+
:width: 250pt
|
|
223
|
+
:align: center
|
|
224
|
+
|
|
225
|
+
Common equation of plane:
|
|
226
|
+
|
|
227
|
+
.. math::
|
|
228
|
+
\\\\
|
|
229
|
+
\\vec{e} = \\vec{ap}+\\lambda\\cdot\\vec{rv_{1}}+\\mu\\cdot\\vec{rv_{1}}
|
|
230
|
+
|
|
231
|
+
Common equation of linear function:
|
|
232
|
+
|
|
233
|
+
.. math::
|
|
234
|
+
\\\\
|
|
235
|
+
\\vec{x_{g}} = \\vec{p}+\\omega\\cdot\\vec{rv_{g}}
|
|
236
|
+
|
|
237
|
+
Common equation of projection of the linear function:
|
|
238
|
+
|
|
239
|
+
.. math::
|
|
240
|
+
\\\\
|
|
241
|
+
\\vec{x_{s}} = \\vec{p_{s}}+\\omega\\cdot\\vec{rv_{gs}}
|
|
242
|
+
|
|
243
|
+
Common equations for supporting functions:
|
|
244
|
+
|
|
245
|
+
.. math::
|
|
246
|
+
\\\\
|
|
247
|
+
\\vec{x_{h1}} = \\vec{p}+\\sigma\\cdot\\vec{n},\\, with\\; \\vec{n}\\; the\\; normal\\; vector\\; of\\; \\vec{e}
|
|
248
|
+
\\\\
|
|
249
|
+
\\vec{x_{h2}} = \\vec{q}+\\eta\\cdot\\vec{n},\\, with\\; \\vec{n}\\; the\\; normal\\; vector\\; of\\; \\vec{e}
|
|
250
|
+
|
|
251
|
+
"""
|
|
252
|
+
# Hilfsgeradeen aufstellen
|
|
253
|
+
# h1(omega) = functionPositionVector + omega*self.planeNormalVector
|
|
254
|
+
|
|
255
|
+
# Gleichungssystem loesen:
|
|
256
|
+
# Solve ``-sigma*n_1+lambda*rv1_1+mu*rv2_1 = p_1-ap_1``
|
|
257
|
+
# ``-sigma*n_2+lambda*rv1_2+mu*rv2_2 = p_2-ap_2``
|
|
258
|
+
# ``-sigma*n_3+lambda*rv1_3+mu*rv2_3 = p_3-ap_3``
|
|
259
|
+
|
|
260
|
+
# h1(omega) = E(alpha,beta)
|
|
261
|
+
if len(points) == 1:
|
|
262
|
+
pointsArray = np.array([points[0]])
|
|
263
|
+
else:
|
|
264
|
+
pointsArray = np.array(points, copy=True)
|
|
265
|
+
|
|
266
|
+
rechteSeiten = pointsArray - np.array(self.planePositioningVector)
|
|
267
|
+
|
|
268
|
+
koeffMat = np.array(
|
|
269
|
+
[-1 * self.planeNormalVector[:3], self._planeOrientationVector1[:3], self._planeOrientationVector2[:3]]
|
|
270
|
+
).T
|
|
271
|
+
|
|
272
|
+
# [sigma, lambda, mu]
|
|
273
|
+
unknownParms = np.linalg.solve(koeffMat, rechteSeiten.T)
|
|
274
|
+
|
|
275
|
+
# evaluate supporting function to get intersection point
|
|
276
|
+
planeNormals = np.outer(self.planeNormalVector, np.ones(pointsArray.shape[0]))
|
|
277
|
+
|
|
278
|
+
newPoints = pointsArray + (unknownParms[0, :] * planeNormals).T
|
|
279
|
+
|
|
280
|
+
if transformIntoPlaneCoordinates:
|
|
281
|
+
newPoints -= self.planePositioningVector
|
|
282
|
+
unknownParms = np.linalg.lstsq(self.rotation, newPoints.T, rcond=None)[0]
|
|
283
|
+
newPoints = unknownParms.T
|
|
284
|
+
|
|
285
|
+
return newPoints
|
|
286
|
+
|
|
287
|
+
def setPlaneOrientationVectors(self):
|
|
288
|
+
"""doc"""
|
|
289
|
+
# create a vector deviating a bit from normal vector
|
|
290
|
+
newVector = None
|
|
291
|
+
for translation in np.eye(3, 3):
|
|
292
|
+
newVector = self.planeNormalVector + translation
|
|
293
|
+
auxVector = np.cross(self.planeNormalVector, newVector)
|
|
294
|
+
|
|
295
|
+
# check whether new vector is linear independent from plane normal vector
|
|
296
|
+
vectorMatrix = np.array([self.planeNormalVector, newVector, auxVector])
|
|
297
|
+
|
|
298
|
+
if np.linalg.det(vectorMatrix.T) > epsilon:
|
|
299
|
+
# vectors are linear independent - no new vector has to be created
|
|
300
|
+
break
|
|
301
|
+
|
|
302
|
+
# calculate part of newVector parallel to plane normal vector
|
|
303
|
+
nParallelVec = (
|
|
304
|
+
np.dot(self.planeNormalVector, newVector)
|
|
305
|
+
/ np.dot(self.planeNormalVector, self.planeNormalVector)
|
|
306
|
+
* self.planeNormalVector
|
|
307
|
+
)
|
|
308
|
+
|
|
309
|
+
# calculate first vector in plane
|
|
310
|
+
self._planeOrientationVector1 = Translation(newVector - nParallelVec)
|
|
311
|
+
|
|
312
|
+
# calculate second vector in plane
|
|
313
|
+
self._planeOrientationVector2 = Translation(np.cross(self.planeNormalVector, self._planeOrientationVector1))
|
|
314
|
+
|
|
315
|
+
self.planeNormalVector = Translation(np.cross(self._planeOrientationVector1, self._planeOrientationVector2))
|
|
316
|
+
|
|
317
|
+
def getNearestPointFromList(self, pointList):
|
|
318
|
+
"""Returns the point of list pointList which is closest to the plane.
|
|
319
|
+
|
|
320
|
+
:param pointList: list of keypoints (or 3D coordinates)
|
|
321
|
+
:return: the point of pointList closest to the plane
|
|
322
|
+
"""
|
|
323
|
+
distancesToPlane = np.array([self.getDistanceToPoint(np.array(point)) for point in pointList])
|
|
324
|
+
return pointList[np.argmin(distancesToPlane)]
|
|
325
|
+
|
|
326
|
+
@staticmethod
|
|
327
|
+
def fromTransformation(rotation, position):
|
|
328
|
+
"""doc"""
|
|
329
|
+
refPos1 = position + rotation[:, 0] / np.linalg.norm(rotation[:, 0])
|
|
330
|
+
refPos2 = position + rotation[:, 1] / np.linalg.norm(rotation[:, 1])
|
|
331
|
+
return Plane().generatePlane(position, refPos1, refPos2)
|
|
332
|
+
|
|
333
|
+
def makeOrthogonal(self, adaptVectorNum=1):
|
|
334
|
+
"""doc"""
|
|
335
|
+
# adapt orientation vector to get orthogonal vectors
|
|
336
|
+
if adaptVectorNum not in [1, 2]:
|
|
337
|
+
log.warning(
|
|
338
|
+
"Only [1,2] are valid numbers for parameter 'adaptVectorNum' in function Plane.makeOrthogonal. Set to 1"
|
|
339
|
+
)
|
|
340
|
+
adaptVectorNum = 1
|
|
341
|
+
|
|
342
|
+
if adaptVectorNum == 1:
|
|
343
|
+
self._planeOrientationVector1 = Translation(np.cross(self.planeOrientationVector2, self.planeNormalVector))
|
|
344
|
+
else:
|
|
345
|
+
self._planeOrientationVector2 = Translation(np.cross(self.planeNormalVector, self.planeOrientationVector1))
|
|
346
|
+
|
|
347
|
+
def normalizeVectors(self):
|
|
348
|
+
"""doc"""
|
|
349
|
+
self.planeNormalVector /= np.linalg.norm(self.planeNormalVector)
|
|
350
|
+
self._planeOrientationVector1 /= np.linalg.norm(self._planeOrientationVector1)
|
|
351
|
+
self._planeOrientationVector2 /= np.linalg.norm(self._planeOrientationVector2)
|
|
352
|
+
|
|
353
|
+
def plot(self, axes=None):
|
|
354
|
+
"""doc"""
|
|
355
|
+
import matplotlib.pyplot as plt
|
|
356
|
+
|
|
357
|
+
copyPlane = self.copy()
|
|
358
|
+
copyPlane.makeOrthogonal(2)
|
|
359
|
+
|
|
360
|
+
xx, yy = np.meshgrid(np.linspace(-2, 2, 21), np.linspace(-2, 2, 21))
|
|
361
|
+
allPoints = np.c_[xx.ravel(), yy.ravel()]
|
|
362
|
+
|
|
363
|
+
from scipy.spatial import Delaunay
|
|
364
|
+
|
|
365
|
+
tri = Delaunay(allPoints)
|
|
366
|
+
|
|
367
|
+
allPoints = np.c_[allPoints, np.zeros(allPoints.shape[0])]
|
|
368
|
+
newPoints = (self.rotation * allPoints.T).T + self.planePositioningVector
|
|
369
|
+
|
|
370
|
+
if not axes:
|
|
371
|
+
axes = plt.figure().gca(projection="3d")
|
|
372
|
+
|
|
373
|
+
axes.set_aspect("equal")
|
|
374
|
+
axes.plot_trisurf(
|
|
375
|
+
newPoints[:, 0], newPoints[:, 1], newPoints[:, 2], linewidth=0, triangles=tri.simplices, alpha=0.2
|
|
376
|
+
)
|
|
377
|
+
|
|
378
|
+
return axes
|
|
379
|
+
|
|
380
|
+
def switchAxes(self):
|
|
381
|
+
"""doc"""
|
|
382
|
+
tmpVector1 = self.planeOrientationVector1
|
|
383
|
+
self._planeOrientationVector1 = np.copy(self.planeOrientationVector2)
|
|
384
|
+
self._planeOrientationVector2 = np.copy(tmpVector1)
|
|
385
|
+
self.planeNormalVector = np.cross(self._planeOrientationVector1, self._planeOrientationVector2)
|
|
386
|
+
|
|
387
|
+
def _hasOrthogonalBase(self):
|
|
388
|
+
"""doc"""
|
|
389
|
+
dotProduct = self.planeOrientationVector1 @ self.planeOrientationVector2
|
|
390
|
+
norm = np.linalg.norm(self.planeOrientationVector1) * np.linalg.norm(self.planeOrientationVector2)
|
|
391
|
+
return abs(dotProduct / norm) < 1e-08
|
|
392
|
+
|
|
393
|
+
def _getRotation(self):
|
|
394
|
+
"""doc"""
|
|
395
|
+
if not self.hasOrthogonalBase:
|
|
396
|
+
return None
|
|
397
|
+
else:
|
|
398
|
+
return Rotation(
|
|
399
|
+
np.array([self.planeOrientationVector1, self.planeOrientationVector2, self.planeNormalVector]).T
|
|
400
|
+
)
|
|
401
|
+
|
|
402
|
+
def __str__(self):
|
|
403
|
+
"""doc"""
|
|
404
|
+
if self.planeID:
|
|
405
|
+
return self.planeID
|
|
406
|
+
|
|
407
|
+
return object.__str__(self)
|
|
408
|
+
|
|
409
|
+
def _getNormalVector(self):
|
|
410
|
+
"""doc"""
|
|
411
|
+
return self._n
|
|
412
|
+
|
|
413
|
+
def _setNormalVector(self, normalVector):
|
|
414
|
+
"""doc"""
|
|
415
|
+
self._n = Translation(normalVector / np.linalg.norm(normalVector))
|
|
416
|
+
|
|
417
|
+
def _getPositionVector(self):
|
|
418
|
+
"""doc"""
|
|
419
|
+
return self._position
|
|
420
|
+
|
|
421
|
+
def _setPositionVector(self, positioningVector):
|
|
422
|
+
"""doc"""
|
|
423
|
+
self._position = Translation(positioningVector)
|
|
424
|
+
|
|
425
|
+
def _getplaneOrientationVector1(self):
|
|
426
|
+
"""doc"""
|
|
427
|
+
return self._planeOrientationVector1
|
|
428
|
+
|
|
429
|
+
def _getplaneOrientationVector2(self):
|
|
430
|
+
"""doc"""
|
|
431
|
+
return self._planeOrientationVector2
|
|
432
|
+
|
|
433
|
+
planeNormalVector = property(fget=_getNormalVector, fset=_setNormalVector)
|
|
434
|
+
# normal vector of the plane
|
|
435
|
+
planeOrientationVector1 = property(fget=_getplaneOrientationVector1)
|
|
436
|
+
planeOrientationVector2 = property(fget=_getplaneOrientationVector2)
|
|
437
|
+
planePositioningVector = property(fget=_getPositionVector, fset=_setPositionVector)
|
|
438
|
+
hasOrthogonalBase = property(fget=_hasOrthogonalBase)
|
|
439
|
+
rotation = property(fget=_getRotation)
|
|
440
|
+
|
|
441
|
+
|
|
442
|
+
if __name__ == "__main__":
|
|
443
|
+
|
|
444
|
+
plane = Plane().generatePlane(np.array([1, 1, 1]), planeNormalVector=[2, 4, 3])
|
|
445
|
+
plane2 = plane.copy()
|
|
446
|
+
numPoints = 10
|
|
447
|
+
testPoints = np.random.rand(numPoints * 3).reshape((10, 3)) * 10
|
|
448
|
+
newPoint = plane.getProjectedPoints(testPoints, True)
|
|
449
|
+
|
|
450
|
+
#
|
|
451
|
+
# from mpl_toolkits.mplot3d import axes3d
|
|
452
|
+
# import matplotlib.pyplot as plt
|
|
453
|
+
#
|
|
454
|
+
# fig = plt.figure()
|
|
455
|
+
# ax = fig.gca(projection='3d')
|
|
456
|
+
# ax.scatter(xs = newPoint[:,0], ys = newPoint[:,1], zs = newPoint[:,2], marker="o", label='Data points')
|
|
457
|
+
# #plane.plot(ax)
|
|
458
|
+
# plt.show()
|
|
459
|
+
#
|
|
460
|
+
# #plane = plane.generatePlane([0,0,0], planeNormalVector = [0,0,1])
|
|
461
|
+
# #print(plane.getIntersection(lines = [Line(Translation([0,0,0]),Translation([0,0,1]))]))
|
|
462
|
+
#
|
|
463
|
+
# # import doctest
|
|
464
|
+
# # doctest.testmod()
|