Updated CadQuery library for addition of a feature to allow creation of a workplane from multiple co-planar faces.
This commit is contained in:
parent
b491645783
commit
a5837b8c03
|
@ -262,7 +262,6 @@ class CQ(object):
|
||||||
|
|
||||||
def workplane(self, offset=0.0, invert=False):
|
def workplane(self, offset=0.0, invert=False):
|
||||||
"""
|
"""
|
||||||
|
|
||||||
Creates a new 2-D workplane, located relative to the first face on the stack.
|
Creates a new 2-D workplane, located relative to the first face on the stack.
|
||||||
|
|
||||||
:param offset: offset for the work plane in the Z direction. Default
|
:param offset: offset for the work plane in the Z direction. Default
|
||||||
|
@ -271,14 +270,18 @@ class CQ(object):
|
||||||
:type invert: boolean or None=False
|
:type invert: boolean or None=False
|
||||||
:rtype: Workplane object ( which is a subclass of CQ )
|
:rtype: Workplane object ( which is a subclass of CQ )
|
||||||
|
|
||||||
The first element on the stack must be a face, or a vertex. If a vertex, then the parent
|
The first element on the stack must be a face, a set of
|
||||||
item on the chain immediately before the vertex must be a face.
|
co-planar faces or a vertex. If a vertex, then the parent
|
||||||
|
item on the chain immediately before the vertex must be a
|
||||||
|
face.
|
||||||
|
|
||||||
The result will be a 2-d working plane
|
The result will be a 2-d working plane
|
||||||
with a new coordinate system set up as follows:
|
with a new coordinate system set up as follows:
|
||||||
|
|
||||||
* The origin will be located in the *center* of the face, if a face was selected. If a
|
* The origin will be located in the *center* of the
|
||||||
vertex was selected, the origin will be at the vertex, and located on the face.
|
face/faces, if a face/faces was selected. If a vertex was
|
||||||
|
selected, the origin will be at the vertex, and located
|
||||||
|
on the face.
|
||||||
* 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
|
||||||
|
@ -298,11 +301,21 @@ class CQ(object):
|
||||||
For now you can work around by creating a workplane and then offsetting the center
|
For now you can work around by creating a workplane and then offsetting the center
|
||||||
afterwards.
|
afterwards.
|
||||||
"""
|
"""
|
||||||
if len(self.objects) > 1:
|
def _isCoPlanar(f0, f1):
|
||||||
raise ValueError("Workplane cannot be created if more than"
|
"""Test if two faces are on the same plane."""
|
||||||
" 1 object is selected.")
|
p0 = f0.Center()
|
||||||
|
p1 = f1.Center()
|
||||||
|
n0 = f0.normalAt()
|
||||||
|
n1 = f1.normalAt()
|
||||||
|
|
||||||
obj = self.objects[0]
|
# test normals (direction of planes)
|
||||||
|
if not ((abs(n0.x-n1.x) < self.ctx.tolerance) or
|
||||||
|
(abs(n0.y-n1.y) < self.ctx.tolerance) or
|
||||||
|
(abs(n0.z-n1.z) < self.ctx.tolerance)):
|
||||||
|
return False
|
||||||
|
|
||||||
|
# test if p1 is on the plane of f0 (offset of planes)
|
||||||
|
return abs(n0.dot(p0.sub(p1)) < self.ctx.tolerance)
|
||||||
|
|
||||||
def _computeXdir(normal):
|
def _computeXdir(normal):
|
||||||
"""
|
"""
|
||||||
|
@ -317,28 +330,33 @@ class CQ(object):
|
||||||
xd = Vector(1, 0, 0)
|
xd = Vector(1, 0, 0)
|
||||||
return xd
|
return xd
|
||||||
|
|
||||||
faceToBuildOn = None
|
if len(self.objects) > 1:
|
||||||
center = None
|
# are all objects 'PLANE'?
|
||||||
#if isinstance(obj,Vertex):
|
if not all(o.geomType() == 'PLANE' for o in self.objects):
|
||||||
# f = self.parent.objects[0]
|
raise ValueError("If multiple objects selected, they all must be planar faces.")
|
||||||
# if f != None and isinstance(f,Face):
|
|
||||||
# center = obj.Center()
|
# are all faces co-planar with each other?
|
||||||
# normal = f.normalAt(center)
|
if not all(_isCoPlanar(self.objects[0], f) for f in self.objects[1:]):
|
||||||
# xDir = _computeXdir(normal)
|
raise ValueError("Selected faces must be co-planar.")
|
||||||
# else:
|
|
||||||
# raise ValueError("If a vertex is selected, a face must be the immediate parent")
|
center = Shape.CombinedCenter(self.objects)
|
||||||
if isinstance(obj, Face):
|
normal = self.objects[0].normalAt()
|
||||||
faceToBuildOn = obj
|
|
||||||
center = obj.Center()
|
|
||||||
normal = obj.normalAt(center)
|
|
||||||
xDir = _computeXdir(normal)
|
xDir = _computeXdir(normal)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
if hasattr(obj, 'Center'):
|
obj = self.objects[0]
|
||||||
|
|
||||||
|
if isinstance(obj, Face):
|
||||||
center = obj.Center()
|
center = obj.Center()
|
||||||
normal = self.plane.zDir
|
normal = obj.normalAt(center)
|
||||||
xDir = self.plane.xDir
|
xDir = _computeXdir(normal)
|
||||||
else:
|
else:
|
||||||
raise ValueError("Needs a face or a vertex or point on a work plane")
|
if hasattr(obj, 'Center'):
|
||||||
|
center = obj.Center()
|
||||||
|
normal = self.plane.zDir
|
||||||
|
xDir = self.plane.xDir
|
||||||
|
else:
|
||||||
|
raise ValueError("Needs a face or a vertex or point on a work plane")
|
||||||
|
|
||||||
#invert if requested
|
#invert if requested
|
||||||
if invert:
|
if invert:
|
||||||
|
|
|
@ -98,10 +98,10 @@ class Vector(object):
|
||||||
return Vector( self.wrapped.cross(v.wrapped))
|
return Vector( self.wrapped.cross(v.wrapped))
|
||||||
|
|
||||||
def dot(self,v):
|
def dot(self,v):
|
||||||
return self.wrapped.dot(v.wrapped)
|
return self.wrapped.dot(v.wrapped)
|
||||||
|
|
||||||
def sub(self,v):
|
def sub(self,v):
|
||||||
return self.wrapped.sub(v.wrapped)
|
return Vector(self.wrapped.sub(v.wrapped))
|
||||||
|
|
||||||
def add(self,v):
|
def add(self,v):
|
||||||
return Vector( self.wrapped.add(v.wrapped))
|
return Vector( self.wrapped.add(v.wrapped))
|
||||||
|
|
|
@ -198,6 +198,22 @@ class Shape(object):
|
||||||
else:
|
else:
|
||||||
raise ValueError("Cannot find the center of %s object type" % str(type(self.Solids()[0].wrapped)))
|
raise ValueError("Cannot find the center of %s object type" % str(type(self.Solids()[0].wrapped)))
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def CombinedCenter(objects):
|
||||||
|
"""
|
||||||
|
Calculates the center of mass of multiple objects.
|
||||||
|
|
||||||
|
:param objects: a list of objects with mass
|
||||||
|
"""
|
||||||
|
total_mass = sum(o.wrapped.Mass for o in objects)
|
||||||
|
weighted_centers = [o.wrapped.CenterOfMass.multiply(o.wrapped.Mass) for o in objects]
|
||||||
|
|
||||||
|
sum_wc = weighted_centers[0]
|
||||||
|
for wc in weighted_centers[1:] :
|
||||||
|
sum_wc = sum_wc.add(wc)
|
||||||
|
|
||||||
|
return Vector(sum_wc.multiply(1./total_mass))
|
||||||
|
|
||||||
def Closed(self):
|
def Closed(self):
|
||||||
return self.wrapped.Closed
|
return self.wrapped.Closed
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user