dcowden / cadquery Goto Github PK
View Code? Open in Web Editor NEWCadQuery-- a parametric cad script framework
License: Other
CadQuery-- a parametric cad script framework
License: Other
Thinking about this, I realized that parameters really do need to be internal to the model. The main reason is that the assumptions about parameter relations are model dependent. For example, I have an open box with a pillar in it that can't be higher than the top edge of the box:
Workplane("XY") .box(w, l, h) .faces(">Z") .shell(thickness) .faces(">Z") # here we the *inside* of the box, but CQ currently wouldn't get this right .circle(pillarRadius) .extrude(pillarHeight);
If w, l, h, pillarRadius, and pillarHeight, are all parameters, then they have some inherent dependencies. pillarRadius must be < min(w, l) / 2. pillarHeight must be < h. It doesn't make sense to put these outside of the model. If we change the model, these assumptions might change.
# param function returns a Parameter subclass appropriate for the given default value # the first argument is the default value, it is required. name / description arguments are all optional. w = param(1.0) h = param(1.0) l = param(1.0) pillarRadius = param(0.25) includePillar = param(True) assert w > 0 assert h > 0 assert l > 0 assert pillarRadius > 0 assert pillarRadius < (min(w, l) / 2) assert pillarHeight > 0 assert pillarHeight < h
Numerical parameters should override all the arithmetic and comparison operators described in the Python Data Model section of the python documentation. This allows parameters to be used directly as operands in expressions.
In a naive implementation, the assertions present in the code would just execute normally, and would provide direct validation of the input values. A simple parser script can scan the code for statements of the form = param(...) and extract those. Param would not be allowed in any other context.
A more sophisticated implementation can, with a little trickery, produce a graph of parameter relations from this notation. We would need the help of the compiler
module to do this, but basically the idea is that assertion statements would be transformed into explict calls to a constraint library:
assert pillarRadius > 0
becomes constraints.gt(pillarRadius, 0)
assert pillarRadius < min(w, l)
becomes constraints.lt(pillarRadius, constraints.div(constraints.min(w, l)), 2)
The code would then be compiled and executed as normal, with the crucial difference that now we can extract all the parameters in the model and the relationships between them based on the calls to to param() and the constraints.x. We could feed these relationships into a generalized constraint solver, or we could check them directly. We can also construct a gui.
For example, if we determine that a particular numeric constraint has gt and lt constraints applied on it, then we know it is in a closed interval and we can show a slider along with the usual spin button / entry. Whereas if a parameter has a "oneOf" constraint applied to it (translated from the "in" operator), then we can show a combo box.
It might also be possible to recompute the model from changes to the parameters without having to completely re-evaluate the script.
There are some places where this could fall down, so I wouldn't be in a rush to adopt this straight-away, I just want to get the idea out there. Limitations I can think of include:
Might make sense to explicitly mark the end of the parameter section and the beginning of the rest of the model. This could be done by, say calling a function, such as endOfParameters()
or something along those lines. After this call, it would be an error to attempt to add new paramters or parameter relations. It would be an error for a script to start building a model BEFORE calling this function. This would also allow for easily running a script JUST to validate the parameters, since we can replace the marker with a version that returns immediately.
Might make sense to do away with the assertion mechanism, and just use the constraint library explicitly. The main downside would be readability.
Other wacky ideas:
More explicit parameter types. This would be to allow for more interesting gui interaction.
x, y = param((0, 0))
y = param(radians(pi))
holes = param([(0, 0), (-1, 0), (1, 0)])
any() / all()
functions over the list for validationIs there any reason that a Vector is used here instead of accepting a Vector or a three tuple like CQ does in other places? Seems like we're heading more towards using standard data structures instead of (or as an alternative to) Vectors, so I wanted to check. This will force me to do an extra import in my script.
cadquery/cadquery/workplane.py
Line 92 in a735b74
The toWorldCoords documentation says that it returns a 3 tuple, but when I print what's returned I see that it's a Vector and FreeCAD complains that it's a Vector, not a Base.Vector.
Based on PM conversations with Dave we're a ways from getting serious about a GUI, but I wanted to capture these thoughts somewhere. I can move them to the wiki or something else if that's preferred.
The CQ object has translate() and rotateAboutCenter() functions, but not a rotate() function. That's only on cad.Shape.
http://parametricparts.com/docs/search.html?q=rotate
Why is that?
Is there already a CQ cheatsheet out there somewhere?
A couple of the items so far that I've thought would be nice to have on a cheatsheet would be the selector string modifiers and named planes. Any others?
Hello,
(This is more of a question than an issue - I hope that's ok...)
I'm toying around, trying to understand how it works. I understand this example:
result = cadquery.Workplane("XY").box(length, height, thickness) \
.faces(">Z").workplane().hole(center_hole_dia)
so as an experiment I'm trying to change it to bore holes through the box parallel to all three axes:
result = cadquery.Workplane("XY").box(length, height, thickness) \
.faces().each(lambda face: face.workplane().hole(center_hole_dia))
which doesn't work. My thinking was that by removing the selector from the call to faces() I would get all of the faces, and then with each one I create a workplane and put a hole in it.
Can you give me some clues about how to use each()?
Also, what's the best way to debug Python scripts inside FreeCAD? I tried to 'print' variables:
faces = cadquery.Workplane("XY").box(length, height, thickness).faces()
print faces
result = faces.workplane().hole(center_hole_dia)
but I don't know where the output goes.
As of commit 4d9692e some of the tests fail when running
python runtests.py
These tests succeeded the last time I ran them last week. I suspect I introduced a bug with the import fixes that nobody has noticed yet.
I bumped the version number to 0.1.7 when the revolve operation was added. It would probably be a good time to push this out so that it shows up when someone does a 'pip install cadquery'.
It would be very helpful if CQ had a GUI, and the easiest way to do that with the current architecture of CQ is as a FreeCAD module with an associated workbench. I'd like to start a discussion about that here. I've included a couple of links on creating modules and workbenches below.
Modules:
http://www.freecadweb.org/wiki/index.php?title=Module_Creation
Workbenches:
http://free-cad.sourceforge.net/SrcDocu/d7/dc3/group__workbench.html
In OpenSCAD, I could define parts in separate files, import them into a main assembly file, and then translate them into position. What's the best way to do this with CQ? Should I follow the same general steps?
The unit tests seem to run against the installed copy (via pip) of CQ instead of the local development copy. I tried to make the imports relative to fix this, but it complained that the relative import wouldn't work because it wasn't a package. Is there another way to handle this?
I still don't understand where cadfile.cadutils.cad
(referenced in the PParts.com documentation) comes from. There's a Shape class in freecad_impl/shapes.py
, but I don't see cadfile..Shape
implemented anywhere.
@dcowden - Can you explain this to me? I think I've heard you refer to this as the "imfamous" cadfile package before.
When the screw posts are created in the example, the following code is used to generate the posts.
http://parametricparts.com/docs/examples.html#id23
for v in postCenters.all():
v.circle(p_screwpostOD/2.0).circle(p_screwpostID/2.0)\
.extrude((-1.0)*(p_outerHeight + p_lipHeight -p_thickness ),True)
What I end up with are screw posts that go all the way through the enclosure's bottom wall and show up on the outside. Based on how the thickness offset is handled in the code above this snippet, I believe that this is the fix (notice the "2.0 * p_thickness" change).
for v in postCenters.all():
v.circle(p_screwpostOD / 2.0).circle(p_screwpostID / 2.0)\
.extrude((-1.0) * ((p_outerHeight + p_lipHeight) - (2.0 * p_thickness)), True)
Am I correct that this is the way to handle it?
This example works fine in FreeCAD 0.15 on Ubuntu 14.04. The last line complains about ChFi3d_Builder:only 2 faces
.
Opened C:\Program Files\FreeCAD 0.14\Mod\CadQuery\Examples\Ex027_Remote_Enclosure.py
Running the Python command '<p>FreeCAD Standard File</p>' failed:
Traceback (most recent call last):
File "C:\Program Files\FreeCAD 0.14\Mod\CadQuery\Gui\Command.py", line 135, in Activated
CadQueryExecuteScript().Activated()
File "C:\Program Files\FreeCAD 0.14\Mod\CadQuery\Gui\Command.py", line 178, in Activated
imp.load_source('temp.module', tempFile.name)
File "c:\users\jeremy\appdata\local\temp\tmp6tshb5", line 82, in <module>
.fillet(.020)
File "C:\Program Files\FreeCAD 0.14\Mod\CadQuery\Libs\cadquery\CQ.py", line 793, in fillet
s = solid.fillet(radius,edgeList)
File "C:\Program Files\FreeCAD 0.14\Mod\CadQuery\Libs\cadquery\freecad_impl\shapes.py", line 813, in fillet
return Shape.cast(self.wrapped.makeFillet(radius, nativeEdges))
ChFi3d_Builder:only 2 faces
I'm thinking FreeCAD bug, but I'm not sure yet. Curious if @emdash has any thoughts on what might cause this.
I was working through the first example on ParametricParts.com and found that I had to modify the code to get it to work. For instance, FloatParam
doesn't seem to exist in my local CadQuery install. That makes sense as it seems to carry meta data to make the web interface work properly. This leads to some other differences like needing to reference just length
instead of length.value
.
This will probably be confusing for anybody trying to work through the ParametricParts examples using their local copy of CadQuery. Does there need to be (or is there) a set of docs for the locally installed CadQuery? Was it ever the intention to have users walk through the ParametricParts examples with CadQuery installed, or am I using it wrong?
I'm working through the examples on ParametricParts.com using FreeCAD 0.14 in Ubuntu 14.04. I've hit a problem where the 'cad' module is not defined. I'm not quite sure where this module is supposed to come from. Here's the stack trace from the FreeCAD Python console.
import Ex015_Rotated_Workplanes
Traceback (most recent call last):
File "<input>", line 1, in <module>
File "/home/jwright/Documents/Projects/CadQuery/cadquery/examples/FreeCAD/Ex015_Rotated_Workplanes.py", line 24, in <module>
.transformed(offset=cad.Vector(0,-1.5,1.0),rotate=cad.Vector(60,0,0)) \
NameError: name 'cad' is not defined
cadquery looks promising, but how to make a sphere?
I get an error that says there's no module named Part when trying to import cadquery. I'm running Ubuntu 14.04, Python 2.7.6, and FreeCAD 0.14. I've checked to make sure that the /usr/lib/freecad/lib directory exists, and it does. There is also a Part.so file within that directory. I'm also installing cadquery inside of the virtual environment with:
pip install cadquery
(cquery)user@u1404:~/bin/cquery$ python
>>> import sys
>>> sys.path.append('/usr/lib/freecad/lib')
>>> from cadquery import *
FreeCAD 0.14, Libs: 0.14R2935 (Git)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/home/user/bin/cquery/local/lib/python2.7/site-packages/cadquery/__init__.py", line 4, in <module>
from .freecad_impl.geom import Plane,BoundBox,Vector,Matrix,sortWiresByBuildOrder
File "/home/user/bin/cquery/local/lib/python2.7/site-packages/cadquery/freecad_impl/geom.py", line 22, in <module>
import FreeCAD.Part
ImportError: No module named Part
This does not throw any exceptions:
from FreeCAD import *
However, this gives a "cannot import name Part" exception (not sure if I'm even doing this import correctly).
from FreeCAD import Part
There was a question a couple of weeks ago about revolve operations, and I'm getting to the point on a project where I think a sweep operation might be needed (or at least helpful). I noticed that Sweep is stubbed in on ModelScript on ParametricParts.com, but I can't find a matching Sweep function in CadQuery. According to the docs it looks like extrude might just be extended to handle sweep, and revolve is on the roadmap too. Any thoughts on where these operations fall among all the other priorities for CQ?
Is there any way to scale a 3D object?
In the polygon example, cutThruAll is used to cut polygons into a plate. When I tried the example in FreeCAD the polygons did not extrude all the way through, and I'm having trouble understanding where the cut depth is set for them.
http://parametricparts.com/docs/examples.html#id8
Also, the origin for the part seems to be offset, but hasn't been on any of the other examples. I don't see anything in this example code that screams "origin change" to me.
Any thoughts?
When I run all the tests, I end up with the following.
*******************************************************************
****** Statistics on Transfer (Write) ******
*******************************************************************
****** Transfer Mode = 0 I.E. As Is ******
****** Transferring Shape, ShapeType = 2 ******
** WorkSession : Sending all data
Step File Name : /tmp/testFrontReference.step(434 ents) Write Done
Exporting SVG...
<Solid object at 0x2484580>
*** Abort *** an exception was raised, but no catch was found.
... The exception is:SIGSEGV 'segmentation violation' detected. Address 0
The "Exporting SVG..." line is troubleshooting output that I added. The code seems ot segfault on this line.
(visibleG0,visibleG1,hiddenG0,hiddenG1) = Drawing.project(shape,viewVector)
There's something about the shape that Drawing.project can't handle, but if I build the shape manually and pass it to the function with the same viewVector, I can't reproduce the segfault. There are several tests that succeed before this one, so I wonder if there's a cumulative error (like a memory leak) in Drawing.project.
I'm running FreeCAD 0.14 on Ubuntu 14.04.
I haven't seen a way to directly import step files in CQ, so I assume I'll need to go about importing them through FreeCAD. Once I import them, how do I go about using them as CQ objects?
When I run the following code, the part is translated along the Y-axis instead of the X-axis. Am I missing something similar to toLocalCoords?
step_location = '/home/jwright/Documents/Projects/Switch/vendor/SS_01GL_E.step'
self.elec_switch = importers.importStep(step_location)
self.elec_switch = self.elec_switch.combine().translate((10, 0, 0))
If I do the following in FreeCAD, the part is translated properly along the X-axis.
new_part = Part.read('/home/jwright/Documents/Projects/Switch/vendor/SS_01GL_E.step')
new_part.translate((10, 0, 0))
CQ's translate seems to use FreeCAD's translate under the hood, so I'm not sure where this swapping of axes is coming from.
Hi,
I've installed FreeCAD 0.14 on a Mac (running Yosemite), and downloaded cadquery-0.1.7. I'm trying to follow the instructions to install it, but stuck here:
"use the Python version embedded with Freecad..."
There doesn't seem to be a separate python installation in FreeCAD - I might be wrong but it seems that Python is built into the FreeCAD binary.
Please advise...
Thanks,
Rob.
This is already in the roadmap, but seems like a significant limitation currently. Following the form of the extrude function, this might look something like:
revolve(angle=360, combine=True)
angle allows the user to do an incomplete revolution, leaving the resulting solid "open". The default of 360 would give a closed solid.
I extruded a cylinder and used the shell operation on it. Now I would like to extrude another cylinder from the inside bottom face. This image will illustrate what I'm thinking.
However, there doesn't seem to be any way to select the inside face directly. I can do >Z which selects the top most face that was cut out during the shell, and <Z selects the bottom most face in the Z direction.
It seems like there should be something like a >>Z combo that allows you to select the next face down from the top. Or am I just missing something?
In the "Locating a Workplane on a Vertex" example, it says that cutThruAll is being introduced for the first time. However, it was introduced in a previous example.
http://parametricparts.com/docs/examples.html#id13
Also, the names of the sections don't seem to be set up correctly on that page so the links don't work properly. The link above should take you directly to the section I'm talking about, but it goes to the top of the page instead.
freecad_import is causing problems for us on Windows, and seems to have unnecessary logic in it. This needs to be investigated to see if the import process can be simplified.
This looks great, I have been wanting to see someone make a programmatic 3d modeler that uses python. Unfortunately, it seems there is a missing dependency not mentioned in the install instructions. The first line of setup.py tries to import from a module named sutuptools.
Traceback (most recent call last):
File "cadquery-master\setup.py", line 1, in <module>
from setuptools import setup
ImportError: No module named setuptools
Anyone know where this module can be found?
OS: Ubuntu 14.04
CQ Version: 0.1.5 (installed via pip)
FreeCAD Version: 0.14
I've tried quite a few configurations of rotateAboutCenter and have not been able to get any of them to work in FreeCAD. I looked back through the examples to try to find how to call it correctly, and found this one:
Ex023_Parametric_Enclosure
I tested that example in FreeCAD and found that rotateAboutCenter does not seem to work in it either.
Importing inside a Virtualenv:
(testing_cadquery)➜ ~VIRTUAL_ENV python
Python 2.7.3 (default, Sep 26 2012, 21:51:14)
[GCC 4.7.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import sys
>>> sys.path.append('/usr/lib/freecad/lib')
>>> import cadquery
FreeCAD 0.13, Libs: 0.13R2055 (Git)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/home/enki/workspace/testing_cadquery/local/lib/python2.7/site-packages/cadquery/__init__.py", line 4, in <module>
from .freecad_impl.geom import Plane,BoundBox,Vector,Matrix,sortWiresByBuildOrder
File "/home/enki/workspace/testing_cadquery/local/lib/python2.7/site-packages/cadquery/freecad_impl/geom.py", line 22, in <module>
import FreeCAD.Part
ImportError: No module named Part
>>>
(testing_cadquery)➜ ~VIRTUAL_ENV ls /usr/lib/freecad/lib/
AssemblyGui.so ImageGui.so MeshGui.so QtUnitGui.so Sketcher.so
Assembly.so Image.so MeshPartGui.so RaytracingGui.so StartGui.so
CompleteGui.so ImportGui.so MeshPart.so Raytracing.so Start.so
Complete.so InspectionGui.so Mesh.so ReverseEngineeringGui.so WebGui.so
DrawingGui.so Inspection.so PartGui.so ReverseEngineering.so
Drawing.so libFreeCADApp.so Part.so RobotGui.so
FreeCADGui.so libFreeCADBase.so PointsGui.so Robot.so
FreeCAD.so libFreeCADGui.so Points.so SketcherGui.so
(testing_cadquery)➜ ~VIRTUAL_ENV freecad
and then when I explore in Freecad:
Python 2.7.3 (default, Sep 26 2012, 21:53:55)
[GCC 4.7.2] on linux2
Type 'help', 'copyright', 'credits' or 'license' for more information.
>>> import Part
>>> Part
<module 'Part' from '/usr/lib/freecad/lib/Part.so'>
Looks like Freecad has reorganized a bit? I'll dig into the implementation module and see if it is easy to fix.
If I I've created a box with 'p = Workplane("XY").box(1,2,3)', how do I get the x (1), y (2) and z (3) dimensions back out?
I can import a STEP file in FreeCAD and convert it to a CQ object, but this is messy. It would be great to be able to import a STEP file directly to a CQ object. As an optional feature, it would be nice to be able to union all the individual components inside of a single STEP file into a single solid. Maybe something like:
importSTEP(filename, combine)
Where filename is the path and name of the STEP file, and combine defaults to false and controls whether or not the STEP subparts are unioned.
http://parametricparts.com/docs/primitiveref.html
Some of the examples on ParametricParts.com have the following code.
UOM = "mm"
Looking forward, when auto-generating drawings or interfacing with analysis tools, we need to track and enforce the units. In the short term it's at least good for users to have a reference of what the units are.
I would like to make sure that we keep this in mind, in whatever form it takes on.
The source code makes note that this functionality might be added to the extrude function at some point. While I don't see this being as important as the revolve operation, I think it's something that will be needed.
I'll need to think a little bit about how this could most cleanly be merged with the extrude function.
We search default FreeCAD paths for Windows and Linux, but not for Mac OS. This is causing a Mac user of the CQ module to get an error about the path.
It's stated in the readme that you're interested in developing a GUI. Has there been any work done on this yet?
I'm also wondering about the current development status. It looks like there hasn't been any commit activity for about a year. Are there plans to start back up?
Thanks.
(edit): I had originally requested some features already covered on the roadmap. I have removed those requests, and will just leave you with the following:
It would be useful also for creating features that derive from a solid shape. I could take a cross section, project it onto a work plane, and extrude the cross-section.
I have not seen this implemented in any other CAD package.
Just want to add that this stuff is actually really cool, and off to a very promising start.
For "tagged entities" - Would it make sense to allow selector IDs to be chained?
Ex. parent.first_child.child_of_first_child
That would require each child feature to be tagged with a unique name as well.
It's noted that the current translate method modifies the original object rather than returning a copy. I'm having trouble thinking of a situation where I would want a copy rather than having the original modified.
Several primitives are mentioned in the roadmap that seem to have constructions methods in the class reference.
In the 3-d Operations section - "surface ,rather than" should be "surface, rather than"
Loft is mentioned under 3-d Operations, but is specified in the class reference. Are you looking to add new functionality to the loft method?
Is the version number in this file supposed to match the current CQ version number?
I want to display the CQ version number in the output window of the FreeCAD module, and this is the most direct way I see of getting the version.
In cadquery/init.py there's the following line at the bottom.
__version__ = 0.9
What does that version number relate to?
I'm following the readme instructions here: https://github.com/dcowden/cadquery#installing----using-cadquery-from-inside-freecad
I'm running Ubuntu 14.04 with Python 2.7.6 installed.
As far as I can tell, FreeCAD in Linux uses the system-wide Python and GCC versions.
When I try to type "python setup.py" per the readme instructions, it complains that I'm not supplying a command. I'm assuming that I need to supply the "build" command, which seems to work fine. Is that the correct thing to do?
Step 4 in the instructions also says to "copy generated binaries from FreeCAD0.13/bin/cadquery/cadquery into FreeCAD/Mod/Scripts". I don't see any .pyc files in the cadquery directory. Am I missing something?
I also can't find a "Scripts" directory anywhere within the FreeCAD installation. Should it be there already? I created that directory under freecad/Mod and then copied everything from the cadquery/cadquery directory into it. When I restart FreeCAD and try to do...
import cadquery
in FreeCAD's Python console, I get...
ImportError: No module named cadquery
Which tells me that I didn't get things installed correctly.
Any thoughts?
http://parametricparts.com/docs/classreference.html#cadfile.cadutils.cadquery.Workplane.circle
In that doc it explains that extruding the two concentric circles shown in the example would result in a ring. This works unless you swap the order. So, this works...
s = Workplane().circle(2.0).circle(1.0)
...but this seems to create a smaller cylinder within a larger cylinder...
s = Workplane().circle(1.0).circle(2.0)
I'm sure there's some sort of 3D logic behind the order, but I can't figure out what it is.
I'm considering using cadquery but can't see from the documentation & examples how to revolve a 2D shape about an axis to make a rotationally-symmetric solid.
How can I do this with cadquery?
Thanks!
There has been some informal discussion about making CQ work with multiple kernels, and I'd like to try to get a conversation started on the nuts and bolts of doing that.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.