Differentiated projected plane origin and global origin for creating workplanes
Added ProjectedGlobalOrigin as centerOption for worplane constructor to differentiate between projecting the global origin and the current plane origin when creating new workplanes. Also updated projectToPlane method of Vector to only accept plane objects and it no longer does in inplace modification. Updated test converage for ProjectedOrigin and ProjectedGlobalOrigin options.
This commit is contained in:
@ -285,7 +285,11 @@ class CQ(object):
|
|||||||
face/faces, if a face/faces was selected. If a vertex was
|
face/faces, if a face/faces was selected. If a vertex was
|
||||||
selected, the origin will be at the vertex, and located
|
selected, the origin will be at the vertex, and located
|
||||||
on the face. The centerOption paramter sets how the center is defined.
|
on the face. The centerOption paramter sets how the center is defined.
|
||||||
Options are 'CenterOfMass', 'CenterOfBoundBox', or 'ProjectedOrigin'.
|
Options are 'CenterOfMass', 'CenterOfBoundBox', 'ProjectedOrigin', or
|
||||||
|
'ProjectedGlobalOrigin'. 'CenterOfMass' and 'CenterOfBoundBox' are
|
||||||
|
in relation to the selected face/faces. 'ProjectedOrigin' uses the
|
||||||
|
current origin that may have been updated by calls to transformed or
|
||||||
|
center. 'ProjectedGlobalOrigin' projects the global (0,0,0) origin.
|
||||||
* The Z direction will be normal to the plane of the face,computed
|
* The Z direction will be normal to the plane of the face,computed
|
||||||
at the center point.
|
at the center point.
|
||||||
* The X direction will be parallel to the x-y plane. If the workplane is parallel to
|
* The X direction will be parallel to the x-y plane. If the workplane is parallel to
|
||||||
@ -344,10 +348,12 @@ class CQ(object):
|
|||||||
if not all(_isCoPlanar(self.objects[0], f) for f in self.objects[1:]):
|
if not all(_isCoPlanar(self.objects[0], f) for f in self.objects[1:]):
|
||||||
raise ValueError("Selected faces must be co-planar.")
|
raise ValueError("Selected faces must be co-planar.")
|
||||||
|
|
||||||
if centerOption == 'CenterOfMass' or centerOption == 'ProjectedOrigin':
|
if centerOption in {'CenterOfMass', 'ProjectedOrigin', 'ProjectedGlobalOrigin'}:
|
||||||
center = Shape.CombinedCenter(self.objects)
|
center = Shape.CombinedCenter(self.objects)
|
||||||
elif centerOption == 'CenterOfBoundBox':
|
elif centerOption == 'CenterOfBoundBox':
|
||||||
center = Shape.CombinedCenterOfBoundBox(self.objects)
|
center = Shape.CombinedCenterOfBoundBox(self.objects)
|
||||||
|
else:
|
||||||
|
raise ValueError('Undefined value passed to centerOption')
|
||||||
|
|
||||||
normal = self.objects[0].normalAt()
|
normal = self.objects[0].normalAt()
|
||||||
xDir = _computeXdir(normal)
|
xDir = _computeXdir(normal)
|
||||||
@ -356,7 +362,7 @@ class CQ(object):
|
|||||||
obj = self.objects[0]
|
obj = self.objects[0]
|
||||||
|
|
||||||
if isinstance(obj, Face):
|
if isinstance(obj, Face):
|
||||||
if centerOption == 'CenterOfMass' or centerOption == 'ProjectedOrigin':
|
if centerOption in {'CenterOfMass', 'ProjectedOrigin', 'ProjectedGlobalOrigin'}:
|
||||||
center = obj.Center()
|
center = obj.Center()
|
||||||
elif centerOption == 'CenterOfBoundBox':
|
elif centerOption == 'CenterOfBoundBox':
|
||||||
center = obj.CenterOfBoundBox()
|
center = obj.CenterOfBoundBox()
|
||||||
@ -364,7 +370,7 @@ class CQ(object):
|
|||||||
xDir = _computeXdir(normal)
|
xDir = _computeXdir(normal)
|
||||||
else:
|
else:
|
||||||
if hasattr(obj, 'Center'):
|
if hasattr(obj, 'Center'):
|
||||||
if centerOption == 'CenterOfMass' or centerOption == 'ProjectedOrigin':
|
if centerOption in {'CenterOfMass', 'ProjectedOrigin', 'ProjectedGlobalOrigin'}:
|
||||||
center = obj.Center()
|
center = obj.Center()
|
||||||
elif centerOption == 'CenterOfBoundBox':
|
elif centerOption == 'CenterOfBoundBox':
|
||||||
center = obj.CenterOfBoundBox()
|
center = obj.CenterOfBoundBox()
|
||||||
@ -376,7 +382,9 @@ class CQ(object):
|
|||||||
|
|
||||||
# update center to projected origin if desired
|
# update center to projected origin if desired
|
||||||
if centerOption == 'ProjectedOrigin':
|
if centerOption == 'ProjectedOrigin':
|
||||||
center = Vector(0, 0, 0).projectToPlane(center, normal)
|
center = self.plane.origin.projectToPlane(Plane(center, xDir, normal))
|
||||||
|
elif centerOption == 'ProjectedGlobalOrigin':
|
||||||
|
center = Vector(0,0,0).projectToPlane(Plane(center, xDir, normal))
|
||||||
|
|
||||||
# invert if requested
|
# invert if requested
|
||||||
if invert:
|
if invert:
|
||||||
|
@ -143,31 +143,18 @@ class Vector(object):
|
|||||||
raise NotImplementedError(
|
raise NotImplementedError(
|
||||||
"Have not needed this yet, but FreeCAD supports it!")
|
"Have not needed this yet, but FreeCAD supports it!")
|
||||||
|
|
||||||
def projectToPlane(self, *args):
|
def projectToPlane(self, plane):
|
||||||
"""
|
"""
|
||||||
Vector is projected onto the plane provided as input.
|
Vector is projected onto the plane provided as input.
|
||||||
|
|
||||||
:param args: Plane object or base and normal vectors that define the plane
|
:param args: Plane object
|
||||||
|
|
||||||
This method modifies the vector in place and returns the new vector.
|
Returns the projected vector.
|
||||||
"""
|
"""
|
||||||
if len(args) == 2:
|
base = plane.origin
|
||||||
base = args[0]
|
normal = plane.zDir
|
||||||
normal = args[1]
|
|
||||||
elif len(args) == 1:
|
|
||||||
base = args[0].origin
|
|
||||||
normal = args[0].zDir
|
|
||||||
else:
|
|
||||||
raise TypeError("Expected 1 or 2 arguments consisting of 1 Plane object \
|
|
||||||
or a base Vector and a normal Vector object.")
|
|
||||||
|
|
||||||
result = self-normal*(((self-base).dot(normal))/normal.Length**2)
|
return self-normal*(((self-base).dot(normal))/normal.Length**2)
|
||||||
|
|
||||||
self.x = result.x
|
|
||||||
self.y = result.y
|
|
||||||
self.z = result.z
|
|
||||||
|
|
||||||
return self
|
|
||||||
|
|
||||||
def __neg__(self):
|
def __neg__(self):
|
||||||
return self * -1
|
return self * -1
|
||||||
|
@ -161,24 +161,11 @@ class TestCadObjects(BaseTest):
|
|||||||
base = Vector(5, 7, 9)
|
base = Vector(5, 7, 9)
|
||||||
x_dir = Vector(1, 0, 0)
|
x_dir = Vector(1, 0, 0)
|
||||||
|
|
||||||
# test passing plane defined by base and normal
|
|
||||||
point = Vector(10, 11, 12).projectToPlane(base, normal)
|
|
||||||
self.assertTupleAlmostEquals(point.toTuple(), (59/7, 55/7, 51/7),
|
|
||||||
decimal_places)
|
|
||||||
|
|
||||||
point = Vector(10, 11, 12).projectToPlane(base, normal.normalized())
|
|
||||||
self.assertTupleAlmostEquals(point.toTuple(), (59/7, 55/7, 51/7),
|
|
||||||
decimal_places)
|
|
||||||
|
|
||||||
# test passing Plane object
|
# test passing Plane object
|
||||||
point = Vector(10, 11, 12).projectToPlane(Plane(base, x_dir, normal))
|
point = Vector(10, 11, 12).projectToPlane(Plane(base, x_dir, normal))
|
||||||
self.assertTupleAlmostEquals(point.toTuple(), (59/7, 55/7, 51/7),
|
self.assertTupleAlmostEquals(point.toTuple(), (59/7, 55/7, 51/7),
|
||||||
decimal_places)
|
decimal_places)
|
||||||
|
|
||||||
# test wrong number of input arguments
|
|
||||||
with self.assertRaises(TypeError):
|
|
||||||
Vector(10,11.12).projectToPlane(1,1,1)
|
|
||||||
|
|
||||||
def testMatrixCreationAndAccess(self):
|
def testMatrixCreationAndAccess(self):
|
||||||
def matrix_vals(m):
|
def matrix_vals(m):
|
||||||
return [[m[r,c] for c in range(4)] for r in range(4)]
|
return [[m[r,c] for c in range(4)] for r in range(4)]
|
||||||
|
@ -1924,6 +1924,22 @@ class TestCadQuery(BaseTest):
|
|||||||
.plane.origin.toTuple()
|
.plane.origin.toTuple()
|
||||||
self.assertTupleAlmostEquals(origin, (45.0, 30.0, 10.0), decimal_places)
|
self.assertTupleAlmostEquals(origin, (45.0, 30.0, 10.0), decimal_places)
|
||||||
|
|
||||||
|
# test case where plane origin is shifted with center call
|
||||||
|
r = r.faces(">Z").workplane(centerOption='ProjectedOrigin').center(30,0) \
|
||||||
|
.hole(90)
|
||||||
|
|
||||||
|
origin = r.faces(">Z").workplane(centerOption='ProjectedOrigin') \
|
||||||
|
.plane.origin.toTuple()
|
||||||
|
self.assertTupleAlmostEquals(origin, (30.0, 0.0, 10.0), decimal_places)
|
||||||
|
|
||||||
|
origin = r.faces(">Z").workplane(centerOption='ProjectedGlobalOrigin') \
|
||||||
|
.plane.origin.toTuple()
|
||||||
|
self.assertTupleAlmostEquals(origin, (0.0, 0.0, 10.0), decimal_places)
|
||||||
|
|
||||||
|
with self.assertRaises(ValueError):
|
||||||
|
origin = r.faces(">Z").workplane(centerOption='undefined')
|
||||||
|
|
||||||
|
# make sure projection works in all directions
|
||||||
r = Workplane("YZ").polyline(pts).close().extrude(10.0)
|
r = Workplane("YZ").polyline(pts).close().extrude(10.0)
|
||||||
|
|
||||||
origin = r.faces(">X").workplane(centerOption='ProjectedOrigin') \
|
origin = r.faces(">X").workplane(centerOption='ProjectedOrigin') \
|
||||||
@ -1951,6 +1967,3 @@ class TestCadQuery(BaseTest):
|
|||||||
origin = r.faces("<Y").workplane(centerOption='CenterOfBoundBox') \
|
origin = r.faces("<Y").workplane(centerOption='CenterOfBoundBox') \
|
||||||
.plane.origin.toTuple()
|
.plane.origin.toTuple()
|
||||||
self.assertTupleAlmostEquals(origin, (45.0, -10.0, 30.0), decimal_places)
|
self.assertTupleAlmostEquals(origin, (45.0, -10.0, 30.0), decimal_places)
|
||||||
|
|
||||||
|
|
||||||
|
|
Reference in New Issue
Block a user