diff --git a/ThirdParty/cqparts/LICENSE b/ThirdParty/cqparts/LICENSE new file mode 120000 index 0000000..30cff74 --- /dev/null +++ b/ThirdParty/cqparts/LICENSE @@ -0,0 +1 @@ +../../LICENSE \ No newline at end of file diff --git a/ThirdParty/cqparts/README.rst b/ThirdParty/cqparts/README.rst new file mode 100644 index 0000000..78c544d --- /dev/null +++ b/ThirdParty/cqparts/README.rst @@ -0,0 +1,131 @@ + +.. image:: https://fragmuffin.github.io/cqparts/media/logo/dark.svg + :align: center + +===================== +What is `cqparts`? +===================== + +``cqparts`` is CAD for Python programmers, short for "``cadquery`` parts". + +Using ``cqparts`` you can wrap geometry made with ``cadquery`` to build complex +and deeply parametric models. + +Full documentation at: https://fragmuffin.github.io/cqparts + + +Installing +------------------ + +Pre-requisites +^^^^^^^^^^^^^^^^^^ + +You'll need to fulfill the requirements of ``cadquery``, the simplest way to do +that is to install ``cadquery`` first by following the instructions here: + +http://dcowden.github.io/cadquery/installation.html + +PyPI +^^^^^^^^^ + +Once ``cadquery`` is installed, install ``cqparts`` with:: + + pip install cqparts + + +``cqparts_*`` Content Libraries +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +You can also install content libraries with a similar ``pip install`` command. + +List available libraries with:: + + pip search cqparts- + +For example, to install the ``cqparts_bearings`` content library, run:: + + pip install cqparts-bearings + + +_Note_: ``pip`` packages use ``-`` to separate words, but when importing them the +standard ``_`` is used. + + +Example Usage +------------------- + +Here is just one of the simplest examples to give you an idea of what this +library does. + +More detailed examples found in +`the official documentation for cqparts `_. + +Wrapping a Cube +^^^^^^^^^^^^^^^^^^ + +.. image:: https://fragmuffin.github.io/cqparts/media/img/unit-cube.png + +A simple cube defined with ``cadquery`` alone:: + + # create unit cube solid + import cadquery + size = 10 + cube = cadquery.Workplane('XY').box(size, size, size) + + # display cube (optional) + from Helpers import show + show(cube) + +Wrapping this in a ``cqparts.Part`` object can be done like this:: + + # create unit cube as cqparts.Part + import cadquery + import cqparts + from cqparts.params import PositiveFloat + + class MyCube(cqparts.Part): + size = PositiveFloat(1, doc="cube size") + def make(self): + return cadquery.Workplane('XY').box(self.size, self.size, self.size) + + # create cube instance + cube = MyCube(size=10) + + # display cube (optional) + from cqparts.display import display + display(cube) + +You can see that under the bonnet (in the ``make`` function) the geometry is +created with ``cadquery``, but the resulting ``MyCube`` class is instantiated +more intuitively, and more object orientated. + + +Creating a Hierarchy +^^^^^^^^^^^^^^^^^^^^^^ + +``cqparts`` can also be used to create a deep hierarchy of *parts* and +*assemblies* to build something deeply complicated and entirely parametric. + +A simple example of this is the +`toy car tutorial `_. + +.. image:: https://fragmuffin.github.io/cqparts/media/img/toy-car.png + + +``cqparts`` Capabilities +^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The work done in ``cqparts_fasteners`` is a good example of how useful +``cqparts`` wrapping can be; read about the ``Fastener`` class, how it works, +and what can be done with it in the +`cqparts_fasteners docs `_ + +.. image:: https://fragmuffin.github.io/cqparts/media/img/nut-bolt-fastener.png + + +Contributing +----------------- + +Issues, and Pull Requests are encouraged, and happily received, please read +`CONTRIBUTING.md `_ +for guidance on how to contribute. diff --git a/ThirdParty/cqparts/__init__.py b/ThirdParty/cqparts/__init__.py index 541392c..07902f3 100644 --- a/ThirdParty/cqparts/__init__.py +++ b/ThirdParty/cqparts/__init__.py @@ -22,7 +22,7 @@ limitations under the License. # 1.x - Development Status :: 5 - Production/Stable # .y - developments on that version (pre-release) # *.dev* - development release (intended purely to test deployment) -__version__ = '0.2.1' +__version__ = '0.2.2.dev1' __title__ = 'cqparts' __description__ = 'Hierarchical and deeply parametric models using cadquery' @@ -31,7 +31,7 @@ __url__ = 'https://github.com/fragmuffin/cqparts' __author__ = 'Peter Boin' __email__ = 'peter.boin+cqparts@gmail.com' -__license__ = 'GPLv3' +__license__ = 'Apache Public License 2.0' __keywords__ = ['cadquery', 'cad', '3d', 'modeling'] diff --git a/ThirdParty/cqparts/codec/step.py b/ThirdParty/cqparts/codec/step.py index c7db4f5..a1ec615 100644 --- a/ThirdParty/cqparts/codec/step.py +++ b/ThirdParty/cqparts/codec/step.py @@ -47,8 +47,23 @@ class STEPPartImporter(Importer): Abstraction layer to avoid duplicate code for :meth:`_mangled_filename`. """ @classmethod - def _mangled_filename(cls, filename): - return re.sub(r'(^\d|[^a-z0-9_\-+])', '_', filename, flags=re.I) + def _mangled_filename(cls, name): + # ignore sub-directories + name = os.path.basename(name) + + # encode to ascii (for a clean class name) + name = name.encode('ascii', 'ignore') + if type(name).__name__ == 'bytes': # a python3 thing + name = name.decode() # type: bytes -> str + + # if begins with a number, inject a '_' at the beginning + if re.search(r'^\d', name): + name = '_' + name + + # replace non alpha-numeric characters with a '_' + name = re.sub(r'[^a-z0-9_]', '_', name, flags=re.I) + + return name @register_importer('step', Part) diff --git a/ThirdParty/cqparts/constraint/README.md b/ThirdParty/cqparts/constraint/README.md new file mode 100644 index 0000000..127cacc --- /dev/null +++ b/ThirdParty/cqparts/constraint/README.md @@ -0,0 +1,37 @@ + +# Mainstream CAD Mating / Constraints + +**Solidworks** +http://help.solidworks.com/2013/english/solidworks/sldworks/HelpViewerDS.aspx?version=2013&prod=solidworks&lang=english&path=sldworks%2fr_Types_of_Mates_SWassy.htm + +Types: + +* angle, coincident, concentric, distance, lock, parallel, perpendicular, and tangent mates +* limit, linear/linear coupler, path, symmetry, and width +* cam-follower, gear, hinge, rack and pinion, screw, and universal joint + + +**OnShape** +https://cad.onshape.com/help/Content/mate.htm + +Types: + +* Fastened +* Revolute +* Slider +* Planar +* Cylindrical +* Pin Slot +* Ball + +# Useful links for 3d transforms + +## Basics Explanations + +* https://www.tutorialspoint.com/computer_graphics/3d_transformation.htm +* http://planning.cs.uiuc.edu/node100.html + +## Implementations + +* https://www.lfd.uci.edu/~gohlke/code/transformations.py.html +* https://afni.nimh.nih.gov/pub/dist/src/pkundu/meica.libs/nibabel/eulerangles.py diff --git a/ThirdParty/cqparts/display/cqparts_server.py b/ThirdParty/cqparts/display/cqparts_server.py index 197ed22..e9f27b6 100644 --- a/ThirdParty/cqparts/display/cqparts_server.py +++ b/ThirdParty/cqparts/display/cqparts_server.py @@ -1,21 +1,23 @@ -# generate the files and notify the cqparts server -# look at https://github.com/zignig/cqparts-server -# copied and edited from web.py -# Copyright 2018 Peter Boin -# and Simon Kirkby 2018 +""" generate the files and notify the cqparts server + look at https://github.com/zignig/cqparts-server + copied and edited from web.py + Copyright 2018 Peter Boin + and Simon Kirkby 2018 +""" import os -import sys -import inspect import time -import requests import tempfile +import shutil import logging -log = logging.getLogger(__name__) +import requests from .environment import map_environment, DisplayEnvironment +log = logging.getLogger(__name__) + + ENVVAR_SERVER = 'CQPARTS_SERVER' @@ -38,7 +40,7 @@ class CQPartsServerDisplayEnv(DisplayEnvironment): os.mkdir(dir_path) return dir_path - def display_callback(self, component): + def display_callback(self, component, **kwargs): """ :param component: the component to render :type component: :class:`Component ` @@ -47,6 +49,9 @@ class CQPartsServerDisplayEnv(DisplayEnvironment): if ENVVAR_SERVER not in os.environ: raise KeyError("environment variable '%s' not set" % ENVVAR_SERVER) + # get the server from the environment + server_url = os.environ[ENVVAR_SERVER] + # Verify Parameter(s) # check that it is a component from .. import Component @@ -55,23 +60,55 @@ class CQPartsServerDisplayEnv(DisplayEnvironment): Component, type(component) )) + # check that the server is running + try: + requests.get(server_url + '/status') + #TODO inspect response for actual status and do stuff + except requests.exceptions.ConnectionError: + print('cqpart-server unavailable') + return + + # get the name of the object cp_name = type(component).__name__ # create temporary folder - temp_dir = self._mkdir(tempfile.gettempdir(), 'cqpss') - temp_dir = self._mkdir(tempfile.gettempdir(), 'cqpss', cp_name) + temp_dir = tempfile.mkdtemp() + base_dir = self._mkdir(temp_dir, cp_name) - # export the files to the name folder - exporter = component.exporter('gltf') - exporter( - filename=os.path.join(temp_dir, 'out.gltf'), - embed=False, - ) + try: + # export the files to the name folder + start_time = time.time() + exporter = component.exporter('gltf') + exporter( + filename=os.path.join(base_dir, 'out.gltf'), + embed=False, + ) + finish_time = time.time() + duration = finish_time - start_time - # get the server from the environment - server_url = os.environ[ENVVAR_SERVER] + # create the list of files to upload + file_list = os.listdir(base_dir) + file_load_list = [] + for i in file_list: + # path of file to upload + file_name = os.path.join(base_dir, i) + # short reference to file + file_ref = os.path.join(cp_name, i) + # make dict for file upload + file_load_list.append( + ('objs', (file_ref, open(file_name, 'rb'))) + ) - # notify the cq parts server - resp = requests.post(server_url + '/notify', data={ - 'name': cp_name, - }) + # upload the files as multipart upload + requests.post(server_url + '/upload', files=file_load_list) + # notify the cq parts server + # TODO more data in post, bounding box , other data + requests.post(server_url + '/notify', data={ + 'duration': duration, + 'name': cp_name, + }) + + finally: + # finally check that it's sane and delete + if os.path.isdir(temp_dir): + shutil.rmtree(temp_dir) diff --git a/ThirdParty/cqparts/display/environment.py b/ThirdParty/cqparts/display/environment.py index 80b93d1..d0b6e54 100644 --- a/ThirdParty/cqparts/display/environment.py +++ b/ThirdParty/cqparts/display/environment.py @@ -102,7 +102,7 @@ class DisplayEnvironment(object): def display(self, *args, **kwargs): return self.display_callback(*args, **kwargs) - def display_callback(self, *args, **kwargs): + def display_callback(self, component, **kwargs): """ Display given component in this environment. diff --git a/ThirdParty/cqparts/display/web-template/index.html b/ThirdParty/cqparts/display/web-template/index.html index 1c6ad2b..56f027e 100644 --- a/ThirdParty/cqparts/display/web-template/index.html +++ b/ThirdParty/cqparts/display/web-template/index.html @@ -2,12 +2,14 @@ CQParts display-o-tron + - - + + +