CadQuery / cadquery

A python parametric CAD scripting framework based on OCCT
https://cadquery.readthedocs.io
Other
3.21k stars 292 forks source link

Where can I find more details about extending cq? #273

Closed KeithSloan closed 4 years ago

KeithSloan commented 4 years ago

Where can I find more details about extending cq? i.e own functions that also use PythonOCC

adam-urbanczyk commented 4 years ago

You can find some information in the docs: https://cadquery.readthedocs.io/en/latest/extending.html . Otherwise just ask here. Out of curiosity: what are you interested in specifically?

KeithSloan commented 4 years ago

I had a look and it seems to be offering out of line functions.

I would like to provide new types of objects. Implemented using PythonOCC and essentially hidden away, don't want to clutter up source window. Specifically I would like to develop some functions for GDML solids where the parameters are very close to the GDML specification

adam-urbanczyk commented 4 years ago

What do you mean by out of line functions? Regarding clutter you can always define a module with your extensions or wrap CQ in an additional module. Here you can find our sister project that does the latter: https://github.com/cqparts/cqparts .

KeithSloan commented 4 years ago

out of line I mean def functions that you then call.

Thanks for the pointer to cqparts.

I wouid like to implement something that allowed for display and export of GDML like the following `import cadquery import cqgdml

v = gVol("world") s = gBox(10,10,10) m = gMaterial('Air') o = gObject(s,m,position,rotation) v.add(o) v.export("/tmp/file.gdml") ~ I can see how to setup class for the drawable things but not sure how to make it so that a export would output formatted GDML to a file.

Made a start at https://github.com/KeithSloan/CQ-GDML-Module `

jmwright commented 4 years ago

If you haven't already, you might want to have a look through CQ's exporters.py code to see how different formats are converted and written to disk now.

KeithSloan commented 4 years ago

Struggling with best way to develop.

I assume the ultimate aim would be to create an installable python module.

I am trying to develop with the definitions in another file i.e. `import cadquery import cqgdml

position = 0 rotation = 0

v = gVol("world") s = gBox(10,10,10) m = gMaterial('Air') o = gObject(s,m,position,rotation) v.add(o) v.export("/tmp/file.gdml") `

But it is not finding the definitions in cqgdml.py

adam-urbanczyk commented 4 years ago

Maybe you wanted to do this:

from cqgdml import *

i.s.o.

import cqgdml
KeithSloan commented 4 years ago

Okay

I now have the situation where I get an error NameError name show_object not defined.

What do I have to import for things to find show_object the examples on the web don't seem to require an import see https://github.com/KeithSloan/CQ_GDML_Package

jmwright commented 4 years ago

The CQGI does some implicit import magic that's not one of the community's favorite features, but it's designed to make the scripts more portable between execution environments.

https://cadquery.readthedocs.io/en/latest/cqgi.html#the-execution-environment-side

KeithSloan commented 4 years ago

I looked at the doc, but still don't know how to do

`shape = cq.Workplane('XY').box(self.x,self.y,self.z)

show_object(shape)`

In an imported python class

adam-urbanczyk commented 4 years ago

Essentially you need to define show_object yourself (or run it in some sort of execution environment like CQ-editor).

KeithSloan commented 4 years ago

Well I am running under cq-editor and it barfs that the function is not defined.

If I code something without an import is works see testBox.py but test.py which imports cqgdml.py does not.

KeithSloan commented 4 years ago

Okay from the imported module I loose access to show_object in the "parent" cq-editor code/script.

Is there anyway round this?

adam-urbanczyk commented 4 years ago

I'm not sure if you be doing such things, but the following seems to work:

import sys
sys.modules['builtins'].__dict__['show_object'] = show_object

I'd personally only generate the object in modules and call show_object in the top level function only.

KeithSloan commented 4 years ago

Thanks but did not work for me.

Tried print(sys.modules['builtins'].dict)

