Updated to work with 0.13
- This is _totally_ experimental, and I haven't done exhaustive tests - 88 unit tests do pass though, and I added a new import test. - 0.12 and 0.13 seem to structure stuff a bit differently, probably due to changes in the FreeCAD lib wrappers. - Not tested on windows (but should work) or 0.12. Need some help there.
This commit is contained in:
parent
8089ef1e04
commit
c3290fca92
|
@ -2,7 +2,7 @@
|
||||||
Copyright (C) 2011-2013 Parametric Products Intellectual Holdings, LLC
|
Copyright (C) 2011-2013 Parametric Products Intellectual Holdings, LLC
|
||||||
|
|
||||||
This file is part of CadQuery.
|
This file is part of CadQuery.
|
||||||
|
|
||||||
CadQuery is free software; you can redistribute it and/or
|
CadQuery is free software; you can redistribute it and/or
|
||||||
modify it under the terms of the GNU Lesser General Public
|
modify it under the terms of the GNU Lesser General Public
|
||||||
License as published by the Free Software Foundation; either
|
License as published by the Free Software Foundation; either
|
||||||
|
@ -15,14 +15,25 @@
|
||||||
|
|
||||||
You should have received a copy of the GNU Lesser General Public
|
You should have received a copy of the GNU Lesser General Public
|
||||||
License along with this library; If not, see <http://www.gnu.org/licenses/>
|
License along with this library; If not, see <http://www.gnu.org/licenses/>
|
||||||
|
|
||||||
An exporter should provide functionality to accept a shape, and return
|
An exporter should provide functionality to accept a shape, and return
|
||||||
a string containing the model content.
|
a string containing the model content.
|
||||||
"""
|
"""
|
||||||
import cadquery
|
import cadquery
|
||||||
|
|
||||||
import FreeCAD,tempfile,os,StringIO
|
from .verutil import fc_import
|
||||||
from FreeCAD import Drawing
|
FreeCAD = fc_import("FreeCAD")
|
||||||
|
import tempfile,os,StringIO
|
||||||
|
|
||||||
|
Drawing = fc_import("FreeCAD.Drawing")
|
||||||
|
#_FCVER = freecad_version()
|
||||||
|
#if _FCVER>=(0,13):
|
||||||
|
#import Drawing as FreeCADDrawing #It's in FreeCAD lib path
|
||||||
|
#elif _FCVER>=(0,12):
|
||||||
|
#import FreeCAD.Drawing as FreeCADDrawing
|
||||||
|
#else:
|
||||||
|
#raise RuntimeError, "Invalid freecad version: %s" % str(".".join(_FCVER))
|
||||||
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
import xml.etree.cElementTree as ET
|
import xml.etree.cElementTree as ET
|
||||||
|
@ -35,7 +46,7 @@ class ExportTypes:
|
||||||
AMF = "AMF"
|
AMF = "AMF"
|
||||||
SVG = "SVG"
|
SVG = "SVG"
|
||||||
TJS = "TJS"
|
TJS = "TJS"
|
||||||
|
|
||||||
class UNITS:
|
class UNITS:
|
||||||
MM = "mm"
|
MM = "mm"
|
||||||
IN = "in"
|
IN = "in"
|
||||||
|
@ -45,7 +56,7 @@ def toString(shape,exportType,tolerance=0.1):
|
||||||
s= StringIO.StringIO()
|
s= StringIO.StringIO()
|
||||||
exportShape(shape,exportType,s,tolerance)
|
exportShape(shape,exportType,s,tolerance)
|
||||||
return s.getvalue()
|
return s.getvalue()
|
||||||
|
|
||||||
def exportShape(shape,exportType,fileLike,tolerance=0.1):
|
def exportShape(shape,exportType,fileLike,tolerance=0.1):
|
||||||
"""
|
"""
|
||||||
:param shape: the shape to export. it can be a shape object, or a cadquery object. If a cadquery
|
:param shape: the shape to export. it can be a shape object, or a cadquery object. If a cadquery
|
||||||
|
@ -54,13 +65,13 @@ def exportShape(shape,exportType,fileLike,tolerance=0.1):
|
||||||
:param tolerance: the tolerance, in model units
|
:param tolerance: the tolerance, in model units
|
||||||
:param fileLike: a file like object to which the content will be written.
|
:param fileLike: a file like object to which the content will be written.
|
||||||
The object should be already open and ready to write. The caller is responsible
|
The object should be already open and ready to write. The caller is responsible
|
||||||
for closing the object
|
for closing the object
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
if isinstance(shape,cadquery.CQ):
|
if isinstance(shape,cadquery.CQ):
|
||||||
shape = shape.val()
|
shape = shape.val()
|
||||||
|
|
||||||
if exportType == ExportTypes.TJS:
|
if exportType == ExportTypes.TJS:
|
||||||
#tessellate the model
|
#tessellate the model
|
||||||
tess = shape.tessellate(tolerance)
|
tess = shape.tessellate(tolerance)
|
||||||
|
@ -78,9 +89,9 @@ def exportShape(shape,exportType,fileLike,tolerance=0.1):
|
||||||
fileLike.write(getSVG(shape.wrapped))
|
fileLike.write(getSVG(shape.wrapped))
|
||||||
elif exportType == ExportTypes.AMF:
|
elif exportType == ExportTypes.AMF:
|
||||||
tess = shape.tessellate(tolerance)
|
tess = shape.tessellate(tolerance)
|
||||||
aw = AmfWriter(tess).writeAmf(fileLike)
|
aw = AmfWriter(tess).writeAmf(fileLike)
|
||||||
else:
|
else:
|
||||||
|
|
||||||
#all these types required writing to a file and then
|
#all these types required writing to a file and then
|
||||||
#re-reading. this is due to the fact that FreeCAD writes these
|
#re-reading. this is due to the fact that FreeCAD writes these
|
||||||
(h, outFileName) = tempfile.mkstemp()
|
(h, outFileName) = tempfile.mkstemp()
|
||||||
|
@ -130,8 +141,8 @@ def guessUnitOfMeasure(shape):
|
||||||
if sum(dimList) < 10:
|
if sum(dimList) < 10:
|
||||||
return UNITS.IN
|
return UNITS.IN
|
||||||
|
|
||||||
return UNITS.MM
|
return UNITS.MM
|
||||||
|
|
||||||
|
|
||||||
class AmfWriter(object):
|
class AmfWriter(object):
|
||||||
def __init__(self,tessellation):
|
def __init__(self,tessellation):
|
||||||
|
@ -172,7 +183,7 @@ class AmfWriter(object):
|
||||||
ET.ElementTree(amf).write(outFile,encoding='ISO-8859-1')
|
ET.ElementTree(amf).write(outFile,encoding='ISO-8859-1')
|
||||||
|
|
||||||
"""
|
"""
|
||||||
Objects that represent
|
Objects that represent
|
||||||
three.js JSON object notation
|
three.js JSON object notation
|
||||||
https://github.com/mrdoob/three.js/wiki/JSON-Model-format-3.0
|
https://github.com/mrdoob/three.js/wiki/JSON-Model-format-3.0
|
||||||
"""
|
"""
|
||||||
|
@ -183,21 +194,21 @@ class JsonMesh(object):
|
||||||
self.faces = [];
|
self.faces = [];
|
||||||
self.nVertices = 0;
|
self.nVertices = 0;
|
||||||
self.nFaces = 0;
|
self.nFaces = 0;
|
||||||
|
|
||||||
def addVertex(self,x,y,z):
|
def addVertex(self,x,y,z):
|
||||||
self.nVertices += 1;
|
self.nVertices += 1;
|
||||||
self.vertices.extend([x,y,z]);
|
self.vertices.extend([x,y,z]);
|
||||||
|
|
||||||
#add triangle composed of the three provided vertex indices
|
#add triangle composed of the three provided vertex indices
|
||||||
def addTriangleFace(self, i,j,k):
|
def addTriangleFace(self, i,j,k):
|
||||||
#first position means justa simple triangle
|
#first position means justa simple triangle
|
||||||
self.nFaces += 1;
|
self.nFaces += 1;
|
||||||
self.faces.extend([0,int(i),int(j),int(k)]);
|
self.faces.extend([0,int(i),int(j),int(k)]);
|
||||||
|
|
||||||
"""
|
"""
|
||||||
Get a json model from this model.
|
Get a json model from this model.
|
||||||
For now we'll forget about colors, vertex normals, and all that stuff
|
For now we'll forget about colors, vertex normals, and all that stuff
|
||||||
"""
|
"""
|
||||||
def toJson(self):
|
def toJson(self):
|
||||||
return JSON_TEMPLATE % {
|
return JSON_TEMPLATE % {
|
||||||
'vertices' : str(self.vertices),
|
'vertices' : str(self.vertices),
|
||||||
|
@ -249,7 +260,7 @@ def getSVG(shape,opts=None):
|
||||||
"""
|
"""
|
||||||
|
|
||||||
d = {'width':800,'height':240,'marginLeft':200,'marginTop':20}
|
d = {'width':800,'height':240,'marginLeft':200,'marginTop':20}
|
||||||
|
|
||||||
if opts:
|
if opts:
|
||||||
d.update(opts)
|
d.update(opts)
|
||||||
|
|
||||||
|
@ -314,14 +325,14 @@ def exportSVG(shape, fileName):
|
||||||
TODO: should use file-like objects, not a fileName, and/or be able to return a string instead
|
TODO: should use file-like objects, not a fileName, and/or be able to return a string instead
|
||||||
export a view of a part to svg
|
export a view of a part to svg
|
||||||
"""
|
"""
|
||||||
|
|
||||||
svg = getSVG(shape.val().wrapped)
|
svg = getSVG(shape.val().wrapped)
|
||||||
f = open(fileName,'w')
|
f = open(fileName,'w')
|
||||||
f.write(svg)
|
f.write(svg)
|
||||||
f.close()
|
f.close()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
JSON_TEMPLATE= """\
|
JSON_TEMPLATE= """\
|
||||||
{
|
{
|
||||||
"metadata" :
|
"metadata" :
|
||||||
|
@ -336,9 +347,9 @@ JSON_TEMPLATE= """\
|
||||||
"materials" : 1,
|
"materials" : 1,
|
||||||
"morphTargets" : 0
|
"morphTargets" : 0
|
||||||
},
|
},
|
||||||
|
|
||||||
"scale" : 1.0,
|
"scale" : 1.0,
|
||||||
|
|
||||||
"materials": [ {
|
"materials": [ {
|
||||||
"DbgColor" : 15658734,
|
"DbgColor" : 15658734,
|
||||||
"DbgIndex" : 0,
|
"DbgIndex" : 0,
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
Copyright (C) 2011-2013 Parametric Products Intellectual Holdings, LLC
|
Copyright (C) 2011-2013 Parametric Products Intellectual Holdings, LLC
|
||||||
|
|
||||||
This file is part of CadQuery.
|
This file is part of CadQuery.
|
||||||
|
|
||||||
CadQuery is free software; you can redistribute it and/or
|
CadQuery is free software; you can redistribute it and/or
|
||||||
modify it under the terms of the GNU Lesser General Public
|
modify it under the terms of the GNU Lesser General Public
|
||||||
License as published by the Free Software Foundation; either
|
License as published by the Free Software Foundation; either
|
||||||
|
@ -18,8 +18,10 @@
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import math,sys
|
import math,sys
|
||||||
import FreeCAD
|
#import FreeCAD
|
||||||
import FreeCAD.Part
|
from .verutil import fc_import
|
||||||
|
FreeCAD = fc_import("FreeCAD")
|
||||||
|
#Turns out we don't need the Part module here.
|
||||||
|
|
||||||
def sortWiresByBuildOrder(wireList,plane,result=[]):
|
def sortWiresByBuildOrder(wireList,plane,result=[]):
|
||||||
"""
|
"""
|
||||||
|
@ -187,8 +189,8 @@ class Vector(object):
|
||||||
|
|
||||||
class Matrix:
|
class Matrix:
|
||||||
"""
|
"""
|
||||||
A 3d , 4x4 transformation matrix.
|
A 3d , 4x4 transformation matrix.
|
||||||
|
|
||||||
Used to move geometry in space.
|
Used to move geometry in space.
|
||||||
"""
|
"""
|
||||||
def __init__(self,matrix=None):
|
def __init__(self,matrix=None):
|
||||||
|
@ -196,14 +198,14 @@ class Matrix:
|
||||||
self.wrapped = FreeCAD.Base.Matrix()
|
self.wrapped = FreeCAD.Base.Matrix()
|
||||||
else:
|
else:
|
||||||
self.wrapped = matrix
|
self.wrapped = matrix
|
||||||
|
|
||||||
def rotateX(self,angle):
|
def rotateX(self,angle):
|
||||||
self.wrapped.rotateX(angle)
|
self.wrapped.rotateX(angle)
|
||||||
|
|
||||||
def rotateY(self,angle):
|
def rotateY(self,angle):
|
||||||
self.wrapped.rotateY(angle)
|
self.wrapped.rotateY(angle)
|
||||||
|
|
||||||
|
|
||||||
class Plane:
|
class Plane:
|
||||||
"""
|
"""
|
||||||
A 2d coordinate system in space, with the x-y axes on the a plane, and a particular point as the origin.
|
A 2d coordinate system in space, with the x-y axes on the a plane, and a particular point as the origin.
|
||||||
|
@ -321,7 +323,7 @@ class Plane:
|
||||||
|
|
||||||
self.setOrigin3d(origin)
|
self.setOrigin3d(origin)
|
||||||
|
|
||||||
|
|
||||||
def setOrigin3d(self,originVector):
|
def setOrigin3d(self,originVector):
|
||||||
"""
|
"""
|
||||||
Move the origin of the plane, leaving its orientation and xDirection unchanged.
|
Move the origin of the plane, leaving its orientation and xDirection unchanged.
|
||||||
|
@ -427,7 +429,7 @@ class Plane:
|
||||||
v = Vector(tuplePoint[0],tuplePoint[1],tuplePoint[2])
|
v = Vector(tuplePoint[0],tuplePoint[1],tuplePoint[2])
|
||||||
return Vector(self.rG.multiply(v.wrapped))
|
return Vector(self.rG.multiply(v.wrapped))
|
||||||
|
|
||||||
|
|
||||||
def rotated(self,rotate=(0,0,0)):
|
def rotated(self,rotate=(0,0,0)):
|
||||||
"""
|
"""
|
||||||
returns a copy of this plane, rotated about the specified axes, as measured from horizontal
|
returns a copy of this plane, rotated about the specified axes, as measured from horizontal
|
||||||
|
@ -445,7 +447,7 @@ class Plane:
|
||||||
"""
|
"""
|
||||||
|
|
||||||
if rotate.__class__.__name__ != 'Vector':
|
if rotate.__class__.__name__ != 'Vector':
|
||||||
rotate = Vector(rotate)
|
rotate = Vector(rotate)
|
||||||
#convert to radians
|
#convert to radians
|
||||||
rotate = rotate.multiply(math.pi / 180.0 )
|
rotate = rotate.multiply(math.pi / 180.0 )
|
||||||
|
|
||||||
|
@ -473,13 +475,13 @@ class Plane:
|
||||||
#compute rotation matrix ( global --> local --> rotate --> global )
|
#compute rotation matrix ( global --> local --> rotate --> global )
|
||||||
#rm = self.plane.fG.multiply(matrix).multiply(self.plane.rG)
|
#rm = self.plane.fG.multiply(matrix).multiply(self.plane.rG)
|
||||||
rm = self.computeTransform(rotationMatrix)
|
rm = self.computeTransform(rotationMatrix)
|
||||||
|
|
||||||
|
|
||||||
#There might be a better way, but to do this rotation takes 3 steps
|
#There might be a better way, but to do this rotation takes 3 steps
|
||||||
#transform geometry to local coordinates
|
#transform geometry to local coordinates
|
||||||
#then rotate about x
|
#then rotate about x
|
||||||
#then transform back to global coordiante
|
#then transform back to global coordiante
|
||||||
|
|
||||||
resultWires = []
|
resultWires = []
|
||||||
for w in listOfShapes:
|
for w in listOfShapes:
|
||||||
mirrored = w.transformGeometry(rotationMatrix.wrapped)
|
mirrored = w.transformGeometry(rotationMatrix.wrapped)
|
||||||
|
@ -487,7 +489,7 @@ class Plane:
|
||||||
|
|
||||||
return resultWires
|
return resultWires
|
||||||
|
|
||||||
|
|
||||||
def _calcTransforms(self):
|
def _calcTransforms(self):
|
||||||
"""
|
"""
|
||||||
Computes transformation martrices to convert betwene local and global coordinates
|
Computes transformation martrices to convert betwene local and global coordinates
|
||||||
|
@ -507,12 +509,12 @@ class Plane:
|
||||||
(invR.A14,invR.A24,invR.A34) = (self.origin.x,self.origin.y,self.origin.z)
|
(invR.A14,invR.A24,invR.A34) = (self.origin.x,self.origin.y,self.origin.z)
|
||||||
|
|
||||||
( self.rG,self.fG ) = ( invR,invR.inverse() )
|
( self.rG,self.fG ) = ( invR,invR.inverse() )
|
||||||
|
|
||||||
def computeTransform(self,tMatrix):
|
def computeTransform(self,tMatrix):
|
||||||
"""
|
"""
|
||||||
Computes the 2-d projection of the supplied matrix
|
Computes the 2-d projection of the supplied matrix
|
||||||
"""
|
"""
|
||||||
|
|
||||||
rm = self.fG.multiply(tMatrix.wrapped).multiply(self.rG)
|
rm = self.fG.multiply(tMatrix.wrapped).multiply(self.rG)
|
||||||
return Matrix(rm)
|
return Matrix(rm)
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
Copyright (C) 2011-2013 Parametric Products Intellectual Holdings, LLC
|
Copyright (C) 2011-2013 Parametric Products Intellectual Holdings, LLC
|
||||||
|
|
||||||
This file is part of CadQuery.
|
This file is part of CadQuery.
|
||||||
|
|
||||||
CadQuery is free software; you can redistribute it and/or
|
CadQuery is free software; you can redistribute it and/or
|
||||||
modify it under the terms of the GNU Lesser General Public
|
modify it under the terms of the GNU Lesser General Public
|
||||||
License as published by the Free Software Foundation; either
|
License as published by the Free Software Foundation; either
|
||||||
|
@ -43,13 +43,15 @@
|
||||||
|
|
||||||
5. allow changing interfaces when we'd like. there are few cases where the freecad api is not
|
5. allow changing interfaces when we'd like. there are few cases where the freecad api is not
|
||||||
very userfriendly: we like to change those when necesary. As an example, in the freecad api,
|
very userfriendly: we like to change those when necesary. As an example, in the freecad api,
|
||||||
all factory methods are on the 'Part' object, but it is very useful to know what kind of
|
all factory methods are on the 'Part' object, but it is very useful to know what kind of
|
||||||
object each one returns, so these are better grouped by the type of object they return.
|
object each one returns, so these are better grouped by the type of object they return.
|
||||||
(who would know that Part.makeCircle() returns an Edge, but Part.makePolygon() returns a Wire ?
|
(who would know that Part.makeCircle() returns an Edge, but Part.makePolygon() returns a Wire ?
|
||||||
"""
|
"""
|
||||||
from cadquery import Vector,BoundBox
|
from cadquery import Vector,BoundBox
|
||||||
import FreeCAD
|
import FreeCAD
|
||||||
import FreeCAD.Part
|
|
||||||
|
from .verutil import fc_import
|
||||||
|
FreeCADPart = fc_import("FreeCAD.Part")
|
||||||
|
|
||||||
class Shape(object):
|
class Shape(object):
|
||||||
"""
|
"""
|
||||||
|
@ -269,7 +271,7 @@ class Shape(object):
|
||||||
def transformGeometry(self,tMatrix):
|
def transformGeometry(self,tMatrix):
|
||||||
"""
|
"""
|
||||||
tMatrix is a matrix object.
|
tMatrix is a matrix object.
|
||||||
|
|
||||||
returns a copy of the object, but with geometry transformed insetad of just
|
returns a copy of the object, but with geometry transformed insetad of just
|
||||||
rotated.
|
rotated.
|
||||||
|
|
||||||
|
@ -316,9 +318,9 @@ class Edge(Shape):
|
||||||
#self.endPoint = None
|
#self.endPoint = None
|
||||||
|
|
||||||
self.edgetypes= {
|
self.edgetypes= {
|
||||||
FreeCAD.Part.Line : 'LINE',
|
FreeCADPart.Line : 'LINE',
|
||||||
FreeCAD.Part.ArcOfCircle : 'ARC',
|
FreeCADPart.ArcOfCircle : 'ARC',
|
||||||
FreeCAD.Part.Circle : 'CIRCLE'
|
FreeCADPart.Circle : 'CIRCLE'
|
||||||
}
|
}
|
||||||
|
|
||||||
def geomType(self):
|
def geomType(self):
|
||||||
|
@ -368,7 +370,7 @@ class Edge(Shape):
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def makeCircle(cls,radius,pnt=(0,0,0),dir=(0,0,1),angle1=360.0,angle2=360):
|
def makeCircle(cls,radius,pnt=(0,0,0),dir=(0,0,1),angle1=360.0,angle2=360):
|
||||||
return Edge(FreeCAD.Part.makeCircle(radius,toVector(pnt),toVector(dir),angle1,angle2))
|
return Edge(FreeCADPart.makeCircle(radius,toVector(pnt),toVector(dir),angle1,angle2))
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def makeSpline(cls,listOfVector):
|
def makeSpline(cls,listOfVector):
|
||||||
|
@ -380,7 +382,7 @@ class Edge(Shape):
|
||||||
"""
|
"""
|
||||||
vecs = [v.wrapped for v in listOfVector]
|
vecs = [v.wrapped for v in listOfVector]
|
||||||
|
|
||||||
spline = FreeCAD.Part.BSplineCurve()
|
spline = FreeCADPart.BSplineCurve()
|
||||||
spline.interpolate(vecs,False)
|
spline.interpolate(vecs,False)
|
||||||
return Edge(spline.toShape())
|
return Edge(spline.toShape())
|
||||||
|
|
||||||
|
@ -394,7 +396,7 @@ class Edge(Shape):
|
||||||
:param v3: end vector
|
:param v3: end vector
|
||||||
:return: an edge object through the three points
|
:return: an edge object through the three points
|
||||||
"""
|
"""
|
||||||
arc = FreeCAD.Part.Arc(v1.wrapped,v2.wrapped,v3.wrapped)
|
arc = FreeCADPart.Arc(v1.wrapped,v2.wrapped,v3.wrapped)
|
||||||
e = Edge(arc.toShape())
|
e = Edge(arc.toShape())
|
||||||
return e #arcane and undocumented, this creates an Edge object
|
return e #arcane and undocumented, this creates an Edge object
|
||||||
|
|
||||||
|
@ -406,7 +408,7 @@ class Edge(Shape):
|
||||||
:param v2: Vector that represents the second point
|
:param v2: Vector that represents the second point
|
||||||
:return: A linear edge between the two provided points
|
:return: A linear edge between the two provided points
|
||||||
"""
|
"""
|
||||||
return Edge(FreeCAD.Part.makeLine(v1.toTuple(),v2.toTuple() ))
|
return Edge(FreeCADPart.makeLine(v1.toTuple(),v2.toTuple() ))
|
||||||
|
|
||||||
|
|
||||||
class Wire(Shape):
|
class Wire(Shape):
|
||||||
|
@ -425,7 +427,7 @@ class Wire(Shape):
|
||||||
:param listOfWires:
|
:param listOfWires:
|
||||||
:return:
|
:return:
|
||||||
"""
|
"""
|
||||||
return Shape.cast(FreeCAD.Part.Wire([w.wrapped for w in listOfWires]))
|
return Shape.cast(FreeCADPart.Wire([w.wrapped for w in listOfWires]))
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def assembleEdges(cls,listOfEdges):
|
def assembleEdges(cls,listOfEdges):
|
||||||
|
@ -437,7 +439,7 @@ class Wire(Shape):
|
||||||
"""
|
"""
|
||||||
fCEdges = [a.wrapped for a in listOfEdges]
|
fCEdges = [a.wrapped for a in listOfEdges]
|
||||||
|
|
||||||
wa = Wire( FreeCAD.Part.Wire(fCEdges) )
|
wa = Wire( FreeCADPart.Wire(fCEdges) )
|
||||||
return wa
|
return wa
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
|
@ -449,13 +451,13 @@ class Wire(Shape):
|
||||||
:param normal: vector representing the direction of the plane the circle should lie in
|
:param normal: vector representing the direction of the plane the circle should lie in
|
||||||
:return:
|
:return:
|
||||||
"""
|
"""
|
||||||
w = Wire(FreeCAD.Part.Wire([FreeCAD.Part.makeCircle(radius,center.wrapped,normal.wrapped)]))
|
w = Wire(FreeCADPart.Wire([FreeCADPart.makeCircle(radius,center.wrapped,normal.wrapped)]))
|
||||||
return w
|
return w
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def makePolygon(cls,listOfVertices,forConstruction=False):
|
def makePolygon(cls,listOfVertices,forConstruction=False):
|
||||||
#convert list of tuples into Vectors.
|
#convert list of tuples into Vectors.
|
||||||
w = Wire(FreeCAD.Part.makePolygon([i.wrapped for i in listOfVertices]))
|
w = Wire(FreeCADPart.makePolygon([i.wrapped for i in listOfVertices]))
|
||||||
w.forConstruction = forConstruction
|
w.forConstruction = forConstruction
|
||||||
return w
|
return w
|
||||||
|
|
||||||
|
@ -466,7 +468,7 @@ class Wire(Shape):
|
||||||
By default a cylindrical surface is used to create the helix. If
|
By default a cylindrical surface is used to create the helix. If
|
||||||
the fourth parameter is set (the apex given in degree) a conical surface is used instead'
|
the fourth parameter is set (the apex given in degree) a conical surface is used instead'
|
||||||
"""
|
"""
|
||||||
return Wire(FreeCAD.Part.makeHelix(pitch,height,radius,angle))
|
return Wire(FreeCADPart.makeHelix(pitch,height,radius,angle))
|
||||||
|
|
||||||
|
|
||||||
class Face(Shape):
|
class Face(Shape):
|
||||||
|
@ -478,9 +480,9 @@ class Face(Shape):
|
||||||
|
|
||||||
self.facetypes = {
|
self.facetypes = {
|
||||||
#TODO: bezier,bspline etc
|
#TODO: bezier,bspline etc
|
||||||
FreeCAD.Part.Plane : 'PLANE',
|
FreeCADPart.Plane : 'PLANE',
|
||||||
FreeCAD.Part.Sphere : 'SPHERE',
|
FreeCADPart.Sphere : 'SPHERE',
|
||||||
FreeCAD.Part.Cone : 'CONE'
|
FreeCADPart.Cone : 'CONE'
|
||||||
}
|
}
|
||||||
|
|
||||||
def geomType(self):
|
def geomType(self):
|
||||||
|
@ -506,7 +508,7 @@ class Face(Shape):
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def makePlane(cls,length,width,basePnt=None,dir=None):
|
def makePlane(cls,length,width,basePnt=None,dir=None):
|
||||||
return Face(FreeCAD.Part.makePlan(length,width,toVector(basePnt),toVector(dir)))
|
return Face(FreeCADPart.makePlan(length,width,toVector(basePnt),toVector(dir)))
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def makeRuledSurface(cls,edgeOrWire1,edgeOrWire2,dist=None):
|
def makeRuledSurface(cls,edgeOrWire1,edgeOrWire2,dist=None):
|
||||||
|
@ -515,7 +517,7 @@ class Face(Shape):
|
||||||
Create a ruled surface out of two edges or wires. If wires are used then
|
Create a ruled surface out of two edges or wires. If wires are used then
|
||||||
these must have the same
|
these must have the same
|
||||||
"""
|
"""
|
||||||
return Shape.cast(FreeCAD.Part.makeRuledSurface(edgeOrWire1.obj,edgeOrWire2.obj,dist))
|
return Shape.cast(FreeCADPart.makeRuledSurface(edgeOrWire1.obj,edgeOrWire2.obj,dist))
|
||||||
|
|
||||||
def cut(self,faceToCut):
|
def cut(self,faceToCut):
|
||||||
"Remove a face from another one"
|
"Remove a face from another one"
|
||||||
|
@ -541,7 +543,7 @@ class Shell(Shape):
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def makeShell(cls,listOfFaces):
|
def makeShell(cls,listOfFaces):
|
||||||
return Shell(FreeCAD.Part.makeShell([i.obj for i in listOfFaces]))
|
return Shell(FreeCADPart.makeShell([i.obj for i in listOfFaces]))
|
||||||
|
|
||||||
|
|
||||||
class Solid(Shape):
|
class Solid(Shape):
|
||||||
|
@ -568,7 +570,7 @@ class Solid(Shape):
|
||||||
makeBox(length,width,height,[pnt,dir]) -- Make a box located\nin pnt with the d
|
makeBox(length,width,height,[pnt,dir]) -- Make a box located\nin pnt with the d
|
||||||
imensions (length,width,height)\nBy default pnt=Vector(0,0,0) and dir=Vector(0,0,1)'
|
imensions (length,width,height)\nBy default pnt=Vector(0,0,0) and dir=Vector(0,0,1)'
|
||||||
"""
|
"""
|
||||||
return Shape.cast(FreeCAD.Part.makeBox(length,width,height,pnt.wrapped,dir.wrapped))
|
return Shape.cast(FreeCADPart.makeBox(length,width,height,pnt.wrapped,dir.wrapped))
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def makeCone(cls,radius1,radius2,height,pnt=Vector(0,0,0),dir=Vector(0,0,1),angleDegrees=360):
|
def makeCone(cls,radius1,radius2,height,pnt=Vector(0,0,0),dir=Vector(0,0,1),angleDegrees=360):
|
||||||
|
@ -577,7 +579,7 @@ class Solid(Shape):
|
||||||
Make a cone with given radii and height\nBy default pnt=Vector(0,0,0),
|
Make a cone with given radii and height\nBy default pnt=Vector(0,0,0),
|
||||||
dir=Vector(0,0,1) and angle=360'
|
dir=Vector(0,0,1) and angle=360'
|
||||||
"""
|
"""
|
||||||
return Shape.cast(FreeCAD.Part.makeCone(radius1,radius2,height,pnt.wrapped,dir.wrapped,angleDegrees))
|
return Shape.cast(FreeCADPart.makeCone(radius1,radius2,height,pnt.wrapped,dir.wrapped,angleDegrees))
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def makeCylinder(cls,radius,height,pnt=Vector(0,0,0),dir=Vector(0,0,1),angleDegrees=360):
|
def makeCylinder(cls,radius,height,pnt=Vector(0,0,0),dir=Vector(0,0,1),angleDegrees=360):
|
||||||
|
@ -586,7 +588,7 @@ class Solid(Shape):
|
||||||
Make a cylinder with a given radius and height
|
Make a cylinder with a given radius and height
|
||||||
By default pnt=Vector(0,0,0),dir=Vector(0,0,1) and angle=360'
|
By default pnt=Vector(0,0,0),dir=Vector(0,0,1) and angle=360'
|
||||||
"""
|
"""
|
||||||
return Shape.cast(FreeCAD.Part.makeCylinder(radius,height,pnt.wrapped,dir.wrapped,angleDegrees))
|
return Shape.cast(FreeCADPart.makeCylinder(radius,height,pnt.wrapped,dir.wrapped,angleDegrees))
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def makeTorus(cls,radius1,radius2,pnt=None,dir=None,angleDegrees1=None,angleDegrees2=None):
|
def makeTorus(cls,radius1,radius2,pnt=None,dir=None,angleDegrees1=None,angleDegrees2=None):
|
||||||
|
@ -596,7 +598,7 @@ class Solid(Shape):
|
||||||
By default pnt=Vector(0,0,0),dir=Vector(0,0,1),angle1=0
|
By default pnt=Vector(0,0,0),dir=Vector(0,0,1),angle1=0
|
||||||
,angle1=360 and angle=360'
|
,angle1=360 and angle=360'
|
||||||
"""
|
"""
|
||||||
return Shape.cast(FreeCAD.Part.makeTorus(radius1,radius2,pnt,dir,angleDegrees1,angleDegrees2))
|
return Shape.cast(FreeCADPart.makeTorus(radius1,radius2,pnt,dir,angleDegrees1,angleDegrees2))
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def sweep(cls,profileWire,pathWire):
|
def sweep(cls,profileWire,pathWire):
|
||||||
|
@ -615,11 +617,11 @@ class Solid(Shape):
|
||||||
"""
|
"""
|
||||||
makes a loft from a list of wires
|
makes a loft from a list of wires
|
||||||
The wires will be converted into faces when possible-- it is presumed that nobody ever actually
|
The wires will be converted into faces when possible-- it is presumed that nobody ever actually
|
||||||
wants to make an infinitely thin shell for a real FreeCAD.Part.
|
wants to make an infinitely thin shell for a real FreeCADPart.
|
||||||
"""
|
"""
|
||||||
#the True flag requests building a solid instead of a shell.
|
#the True flag requests building a solid instead of a shell.
|
||||||
|
|
||||||
return Shape.cast(FreeCAD.Part.makeLoft([i.wrapped for i in listOfWire],True))
|
return Shape.cast(FreeCADPart.makeLoft([i.wrapped for i in listOfWire],True))
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def makeWedge(cls,xmin,ymin,zmin,z2min,x2min,xmax,ymax,zmax,z2max,x2max,pnt=None,dir=None):
|
def makeWedge(cls,xmin,ymin,zmin,z2min,x2min,xmax,ymax,zmax,z2max,x2max,pnt=None,dir=None):
|
||||||
|
@ -629,7 +631,7 @@ class Solid(Shape):
|
||||||
Make a wedge located in pnt\nBy default pnt=Vector(0,0,0) and dir=Vec
|
Make a wedge located in pnt\nBy default pnt=Vector(0,0,0) and dir=Vec
|
||||||
tor(0,0,1)'
|
tor(0,0,1)'
|
||||||
"""
|
"""
|
||||||
return Shape.cast(FreeCAD.Part.makeWedge(xmin,ymin,zmin,z2min,x2min,xmax,ymax,zmax,z2max,x2max,pnt,dir))
|
return Shape.cast(FreeCADPart.makeWedge(xmin,ymin,zmin,z2min,x2min,xmax,ymax,zmax,z2max,x2max,pnt,dir))
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def makeSphere(cls,radius,pnt=None,angleDegrees1=None,angleDegrees2=None,angleDegrees3=None):
|
def makeSphere(cls,radius,pnt=None,angleDegrees1=None,angleDegrees2=None,angleDegrees3=None):
|
||||||
|
@ -638,7 +640,7 @@ class Solid(Shape):
|
||||||
Make a sphere with a giv
|
Make a sphere with a giv
|
||||||
en radius\nBy default pnt=Vector(0,0,0), dir=Vector(0,0,1), angle1=0, angle2=90 and angle3=360'
|
en radius\nBy default pnt=Vector(0,0,0), dir=Vector(0,0,1), angle1=0, angle2=90 and angle3=360'
|
||||||
"""
|
"""
|
||||||
return Solid(FreeCAD.Part.makeSphere(radius,pnt,angleDegrees1,angleDegrees2,angleDegrees3))
|
return Solid(FreeCADPart.makeSphere(radius,pnt,angleDegrees1,angleDegrees2,angleDegrees3))
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def extrudeLinearWithRotation(cls,outerWire,innerWires,vecCenter, vecNormal,angleDegrees):
|
def extrudeLinearWithRotation(cls,outerWire,innerWires,vecCenter, vecNormal,angleDegrees):
|
||||||
|
@ -679,12 +681,12 @@ class Solid(Shape):
|
||||||
#make a ruled surface for each set of wires
|
#make a ruled surface for each set of wires
|
||||||
sides = []
|
sides = []
|
||||||
for w1,w2 in zip(startWires,endWires):
|
for w1,w2 in zip(startWires,endWires):
|
||||||
rs = FreeCAD.Part.makeRuledSurface(w1,w2)
|
rs = FreeCADPart.makeRuledSurface(w1,w2)
|
||||||
sides.append(rs)
|
sides.append(rs)
|
||||||
|
|
||||||
#make faces for the top and bottom
|
#make faces for the top and bottom
|
||||||
startFace = FreeCAD.Part.Face(startWires)
|
startFace = FreeCADPart.Face(startWires)
|
||||||
endFace = FreeCAD.Part.Face(endWires)
|
endFace = FreeCADPart.Face(endWires)
|
||||||
|
|
||||||
#collect all the faces from the sides
|
#collect all the faces from the sides
|
||||||
faceList = [ startFace]
|
faceList = [ startFace]
|
||||||
|
@ -692,8 +694,8 @@ class Solid(Shape):
|
||||||
faceList.extend(s.Faces)
|
faceList.extend(s.Faces)
|
||||||
faceList.append(endFace)
|
faceList.append(endFace)
|
||||||
|
|
||||||
shell = FreeCAD.Part.makeShell(faceList)
|
shell = FreeCADPart.makeShell(faceList)
|
||||||
solid = FreeCAD.Part.makeSolid(shell)
|
solid = FreeCADPart.makeSolid(shell)
|
||||||
return Shape.cast(solid)
|
return Shape.cast(solid)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
|
@ -730,7 +732,7 @@ class Solid(Shape):
|
||||||
for w in innerWires:
|
for w in innerWires:
|
||||||
freeCADWires.append(w.wrapped)
|
freeCADWires.append(w.wrapped)
|
||||||
|
|
||||||
f = FreeCAD.Part.Face(freeCADWires)
|
f = FreeCADPart.Face(freeCADWires)
|
||||||
result = f.extrude(vecNormal.wrapped)
|
result = f.extrude(vecNormal.wrapped)
|
||||||
|
|
||||||
return Shape.cast(result)
|
return Shape.cast(result)
|
||||||
|
@ -794,11 +796,11 @@ class Compound(Shape):
|
||||||
Create a compound out of a list of shapes
|
Create a compound out of a list of shapes
|
||||||
"""
|
"""
|
||||||
solids = [s.wrapped for s in listOfShapes]
|
solids = [s.wrapped for s in listOfShapes]
|
||||||
c = FreeCAD.Part.Compound(solids)
|
c = FreeCADPart.Compound(solids)
|
||||||
return Shape.cast( c)
|
return Shape.cast( c)
|
||||||
|
|
||||||
def fuse(self,toJoin):
|
def fuse(self,toJoin):
|
||||||
return Shape.cast(self.wrapped.fuse(toJoin.wrapped))
|
return Shape.cast(self.wrapped.fuse(toJoin.wrapped))
|
||||||
|
|
||||||
def tessellate(self,tolerance):
|
def tessellate(self,tolerance):
|
||||||
return self.wrapped.tessellate(tolerance)
|
return self.wrapped.tessellate(tolerance)
|
||||||
|
|
113
cadquery/freecad_impl/verutil.py
Normal file
113
cadquery/freecad_impl/verutil.py
Normal file
|
@ -0,0 +1,113 @@
|
||||||
|
"""
|
||||||
|
This file is part of CadQuery.
|
||||||
|
|
||||||
|
CadQuery is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Lesser General Public
|
||||||
|
License as published by the Free Software Foundation; either
|
||||||
|
version 2.1 of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
CadQuery is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public
|
||||||
|
License along with this library; If not, see <http://www.gnu.org/licenses/>
|
||||||
|
|
||||||
|
An exporter should provide functionality to accept a shape, and return
|
||||||
|
a string containing the model content.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import re
|
||||||
|
from importlib import import_module
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
|
||||||
|
MEMO_VERSION = None
|
||||||
|
SUBMODULES = None
|
||||||
|
_PATH = None
|
||||||
|
|
||||||
|
def _figure_out_version(freecadversion):
|
||||||
|
"""Break this out for testability."""
|
||||||
|
return tuple(
|
||||||
|
((int(re.sub("([0-9]*).*", "\\1", part) or 0))
|
||||||
|
for part in freecadversion[:3]))
|
||||||
|
|
||||||
|
|
||||||
|
def _fc_path():
|
||||||
|
"""Find FreeCAD"""
|
||||||
|
global _PATH
|
||||||
|
if _PATH:
|
||||||
|
return _PATH
|
||||||
|
if sys.platform.startswith('linux'):
|
||||||
|
#Make some dangerous assumptions...
|
||||||
|
for _PATH in [
|
||||||
|
os.path.join(os.path.expanduser("~"), "lib/freecad/lib"),
|
||||||
|
"/usr/local/lib/freecad/lib",
|
||||||
|
"/usr/lib/freecad/lib",
|
||||||
|
]:
|
||||||
|
if os.path.exists(_PATH):
|
||||||
|
return _PATH
|
||||||
|
|
||||||
|
elif sys.platform.startswith('win'):
|
||||||
|
for _PATH in [
|
||||||
|
"c:/apps/FreeCAD0.12/bin",
|
||||||
|
"c:/apps/FreeCAD0.13/bin",
|
||||||
|
]:
|
||||||
|
if os.path.exists(_PATH):
|
||||||
|
return _PATH
|
||||||
|
|
||||||
|
def freecad_version():
|
||||||
|
"""Determine the freecad version and return it as a simple
|
||||||
|
comparable tuple"""
|
||||||
|
#If we cannot find freecad, we append it to the path if possible
|
||||||
|
_pthtmp = _fc_path()
|
||||||
|
if not _pthtmp in sys.path:
|
||||||
|
sys.path.append(_pthtmp)
|
||||||
|
import FreeCAD
|
||||||
|
global MEMO_VERSION
|
||||||
|
if not MEMO_VERSION:
|
||||||
|
MEMO_VERSION = _figure_out_version(FreeCAD.Version())
|
||||||
|
return MEMO_VERSION
|
||||||
|
|
||||||
|
def _find_submodules():
|
||||||
|
"""Find the list of allowable submodules in fc13"""
|
||||||
|
global SUBMODULES
|
||||||
|
searchpath = _fc_path()
|
||||||
|
if not SUBMODULES:
|
||||||
|
SUBMODULES = [
|
||||||
|
re.sub("(.*)\\.(py|so)","\\1", filename)
|
||||||
|
for filename in os.listdir(searchpath)
|
||||||
|
if (
|
||||||
|
filename.endswith(".so") or
|
||||||
|
filename.endswith(".py") or
|
||||||
|
filename.endswith(".dll") )] #Yes, complex. Sorry.
|
||||||
|
return SUBMODULES
|
||||||
|
|
||||||
|
|
||||||
|
def fc_import(modulename):
|
||||||
|
"""Intelligent import of freecad components.
|
||||||
|
If we are in 0.12, we can import FreeCAD.Drawing
|
||||||
|
If we are in 0.13, we need to set sys.path and import Drawing as toplevel.
|
||||||
|
This may or may not be a FreeCAD bug though.
|
||||||
|
This is ludicrously complex and feels awful. Kinda like a lot of OCC.
|
||||||
|
"""
|
||||||
|
#Note that this also sets the path as a side effect.
|
||||||
|
|
||||||
|
_fcver = freecad_version()
|
||||||
|
|
||||||
|
if _fcver >= (0, 13):
|
||||||
|
if modulename in _find_submodules():
|
||||||
|
return import_module(modulename)
|
||||||
|
elif re.sub("^FreeCAD\\.", "", modulename) in _find_submodules():
|
||||||
|
return import_module(re.sub("^FreeCAD\\.", "", modulename))
|
||||||
|
else:
|
||||||
|
raise ImportError, "Module %s not found/allowed in %s" % (
|
||||||
|
modulename, _PATH)
|
||||||
|
elif _fcver >= (0, 12):
|
||||||
|
return import_module(modulename)
|
||||||
|
else:
|
||||||
|
raise RuntimeError, "Invalid freecad version: %s" % \
|
||||||
|
str(".".join(_fcver))
|
||||||
|
|
||||||
|
__ALL__ = ['fc_import', 'freecad_version']
|
4
setup.py
4
setup.py
|
@ -1,4 +1,4 @@
|
||||||
from distutils.core import setup
|
from setuptools import setup
|
||||||
|
|
||||||
setup(
|
setup(
|
||||||
name='cadquery',
|
name='cadquery',
|
||||||
|
@ -37,4 +37,4 @@ setup(
|
||||||
'Topic :: Internet',
|
'Topic :: Internet',
|
||||||
'Topic :: Scientific/Engineering'
|
'Topic :: Scientific/Engineering'
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
|
@ -3,9 +3,15 @@ import sys
|
||||||
|
|
||||||
import unittest
|
import unittest
|
||||||
from tests import BaseTest
|
from tests import BaseTest
|
||||||
import FreeCAD
|
|
||||||
|
from cadquery.freecad_impl.verutil import fc_import
|
||||||
|
FreeCAD = fc_import("FreeCAD")
|
||||||
|
if not hasattr(FreeCAD, 'Part'):
|
||||||
|
FreeCAD.Part = fc_import("FreeCAD.Part")
|
||||||
|
|
||||||
|
|
||||||
from cadquery import *
|
from cadquery import *
|
||||||
|
|
||||||
class TestCadObjects(BaseTest):
|
class TestCadObjects(BaseTest):
|
||||||
|
|
||||||
def testVectorConstructors(self):
|
def testVectorConstructors(self):
|
||||||
|
@ -57,6 +63,6 @@ class TestCadObjects(BaseTest):
|
||||||
def testVertices(self):
|
def testVertices(self):
|
||||||
e = Shape.cast(FreeCAD.Part.makeLine((0,0,0),(1,1,0)))
|
e = Shape.cast(FreeCAD.Part.makeLine((0,0,0),(1,1,0)))
|
||||||
self.assertEquals(2,len(e.Vertices()))
|
self.assertEquals(2,len(e.Vertices()))
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
|
|
@ -11,7 +11,11 @@ from cadquery import exporters
|
||||||
from tests import BaseTest,writeStringToFile,makeUnitCube,readFileAsString,makeUnitSquareWire,makeCube
|
from tests import BaseTest,writeStringToFile,makeUnitCube,readFileAsString,makeUnitSquareWire,makeCube
|
||||||
|
|
||||||
#where unit test output will be saved
|
#where unit test output will be saved
|
||||||
OUTDIR = "c:/temp"
|
import sys
|
||||||
|
if sys.platform.startswith("win"):
|
||||||
|
OUTDIR = "c:/temp"
|
||||||
|
else:
|
||||||
|
OUTDIR = "/tmp"
|
||||||
SUMMARY_FILE = os.path.join(OUTDIR,"testSummary.html")
|
SUMMARY_FILE = os.path.join(OUTDIR,"testSummary.html")
|
||||||
|
|
||||||
SUMMARY_TEMPLATE="""<html>
|
SUMMARY_TEMPLATE="""<html>
|
||||||
|
@ -422,13 +426,14 @@ class TestCadQuery(BaseTest):
|
||||||
|
|
||||||
def testBasicLines(self):
|
def testBasicLines(self):
|
||||||
"Make a triangluar boss"
|
"Make a triangluar boss"
|
||||||
|
global OUTDIR
|
||||||
s = Workplane(Plane.XY())
|
s = Workplane(Plane.XY())
|
||||||
|
|
||||||
#TODO: extrude() should imply wire() if not done already
|
#TODO: extrude() should imply wire() if not done already
|
||||||
#most users dont understand what a wire is, they are just drawing
|
#most users dont understand what a wire is, they are just drawing
|
||||||
|
|
||||||
r = s.lineTo(1.0,0).lineTo(0,1.0).close().wire().extrude(0.25)
|
r = s.lineTo(1.0,0).lineTo(0,1.0).close().wire().extrude(0.25)
|
||||||
r.val().exportStep('c:/temp/testBasicLinesStep1.STEP')
|
r.val().exportStep(os.path.join(OUTDIR, 'testBasicLinesStep1.STEP'))
|
||||||
|
|
||||||
self.assertEqual(0,s.faces().size()) #no faces on the original workplane
|
self.assertEqual(0,s.faces().size()) #no faces on the original workplane
|
||||||
self.assertEqual(5,r.faces().size() ) # 5 faces on newly created object
|
self.assertEqual(5,r.faces().size() ) # 5 faces on newly created object
|
||||||
|
@ -436,12 +441,12 @@ class TestCadQuery(BaseTest):
|
||||||
#now add a circle through a side face
|
#now add a circle through a side face
|
||||||
r.faces("+XY").workplane().circle(0.08).cutThruAll()
|
r.faces("+XY").workplane().circle(0.08).cutThruAll()
|
||||||
self.assertEqual(6,r.faces().size())
|
self.assertEqual(6,r.faces().size())
|
||||||
r.val().exportStep('c:/temp/testBasicLinesXY.STEP')
|
r.val().exportStep(os.path.join(OUTDIR, 'testBasicLinesXY.STEP'))
|
||||||
|
|
||||||
#now add a circle through a top
|
#now add a circle through a top
|
||||||
r.faces("+Z").workplane().circle(0.08).cutThruAll()
|
r.faces("+Z").workplane().circle(0.08).cutThruAll()
|
||||||
self.assertEqual(9,r.faces().size())
|
self.assertEqual(9,r.faces().size())
|
||||||
r.val().exportStep('c:/temp/testBasicLinesZ.STEP')
|
r.val().exportStep(os.path.join(OUTDIR, 'testBasicLinesZ.STEP'))
|
||||||
|
|
||||||
self.saveModel(r)
|
self.saveModel(r)
|
||||||
|
|
||||||
|
|
30
tests/TestImports.py
Normal file
30
tests/TestImports.py
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
"""
|
||||||
|
Tests basic workplane functionality
|
||||||
|
"""
|
||||||
|
#core modules
|
||||||
|
|
||||||
|
#my modules
|
||||||
|
from cadquery.freecad_impl import verutil
|
||||||
|
from tests import BaseTest
|
||||||
|
|
||||||
|
class TestVersionsForImport(BaseTest):
|
||||||
|
"""Test version checks."""
|
||||||
|
|
||||||
|
def test_013_version(self):
|
||||||
|
"""Make sure various 0.13 Version calls work correctly"""
|
||||||
|
self.assertEquals(verutil._figure_out_version(
|
||||||
|
['0', '13', '2055 (Git)',
|
||||||
|
'git://git.code.sf.net/p/free-cad/code',
|
||||||
|
'2013/04/18 13:48:49', 'master',
|
||||||
|
'3511a807a30cf41909aaf12a1efe1db6c53db577']),
|
||||||
|
(0,13,2055))
|
||||||
|
self.assertEquals(verutil._figure_out_version(
|
||||||
|
['0', '13', '12345']),
|
||||||
|
(0,13,12345))
|
||||||
|
self.assertEquals(verutil._figure_out_version(
|
||||||
|
['0', '13', 'SOMETAGTHATBREAKSSTUFF']),
|
||||||
|
(0,13,0))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,12 +1,13 @@
|
||||||
from cadquery import *
|
from cadquery import *
|
||||||
import unittest
|
import unittest
|
||||||
import sys
|
import sys
|
||||||
FREECAD_LIB = "c:/apps/FreeCAD0.12/bin";
|
import os
|
||||||
sys.path.append(FREECAD_LIB);
|
|
||||||
import FreeCAD
|
|
||||||
|
|
||||||
P = FreeCAD.Part
|
from cadquery.freecad_impl.verutil import fc_import
|
||||||
V = FreeCAD.Base.Vector
|
FreeCAD = fc_import("FreeCAD")
|
||||||
|
|
||||||
|
P = fc_import("FreeCAD.Part")
|
||||||
|
V = fc_import("FreeCAD").Base.Vector
|
||||||
|
|
||||||
def readFileAsString(fileName):
|
def readFileAsString(fileName):
|
||||||
f= open(fileName,'r')
|
f= open(fileName,'r')
|
||||||
|
@ -18,7 +19,7 @@ def writeStringToFile(strToWrite,fileName):
|
||||||
f = open(fileName,'w')
|
f = open(fileName,'w')
|
||||||
f.write(strToWrite)
|
f.write(strToWrite)
|
||||||
f.close()
|
f.close()
|
||||||
|
|
||||||
|
|
||||||
def makeUnitSquareWire():
|
def makeUnitSquareWire():
|
||||||
return Solid.cast(P.makePolygon([V(0,0,0),V(1,0,0),V(1,1,0),V(0,1,0),V(0,0,0)]))
|
return Solid.cast(P.makePolygon([V(0,0,0),V(1,0,0),V(1,1,0),V(0,1,0),V(0,0,0)]))
|
||||||
|
|
Loading…
Reference in New Issue
Block a user