CadQuery / cadquery

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

Add support for Customizer-style interface #718

Open WillAdams opened 3 years ago

WillAdams commented 3 years ago

One very powerful aspect of OpenSCAD is the Customizer interface as documented at:

https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/Customizer

It would be great if there was a similar facility for creating a customizable interface using comments around variables --- even better if there was a mode in CQeditor so that one could hide everything but the customizer interface for a file and the 3D view and any necessary controls.

In implementing this, it would be nice to continue to use JSON files for storing customizations.

fedorkotov commented 3 years ago

Have you looked into combining Jupyter Notebook widgets with jupyter-cadquery? I haven't done this and can't say for sure if it is possible but I think it's worth a try.

Also cadquery models are written in python (a general purpose language) and not a specialized limited language as OpenSCAD. This gives you access to almost all major GUI frameworks. I agree that it's much more work than if there was some support for some sort of customizer interface in CQ-editor. But still.

Another thought. What is the use case for this proposed GUI? You can organize your cadquery model code so that all the parameters are in one place and not scattered all over the code. You (or even anyone who knows next to nothing about python) can just change constants at the top of the file and run the model again. Or you can load and deserialize JSON/YAML/TOML from your model code and get parameters from there.

fedorkotov commented 3 years ago

Regarding configuration data import I should probably mention that there are issues with some serialization libraries when the code is run in CQ-editor (see #702). But it seems that a workaround exists (https://github.com/CadQuery/cadquery/issues/702#issuecomment-808891526 )

WillAdams commented 3 years ago

Using Jupyter Notebook would be an option if I could get it installed/working.

I want to make using the program more accessible --- lots of folks who don't know what variables are, but who could manage to use a nice customization interface --- if I'm going to program my own interface I might as well do that in a tool which has an interface for setting parameters and writing out OpenSCAD code.

fedorkotov commented 3 years ago

Using Jupyter Notebook would be an option if I could get it installed/working.

You should open an issue in jupyter-cadquery repository. Even if the question is "don't know where to start". The project owner seem to be quite responsive and supportive.

[..] lots of folks who don't know what variables are, but who could manage to use a nice customization interface [..]

You don't really need to know what variables are to change a well-named and commented value in a python script or specialized config like YAML. But I agree that Customizer you ask for would be beneficial to "non-IT" people who want to treat a parametric model prepared for them by others as a black box with few knobs and switches attached. On the other hand. How would such folks even install CadQuery and CQ-editor? I stand to be corrected on that but as far as I know to use CQ-editor you have to be tech-savvy enough to install miniconda and to run at least a few commands in terminal. And if one is willing and able to do that probably they have some idea of what a variable is.

[..] if I'm going to program my own interface [..]

If we are not talking about embedding a 3D viewer writing a simple GUI app in tkinter (usually bundled with python) to take some values and spit out STEP or STL is really easy.

Jojain commented 3 years ago

As @fedorkotov just said you can always write a GUI using any framework that you want. If you have stored your variables in a separate file you can use your the GUI to parse it and display it as A customizer.

That being said for it to work it would need every model to use the same file variable organisazion as you did etc.

And at this point I don't see how this is really better than just changing value in the file directly.

It seems to me to be a "lot" of work for nothing. Writing a good readme file to explain how the user should modify your python script to get the result he wants is probably better anyway.

adam-urbanczyk commented 3 years ago

@WillAdams there is support for defining parameters in CQGI: take a look here: https://cadquery.readthedocs.io/en/latest/cqgi.html#more-about-script-variables . I'm not so familiar with this part of the codebase, maybe @jmwright would remember more. Making GUIs is not part of CQ - you will have to manage yourself.

fedorkotov commented 3 years ago

I combined recently added example #711 with parameters API mentioned by @adam-urbanczyk and wrote this simple PySimpleGUI based standalone customizer.

# =========== The model ==============
N = 3
d = 4
h = 5

show_object(
    cq.Workplane("XY")\
    .polygon(N, d)\
    .extrude(h))

image

# ========= customizer ================
import cadquery.cqgi as cqgi
import cadquery as cq
import PySimpleGUI as sg

def export_model(N, d, h, model_path):
  print(f'N={N}, d={d}, h={h}, model_path={model_path}')
  model = cqgi.parse(open("example.py").read())

  params = model.metadata.parameters
  params['N'].set_value(int(N))
  params['d'].set_value(float(d))
  params['h'].set_value(float(h))

  # run the script and store the result (from the show_object call in the script)
  build_result = model.build()

  # test to ensure the process worked.
  if build_result.success:      
      # export first result
      cq.exporters\
        .export(
          build_result.results[0].shape, 
          model_path)
  else:
      print(f"BUILD FAILED: {build_result.exception}")      

layout = [
  [sg.Text('Please select polygonal prism parameters')],
  [sg.Text('N'),
   sg.Spin([i for i in range(3,10)], initial_value=3, key='-SPIN-N-', size=(5,1)),
   sg.Text('number of base polygon sides')],
  [sg.Text('d'),
   sg.Input(key='-INPUT-d-', size=(5,1)),
   sg.Text('Diameter of escribed circle')],
  [sg.Text('h'),
   sg.Input(key='-INPUT-h-', size=(5,1)),
   sg.Text('Prism height')],
  [sg.Button('Export model', key='-SAVE-AS-'),
   sg.Exit()],
]  

window = sg.Window('CadQuery polygonal prism', layout)

while True:             # Event Loop
    event, values = window.Read()
    if event in (None, 'Exit'):
      break      
    if event == '-SAVE-AS-':      
      try:    
        N = int(values["-SPIN-N-"])
      except:
        sg.Popup('Opps!', f'\'{values["-SPIN-N-"]}\' is not a valid N value')
        continue

      try:
        d = float(values["-INPUT-d-"])
      except:
        sg.Popup('Opps!', f'\'{values["-INPUT-d-"]}\' is not a valid d value')
        continue

      try:
        h = float(values["-INPUT-h-"])
      except:
        sg.Popup('Opps!', f'\'{values["-INPUT-h-"]}\' is not a valid h value')
        continue

      fpath = sg.PopupGetFile(
        'Model file path', 
        save_as=True, 
        file_types=(('STEP', '.step'), ('STL', '.stl')))
      if not fpath:
        continue
      export_model(N, d, h, fpath)

window.Close()   

customizer.py.txt example.py.txt

fedorkotov commented 3 years ago

Another thought on customizer GUIs. Model parameters are often not independent. Something like bolts or flanges are standardized. In other cases some configurations just don't make sense (hole larger than part etc.) Correct me if I'm wrong but OpenSCAD's customizer can't handle that. All parameters are independent there. It allows customizer GUI user to shot in their own foot. But you can easily implement such constraints in your own GUI which as I've shown above can take under 100 lines of code.

jmwright commented 3 years ago

@fedorkotov

On the other hand. How would such folks even install CadQuery and CQ-editor? I stand to be corrected on that but as far as I know to use CQ-editor you have to be tech-savvy enough to install miniconda and to run at least a few commands in terminal. And if one is willing and able to do that probably they have some idea of what a variable is.

There are release builds available for CQ-editor on the release and there are also development builds for those logged into GitHub. We're working on CI builds on the main repo instead of my fork too. Those don't require Anaconda/Miniconda.

I'm not so familiar with this part of the codebase, maybe @jmwright would remember more. Making GUIs is not part of CQ - you will have to manage yourself.

You can pass a build_parameters parameter to the build method of CQGI. https://cadquery.readthedocs.io/en/latest/cqgi.html#the-execution-environment-side

I would not recommend building on the FreeCAD workbench (no CQ 2.x support at this time), but it had/has a parameter editor that you could look at for inspiration. https://github.com/jmwright/cadquery-freecad-module/blob/master/CQGui/Command.py#L391

bernhard-42 commented 3 years ago

@fedorkotov

Have you looked into combining Jupyter Notebook widgets with jupyter-cadquery? I haven't done this and can't say for sure if it is possible but I think it's worth a try.

Please see https://github.com/CadQuery/CQ-editor/issues/258 for an example I quickly hacked together

fedorkotov commented 3 years ago

Very cool. Thanks. Maybe your and my examples of model customization GUI should be added somewhere in Extending CadQuery chapter of CadQuery manual.