and got {'__name__': 'builtins', '__doc__': "Built-in functions, exceptions, and other objects.\n\nNoteworthy: None is thenil' object; Ellipsis represents `...' in slices.", 'package': '', 'loader': <class '_frozen_importlib.BuiltinImporter'>, 'spec': ModuleSpec(name='builtins', loader=<class '_frozen_importlib.BuiltinImporter'>), 'build_class': <built-in function build_class>, 'import': , 'abs': , 'all': , 'any': , 'ascii': , 'bin': , 'breakpoint': , 'callable': , 'chr': , 'compile': , 'delattr': , 'dir': , 'divmod': , 'eval': , 'exec': , 'format': , 'getattr': , 'globals': , 'hasattr': , 'hash': , 'hex': , 'id': , 'input': , 'isinstance': , 'issubclass': , 'iter': , 'len': , 'locals': , 'max': , 'min': , 'next': , 'oct': , 'ord': , 'pow': , 'print': , 'repr': , 'round': , 'setattr': , 'sorted': , 'sum': , 'vars': , 'None': None, 'Ellipsis': Ellipsis, 'NotImplemented': NotImplemented, 'False': False, 'True': True, 'bool': <class 'bool'>, 'memoryview': <class 'memoryview'>, 'bytearray': <class 'bytearray'>, 'bytes': <class 'bytes'>, 'classmethod': <class 'classmethod'>, 'complex': <class 'complex'>, 'dict': <class 'dict'>, 'enumerate': <class 'enumerate'>, 'filter': <class 'filter'>, 'float': <class 'float'>, 'frozenset': <class 'frozenset'>, 'property': <class 'property'>, 'int': <class 'int'>, 'list': <class 'list'>, 'map': <class 'map'>, 'object': <class 'object'>, 'range': <class 'range'>, 'reversed': <class 'reversed'>, 'set': <class 'set'>, 'slice': <class 'slice'>, 'staticmethod': <class 'staticmethod'>, 'str': <class 'str'>, 'super': <class 'super'>, 'tuple': <class 'tuple'>, 'type': <class 'type'>, 'zip': <class 'zip'>, 'debug': True, 'BaseException': <class 'BaseException'>, 'Exception': <class 'Exception'>, 'TypeError': <class 'TypeError'>, 'StopAsyncIteration': <class 'StopAsyncIteration'>, 'StopIteration': <class 'StopIteration'>, 'GeneratorExit': <class 'GeneratorExit'>, 'SystemExit': <class 'SystemExit'>, 'KeyboardInterrupt': <class 'KeyboardInterrupt'>, 'ImportError': <class 'ImportError'>, 'ModuleNotFoundError': <class 'ModuleNotFoundError'>, 'OSError': <class 'OSError'>, 'EnvironmentError': <class 'OSError'>, 'IOError': <class 'OSError'>, 'EOFError': <class 'EOFError'>, 'RuntimeError': <class 'RuntimeError'>, 'RecursionError': <class 'RecursionError'>, 'NotImplementedError': <class 'NotImplementedError'>, 'NameError': <class 'NameError'>, 'UnboundLocalError': <class 'UnboundLocalError'>, 'AttributeError': <class 'AttributeError'>, 'SyntaxError': <class 'SyntaxError'>, 'IndentationError': <class 'IndentationError'>, 'TabError': <class 'TabError'>, 'LookupError': <class 'LookupError'>, 'IndexError': <class 'IndexError'>, 'KeyError': <class 'KeyError'>, 'ValueError': <class 'ValueError'>, 'UnicodeError': <class 'UnicodeError'>, 'UnicodeEncodeError': <class 'UnicodeEncodeError'>, 'UnicodeDecodeError': <class 'UnicodeDecodeError'>, 'UnicodeTranslateError': <class 'UnicodeTranslateError'>, 'AssertionError': <class 'AssertionError'>, 'ArithmeticError': <class 'ArithmeticError'>, 'FloatingPointError': <class 'FloatingPointError'>, 'OverflowError': <class 'OverflowError'>, 'ZeroDivisionError': <class 'ZeroDivisionError'>, 'SystemError': <class 'SystemError'>, 'ReferenceError': <class 'ReferenceError'>, 'MemoryError': <class 'MemoryError'>, 'BufferError': <class 'BufferError'>, 'Warning': <class 'Warning'>, 'UserWarning': <class 'UserWarning'>, 'DeprecationWarning': <class 'DeprecationWarning'>, 'PendingDeprecationWarning': <class 'PendingDeprecationWarning'>, 'SyntaxWarning': <class 'SyntaxWarning'>, 'RuntimeWarning': <class 'RuntimeWarning'>, 'FutureWarning': <class 'FutureWarning'>, 'ImportWarning': <class 'ImportWarning'>, 'UnicodeWarning': <class 'UnicodeWarning'>, 'BytesWarning': <class 'BytesWarning'>, 'ResourceWarning': <class 'ResourceWarning'>, 'ConnectionError': <class 'ConnectionError'>, 'BlockingIOError': <class 'BlockingIOError'>, 'BrokenPipeError': <class 'BrokenPipeError'>, 'ChildProcessError': <class 'ChildProcessError'>, 'ConnectionAbortedError': <class 'ConnectionAbortedError'>, 'ConnectionRefusedError': <class 'ConnectionRefusedError'>, 'ConnectionResetError': <class 'ConnectionResetError'>, 'FileExistsError': <class 'FileExistsError'>, 'FileNotFoundError': <class 'FileNotFoundError'>, 'IsADirectoryError': <class 'IsADirectoryError'>, 'NotADirectoryError': <class 'NotADirectoryError'>, 'InterruptedError': <class 'InterruptedError'>, 'PermissionError': <class 'PermissionError'>, 'ProcessLookupError': <class 'ProcessLookupError'>, 'TimeoutError': <class 'TimeoutError'>, 'open': , 'copyright': Copyright (c) 2001-2019 Python Software Foundation. All Rights Reserved.

Copyright (c) 2000 BeOpen.com. All Rights Reserved.

Copyright (c) 1995-2001 Corporation for National Research Initiatives. All Rights Reserved.

Copyright (c) 1991-1995 Stichting Mathematisch Centrum, Amsterdam. All Rights Reserved., 'credits': Thanks to CWI, CNRI, BeOpen.com, Zope Corporation and a cast of thousands for supporting Python development. See www.python.org for more information.

Will have to look into returning shape to top level`

adam-urbanczyk commented 4 years ago

What does not work @KeithSloan ? You need to run the code I pasted in your top level CQ script. I do not get why are you printing sys.modules['builtins'].__dict__

KeithSloan commented 4 years ago

Okay I am trying to now return things to the top level. Ultimately I want a number of functions that add to the stack and finally process the stack and return a shape to be shown.

For now I just want to test I can add a single object, and return it. which has

v = gVol("world") show_object(v.shape2show())

and gVol has the following function def shape2show(self) : import cadquery as cq cq.add(cq.Workplane('XY').box(10,10,10))

cq.Workplane.combine(self)

      return(cq.first(self))
      #return(cq.Workplane('XY').box(10,10,10))

If I return the commented return I get a box, but it barfs cqquery has no attribute add where as this page seems to imply it is available~ https://pythonhosted.org/cadquery/apireference.html

adam-urbanczyk commented 4 years ago

I think you are misinterpreting the docs. This is roughly what you want:

import cadquery as cq

box1 = cq.Workplane('XY').box(1,1,1)
box2 = cq.Workplane('XY').transformed(offset=(0,0,2)).box(1,1,1)
combined = box1.add(box2)
show_object(combined)

NB: cq.CQ is a superclass of cq.Workplane and you were calling a (non-existing) function add from module cq.

KeithSloan commented 4 years ago

Well I would like to access the stack as documented "CadQuery methods that operate on the stack" under https://pythonhosted.org/cadquery/apireference.html

For GDML I would need to have a number of functions create shapes. I was hoping to add them to the stack and when I need to display access the stack, combine and return the highest level for show_object

adam-urbanczyk commented 4 years ago

Does the snippet not work for you? It is combining multiple objects using the add method just like you intended (NB: you can chain the add calls). Those objects could be created by your GDML module or any other means.

KeithSloan commented 4 years ago

I am sure it works but using the stack would work better. Is the documentation on the stack not correct?

adam-urbanczyk commented 4 years ago

I am sure it works but using the stack would work better. Is the documentation on the stack not correct?

In the example I used the method add as it is documented and the resulting object is of type cq.Workplane which is a subclass of cq.CQ. In what sense would the documentation be not correct?

KeithSloan commented 4 years ago

Is there a way to make an object display as wireframe?

jmwright commented 4 years ago

@KeithSloan If you're using CQ-editor, look for the following button in the toolbar.

Screenshot from 2020-02-24 06-25-50

KeithSloan commented 4 years ago

Thanks - How about under program control?

adam-urbanczyk commented 4 years ago

It is not implemented. Can I actually close this issue @KeithSloan ? Are your questions regarding extending CQ answered?

KeithSloan commented 4 years ago

Thanks - How about under program control? Yes you can close. My questions are really more support than issues

tanius commented 3 years ago

Is there a way to make an object display as wireframe? […] How about under program control?

I accidentally found out that this can be done in CQ-editor by rendering an object with full transparency. You can use one of these options:

show_object(part, options = {"color": (64, 164, 100), "alpha": 1})  # preferred syntax
show_object(part, options = {"rgba": (64, 164, 100, 1)})  # mostly for backward compatibility

The only difference between this and the "real" wireframe mode available with the toolbar button in CQ-editor is that a fully transparent object will only show the helper wires in the face center when selected, while a real wireframe object will show them always.

The best available documentation of the show_object() syntax is its test. In addition, the list of available color names can be found by typing this into the CQ-editor Console tab: from PyQt5.QtGui import QColor; QColor.colorNames(). As seen in the source code, the color names come from Qt's QColor predefined colors, which themselves mostly consist of the SVG color keyword names. See there for a list with color samples.