Updated all cqparts libraries and catalogs.
This commit is contained in:
parent
4fc32ec77b
commit
3b9ea9d1cb
1
ThirdParty/cqparts/LICENSE
vendored
Symbolic link
1
ThirdParty/cqparts/LICENSE
vendored
Symbolic link
|
@ -0,0 +1 @@
|
|||
../../LICENSE
|
131
ThirdParty/cqparts/README.rst
vendored
Normal file
131
ThirdParty/cqparts/README.rst
vendored
Normal file
|
@ -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 <https://fragmuffin.github.io/cqparts/doc>`_.
|
||||
|
||||
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 <https://fragmuffin.github.io/cqparts/doc/tutorials/assembly.html>`_.
|
||||
|
||||
.. 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 <https://fragmuffin.github.io/cqparts/doc/cqparts_fasteners/index.html>`_
|
||||
|
||||
.. 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 <https://github.com/fragmuffin/cqparts/blob/master/CONTRIBUTING.md>`_
|
||||
for guidance on how to contribute.
|
4
ThirdParty/cqparts/__init__.py
vendored
4
ThirdParty/cqparts/__init__.py
vendored
|
@ -22,7 +22,7 @@ limitations under the License.
|
|||
# 1.x - Development Status :: 5 - Production/Stable
|
||||
# <any above>.y - developments on that version (pre-release)
|
||||
# <any above>*.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']
|
||||
|
||||
|
|
19
ThirdParty/cqparts/codec/step.py
vendored
19
ThirdParty/cqparts/codec/step.py
vendored
|
@ -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)
|
||||
|
|
37
ThirdParty/cqparts/constraint/README.md
vendored
Normal file
37
ThirdParty/cqparts/constraint/README.md
vendored
Normal file
|
@ -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
|
85
ThirdParty/cqparts/display/cqparts_server.py
vendored
85
ThirdParty/cqparts/display/cqparts_server.py
vendored
|
@ -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 <cqparts.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)
|
||||
|
|
2
ThirdParty/cqparts/display/environment.py
vendored
2
ThirdParty/cqparts/display/environment.py
vendored
|
@ -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.
|
||||
|
||||
|
|
|
@ -2,12 +2,14 @@
|
|||
<html>
|
||||
<head>
|
||||
<title>CQParts display-o-tron</title>
|
||||
<link rel="stylesheet" href="/static/css/viewer.css">
|
||||
<script src="/static/js/three.min.js"></script>
|
||||
<script src="/static/js/OrbitControls.js"></script>
|
||||
<script src="/static/js/GLTFLoader.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<script src="/static/js/app.js"></script>
|
||||
<body style="margin:0; overflow:hidden;">
|
||||
<button id="autorotate" onclick="ActivateAutorotate()">AutoRotate</button>
|
||||
<script src="/static/js/cqpartsViewer.js"></script>
|
||||
<script>
|
||||
camera.position.set({{camera_pos}});
|
||||
controls.target.set({{camera_target}});
|
||||
|
|
7
ThirdParty/cqparts/display/web-template/static/css/viewer.css
vendored
Normal file
7
ThirdParty/cqparts/display/web-template/static/css/viewer.css
vendored
Normal file
|
@ -0,0 +1,7 @@
|
|||
/* CSS for the viewer */
|
||||
|
||||
#autorotate {
|
||||
position: absolute;
|
||||
left: 5px;
|
||||
};
|
||||
|
|
@ -1,51 +0,0 @@
|
|||
// three js local files
|
||||
//
|
||||
var container, controls , obj;
|
||||
var camera, scene, renderer, light;
|
||||
init();
|
||||
animate();
|
||||
function init() {
|
||||
container = document.createElement( 'div' );
|
||||
document.body.appendChild( container );
|
||||
camera = new THREE.PerspectiveCamera( 90, window.innerWidth / window.innerHeight,0.0001);
|
||||
camera.position.set(0.5,0.5,0.5);
|
||||
controls = new THREE.OrbitControls( camera );
|
||||
controls.autoRotate = true;
|
||||
controls.autoRotateSpeed = 2;
|
||||
controls.target.set(0,0,0);
|
||||
controls.update();
|
||||
scene = new THREE.Scene({antialias: true});
|
||||
scene.background = new THREE.Color(255,255,255)
|
||||
// light 1
|
||||
light = new THREE.HemisphereLight( 0xbbbbff, 0x444422 );
|
||||
light.position.set( 0, 20, 0 );
|
||||
scene.add( light );
|
||||
// light 2
|
||||
light2 = new THREE.PointLight(0xf0f0f0,2,100);
|
||||
light2.position.set( 50,50,50);
|
||||
scene.add( light2 );
|
||||
// model
|
||||
var loader = new THREE.GLTFLoader();
|
||||
loader.load( 'model/out.gltf', function ( gltf ) {
|
||||
scene.add( gltf.scene );
|
||||
obj = gltf.scene;
|
||||
} );
|
||||
renderer = new THREE.WebGLRenderer( { antialias: true } );
|
||||
renderer.setPixelRatio( window.devicePixelRatio );
|
||||
renderer.setSize( window.innerWidth, window.innerHeight );
|
||||
renderer.gammaOutput = true;
|
||||
container.appendChild( renderer.domElement );
|
||||
window.addEventListener( 'resize', onWindowResize, false );
|
||||
}
|
||||
|
||||
function onWindowResize() {
|
||||
camera.aspect = window.innerWidth / window.innerHeight;
|
||||
camera.updateProjectionMatrix();
|
||||
renderer.setSize( window.innerWidth, window.innerHeight );
|
||||
}
|
||||
|
||||
function animate() {
|
||||
requestAnimationFrame( animate );
|
||||
controls.update();
|
||||
renderer.render( scene, camera );
|
||||
}
|
141
ThirdParty/cqparts/display/web-template/static/js/cqpartsViewer.js
vendored
Normal file
141
ThirdParty/cqparts/display/web-template/static/js/cqpartsViewer.js
vendored
Normal file
|
@ -0,0 +1,141 @@
|
|||
// A viewer for cqparts
|
||||
//
|
||||
var container, controls , obj;
|
||||
var camera, scene, renderer, light;
|
||||
var meshlist = [];
|
||||
var raycaster ;
|
||||
var mouse = new THREE.Vector2(), INTERSECTED ;
|
||||
|
||||
init();
|
||||
animate();
|
||||
load('./model/out.gltf');
|
||||
|
||||
function clear(){
|
||||
scene.remove(obj);
|
||||
}
|
||||
|
||||
function load(name){
|
||||
var loader = new THREE.GLTFLoader();
|
||||
loader.load( name, function ( gltf ) {
|
||||
scene.add( gltf.scene );
|
||||
obj = gltf.scene;
|
||||
//grab all the meshes for selection
|
||||
meshlist = [];
|
||||
gltf.scene.traverse( function ( child ) {
|
||||
if ( child.isMesh ) {
|
||||
meshlist.push(child);
|
||||
}
|
||||
} );
|
||||
} );
|
||||
}
|
||||
|
||||
function init() {
|
||||
|
||||
container = document.createElement('div');
|
||||
document.body.appendChild(container)
|
||||
camera = new THREE.PerspectiveCamera( 30, window.innerWidth/ window.innerHeight, 0.001, 1000);
|
||||
camera.position.set( 0.2, 0.2, 0.2);
|
||||
controls = new THREE.OrbitControls(camera);
|
||||
//controls.autoRotate = true;
|
||||
controls.autoRotateSpeed = 2;
|
||||
controls.target.set(0,0,0);
|
||||
controls.update();
|
||||
scene = new THREE.Scene({antialias: true});
|
||||
scene.background = new THREE.Color(255,255,255)
|
||||
// light 1
|
||||
light = new THREE.HemisphereLight( 0xbbbbff, 0x444422 );
|
||||
light.position.set( 0, 20, 0 );
|
||||
scene.add( light );
|
||||
// light 2
|
||||
light2 = new THREE.PointLight(0xf0f0f0,2,100);
|
||||
light2.position.set( 50,50,50);
|
||||
scene.add( light2 );
|
||||
// light 3
|
||||
light3 = new THREE.PointLight(0xf0f0f0,2,100);
|
||||
light3.position.set( 0,0,-50);
|
||||
scene.add( light2) ;
|
||||
// renderer
|
||||
renderer = new THREE.WebGLRenderer( {antialias: true, preserveDrawingBuffer: true } );
|
||||
renderer.setPixelRatio( window.devicePixelRatio );
|
||||
renderer.setSize(window.innerWidth,window.innerHeight);
|
||||
renderer.gammaOutput = true;
|
||||
// raycaster
|
||||
raycaster = new THREE.Raycaster();
|
||||
// add to doc and bind events
|
||||
window.addEventListener( 'resize', onWindowResize, false );
|
||||
window.addEventListener('mousemove',onDocumentMouseMove,false);
|
||||
window.addEventListener('mousedown',onDocumentClick,false);
|
||||
window.addEventListener('keydown',onKey,false);
|
||||
// Base grid helps us orient ourselves
|
||||
var baseGrid = new THREE.GridHelper(1, 10);
|
||||
//baseGrid.geometry.rotateX( Math.PI / 2 );
|
||||
scene.add(baseGrid);
|
||||
container.appendChild(renderer.domElement);
|
||||
}
|
||||
|
||||
function ActivateAutorotate(){
|
||||
but = document.getElementById("autorotate");
|
||||
if (controls.autoRotate == true){
|
||||
controls.autoRotate = false;
|
||||
} else {
|
||||
controls.autoRotate = true;
|
||||
}
|
||||
}
|
||||
|
||||
function onKey( event ) {
|
||||
if (event.code == "KeyA"){
|
||||
//console.log(event);
|
||||
for ( var i in meshlist){
|
||||
meshlist[i].visible = true;
|
||||
}
|
||||
};
|
||||
//console.log(event);
|
||||
if (event.code == "Space"){
|
||||
if ( INTERSECTED ) {
|
||||
INTERSECTED.visible = false;
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
function onDocumentClick( event ) {
|
||||
if ( INTERSECTED ) {
|
||||
//console.log(INTERSECTED);
|
||||
//INTERSECTED.visible = false;
|
||||
};
|
||||
}
|
||||
|
||||
function onDocumentMouseMove( event ) {
|
||||
event.preventDefault();
|
||||
var rect = renderer.domElement.getBoundingClientRect();
|
||||
mouse.x = ( ( event.clientX - rect.left ) / (rect.right - rect.left)) * 2 - 1;
|
||||
mouse.y = - ( ( event.clientY - rect.top ) / (rect.bottom - rect.top)) * 2 + 1;
|
||||
}
|
||||
|
||||
function onWindowResize() {
|
||||
camera.aspect = window.innerWidth/window.innerHeight;
|
||||
camera.updateProjectionMatrix();
|
||||
renderer.setSize( window.innerWidth,window.innerHeight);
|
||||
}
|
||||
|
||||
function animate() {
|
||||
requestAnimationFrame( animate );
|
||||
controls.update();
|
||||
render();
|
||||
}
|
||||
|
||||
function render(){
|
||||
raycaster.setFromCamera(mouse,camera);
|
||||
var intersects = raycaster.intersectObjects(meshlist);
|
||||
if (intersects.length > 0){
|
||||
if ( INTERSECTED != intersects[0].object){
|
||||
if (INTERSECTED) INTERSECTED.material.emissive.setHex(INTERSECTED.currentHEX);
|
||||
INTERSECTED = intersects[0].object;
|
||||
INTERSECTED.currentHex = INTERSECTED.material.emissive.getHex();
|
||||
INTERSECTED.material.emissive.setHex(0x551111);
|
||||
}
|
||||
} else {
|
||||
if ( INTERSECTED ) INTERSECTED.material.emissive.setHex(INTERSECTED.currentHex);
|
||||
INTERSECTED = null;
|
||||
}
|
||||
renderer.render( scene, camera );
|
||||
}
|
6
ThirdParty/cqparts/display/web.py
vendored
6
ThirdParty/cqparts/display/web.py
vendored
|
@ -84,7 +84,7 @@ class WebDisplayEnv(DisplayEnvironment):
|
|||
an errorcode 404 (file not found), because the http service has stopped.
|
||||
"""
|
||||
|
||||
def display_callback(self, component, port=9041, autorotate=False):
|
||||
def display_callback(self, component, **kwargs):
|
||||
"""
|
||||
:param component: the component to render
|
||||
:type component: :class:`Component <cqparts.Component>`
|
||||
|
@ -103,6 +103,10 @@ class WebDisplayEnv(DisplayEnvironment):
|
|||
Component, type(component)
|
||||
))
|
||||
|
||||
# Parameter defaults
|
||||
port = kwargs.get('port', 9041)
|
||||
autorotate = kwargs.get('autorotate', False)
|
||||
|
||||
# Create temporary file to host files
|
||||
temp_dir = tempfile.mkdtemp()
|
||||
host_dir = os.path.join(temp_dir, 'html')
|
||||
|
|
6
ThirdParty/cqparts/requirements.txt
vendored
Normal file
6
ThirdParty/cqparts/requirements.txt
vendored
Normal file
|
@ -0,0 +1,6 @@
|
|||
cadquery
|
||||
six
|
||||
numpy
|
||||
Jinja2
|
||||
tinydb
|
||||
requests
|
40
ThirdParty/cqparts/utils/env.py
vendored
40
ThirdParty/cqparts/utils/env.py
vendored
|
@ -1,40 +0,0 @@
|
|||
import os
|
||||
|
||||
|
||||
def get_env_name():
|
||||
"""
|
||||
Get the name of the currently running environment.
|
||||
|
||||
:return: environment name
|
||||
:rtype: :class:`str`
|
||||
|
||||
=========== =============
|
||||
Name Environment
|
||||
=========== =============
|
||||
``freecad`` freecad module
|
||||
``cmdline`` directly in a python interpreter
|
||||
=========== =============
|
||||
|
||||
These environments are intended to switch a script's behaviour from
|
||||
displaying models, or exporting them to file.
|
||||
|
||||
For example::
|
||||
|
||||
from cqparts.utils.env import get_env_name
|
||||
from cqparts.display import display
|
||||
|
||||
my_model = SomeAssembly(foo=10, bar=-3)
|
||||
|
||||
if get_env_name() == 'cmdline':
|
||||
with open('model.gltf', 'w') as fh:
|
||||
fh.write(my_model.get_export_gltf())
|
||||
else:
|
||||
display(my_model)
|
||||
"""
|
||||
# FIXME: this is not a good test method, but it will do for now.
|
||||
if 'MYSCRIPT_DIR' in os.environ:
|
||||
return 'freecad'
|
||||
return 'cmdline'
|
||||
|
||||
|
||||
env_name = get_env_name() # it's unlikely to change
|
674
ThirdParty/cqparts_bearings/LICENSE
vendored
674
ThirdParty/cqparts_bearings/LICENSE
vendored
|
@ -1,674 +0,0 @@
|
|||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 3, 29 June 2007
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The GNU General Public License is a free, copyleft license for
|
||||
software and other kinds of works.
|
||||
|
||||
The licenses for most software and other practical works are designed
|
||||
to take away your freedom to share and change the works. By contrast,
|
||||
the GNU General Public License is intended to guarantee your freedom to
|
||||
share and change all versions of a program--to make sure it remains free
|
||||
software for all its users. We, the Free Software Foundation, use the
|
||||
GNU General Public License for most of our software; it applies also to
|
||||
any other work released this way by its authors. You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
them if you wish), that you receive source code or can get it if you
|
||||
want it, that you can change the software or use pieces of it in new
|
||||
free programs, and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to prevent others from denying you
|
||||
these rights or asking you to surrender the rights. Therefore, you have
|
||||
certain responsibilities if you distribute copies of the software, or if
|
||||
you modify it: responsibilities to respect the freedom of others.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must pass on to the recipients the same
|
||||
freedoms that you received. You must make sure that they, too, receive
|
||||
or can get the source code. And you must show them these terms so they
|
||||
know their rights.
|
||||
|
||||
Developers that use the GNU GPL protect your rights with two steps:
|
||||
(1) assert copyright on the software, and (2) offer you this License
|
||||
giving you legal permission to copy, distribute and/or modify it.
|
||||
|
||||
For the developers' and authors' protection, the GPL clearly explains
|
||||
that there is no warranty for this free software. For both users' and
|
||||
authors' sake, the GPL requires that modified versions be marked as
|
||||
changed, so that their problems will not be attributed erroneously to
|
||||
authors of previous versions.
|
||||
|
||||
Some devices are designed to deny users access to install or run
|
||||
modified versions of the software inside them, although the manufacturer
|
||||
can do so. This is fundamentally incompatible with the aim of
|
||||
protecting users' freedom to change the software. The systematic
|
||||
pattern of such abuse occurs in the area of products for individuals to
|
||||
use, which is precisely where it is most unacceptable. Therefore, we
|
||||
have designed this version of the GPL to prohibit the practice for those
|
||||
products. If such problems arise substantially in other domains, we
|
||||
stand ready to extend this provision to those domains in future versions
|
||||
of the GPL, as needed to protect the freedom of users.
|
||||
|
||||
Finally, every program is threatened constantly by software patents.
|
||||
States should not allow patents to restrict development and use of
|
||||
software on general-purpose computers, but in those that do, we wish to
|
||||
avoid the special danger that patents applied to a free program could
|
||||
make it effectively proprietary. To prevent this, the GPL assures that
|
||||
patents cannot be used to render the program non-free.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
TERMS AND CONDITIONS
|
||||
|
||||
0. Definitions.
|
||||
|
||||
"This License" refers to version 3 of the GNU General Public License.
|
||||
|
||||
"Copyright" also means copyright-like laws that apply to other kinds of
|
||||
works, such as semiconductor masks.
|
||||
|
||||
"The Program" refers to any copyrightable work licensed under this
|
||||
License. Each licensee is addressed as "you". "Licensees" and
|
||||
"recipients" may be individuals or organizations.
|
||||
|
||||
To "modify" a work means to copy from or adapt all or part of the work
|
||||
in a fashion requiring copyright permission, other than the making of an
|
||||
exact copy. The resulting work is called a "modified version" of the
|
||||
earlier work or a work "based on" the earlier work.
|
||||
|
||||
A "covered work" means either the unmodified Program or a work based
|
||||
on the Program.
|
||||
|
||||
To "propagate" a work means to do anything with it that, without
|
||||
permission, would make you directly or secondarily liable for
|
||||
infringement under applicable copyright law, except executing it on a
|
||||
computer or modifying a private copy. Propagation includes copying,
|
||||
distribution (with or without modification), making available to the
|
||||
public, and in some countries other activities as well.
|
||||
|
||||
To "convey" a work means any kind of propagation that enables other
|
||||
parties to make or receive copies. Mere interaction with a user through
|
||||
a computer network, with no transfer of a copy, is not conveying.
|
||||
|
||||
An interactive user interface displays "Appropriate Legal Notices"
|
||||
to the extent that it includes a convenient and prominently visible
|
||||
feature that (1) displays an appropriate copyright notice, and (2)
|
||||
tells the user that there is no warranty for the work (except to the
|
||||
extent that warranties are provided), that licensees may convey the
|
||||
work under this License, and how to view a copy of this License. If
|
||||
the interface presents a list of user commands or options, such as a
|
||||
menu, a prominent item in the list meets this criterion.
|
||||
|
||||
1. Source Code.
|
||||
|
||||
The "source code" for a work means the preferred form of the work
|
||||
for making modifications to it. "Object code" means any non-source
|
||||
form of a work.
|
||||
|
||||
A "Standard Interface" means an interface that either is an official
|
||||
standard defined by a recognized standards body, or, in the case of
|
||||
interfaces specified for a particular programming language, one that
|
||||
is widely used among developers working in that language.
|
||||
|
||||
The "System Libraries" of an executable work include anything, other
|
||||
than the work as a whole, that (a) is included in the normal form of
|
||||
packaging a Major Component, but which is not part of that Major
|
||||
Component, and (b) serves only to enable use of the work with that
|
||||
Major Component, or to implement a Standard Interface for which an
|
||||
implementation is available to the public in source code form. A
|
||||
"Major Component", in this context, means a major essential component
|
||||
(kernel, window system, and so on) of the specific operating system
|
||||
(if any) on which the executable work runs, or a compiler used to
|
||||
produce the work, or an object code interpreter used to run it.
|
||||
|
||||
The "Corresponding Source" for a work in object code form means all
|
||||
the source code needed to generate, install, and (for an executable
|
||||
work) run the object code and to modify the work, including scripts to
|
||||
control those activities. However, it does not include the work's
|
||||
System Libraries, or general-purpose tools or generally available free
|
||||
programs which are used unmodified in performing those activities but
|
||||
which are not part of the work. For example, Corresponding Source
|
||||
includes interface definition files associated with source files for
|
||||
the work, and the source code for shared libraries and dynamically
|
||||
linked subprograms that the work is specifically designed to require,
|
||||
such as by intimate data communication or control flow between those
|
||||
subprograms and other parts of the work.
|
||||
|
||||
The Corresponding Source need not include anything that users
|
||||
can regenerate automatically from other parts of the Corresponding
|
||||
Source.
|
||||
|
||||
The Corresponding Source for a work in source code form is that
|
||||
same work.
|
||||
|
||||
2. Basic Permissions.
|
||||
|
||||
All rights granted under this License are granted for the term of
|
||||
copyright on the Program, and are irrevocable provided the stated
|
||||
conditions are met. This License explicitly affirms your unlimited
|
||||
permission to run the unmodified Program. The output from running a
|
||||
covered work is covered by this License only if the output, given its
|
||||
content, constitutes a covered work. This License acknowledges your
|
||||
rights of fair use or other equivalent, as provided by copyright law.
|
||||
|
||||
You may make, run and propagate covered works that you do not
|
||||
convey, without conditions so long as your license otherwise remains
|
||||
in force. You may convey covered works to others for the sole purpose
|
||||
of having them make modifications exclusively for you, or provide you
|
||||
with facilities for running those works, provided that you comply with
|
||||
the terms of this License in conveying all material for which you do
|
||||
not control copyright. Those thus making or running the covered works
|
||||
for you must do so exclusively on your behalf, under your direction
|
||||
and control, on terms that prohibit them from making any copies of
|
||||
your copyrighted material outside their relationship with you.
|
||||
|
||||
Conveying under any other circumstances is permitted solely under
|
||||
the conditions stated below. Sublicensing is not allowed; section 10
|
||||
makes it unnecessary.
|
||||
|
||||
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
|
||||
|
||||
No covered work shall be deemed part of an effective technological
|
||||
measure under any applicable law fulfilling obligations under article
|
||||
11 of the WIPO copyright treaty adopted on 20 December 1996, or
|
||||
similar laws prohibiting or restricting circumvention of such
|
||||
measures.
|
||||
|
||||
When you convey a covered work, you waive any legal power to forbid
|
||||
circumvention of technological measures to the extent such circumvention
|
||||
is effected by exercising rights under this License with respect to
|
||||
the covered work, and you disclaim any intention to limit operation or
|
||||
modification of the work as a means of enforcing, against the work's
|
||||
users, your or third parties' legal rights to forbid circumvention of
|
||||
technological measures.
|
||||
|
||||
4. Conveying Verbatim Copies.
|
||||
|
||||
You may convey verbatim copies of the Program's source code as you
|
||||
receive it, in any medium, provided that you conspicuously and
|
||||
appropriately publish on each copy an appropriate copyright notice;
|
||||
keep intact all notices stating that this License and any
|
||||
non-permissive terms added in accord with section 7 apply to the code;
|
||||
keep intact all notices of the absence of any warranty; and give all
|
||||
recipients a copy of this License along with the Program.
|
||||
|
||||
You may charge any price or no price for each copy that you convey,
|
||||
and you may offer support or warranty protection for a fee.
|
||||
|
||||
5. Conveying Modified Source Versions.
|
||||
|
||||
You may convey a work based on the Program, or the modifications to
|
||||
produce it from the Program, in the form of source code under the
|
||||
terms of section 4, provided that you also meet all of these conditions:
|
||||
|
||||
a) The work must carry prominent notices stating that you modified
|
||||
it, and giving a relevant date.
|
||||
|
||||
b) The work must carry prominent notices stating that it is
|
||||
released under this License and any conditions added under section
|
||||
7. This requirement modifies the requirement in section 4 to
|
||||
"keep intact all notices".
|
||||
|
||||
c) You must license the entire work, as a whole, under this
|
||||
License to anyone who comes into possession of a copy. This
|
||||
License will therefore apply, along with any applicable section 7
|
||||
additional terms, to the whole of the work, and all its parts,
|
||||
regardless of how they are packaged. This License gives no
|
||||
permission to license the work in any other way, but it does not
|
||||
invalidate such permission if you have separately received it.
|
||||
|
||||
d) If the work has interactive user interfaces, each must display
|
||||
Appropriate Legal Notices; however, if the Program has interactive
|
||||
interfaces that do not display Appropriate Legal Notices, your
|
||||
work need not make them do so.
|
||||
|
||||
A compilation of a covered work with other separate and independent
|
||||
works, which are not by their nature extensions of the covered work,
|
||||
and which are not combined with it such as to form a larger program,
|
||||
in or on a volume of a storage or distribution medium, is called an
|
||||
"aggregate" if the compilation and its resulting copyright are not
|
||||
used to limit the access or legal rights of the compilation's users
|
||||
beyond what the individual works permit. Inclusion of a covered work
|
||||
in an aggregate does not cause this License to apply to the other
|
||||
parts of the aggregate.
|
||||
|
||||
6. Conveying Non-Source Forms.
|
||||
|
||||
You may convey a covered work in object code form under the terms
|
||||
of sections 4 and 5, provided that you also convey the
|
||||
machine-readable Corresponding Source under the terms of this License,
|
||||
in one of these ways:
|
||||
|
||||
a) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by the
|
||||
Corresponding Source fixed on a durable physical medium
|
||||
customarily used for software interchange.
|
||||
|
||||
b) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by a
|
||||
written offer, valid for at least three years and valid for as
|
||||
long as you offer spare parts or customer support for that product
|
||||
model, to give anyone who possesses the object code either (1) a
|
||||
copy of the Corresponding Source for all the software in the
|
||||
product that is covered by this License, on a durable physical
|
||||
medium customarily used for software interchange, for a price no
|
||||
more than your reasonable cost of physically performing this
|
||||
conveying of source, or (2) access to copy the
|
||||
Corresponding Source from a network server at no charge.
|
||||
|
||||
c) Convey individual copies of the object code with a copy of the
|
||||
written offer to provide the Corresponding Source. This
|
||||
alternative is allowed only occasionally and noncommercially, and
|
||||
only if you received the object code with such an offer, in accord
|
||||
with subsection 6b.
|
||||
|
||||
d) Convey the object code by offering access from a designated
|
||||
place (gratis or for a charge), and offer equivalent access to the
|
||||
Corresponding Source in the same way through the same place at no
|
||||
further charge. You need not require recipients to copy the
|
||||
Corresponding Source along with the object code. If the place to
|
||||
copy the object code is a network server, the Corresponding Source
|
||||
may be on a different server (operated by you or a third party)
|
||||
that supports equivalent copying facilities, provided you maintain
|
||||
clear directions next to the object code saying where to find the
|
||||
Corresponding Source. Regardless of what server hosts the
|
||||
Corresponding Source, you remain obligated to ensure that it is
|
||||
available for as long as needed to satisfy these requirements.
|
||||
|
||||
e) Convey the object code using peer-to-peer transmission, provided
|
||||
you inform other peers where the object code and Corresponding
|
||||
Source of the work are being offered to the general public at no
|
||||
charge under subsection 6d.
|
||||
|
||||
A separable portion of the object code, whose source code is excluded
|
||||
from the Corresponding Source as a System Library, need not be
|
||||
included in conveying the object code work.
|
||||
|
||||
A "User Product" is either (1) a "consumer product", which means any
|
||||
tangible personal property which is normally used for personal, family,
|
||||
or household purposes, or (2) anything designed or sold for incorporation
|
||||
into a dwelling. In determining whether a product is a consumer product,
|
||||
doubtful cases shall be resolved in favor of coverage. For a particular
|
||||
product received by a particular user, "normally used" refers to a
|
||||
typical or common use of that class of product, regardless of the status
|
||||
of the particular user or of the way in which the particular user
|
||||
actually uses, or expects or is expected to use, the product. A product
|
||||
is a consumer product regardless of whether the product has substantial
|
||||
commercial, industrial or non-consumer uses, unless such uses represent
|
||||
the only significant mode of use of the product.
|
||||
|
||||
"Installation Information" for a User Product means any methods,
|
||||
procedures, authorization keys, or other information required to install
|
||||
and execute modified versions of a covered work in that User Product from
|
||||
a modified version of its Corresponding Source. The information must
|
||||
suffice to ensure that the continued functioning of the modified object
|
||||
code is in no case prevented or interfered with solely because
|
||||
modification has been made.
|
||||
|
||||
If you convey an object code work under this section in, or with, or
|
||||
specifically for use in, a User Product, and the conveying occurs as
|
||||
part of a transaction in which the right of possession and use of the
|
||||
User Product is transferred to the recipient in perpetuity or for a
|
||||
fixed term (regardless of how the transaction is characterized), the
|
||||
Corresponding Source conveyed under this section must be accompanied
|
||||
by the Installation Information. But this requirement does not apply
|
||||
if neither you nor any third party retains the ability to install
|
||||
modified object code on the User Product (for example, the work has
|
||||
been installed in ROM).
|
||||
|
||||
The requirement to provide Installation Information does not include a
|
||||
requirement to continue to provide support service, warranty, or updates
|
||||
for a work that has been modified or installed by the recipient, or for
|
||||
the User Product in which it has been modified or installed. Access to a
|
||||
network may be denied when the modification itself materially and
|
||||
adversely affects the operation of the network or violates the rules and
|
||||
protocols for communication across the network.
|
||||
|
||||
Corresponding Source conveyed, and Installation Information provided,
|
||||
in accord with this section must be in a format that is publicly
|
||||
documented (and with an implementation available to the public in
|
||||
source code form), and must require no special password or key for
|
||||
unpacking, reading or copying.
|
||||
|
||||
7. Additional Terms.
|
||||
|
||||
"Additional permissions" are terms that supplement the terms of this
|
||||
License by making exceptions from one or more of its conditions.
|
||||
Additional permissions that are applicable to the entire Program shall
|
||||
be treated as though they were included in this License, to the extent
|
||||
that they are valid under applicable law. If additional permissions
|
||||
apply only to part of the Program, that part may be used separately
|
||||
under those permissions, but the entire Program remains governed by
|
||||
this License without regard to the additional permissions.
|
||||
|
||||
When you convey a copy of a covered work, you may at your option
|
||||
remove any additional permissions from that copy, or from any part of
|
||||
it. (Additional permissions may be written to require their own
|
||||
removal in certain cases when you modify the work.) You may place
|
||||
additional permissions on material, added by you to a covered work,
|
||||
for which you have or can give appropriate copyright permission.
|
||||
|
||||
Notwithstanding any other provision of this License, for material you
|
||||
add to a covered work, you may (if authorized by the copyright holders of
|
||||
that material) supplement the terms of this License with terms:
|
||||
|
||||
a) Disclaiming warranty or limiting liability differently from the
|
||||
terms of sections 15 and 16 of this License; or
|
||||
|
||||
b) Requiring preservation of specified reasonable legal notices or
|
||||
author attributions in that material or in the Appropriate Legal
|
||||
Notices displayed by works containing it; or
|
||||
|
||||
c) Prohibiting misrepresentation of the origin of that material, or
|
||||
requiring that modified versions of such material be marked in
|
||||
reasonable ways as different from the original version; or
|
||||
|
||||
d) Limiting the use for publicity purposes of names of licensors or
|
||||
authors of the material; or
|
||||
|
||||
e) Declining to grant rights under trademark law for use of some
|
||||
trade names, trademarks, or service marks; or
|
||||
|
||||
f) Requiring indemnification of licensors and authors of that
|
||||
material by anyone who conveys the material (or modified versions of
|
||||
it) with contractual assumptions of liability to the recipient, for
|
||||
any liability that these contractual assumptions directly impose on
|
||||
those licensors and authors.
|
||||
|
||||
All other non-permissive additional terms are considered "further
|
||||
restrictions" within the meaning of section 10. If the Program as you
|
||||
received it, or any part of it, contains a notice stating that it is
|
||||
governed by this License along with a term that is a further
|
||||
restriction, you may remove that term. If a license document contains
|
||||
a further restriction but permits relicensing or conveying under this
|
||||
License, you may add to a covered work material governed by the terms
|
||||
of that license document, provided that the further restriction does
|
||||
not survive such relicensing or conveying.
|
||||
|
||||
If you add terms to a covered work in accord with this section, you
|
||||
must place, in the relevant source files, a statement of the
|
||||
additional terms that apply to those files, or a notice indicating
|
||||
where to find the applicable terms.
|
||||
|
||||
Additional terms, permissive or non-permissive, may be stated in the
|
||||
form of a separately written license, or stated as exceptions;
|
||||
the above requirements apply either way.
|
||||
|
||||
8. Termination.
|
||||
|
||||
You may not propagate or modify a covered work except as expressly
|
||||
provided under this License. Any attempt otherwise to propagate or
|
||||
modify it is void, and will automatically terminate your rights under
|
||||
this License (including any patent licenses granted under the third
|
||||
paragraph of section 11).
|
||||
|
||||
However, if you cease all violation of this License, then your
|
||||
license from a particular copyright holder is reinstated (a)
|
||||
provisionally, unless and until the copyright holder explicitly and
|
||||
finally terminates your license, and (b) permanently, if the copyright
|
||||
holder fails to notify you of the violation by some reasonable means
|
||||
prior to 60 days after the cessation.
|
||||
|
||||
Moreover, your license from a particular copyright holder is
|
||||
reinstated permanently if the copyright holder notifies you of the
|
||||
violation by some reasonable means, this is the first time you have
|
||||
received notice of violation of this License (for any work) from that
|
||||
copyright holder, and you cure the violation prior to 30 days after
|
||||
your receipt of the notice.
|
||||
|
||||
Termination of your rights under this section does not terminate the
|
||||
licenses of parties who have received copies or rights from you under
|
||||
this License. If your rights have been terminated and not permanently
|
||||
reinstated, you do not qualify to receive new licenses for the same
|
||||
material under section 10.
|
||||
|
||||
9. Acceptance Not Required for Having Copies.
|
||||
|
||||
You are not required to accept this License in order to receive or
|
||||
run a copy of the Program. Ancillary propagation of a covered work
|
||||
occurring solely as a consequence of using peer-to-peer transmission
|
||||
to receive a copy likewise does not require acceptance. However,
|
||||
nothing other than this License grants you permission to propagate or
|
||||
modify any covered work. These actions infringe copyright if you do
|
||||
not accept this License. Therefore, by modifying or propagating a
|
||||
covered work, you indicate your acceptance of this License to do so.
|
||||
|
||||
10. Automatic Licensing of Downstream Recipients.
|
||||
|
||||
Each time you convey a covered work, the recipient automatically
|
||||
receives a license from the original licensors, to run, modify and
|
||||
propagate that work, subject to this License. You are not responsible
|
||||
for enforcing compliance by third parties with this License.
|
||||
|
||||
An "entity transaction" is a transaction transferring control of an
|
||||
organization, or substantially all assets of one, or subdividing an
|
||||
organization, or merging organizations. If propagation of a covered
|
||||
work results from an entity transaction, each party to that
|
||||
transaction who receives a copy of the work also receives whatever
|
||||
licenses to the work the party's predecessor in interest had or could
|
||||
give under the previous paragraph, plus a right to possession of the
|
||||
Corresponding Source of the work from the predecessor in interest, if
|
||||
the predecessor has it or can get it with reasonable efforts.
|
||||
|
||||
You may not impose any further restrictions on the exercise of the
|
||||
rights granted or affirmed under this License. For example, you may
|
||||
not impose a license fee, royalty, or other charge for exercise of
|
||||
rights granted under this License, and you may not initiate litigation
|
||||
(including a cross-claim or counterclaim in a lawsuit) alleging that
|
||||
any patent claim is infringed by making, using, selling, offering for
|
||||
sale, or importing the Program or any portion of it.
|
||||
|
||||
11. Patents.
|
||||
|
||||
A "contributor" is a copyright holder who authorizes use under this
|
||||
License of the Program or a work on which the Program is based. The
|
||||
work thus licensed is called the contributor's "contributor version".
|
||||
|
||||
A contributor's "essential patent claims" are all patent claims
|
||||
owned or controlled by the contributor, whether already acquired or
|
||||
hereafter acquired, that would be infringed by some manner, permitted
|
||||
by this License, of making, using, or selling its contributor version,
|
||||
but do not include claims that would be infringed only as a
|
||||
consequence of further modification of the contributor version. For
|
||||
purposes of this definition, "control" includes the right to grant
|
||||
patent sublicenses in a manner consistent with the requirements of
|
||||
this License.
|
||||
|
||||
Each contributor grants you a non-exclusive, worldwide, royalty-free
|
||||
patent license under the contributor's essential patent claims, to
|
||||
make, use, sell, offer for sale, import and otherwise run, modify and
|
||||
propagate the contents of its contributor version.
|
||||
|
||||
In the following three paragraphs, a "patent license" is any express
|
||||
agreement or commitment, however denominated, not to enforce a patent
|
||||
(such as an express permission to practice a patent or covenant not to
|
||||
sue for patent infringement). To "grant" such a patent license to a
|
||||
party means to make such an agreement or commitment not to enforce a
|
||||
patent against the party.
|
||||
|
||||
If you convey a covered work, knowingly relying on a patent license,
|
||||
and the Corresponding Source of the work is not available for anyone
|
||||
to copy, free of charge and under the terms of this License, through a
|
||||
publicly available network server or other readily accessible means,
|
||||
then you must either (1) cause the Corresponding Source to be so
|
||||
available, or (2) arrange to deprive yourself of the benefit of the
|
||||
patent license for this particular work, or (3) arrange, in a manner
|
||||
consistent with the requirements of this License, to extend the patent
|
||||
license to downstream recipients. "Knowingly relying" means you have
|
||||
actual knowledge that, but for the patent license, your conveying the
|
||||
covered work in a country, or your recipient's use of the covered work
|
||||
in a country, would infringe one or more identifiable patents in that
|
||||
country that you have reason to believe are valid.
|
||||
|
||||
If, pursuant to or in connection with a single transaction or
|
||||
arrangement, you convey, or propagate by procuring conveyance of, a
|
||||
covered work, and grant a patent license to some of the parties
|
||||
receiving the covered work authorizing them to use, propagate, modify
|
||||
or convey a specific copy of the covered work, then the patent license
|
||||
you grant is automatically extended to all recipients of the covered
|
||||
work and works based on it.
|
||||
|
||||
A patent license is "discriminatory" if it does not include within
|
||||
the scope of its coverage, prohibits the exercise of, or is
|
||||
conditioned on the non-exercise of one or more of the rights that are
|
||||
specifically granted under this License. You may not convey a covered
|
||||
work if you are a party to an arrangement with a third party that is
|
||||
in the business of distributing software, under which you make payment
|
||||
to the third party based on the extent of your activity of conveying
|
||||
the work, and under which the third party grants, to any of the
|
||||
parties who would receive the covered work from you, a discriminatory
|
||||
patent license (a) in connection with copies of the covered work
|
||||
conveyed by you (or copies made from those copies), or (b) primarily
|
||||
for and in connection with specific products or compilations that
|
||||
contain the covered work, unless you entered into that arrangement,
|
||||
or that patent license was granted, prior to 28 March 2007.
|
||||
|
||||
Nothing in this License shall be construed as excluding or limiting
|
||||
any implied license or other defenses to infringement that may
|
||||
otherwise be available to you under applicable patent law.
|
||||
|
||||
12. No Surrender of Others' Freedom.
|
||||
|
||||
If conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot convey a
|
||||
covered work so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you may
|
||||
not convey it at all. For example, if you agree to terms that obligate you
|
||||
to collect a royalty for further conveying from those to whom you convey
|
||||
the Program, the only way you could satisfy both those terms and this
|
||||
License would be to refrain entirely from conveying the Program.
|
||||
|
||||
13. Use with the GNU Affero General Public License.
|
||||
|
||||
Notwithstanding any other provision of this License, you have
|
||||
permission to link or combine any covered work with a work licensed
|
||||
under version 3 of the GNU Affero General Public License into a single
|
||||
combined work, and to convey the resulting work. The terms of this
|
||||
License will continue to apply to the part which is the covered work,
|
||||
but the special requirements of the GNU Affero General Public License,
|
||||
section 13, concerning interaction through a network will apply to the
|
||||
combination as such.
|
||||
|
||||
14. Revised Versions of this License.
|
||||
|
||||
The Free Software Foundation may publish revised and/or new versions of
|
||||
the GNU General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the
|
||||
Program specifies that a certain numbered version of the GNU General
|
||||
Public License "or any later version" applies to it, you have the
|
||||
option of following the terms and conditions either of that numbered
|
||||
version or of any later version published by the Free Software
|
||||
Foundation. If the Program does not specify a version number of the
|
||||
GNU General Public License, you may choose any version ever published
|
||||
by the Free Software Foundation.
|
||||
|
||||
If the Program specifies that a proxy can decide which future
|
||||
versions of the GNU General Public License can be used, that proxy's
|
||||
public statement of acceptance of a version permanently authorizes you
|
||||
to choose that version for the Program.
|
||||
|
||||
Later license versions may give you additional or different
|
||||
permissions. However, no additional obligations are imposed on any
|
||||
author or copyright holder as a result of your choosing to follow a
|
||||
later version.
|
||||
|
||||
15. Disclaimer of Warranty.
|
||||
|
||||
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
|
||||
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
|
||||
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
|
||||
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
|
||||
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
|
||||
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
|
||||
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||
|
||||
16. Limitation of Liability.
|
||||
|
||||
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
|
||||
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
|
||||
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
|
||||
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
|
||||
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
|
||||
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
|
||||
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
|
||||
SUCH DAMAGES.
|
||||
|
||||
17. Interpretation of Sections 15 and 16.
|
||||
|
||||
If the disclaimer of warranty and limitation of liability provided
|
||||
above cannot be given local legal effect according to their terms,
|
||||
reviewing courts shall apply local law that most closely approximates
|
||||
an absolute waiver of all civil liability in connection with the
|
||||
Program, unless a warranty or assumption of liability accompanies a
|
||||
copy of the Program in return for a fee.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
state the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
{one line to give the program's name and a brief idea of what it does.}
|
||||
Copyright (C) {year} {name of author}
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program does terminal interaction, make it output a short
|
||||
notice like this when it starts in an interactive mode:
|
||||
|
||||
{project} Copyright (C) {year} {fullname}
|
||||
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, your program's commands
|
||||
might be different; for a GUI interface, you would use an "about box".
|
||||
|
||||
You should also get your employer (if you work as a programmer) or school,
|
||||
if any, to sign a "copyright disclaimer" for the program, if necessary.
|
||||
For more information on this, and how to apply and follow the GNU GPL, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
|
||||
The GNU General Public License does not permit incorporating your program
|
||||
into proprietary programs. If your program is a subroutine library, you
|
||||
may consider it more useful to permit linking proprietary applications with
|
||||
the library. If this is what you want to do, use the GNU Lesser General
|
||||
Public License instead of this License. But first, please read
|
||||
<http://www.gnu.org/philosophy/why-not-lgpl.html>.
|
1
ThirdParty/cqparts_bearings/LICENSE
vendored
Symbolic link
1
ThirdParty/cqparts_bearings/LICENSE
vendored
Symbolic link
|
@ -0,0 +1 @@
|
|||
../../LICENSE
|
58
ThirdParty/cqparts_bearings/README.rst
vendored
Normal file
58
ThirdParty/cqparts_bearings/README.rst
vendored
Normal file
|
@ -0,0 +1,58 @@
|
|||
=========================================
|
||||
`cqparts` Content Library : Bearings
|
||||
=========================================
|
||||
|
||||
Components
|
||||
-------------------------
|
||||
|
||||
* Ball Bearings
|
||||
* Tapered Roller Bearings
|
||||
|
||||
Examples
|
||||
-------------------------
|
||||
|
||||
`BallBearing`
|
||||
^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Create a ball bearing with::
|
||||
|
||||
from cqparts_bearings.ball import BallBearing
|
||||
|
||||
bearing = BallBearing(
|
||||
# outer edges
|
||||
inner_diam=8,
|
||||
outer_diam=20,
|
||||
width=5,
|
||||
|
||||
# internal rolling elements
|
||||
ball_count=6,
|
||||
ball_diam=4,
|
||||
)
|
||||
|
||||
# display [optional]
|
||||
from cqparts.display import display
|
||||
display(bearing)
|
||||
|
||||
# export model to file, various formats available [optional]
|
||||
bearing.exporter('gltf')('bearing.gltf')
|
||||
|
||||
.. image:: https://fragmuffin.github.io/cqparts/media/img/bearings/ball-example.png
|
||||
|
||||
All `BallBearing` parameters are documented
|
||||
`here <https://fragmuffin.github.io/cqparts/doc/api/cqparts_bearings.html#cqparts_bearings.ball.BallBearing>`_.
|
||||
|
||||
The bearing is generated in the following hierarchy:
|
||||
|
||||
::
|
||||
|
||||
>>> print(bearing.tree_str())
|
||||
<BallBearing: angle=0.0, ball_count=6, ball_diam=4.0, ball_min_gap=0.4, inner_diam=8.0, inner_width=2.0, outer_diam=20.0, outer_width=2.0, rolling_radius=7.0, tolerance=0.001, width=5.0>
|
||||
├○ inner_ring
|
||||
├○ outer_ring
|
||||
└─ rolling_elements
|
||||
├○ ball_000
|
||||
├○ ball_001
|
||||
├○ ball_002
|
||||
├○ ball_003
|
||||
├○ ball_004
|
||||
└○ ball_005
|
18
ThirdParty/cqparts_bearings/__init__.py
vendored
18
ThirdParty/cqparts_bearings/__init__.py
vendored
|
@ -1,3 +1,19 @@
|
|||
"""
|
||||
Copyright 2018 Peter Boin
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
"""
|
||||
|
||||
# =========================== Package Information ===========================
|
||||
# Version Planning:
|
||||
# 0.1.x - Development Status :: 2 - Pre-Alpha
|
||||
|
@ -15,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', 'bearings']
|
||||
|
||||
|
|
1
ThirdParty/cqparts_bearings/requirements.txt
vendored
Normal file
1
ThirdParty/cqparts_bearings/requirements.txt
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
cqparts
|
674
ThirdParty/cqparts_fasteners/LICENSE
vendored
674
ThirdParty/cqparts_fasteners/LICENSE
vendored
|
@ -1,674 +0,0 @@
|
|||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 3, 29 June 2007
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The GNU General Public License is a free, copyleft license for
|
||||
software and other kinds of works.
|
||||
|
||||
The licenses for most software and other practical works are designed
|
||||
to take away your freedom to share and change the works. By contrast,
|
||||
the GNU General Public License is intended to guarantee your freedom to
|
||||
share and change all versions of a program--to make sure it remains free
|
||||
software for all its users. We, the Free Software Foundation, use the
|
||||
GNU General Public License for most of our software; it applies also to
|
||||
any other work released this way by its authors. You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
them if you wish), that you receive source code or can get it if you
|
||||
want it, that you can change the software or use pieces of it in new
|
||||
free programs, and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to prevent others from denying you
|
||||
these rights or asking you to surrender the rights. Therefore, you have
|
||||
certain responsibilities if you distribute copies of the software, or if
|
||||
you modify it: responsibilities to respect the freedom of others.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must pass on to the recipients the same
|
||||
freedoms that you received. You must make sure that they, too, receive
|
||||
or can get the source code. And you must show them these terms so they
|
||||
know their rights.
|
||||
|
||||
Developers that use the GNU GPL protect your rights with two steps:
|
||||
(1) assert copyright on the software, and (2) offer you this License
|
||||
giving you legal permission to copy, distribute and/or modify it.
|
||||
|
||||
For the developers' and authors' protection, the GPL clearly explains
|
||||
that there is no warranty for this free software. For both users' and
|
||||
authors' sake, the GPL requires that modified versions be marked as
|
||||
changed, so that their problems will not be attributed erroneously to
|
||||
authors of previous versions.
|
||||
|
||||
Some devices are designed to deny users access to install or run
|
||||
modified versions of the software inside them, although the manufacturer
|
||||
can do so. This is fundamentally incompatible with the aim of
|
||||
protecting users' freedom to change the software. The systematic
|
||||
pattern of such abuse occurs in the area of products for individuals to
|
||||
use, which is precisely where it is most unacceptable. Therefore, we
|
||||
have designed this version of the GPL to prohibit the practice for those
|
||||
products. If such problems arise substantially in other domains, we
|
||||
stand ready to extend this provision to those domains in future versions
|
||||
of the GPL, as needed to protect the freedom of users.
|
||||
|
||||
Finally, every program is threatened constantly by software patents.
|
||||
States should not allow patents to restrict development and use of
|
||||
software on general-purpose computers, but in those that do, we wish to
|
||||
avoid the special danger that patents applied to a free program could
|
||||
make it effectively proprietary. To prevent this, the GPL assures that
|
||||
patents cannot be used to render the program non-free.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
TERMS AND CONDITIONS
|
||||
|
||||
0. Definitions.
|
||||
|
||||
"This License" refers to version 3 of the GNU General Public License.
|
||||
|
||||
"Copyright" also means copyright-like laws that apply to other kinds of
|
||||
works, such as semiconductor masks.
|
||||
|
||||
"The Program" refers to any copyrightable work licensed under this
|
||||
License. Each licensee is addressed as "you". "Licensees" and
|
||||
"recipients" may be individuals or organizations.
|
||||
|
||||
To "modify" a work means to copy from or adapt all or part of the work
|
||||
in a fashion requiring copyright permission, other than the making of an
|
||||
exact copy. The resulting work is called a "modified version" of the
|
||||
earlier work or a work "based on" the earlier work.
|
||||
|
||||
A "covered work" means either the unmodified Program or a work based
|
||||
on the Program.
|
||||
|
||||
To "propagate" a work means to do anything with it that, without
|
||||
permission, would make you directly or secondarily liable for
|
||||
infringement under applicable copyright law, except executing it on a
|
||||
computer or modifying a private copy. Propagation includes copying,
|
||||
distribution (with or without modification), making available to the
|
||||
public, and in some countries other activities as well.
|
||||
|
||||
To "convey" a work means any kind of propagation that enables other
|
||||
parties to make or receive copies. Mere interaction with a user through
|
||||
a computer network, with no transfer of a copy, is not conveying.
|
||||
|
||||
An interactive user interface displays "Appropriate Legal Notices"
|
||||
to the extent that it includes a convenient and prominently visible
|
||||
feature that (1) displays an appropriate copyright notice, and (2)
|
||||
tells the user that there is no warranty for the work (except to the
|
||||
extent that warranties are provided), that licensees may convey the
|
||||
work under this License, and how to view a copy of this License. If
|
||||
the interface presents a list of user commands or options, such as a
|
||||
menu, a prominent item in the list meets this criterion.
|
||||
|
||||
1. Source Code.
|
||||
|
||||
The "source code" for a work means the preferred form of the work
|
||||
for making modifications to it. "Object code" means any non-source
|
||||
form of a work.
|
||||
|
||||
A "Standard Interface" means an interface that either is an official
|
||||
standard defined by a recognized standards body, or, in the case of
|
||||
interfaces specified for a particular programming language, one that
|
||||
is widely used among developers working in that language.
|
||||
|
||||
The "System Libraries" of an executable work include anything, other
|
||||
than the work as a whole, that (a) is included in the normal form of
|
||||
packaging a Major Component, but which is not part of that Major
|
||||
Component, and (b) serves only to enable use of the work with that
|
||||
Major Component, or to implement a Standard Interface for which an
|
||||
implementation is available to the public in source code form. A
|
||||
"Major Component", in this context, means a major essential component
|
||||
(kernel, window system, and so on) of the specific operating system
|
||||
(if any) on which the executable work runs, or a compiler used to
|
||||
produce the work, or an object code interpreter used to run it.
|
||||
|
||||
The "Corresponding Source" for a work in object code form means all
|
||||
the source code needed to generate, install, and (for an executable
|
||||
work) run the object code and to modify the work, including scripts to
|
||||
control those activities. However, it does not include the work's
|
||||
System Libraries, or general-purpose tools or generally available free
|
||||
programs which are used unmodified in performing those activities but
|
||||
which are not part of the work. For example, Corresponding Source
|
||||
includes interface definition files associated with source files for
|
||||
the work, and the source code for shared libraries and dynamically
|
||||
linked subprograms that the work is specifically designed to require,
|
||||
such as by intimate data communication or control flow between those
|
||||
subprograms and other parts of the work.
|
||||
|
||||
The Corresponding Source need not include anything that users
|
||||
can regenerate automatically from other parts of the Corresponding
|
||||
Source.
|
||||
|
||||
The Corresponding Source for a work in source code form is that
|
||||
same work.
|
||||
|
||||
2. Basic Permissions.
|
||||
|
||||
All rights granted under this License are granted for the term of
|
||||
copyright on the Program, and are irrevocable provided the stated
|
||||
conditions are met. This License explicitly affirms your unlimited
|
||||
permission to run the unmodified Program. The output from running a
|
||||
covered work is covered by this License only if the output, given its
|
||||
content, constitutes a covered work. This License acknowledges your
|
||||
rights of fair use or other equivalent, as provided by copyright law.
|
||||
|
||||
You may make, run and propagate covered works that you do not
|
||||
convey, without conditions so long as your license otherwise remains
|
||||
in force. You may convey covered works to others for the sole purpose
|
||||
of having them make modifications exclusively for you, or provide you
|
||||
with facilities for running those works, provided that you comply with
|
||||
the terms of this License in conveying all material for which you do
|
||||
not control copyright. Those thus making or running the covered works
|
||||
for you must do so exclusively on your behalf, under your direction
|
||||
and control, on terms that prohibit them from making any copies of
|
||||
your copyrighted material outside their relationship with you.
|
||||
|
||||
Conveying under any other circumstances is permitted solely under
|
||||
the conditions stated below. Sublicensing is not allowed; section 10
|
||||
makes it unnecessary.
|
||||
|
||||
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
|
||||
|
||||
No covered work shall be deemed part of an effective technological
|
||||
measure under any applicable law fulfilling obligations under article
|
||||
11 of the WIPO copyright treaty adopted on 20 December 1996, or
|
||||
similar laws prohibiting or restricting circumvention of such
|
||||
measures.
|
||||
|
||||
When you convey a covered work, you waive any legal power to forbid
|
||||
circumvention of technological measures to the extent such circumvention
|
||||
is effected by exercising rights under this License with respect to
|
||||
the covered work, and you disclaim any intention to limit operation or
|
||||
modification of the work as a means of enforcing, against the work's
|
||||
users, your or third parties' legal rights to forbid circumvention of
|
||||
technological measures.
|
||||
|
||||
4. Conveying Verbatim Copies.
|
||||
|
||||
You may convey verbatim copies of the Program's source code as you
|
||||
receive it, in any medium, provided that you conspicuously and
|
||||
appropriately publish on each copy an appropriate copyright notice;
|
||||
keep intact all notices stating that this License and any
|
||||
non-permissive terms added in accord with section 7 apply to the code;
|
||||
keep intact all notices of the absence of any warranty; and give all
|
||||
recipients a copy of this License along with the Program.
|
||||
|
||||
You may charge any price or no price for each copy that you convey,
|
||||
and you may offer support or warranty protection for a fee.
|
||||
|
||||
5. Conveying Modified Source Versions.
|
||||
|
||||
You may convey a work based on the Program, or the modifications to
|
||||
produce it from the Program, in the form of source code under the
|
||||
terms of section 4, provided that you also meet all of these conditions:
|
||||
|
||||
a) The work must carry prominent notices stating that you modified
|
||||
it, and giving a relevant date.
|
||||
|
||||
b) The work must carry prominent notices stating that it is
|
||||
released under this License and any conditions added under section
|
||||
7. This requirement modifies the requirement in section 4 to
|
||||
"keep intact all notices".
|
||||
|
||||
c) You must license the entire work, as a whole, under this
|
||||
License to anyone who comes into possession of a copy. This
|
||||
License will therefore apply, along with any applicable section 7
|
||||
additional terms, to the whole of the work, and all its parts,
|
||||
regardless of how they are packaged. This License gives no
|
||||
permission to license the work in any other way, but it does not
|
||||
invalidate such permission if you have separately received it.
|
||||
|
||||
d) If the work has interactive user interfaces, each must display
|
||||
Appropriate Legal Notices; however, if the Program has interactive
|
||||
interfaces that do not display Appropriate Legal Notices, your
|
||||
work need not make them do so.
|
||||
|
||||
A compilation of a covered work with other separate and independent
|
||||
works, which are not by their nature extensions of the covered work,
|
||||
and which are not combined with it such as to form a larger program,
|
||||
in or on a volume of a storage or distribution medium, is called an
|
||||
"aggregate" if the compilation and its resulting copyright are not
|
||||
used to limit the access or legal rights of the compilation's users
|
||||
beyond what the individual works permit. Inclusion of a covered work
|
||||
in an aggregate does not cause this License to apply to the other
|
||||
parts of the aggregate.
|
||||
|
||||
6. Conveying Non-Source Forms.
|
||||
|
||||
You may convey a covered work in object code form under the terms
|
||||
of sections 4 and 5, provided that you also convey the
|
||||
machine-readable Corresponding Source under the terms of this License,
|
||||
in one of these ways:
|
||||
|
||||
a) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by the
|
||||
Corresponding Source fixed on a durable physical medium
|
||||
customarily used for software interchange.
|
||||
|
||||
b) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by a
|
||||
written offer, valid for at least three years and valid for as
|
||||
long as you offer spare parts or customer support for that product
|
||||
model, to give anyone who possesses the object code either (1) a
|
||||
copy of the Corresponding Source for all the software in the
|
||||
product that is covered by this License, on a durable physical
|
||||
medium customarily used for software interchange, for a price no
|
||||
more than your reasonable cost of physically performing this
|
||||
conveying of source, or (2) access to copy the
|
||||
Corresponding Source from a network server at no charge.
|
||||
|
||||
c) Convey individual copies of the object code with a copy of the
|
||||
written offer to provide the Corresponding Source. This
|
||||
alternative is allowed only occasionally and noncommercially, and
|
||||
only if you received the object code with such an offer, in accord
|
||||
with subsection 6b.
|
||||
|
||||
d) Convey the object code by offering access from a designated
|
||||
place (gratis or for a charge), and offer equivalent access to the
|
||||
Corresponding Source in the same way through the same place at no
|
||||
further charge. You need not require recipients to copy the
|
||||
Corresponding Source along with the object code. If the place to
|
||||
copy the object code is a network server, the Corresponding Source
|
||||
may be on a different server (operated by you or a third party)
|
||||
that supports equivalent copying facilities, provided you maintain
|
||||
clear directions next to the object code saying where to find the
|
||||
Corresponding Source. Regardless of what server hosts the
|
||||
Corresponding Source, you remain obligated to ensure that it is
|
||||
available for as long as needed to satisfy these requirements.
|
||||
|
||||
e) Convey the object code using peer-to-peer transmission, provided
|
||||
you inform other peers where the object code and Corresponding
|
||||
Source of the work are being offered to the general public at no
|
||||
charge under subsection 6d.
|
||||
|
||||
A separable portion of the object code, whose source code is excluded
|
||||
from the Corresponding Source as a System Library, need not be
|
||||
included in conveying the object code work.
|
||||
|
||||
A "User Product" is either (1) a "consumer product", which means any
|
||||
tangible personal property which is normally used for personal, family,
|
||||
or household purposes, or (2) anything designed or sold for incorporation
|
||||
into a dwelling. In determining whether a product is a consumer product,
|
||||
doubtful cases shall be resolved in favor of coverage. For a particular
|
||||
product received by a particular user, "normally used" refers to a
|
||||
typical or common use of that class of product, regardless of the status
|
||||
of the particular user or of the way in which the particular user
|
||||
actually uses, or expects or is expected to use, the product. A product
|
||||
is a consumer product regardless of whether the product has substantial
|
||||
commercial, industrial or non-consumer uses, unless such uses represent
|
||||
the only significant mode of use of the product.
|
||||
|
||||
"Installation Information" for a User Product means any methods,
|
||||
procedures, authorization keys, or other information required to install
|
||||
and execute modified versions of a covered work in that User Product from
|
||||
a modified version of its Corresponding Source. The information must
|
||||
suffice to ensure that the continued functioning of the modified object
|
||||
code is in no case prevented or interfered with solely because
|
||||
modification has been made.
|
||||
|
||||
If you convey an object code work under this section in, or with, or
|
||||
specifically for use in, a User Product, and the conveying occurs as
|
||||
part of a transaction in which the right of possession and use of the
|
||||
User Product is transferred to the recipient in perpetuity or for a
|
||||
fixed term (regardless of how the transaction is characterized), the
|
||||
Corresponding Source conveyed under this section must be accompanied
|
||||
by the Installation Information. But this requirement does not apply
|
||||
if neither you nor any third party retains the ability to install
|
||||
modified object code on the User Product (for example, the work has
|
||||
been installed in ROM).
|
||||
|
||||
The requirement to provide Installation Information does not include a
|
||||
requirement to continue to provide support service, warranty, or updates
|
||||
for a work that has been modified or installed by the recipient, or for
|
||||
the User Product in which it has been modified or installed. Access to a
|
||||
network may be denied when the modification itself materially and
|
||||
adversely affects the operation of the network or violates the rules and
|
||||
protocols for communication across the network.
|
||||
|
||||
Corresponding Source conveyed, and Installation Information provided,
|
||||
in accord with this section must be in a format that is publicly
|
||||
documented (and with an implementation available to the public in
|
||||
source code form), and must require no special password or key for
|
||||
unpacking, reading or copying.
|
||||
|
||||
7. Additional Terms.
|
||||
|
||||
"Additional permissions" are terms that supplement the terms of this
|
||||
License by making exceptions from one or more of its conditions.
|
||||
Additional permissions that are applicable to the entire Program shall
|
||||
be treated as though they were included in this License, to the extent
|
||||
that they are valid under applicable law. If additional permissions
|
||||
apply only to part of the Program, that part may be used separately
|
||||
under those permissions, but the entire Program remains governed by
|
||||
this License without regard to the additional permissions.
|
||||
|
||||
When you convey a copy of a covered work, you may at your option
|
||||
remove any additional permissions from that copy, or from any part of
|
||||
it. (Additional permissions may be written to require their own
|
||||
removal in certain cases when you modify the work.) You may place
|
||||
additional permissions on material, added by you to a covered work,
|
||||
for which you have or can give appropriate copyright permission.
|
||||
|
||||
Notwithstanding any other provision of this License, for material you
|
||||
add to a covered work, you may (if authorized by the copyright holders of
|
||||
that material) supplement the terms of this License with terms:
|
||||
|
||||
a) Disclaiming warranty or limiting liability differently from the
|
||||
terms of sections 15 and 16 of this License; or
|
||||
|
||||
b) Requiring preservation of specified reasonable legal notices or
|
||||
author attributions in that material or in the Appropriate Legal
|
||||
Notices displayed by works containing it; or
|
||||
|
||||
c) Prohibiting misrepresentation of the origin of that material, or
|
||||
requiring that modified versions of such material be marked in
|
||||
reasonable ways as different from the original version; or
|
||||
|
||||
d) Limiting the use for publicity purposes of names of licensors or
|
||||
authors of the material; or
|
||||
|
||||
e) Declining to grant rights under trademark law for use of some
|
||||
trade names, trademarks, or service marks; or
|
||||
|
||||
f) Requiring indemnification of licensors and authors of that
|
||||
material by anyone who conveys the material (or modified versions of
|
||||
it) with contractual assumptions of liability to the recipient, for
|
||||
any liability that these contractual assumptions directly impose on
|
||||
those licensors and authors.
|
||||
|
||||
All other non-permissive additional terms are considered "further
|
||||
restrictions" within the meaning of section 10. If the Program as you
|
||||
received it, or any part of it, contains a notice stating that it is
|
||||
governed by this License along with a term that is a further
|
||||
restriction, you may remove that term. If a license document contains
|
||||
a further restriction but permits relicensing or conveying under this
|
||||
License, you may add to a covered work material governed by the terms
|
||||
of that license document, provided that the further restriction does
|
||||
not survive such relicensing or conveying.
|
||||
|
||||
If you add terms to a covered work in accord with this section, you
|
||||
must place, in the relevant source files, a statement of the
|
||||
additional terms that apply to those files, or a notice indicating
|
||||
where to find the applicable terms.
|
||||
|
||||
Additional terms, permissive or non-permissive, may be stated in the
|
||||
form of a separately written license, or stated as exceptions;
|
||||
the above requirements apply either way.
|
||||
|
||||
8. Termination.
|
||||
|
||||
You may not propagate or modify a covered work except as expressly
|
||||
provided under this License. Any attempt otherwise to propagate or
|
||||
modify it is void, and will automatically terminate your rights under
|
||||
this License (including any patent licenses granted under the third
|
||||
paragraph of section 11).
|
||||
|
||||
However, if you cease all violation of this License, then your
|
||||
license from a particular copyright holder is reinstated (a)
|
||||
provisionally, unless and until the copyright holder explicitly and
|
||||
finally terminates your license, and (b) permanently, if the copyright
|
||||
holder fails to notify you of the violation by some reasonable means
|
||||
prior to 60 days after the cessation.
|
||||
|
||||
Moreover, your license from a particular copyright holder is
|
||||
reinstated permanently if the copyright holder notifies you of the
|
||||
violation by some reasonable means, this is the first time you have
|
||||
received notice of violation of this License (for any work) from that
|
||||
copyright holder, and you cure the violation prior to 30 days after
|
||||
your receipt of the notice.
|
||||
|
||||
Termination of your rights under this section does not terminate the
|
||||
licenses of parties who have received copies or rights from you under
|
||||
this License. If your rights have been terminated and not permanently
|
||||
reinstated, you do not qualify to receive new licenses for the same
|
||||
material under section 10.
|
||||
|
||||
9. Acceptance Not Required for Having Copies.
|
||||
|
||||
You are not required to accept this License in order to receive or
|
||||
run a copy of the Program. Ancillary propagation of a covered work
|
||||
occurring solely as a consequence of using peer-to-peer transmission
|
||||
to receive a copy likewise does not require acceptance. However,
|
||||
nothing other than this License grants you permission to propagate or
|
||||
modify any covered work. These actions infringe copyright if you do
|
||||
not accept this License. Therefore, by modifying or propagating a
|
||||
covered work, you indicate your acceptance of this License to do so.
|
||||
|
||||
10. Automatic Licensing of Downstream Recipients.
|
||||
|
||||
Each time you convey a covered work, the recipient automatically
|
||||
receives a license from the original licensors, to run, modify and
|
||||
propagate that work, subject to this License. You are not responsible
|
||||
for enforcing compliance by third parties with this License.
|
||||
|
||||
An "entity transaction" is a transaction transferring control of an
|
||||
organization, or substantially all assets of one, or subdividing an
|
||||
organization, or merging organizations. If propagation of a covered
|
||||
work results from an entity transaction, each party to that
|
||||
transaction who receives a copy of the work also receives whatever
|
||||
licenses to the work the party's predecessor in interest had or could
|
||||
give under the previous paragraph, plus a right to possession of the
|
||||
Corresponding Source of the work from the predecessor in interest, if
|
||||
the predecessor has it or can get it with reasonable efforts.
|
||||
|
||||
You may not impose any further restrictions on the exercise of the
|
||||
rights granted or affirmed under this License. For example, you may
|
||||
not impose a license fee, royalty, or other charge for exercise of
|
||||
rights granted under this License, and you may not initiate litigation
|
||||
(including a cross-claim or counterclaim in a lawsuit) alleging that
|
||||
any patent claim is infringed by making, using, selling, offering for
|
||||
sale, or importing the Program or any portion of it.
|
||||
|
||||
11. Patents.
|
||||
|
||||
A "contributor" is a copyright holder who authorizes use under this
|
||||
License of the Program or a work on which the Program is based. The
|
||||
work thus licensed is called the contributor's "contributor version".
|
||||
|
||||
A contributor's "essential patent claims" are all patent claims
|
||||
owned or controlled by the contributor, whether already acquired or
|
||||
hereafter acquired, that would be infringed by some manner, permitted
|
||||
by this License, of making, using, or selling its contributor version,
|
||||
but do not include claims that would be infringed only as a
|
||||
consequence of further modification of the contributor version. For
|
||||
purposes of this definition, "control" includes the right to grant
|
||||
patent sublicenses in a manner consistent with the requirements of
|
||||
this License.
|
||||
|
||||
Each contributor grants you a non-exclusive, worldwide, royalty-free
|
||||
patent license under the contributor's essential patent claims, to
|
||||
make, use, sell, offer for sale, import and otherwise run, modify and
|
||||
propagate the contents of its contributor version.
|
||||
|
||||
In the following three paragraphs, a "patent license" is any express
|
||||
agreement or commitment, however denominated, not to enforce a patent
|
||||
(such as an express permission to practice a patent or covenant not to
|
||||
sue for patent infringement). To "grant" such a patent license to a
|
||||
party means to make such an agreement or commitment not to enforce a
|
||||
patent against the party.
|
||||
|
||||
If you convey a covered work, knowingly relying on a patent license,
|
||||
and the Corresponding Source of the work is not available for anyone
|
||||
to copy, free of charge and under the terms of this License, through a
|
||||
publicly available network server or other readily accessible means,
|
||||
then you must either (1) cause the Corresponding Source to be so
|
||||
available, or (2) arrange to deprive yourself of the benefit of the
|
||||
patent license for this particular work, or (3) arrange, in a manner
|
||||
consistent with the requirements of this License, to extend the patent
|
||||
license to downstream recipients. "Knowingly relying" means you have
|
||||
actual knowledge that, but for the patent license, your conveying the
|
||||
covered work in a country, or your recipient's use of the covered work
|
||||
in a country, would infringe one or more identifiable patents in that
|
||||
country that you have reason to believe are valid.
|
||||
|
||||
If, pursuant to or in connection with a single transaction or
|
||||
arrangement, you convey, or propagate by procuring conveyance of, a
|
||||
covered work, and grant a patent license to some of the parties
|
||||
receiving the covered work authorizing them to use, propagate, modify
|
||||
or convey a specific copy of the covered work, then the patent license
|
||||
you grant is automatically extended to all recipients of the covered
|
||||
work and works based on it.
|
||||
|
||||
A patent license is "discriminatory" if it does not include within
|
||||
the scope of its coverage, prohibits the exercise of, or is
|
||||
conditioned on the non-exercise of one or more of the rights that are
|
||||
specifically granted under this License. You may not convey a covered
|
||||
work if you are a party to an arrangement with a third party that is
|
||||
in the business of distributing software, under which you make payment
|
||||
to the third party based on the extent of your activity of conveying
|
||||
the work, and under which the third party grants, to any of the
|
||||
parties who would receive the covered work from you, a discriminatory
|
||||
patent license (a) in connection with copies of the covered work
|
||||
conveyed by you (or copies made from those copies), or (b) primarily
|
||||
for and in connection with specific products or compilations that
|
||||
contain the covered work, unless you entered into that arrangement,
|
||||
or that patent license was granted, prior to 28 March 2007.
|
||||
|
||||
Nothing in this License shall be construed as excluding or limiting
|
||||
any implied license or other defenses to infringement that may
|
||||
otherwise be available to you under applicable patent law.
|
||||
|
||||
12. No Surrender of Others' Freedom.
|
||||
|
||||
If conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot convey a
|
||||
covered work so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you may
|
||||
not convey it at all. For example, if you agree to terms that obligate you
|
||||
to collect a royalty for further conveying from those to whom you convey
|
||||
the Program, the only way you could satisfy both those terms and this
|
||||
License would be to refrain entirely from conveying the Program.
|
||||
|
||||
13. Use with the GNU Affero General Public License.
|
||||
|
||||
Notwithstanding any other provision of this License, you have
|
||||
permission to link or combine any covered work with a work licensed
|
||||
under version 3 of the GNU Affero General Public License into a single
|
||||
combined work, and to convey the resulting work. The terms of this
|
||||
License will continue to apply to the part which is the covered work,
|
||||
but the special requirements of the GNU Affero General Public License,
|
||||
section 13, concerning interaction through a network will apply to the
|
||||
combination as such.
|
||||
|
||||
14. Revised Versions of this License.
|
||||
|
||||
The Free Software Foundation may publish revised and/or new versions of
|
||||
the GNU General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the
|
||||
Program specifies that a certain numbered version of the GNU General
|
||||
Public License "or any later version" applies to it, you have the
|
||||
option of following the terms and conditions either of that numbered
|
||||
version or of any later version published by the Free Software
|
||||
Foundation. If the Program does not specify a version number of the
|
||||
GNU General Public License, you may choose any version ever published
|
||||
by the Free Software Foundation.
|
||||
|
||||
If the Program specifies that a proxy can decide which future
|
||||
versions of the GNU General Public License can be used, that proxy's
|
||||
public statement of acceptance of a version permanently authorizes you
|
||||
to choose that version for the Program.
|
||||
|
||||
Later license versions may give you additional or different
|
||||
permissions. However, no additional obligations are imposed on any
|
||||
author or copyright holder as a result of your choosing to follow a
|
||||
later version.
|
||||
|
||||
15. Disclaimer of Warranty.
|
||||
|
||||
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
|
||||
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
|
||||
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
|
||||
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
|
||||
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
|
||||
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
|
||||
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||
|
||||
16. Limitation of Liability.
|
||||
|
||||
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
|
||||
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
|
||||
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
|
||||
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
|
||||
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
|
||||
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
|
||||
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
|
||||
SUCH DAMAGES.
|
||||
|
||||
17. Interpretation of Sections 15 and 16.
|
||||
|
||||
If the disclaimer of warranty and limitation of liability provided
|
||||
above cannot be given local legal effect according to their terms,
|
||||
reviewing courts shall apply local law that most closely approximates
|
||||
an absolute waiver of all civil liability in connection with the
|
||||
Program, unless a warranty or assumption of liability accompanies a
|
||||
copy of the Program in return for a fee.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
state the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
{one line to give the program's name and a brief idea of what it does.}
|
||||
Copyright (C) {year} {name of author}
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program does terminal interaction, make it output a short
|
||||
notice like this when it starts in an interactive mode:
|
||||
|
||||
{project} Copyright (C) {year} {fullname}
|
||||
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, your program's commands
|
||||
might be different; for a GUI interface, you would use an "about box".
|
||||
|
||||
You should also get your employer (if you work as a programmer) or school,
|
||||
if any, to sign a "copyright disclaimer" for the program, if necessary.
|
||||
For more information on this, and how to apply and follow the GNU GPL, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
|
||||
The GNU General Public License does not permit incorporating your program
|
||||
into proprietary programs. If your program is a subroutine library, you
|
||||
may consider it more useful to permit linking proprietary applications with
|
||||
the library. If this is what you want to do, use the GNU Lesser General
|
||||
Public License instead of this License. But first, please read
|
||||
<http://www.gnu.org/philosophy/why-not-lgpl.html>.
|
1
ThirdParty/cqparts_fasteners/LICENSE
vendored
Symbolic link
1
ThirdParty/cqparts_fasteners/LICENSE
vendored
Symbolic link
|
@ -0,0 +1 @@
|
|||
../../LICENSE
|
180
ThirdParty/cqparts_fasteners/README.rst
vendored
Normal file
180
ThirdParty/cqparts_fasteners/README.rst
vendored
Normal file
|
@ -0,0 +1,180 @@
|
|||
|
||||
=========================================
|
||||
`cqparts` Content Library : Fasteners
|
||||
=========================================
|
||||
|
||||
Components
|
||||
-------------------------
|
||||
|
||||
**Base Components**
|
||||
|
||||
Few of these are useful on their own, they're used to build more complex parts.
|
||||
|
||||
Heads
|
||||
^^^^^^^^^^^^^^^^^
|
||||
|
||||
* Counter-sunk varieties
|
||||
* Cylindrical varieties
|
||||
* Externally Driven (eg: hex head)
|
||||
|
||||
.. image:: https://fragmuffin.github.io/cqparts/media/img/fasteners/heads-assorted.png
|
||||
|
||||
Drive Types
|
||||
^^^^^^^^^^^^^^^^^
|
||||
|
||||
* Cruciform varieties (eg: phillips, frearson)
|
||||
* Hex (aka: alan) varieties
|
||||
* Square varieties (eg: single, double, triple square)
|
||||
* Slotted
|
||||
* Tamper Resistant varieties
|
||||
|
||||
.. image:: https://fragmuffin.github.io/cqparts/media/img/fasteners/drives-assorted.png
|
||||
|
||||
Threads
|
||||
^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Standard threads included:
|
||||
|
||||
* ISO68 (standard for metric bolts)
|
||||
* Triangular (eg: for woodscrews)
|
||||
* Ball Screw
|
||||
|
||||
.. image:: https://fragmuffin.github.io/cqparts/media/img/fasteners/threads-assorted.png
|
||||
|
||||
Any custom thread can be built by creating a *profile* as a ``Wire`` from within
|
||||
an object inheriting from the base ``Thread`` class.
|
||||
(`read more here <https://fragmuffin.github.io/cqparts/doc/api/cqparts_fasteners.solidtypes.threads.html?highlight=build_profile#cqparts_fasteners.solidtypes.threads.base.Thread>`_)
|
||||
|
||||
.. note::
|
||||
|
||||
Threads currently bugged by `issue #1 <https://github.com/fragmuffin/cqparts/issues/1>`_.
|
||||
|
||||
Threads are currently simplified to a cylinder until this is fixed.
|
||||
|
||||
Warning when using for 3d printing, threads will not form correctly until the
|
||||
bug is fixed... please ``+1`` the issue if you'd like to use properly formed
|
||||
threads.
|
||||
|
||||
Male Fastener Components
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
* Bolts
|
||||
* Screws
|
||||
|
||||
.. image:: https://fragmuffin.github.io/cqparts/media/img/fasteners/male-assorted.png
|
||||
|
||||
Female Fastener Components
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
* Nuts
|
||||
|
||||
.. image:: https://fragmuffin.github.io/cqparts/media/img/fasteners/female-assorted.png
|
||||
|
||||
Utilities
|
||||
-------------------------
|
||||
|
||||
The ``Fasteners`` utility assembly can be used to automatically apply fasteners
|
||||
to arbitrary materials.
|
||||
|
||||
|
||||
For example, with the following 2 detatched blocks:
|
||||
|
||||
.. image:: https://fragmuffin.github.io/cqparts/media/img/fasteners/fastener-detatched.png
|
||||
|
||||
A ``Fastener`` can be applied to these two blocks to hold them together in a
|
||||
variety of ways, with varied parameters, such as these 2 exmples:
|
||||
|
||||
.. image:: https://fragmuffin.github.io/cqparts/media/img/fasteners/fastener-assorted.png
|
||||
|
||||
More detailed examples of customizing a ``Fastener`` are
|
||||
`documented here <https://fragmuffin.github.io/cqparts/doc/cqparts_fasteners/>`_.
|
||||
|
||||
.. image:: https://fragmuffin.github.io/cqparts/media/img/fasteners/fastener-custom-assorted.png
|
||||
|
||||
|
||||
Catalogue(s)
|
||||
-------------------------
|
||||
|
||||
**BoltDepot**
|
||||
|
||||
`boltdepot.com <https://www.boltdepot.com/>`_ has an exceptional website for
|
||||
details of their products, enough to build 3d models accurate enough for most
|
||||
applications.
|
||||
|
||||
At this time, the catalogue you get with this library contains some of the
|
||||
products for `boltdepot.com <https://www.boltdepot.com/>`_ in the categories:
|
||||
|
||||
* Bolts : ``boltdepot-bolts.json``
|
||||
* Nuts : ``boltdepot-nuts.json``
|
||||
* Woodscrews : ``boltdepot-woodscrews.json``
|
||||
|
||||
**Other Suppliers**
|
||||
|
||||
With increased interest in this library I would like to see this list grow, but
|
||||
at this time, it's just the catalogues listed above.
|
||||
|
||||
|
||||
Examples
|
||||
-------------------------
|
||||
|
||||
Machine Screw
|
||||
^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
We can create a fastener with many tuned parameters, for this example we'll create
|
||||
an M3 machine screw, 4mm long, with a domed cheese head, and a 2mm hex drive::
|
||||
|
||||
from cqparts_fasteners.male import MaleFastenerPart
|
||||
|
||||
screw = MaleFastenerPart(
|
||||
head=('cheese', {
|
||||
'diameter': 4.5,
|
||||
'height': 1.5,
|
||||
'domed': True,
|
||||
'dome_ratio': 0.5,
|
||||
}),
|
||||
drive=('hex', {
|
||||
'depth': 1,
|
||||
'width': 2,
|
||||
}),
|
||||
thread=('iso68', {
|
||||
'diameter': 3, # M3
|
||||
}),
|
||||
length=4,
|
||||
)
|
||||
|
||||
from cqparts.display import display
|
||||
display(screw)
|
||||
|
||||
.. image:: https://fragmuffin.github.io/cqparts/media/img/fasteners/example-screw.png
|
||||
|
||||
Catalogue ``Bolt``
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
With use of a ``JSONCatalogue`` we can search for all fasteners within that
|
||||
catalogue that suit certain parameters, such as length, diameter, anything used
|
||||
as a parameter to build the part.
|
||||
|
||||
For this example, we'll explicitly define the product's ``id``, guarenteeing
|
||||
only one result is returned::
|
||||
|
||||
import os
|
||||
|
||||
from cqparts.catalogue import JSONCatalogue
|
||||
import cqparts_fasteners
|
||||
|
||||
catalogue_filename = os.path.join(
|
||||
os.path.dirname(cqparts_fasteners.__file__),
|
||||
'catalogue',
|
||||
'boltdepot-bolts.json',
|
||||
)
|
||||
catalogue = JSONCatalogue(catalogue_filename)
|
||||
item = catalogue.get_query()
|
||||
bolt = catalogue.get(item.id == '221')
|
||||
|
||||
from cqparts.display import display
|
||||
display(bolt)
|
||||
|
||||
This should generate an accurate model for BoltDepot's
|
||||
`product #221 <https://www.boltdepot.com/Product-Details.aspx?product=221>`_.
|
||||
|
||||
.. image:: https://fragmuffin.github.io/cqparts/media/img/fasteners/example-catalogue.png
|
18
ThirdParty/cqparts_fasteners/__init__.py
vendored
18
ThirdParty/cqparts_fasteners/__init__.py
vendored
|
@ -1,3 +1,19 @@
|
|||
"""
|
||||
Copyright 2018 Peter Boin
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
"""
|
||||
|
||||
# =========================== Package Information ===========================
|
||||
# Version Planning:
|
||||
# 0.1.x - Development Status :: 2 - Pre-Alpha
|
||||
|
@ -15,7 +31,7 @@ __url__ = 'https://github.com/fragmuffin/cqparts/tree/master/src/cqparts_fastene
|
|||
__author__ = 'Peter Boin'
|
||||
__email__ = 'peter.boin+cqparts@gmail.com'
|
||||
|
||||
__license__ = 'GPLv3'
|
||||
__license__ = 'Apache Public License 2.0'
|
||||
|
||||
__keywords__ = ['cadquery', 'cad', '3d', 'modeling', 'fasteners']
|
||||
__package_data__ = ['catalogue/*.json']
|
||||
|
|
6
ThirdParty/cqparts_fasteners/catalogue/scripts/.gitignore
vendored
Normal file
6
ThirdParty/cqparts_fasteners/catalogue/scripts/.gitignore
vendored
Normal file
|
@ -0,0 +1,6 @@
|
|||
# Ignore scrapers' intermediate files
|
||||
*.csv
|
||||
*.json
|
||||
|
||||
# libreoffice lock file (when opening generated csv files)
|
||||
.~lock.*
|
952
ThirdParty/cqparts_fasteners/catalogue/scripts/boltdepot.py
vendored
Executable file
952
ThirdParty/cqparts_fasteners/catalogue/scripts/boltdepot.py
vendored
Executable file
|
@ -0,0 +1,952 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
import os
|
||||
import sys
|
||||
import inspect
|
||||
import scrapy
|
||||
import scrapy.crawler
|
||||
import scrapy.exporters
|
||||
import re
|
||||
import argparse
|
||||
import logging
|
||||
import fnmatch
|
||||
import json
|
||||
import csv
|
||||
import itertools
|
||||
import six
|
||||
import progressbar
|
||||
|
||||
# cqparts
|
||||
import cqparts
|
||||
|
||||
# cqparts_fasteners
|
||||
import cqparts_fasteners
|
||||
import cqparts_fasteners.screws
|
||||
import cqparts_fasteners.bolts
|
||||
import cqparts_fasteners.nuts
|
||||
import cqparts_fasteners.solidtypes
|
||||
from cqparts_fasteners.solidtypes.fastener_heads import find as find_head
|
||||
from cqparts_fasteners.solidtypes.screw_drives import find as find_drive
|
||||
from cqparts_fasteners.solidtypes.threads import find as find_thread
|
||||
|
||||
# ---------- Constants ----------
|
||||
STORE_NAME = 'BoltDepot'
|
||||
STORE_URL = 'https://www.boltdepot.com'
|
||||
|
||||
|
||||
# ---------- Utilities ----------
|
||||
|
||||
def split_url(url):
|
||||
match = re.search(r'^(?P<base>.*)\?(?P<params>.*)$', url, flags=re.I)
|
||||
return (
|
||||
match.group('base'),
|
||||
{k: v for (k, v) in (p.split('=') for p in match.group('params').split('&'))}
|
||||
)
|
||||
|
||||
def join_url(base, params):
|
||||
return "{base}?{params}".format(
|
||||
base=base,
|
||||
params='&'.join('%s=%s' % (k, v) for (k, v) in params.items()),
|
||||
)
|
||||
|
||||
|
||||
def utf8encoded(d):
|
||||
return {k.encode('utf-8'): v.encode('utf-8') for (k, v) in d.items()}
|
||||
|
||||
|
||||
def us2mm(value):
|
||||
if isinstance(value, six.string_types):
|
||||
# valid string formats include:
|
||||
# 1-3/4", 1/2", -5/9", 17/64", 1", 0.34", .34", 6ft
|
||||
match = re.search(
|
||||
r'''^
|
||||
(?P<neg>-)?
|
||||
(?P<whole>(\d+)?(\.\d+)?)??
|
||||
-?
|
||||
((?P<numerator>\d+)/(?P<denominator>\d+))?
|
||||
\s*(?P<unit>("|ft))
|
||||
$''',
|
||||
value,
|
||||
flags=re.MULTILINE | re.VERBOSE,
|
||||
)
|
||||
# calculate value (as decimal quantity)
|
||||
value = float(match.group('whole') or 0) + (
|
||||
float(match.group('numerator') or 0) / \
|
||||
float(match.group('denominator') or 1)
|
||||
)
|
||||
if match.group('neg'):
|
||||
value *= -1
|
||||
|
||||
if match.group('unit') == 'ft':
|
||||
value *= 12
|
||||
|
||||
else:
|
||||
# numeric value given:
|
||||
# assumption: value given in inches
|
||||
pass
|
||||
|
||||
return value * 25.4
|
||||
|
||||
|
||||
def mm2mm(value):
|
||||
if isinstance(value, six.string_types):
|
||||
# valid string formats include:
|
||||
# 1mm, -4mm, -0.3mm, -.3mm, 1m
|
||||
match = re.search(r'^(?P<value>[\-0-9\.]+)\s*(?P<unit>(mm|m|))$', value.lower())
|
||||
value = float(match.group('value'))
|
||||
if match.group('unit') == 'm':
|
||||
value *= 1000
|
||||
return float(value)
|
||||
|
||||
|
||||
UNIT_FUNC_MAP = {
|
||||
'metric': mm2mm,
|
||||
'us': us2mm,
|
||||
}
|
||||
|
||||
def unit2mm(value, unit):
|
||||
unit = unit.strip().lower()
|
||||
if unit in UNIT_FUNC_MAP:
|
||||
return UNIT_FUNC_MAP[unit](value)
|
||||
else:
|
||||
raise ValueError("invalid unit: %r" % unit)
|
||||
|
||||
|
||||
|
||||
# ---------- Scraper Spiders ----------
|
||||
|
||||
class BoltDepotSpider(scrapy.Spider):
|
||||
prefix = '' # no prefix by default
|
||||
name = None # no name, should raise exception if not set
|
||||
|
||||
FEED_URI = "%(prefix)sscrape-%(name)s.json"
|
||||
|
||||
@classmethod
|
||||
def get_feed_uri(cls):
|
||||
return cls.FEED_URI % {k: getattr(cls, k) for k in dir(cls)}
|
||||
|
||||
@classmethod
|
||||
def get_data(cls):
|
||||
if not hasattr(cls, '_data'):
|
||||
with open(cls.get_feed_uri(), 'r') as fh:
|
||||
setattr(cls, '_data', json.load(fh))
|
||||
return cls._data
|
||||
|
||||
@classmethod
|
||||
def get_data_item(cls, key, criteria=lambda i: True, cast=lambda v: v):
|
||||
# utility function to get data out of a json dict list easily
|
||||
valid_data = []
|
||||
for item in cls.get_data():
|
||||
if criteria(item):
|
||||
try:
|
||||
valid_data.append(cast(item[key]))
|
||||
except AttributeError:
|
||||
raise ValueError("%r value %r invalid (cannot be cast)" % (key, item[key]))
|
||||
|
||||
assert len(valid_data) == 1, "%r" % valid_data
|
||||
return valid_data[0]
|
||||
|
||||
|
||||
class BoltDepotProductSpider(BoltDepotSpider):
|
||||
|
||||
# criteria added to every cqparts.catalogue.JSONCatalogue entry
|
||||
common_catalogue_criteria = {
|
||||
'store': STORE_NAME,
|
||||
'store_url': STORE_URL,
|
||||
}
|
||||
|
||||
def parse(self, response):
|
||||
# Look for : Product catalogue table
|
||||
product_catalogue = response.css('table.product-catalog-table')
|
||||
if product_catalogue:
|
||||
for catalogue_link in product_catalogue.css('li a'):
|
||||
next_page_url = catalogue_link.css('::attr("href")').extract_first()
|
||||
yield response.follow(next_page_url, self.parse)
|
||||
|
||||
# Look for : Product list table
|
||||
product_list = response.css('#product-list-table')
|
||||
if product_list:
|
||||
for product in product_list.css('td.cell-prod-no'):
|
||||
next_page_url = product.css('a::attr("href")').extract_first()
|
||||
yield response.follow(next_page_url, self.parse_product_detail)
|
||||
|
||||
def parse_product_detail(self, response):
|
||||
heading = response.css('#catalog-header-title h1::text').extract_first()
|
||||
print("Product: %s" % heading)
|
||||
sys.stdout.flush()
|
||||
|
||||
(url_base, url_params) = split_url(response.url)
|
||||
|
||||
# details table
|
||||
detail_table = response.css('#product-property-list')
|
||||
details = {}
|
||||
for row in detail_table.css('tr'):
|
||||
key = row.css('td.name span::text').extract_first()
|
||||
value = row.css('td.value span::text').extract_first()
|
||||
if key and value:
|
||||
(key, value) = (key.strip('\n\r\t '), value.strip('\n\r\t '))
|
||||
if key and value:
|
||||
details[key] = value
|
||||
|
||||
product_data = {
|
||||
'id': url_params['product'],
|
||||
'name': heading,
|
||||
'url': response.url,
|
||||
'details': details,
|
||||
}
|
||||
|
||||
# Image url
|
||||
image_url = response.css('.catalog-header-product-image::attr("src")').extract_first()
|
||||
if image_url:
|
||||
product_data.update({'image_url': image_url})
|
||||
|
||||
yield product_data
|
||||
|
||||
# --- cqparts catalogue building specific functions
|
||||
# These functions are kept with the spider as a means to encapsulate
|
||||
# component-specific logic.
|
||||
|
||||
@classmethod
|
||||
def add_to_catalogue(cls, data, catalogue):
|
||||
criteria = cls.item_criteria(data)
|
||||
criteria.update(cls.common_catalogue_criteria)
|
||||
criteria.update({'scraperclass': cls.__name__})
|
||||
catalogue.add(
|
||||
id=data['id'],
|
||||
obj=cls.build_component(data),
|
||||
criteria=criteria,
|
||||
_check_id=False,
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def item_criteria(cls, data):
|
||||
return {} # should be overridden
|
||||
|
||||
@classmethod
|
||||
def build_component(cls, data):
|
||||
from cqparts_misc.basic.primatives import Cube
|
||||
return Cube() # should be overridden
|
||||
|
||||
CATALOGUE_URI = "%(prefix)s%(name)s.json"
|
||||
CATALOGUE_CLASS = cqparts.catalogue.JSONCatalogue
|
||||
|
||||
@classmethod
|
||||
def get_catalogue_uri(cls):
|
||||
filename = cls.CATALOGUE_URI % {k: getattr(cls, k) for k in dir(cls)}
|
||||
return os.path.join('..', filename)
|
||||
|
||||
@classmethod
|
||||
def get_catalogue(cls, **kwargs):
|
||||
return cls.CATALOGUE_CLASS(cls.get_catalogue_uri(), **kwargs)
|
||||
|
||||
@classmethod
|
||||
def get_item_str(cls, data):
|
||||
return "[%(id)s] %(name)s" % data
|
||||
|
||||
|
||||
class WoodScrewSpider(BoltDepotProductSpider):
|
||||
name = 'woodscrews'
|
||||
start_urls = [
|
||||
'https://www.boltdepot.com/Wood_screws_Phillips_flat_head.aspx',
|
||||
'https://www.boltdepot.com/Wood_screws_Slotted_flat_head.aspx',
|
||||
]
|
||||
|
||||
@classmethod
|
||||
def item_criteria(cls, data):
|
||||
criteria = {
|
||||
'name': data['name'],
|
||||
'url': data['url'],
|
||||
}
|
||||
criteria_content = [ # (<key>, <header>), ...
|
||||
('units', 'Units:'),
|
||||
('diameter', 'Diameter:'),
|
||||
('material', 'Material:'),
|
||||
('plating', 'Plating:'),
|
||||
]
|
||||
for (key, header) in criteria_content:
|
||||
value = data['details'].get(header, None)
|
||||
if value is not None:
|
||||
criteria[key] = value.lower()
|
||||
return criteria
|
||||
|
||||
@classmethod
|
||||
def build_component(cls, data):
|
||||
details = data['details']
|
||||
|
||||
# --- Head
|
||||
head = None
|
||||
if details['Head style:'] == 'Flat': # countersunk
|
||||
head_diam = ( # averaged min/max
|
||||
unit2mm(details['Head diameter Min:'], details['Units:']) + \
|
||||
unit2mm(details['Head diameter Max:'], details['Units:'])
|
||||
) / 2
|
||||
|
||||
head = find_head(name='countersunk')(
|
||||
diameter=head_diam,
|
||||
bugle=False,
|
||||
raised=0,
|
||||
# TODO: details['Head angle:'] usually 82deg
|
||||
)
|
||||
|
||||
else:
|
||||
raise ValueError("head style %r not supported" % details['Head style:'])
|
||||
|
||||
# --- Drive
|
||||
drive = None
|
||||
if details['Drive type:'] == 'Phillips':
|
||||
# FIXME: use actual drive sizes from DataPhillipsDriveSizes to shape
|
||||
drive = find_drive(name='phillips')(
|
||||
diameter=head_diam * 0.6
|
||||
)
|
||||
|
||||
elif details['Drive type:'] == 'Slotted':
|
||||
drive = find_drive(name='slot')(
|
||||
diameter=head_diam,
|
||||
)
|
||||
|
||||
else:
|
||||
raise ValueError("drive type %r not supported" % details['Drive type:'])
|
||||
|
||||
# --- Thread
|
||||
# Accuracy is Questionable:
|
||||
# Exact screw thread specs are very difficult to find, so some
|
||||
# of this is simply observed from screws I've salvaged / bought.
|
||||
thread_diam = DataWoodScrewDiam.get_data_item(
|
||||
'Decimal',
|
||||
criteria=lambda i: i['Size'] == details['Diameter:'],
|
||||
cast=lambda v: unit2mm(v, 'us'),
|
||||
)
|
||||
|
||||
thread = find_thread(name='triangular')(
|
||||
diameter=thread_diam,
|
||||
pitch=thread_diam * 0.6,
|
||||
)
|
||||
|
||||
# --- Build screw
|
||||
screw_length = unit2mm(details['Length:'], details['Units:'])
|
||||
screw = cqparts_fasteners.screws.Screw(
|
||||
drive=drive,
|
||||
head=head,
|
||||
thread=thread,
|
||||
|
||||
length=screw_length,
|
||||
neck_length=screw_length * 0.25,
|
||||
tip_length=1.5 * thread_diam,
|
||||
)
|
||||
|
||||
return screw
|
||||
|
||||
|
||||
class BoltSpider(BoltDepotProductSpider):
|
||||
name = 'bolts'
|
||||
start_urls = [
|
||||
'https://www.boltdepot.com/Hex_bolts_2.aspx',
|
||||
'https://www.boltdepot.com/Metric_hex_bolts_2.aspx',
|
||||
]
|
||||
|
||||
@classmethod
|
||||
def item_criteria(cls, data):
|
||||
criteria = {
|
||||
'name': data['name'],
|
||||
'url': data['url'],
|
||||
}
|
||||
criteria_content = [ # (<key>, <header>), ...
|
||||
('units', 'Units:'),
|
||||
('diameter', 'Diameter:'),
|
||||
('material', 'Material:'),
|
||||
('plating', 'Plating:'),
|
||||
('finish', 'Finish:'),
|
||||
('color', 'Color:'),
|
||||
]
|
||||
for (key, header) in criteria_content:
|
||||
value = data['details'].get(header, None)
|
||||
if value is not None:
|
||||
criteria[key] = value.lower()
|
||||
return criteria
|
||||
|
||||
@classmethod
|
||||
def build_component(cls, data):
|
||||
details = data['details']
|
||||
|
||||
# --- Thread
|
||||
thread = None
|
||||
thread_diam = unit2mm(details['Diameter:'], details['Units:'])
|
||||
if details['Units:'].lower() == 'us':
|
||||
thread_pitch = unit2mm(1, 'us') / int(details['Thread count:'])
|
||||
elif details['Units:'].lower() == 'metric':
|
||||
thread_pitch = unit2mm(details['Thread pitch:'], details['Units:'])
|
||||
|
||||
# ISO 68 thread: not accurate for imperial bolts, but close enough
|
||||
# FIXME: imperial threads?
|
||||
thread = find_thread(name='iso68')(
|
||||
diameter=thread_diam,
|
||||
pitch=thread_pitch,
|
||||
lefthand=details['Thread direction:'] == 'Left hand',
|
||||
)
|
||||
|
||||
# --- Head
|
||||
head = None
|
||||
if details['Head style:'].lower() == 'hex': # countersunk
|
||||
|
||||
# Width Across Flats
|
||||
try:
|
||||
if details['Units:'].lower() == 'us':
|
||||
across_flats = DataUSBoltHeadSize.get_data_item(
|
||||
'Hex Bolt - Lag Bolt - Square Bolt',
|
||||
criteria=lambda i: i['Bolt Diameter'] == details['Diameter:'],
|
||||
cast=lambda v: DataUSBoltHeadSize.unit_cast(v),
|
||||
)
|
||||
elif details['Units:'].lower() == 'metric':
|
||||
try:
|
||||
across_flats = DataMetricBoltHeadSize.get_data_item(
|
||||
'ANSI/ISO',
|
||||
criteria=lambda i: i['Bolt Diameter (mm)'] == ("%g" % unit2mm(details['Diameter:'], 'metric')),
|
||||
cast=lambda v: unit2mm(v, 'metric'),
|
||||
)
|
||||
except (ValueError, AttributeError):
|
||||
# assumption: 'ANSI/ISO' field is non-numeirc, use 'DIN' instead
|
||||
across_flats = DataMetricBoltHeadSize.get_data_item(
|
||||
'DIN',
|
||||
criteria=lambda i: i['Bolt Diameter (mm)'] == ("%g" % unit2mm(details['Diameter:'], 'metric')),
|
||||
cast=lambda v: unit2mm(v, 'metric'),
|
||||
)
|
||||
else:
|
||||
raise ValueError('unsupported units %r' % details['Units:'])
|
||||
except (AssertionError, AttributeError):
|
||||
# assumption: table lookup unsuccessful, see if it's explicitly specified
|
||||
across_flats = unit2mm(details['Width across the flats:'], details['Units:'])
|
||||
# raises KeyError if 'Width across the flats:' is not specified
|
||||
|
||||
# Head Height
|
||||
head_height = 0.63 * thread_diam # average height of all bolts with a defined head height
|
||||
|
||||
head = find_head(name='hex')(
|
||||
width=across_flats,
|
||||
height=head_height,
|
||||
washer=False,
|
||||
# TODO: details['Head angle:'] usually 82deg
|
||||
)
|
||||
|
||||
else:
|
||||
raise ValueError("head style %r not supported" % details['Head style:'])
|
||||
|
||||
# --- Build bolt
|
||||
length = unit2mm(details['Length:'], details['Units:'])
|
||||
|
||||
# Neck & Thread length
|
||||
neck_len = None
|
||||
try:
|
||||
neck_len = unit2mm(details['Body length Min:'], details['Units:'])
|
||||
except KeyError:
|
||||
pass # 'Body length Min:' not specified
|
||||
|
||||
thread_len = length
|
||||
try:
|
||||
thread_len = unit2mm(details['Thread length Min:'], details['Units:'])
|
||||
if neck_len is None:
|
||||
neck_len = length - thread_len
|
||||
else:
|
||||
neck_len = (neck_len + (length - thread_len)) / 2
|
||||
except KeyError:
|
||||
if neck_len is None:
|
||||
neck_len = 0
|
||||
|
||||
bolt = cqparts_fasteners.bolts.Bolt(
|
||||
head=head,
|
||||
thread=thread,
|
||||
|
||||
length=length,
|
||||
neck_length=neck_len,
|
||||
)
|
||||
|
||||
return bolt
|
||||
|
||||
|
||||
class NutSpider(BoltDepotProductSpider):
|
||||
name = 'nuts'
|
||||
start_urls = [
|
||||
'https://www.boltdepot.com/Hex_nuts.aspx',
|
||||
'https://www.boltdepot.com/Square_nuts.aspx',
|
||||
'https://www.boltdepot.com/Metric_hex_nuts.aspx',
|
||||
]
|
||||
|
||||
@classmethod
|
||||
def item_criteria(cls, data):
|
||||
criteria = {
|
||||
'name': data['name'],
|
||||
'url': data['url'],
|
||||
}
|
||||
criteria_content = [ # (<key>, <header>), ...
|
||||
('units', 'Units:'),
|
||||
('diameter', 'Diameter:'),
|
||||
('material', 'Material:'),
|
||||
('plating', 'Plating:'),
|
||||
('finish', 'Finish:'),
|
||||
('color', 'Color:'),
|
||||
]
|
||||
for (key, header) in criteria_content:
|
||||
value = data['details'].get(header, None)
|
||||
if value is not None:
|
||||
criteria[key] = value.lower()
|
||||
return criteria
|
||||
|
||||
@classmethod
|
||||
def build_component(cls, data):
|
||||
details = data['details']
|
||||
|
||||
# --- Thread
|
||||
thread = None
|
||||
# diameter
|
||||
try:
|
||||
thread_diam = unit2mm(details['Diameter:'], details['Units:'])
|
||||
except AttributeError: # assumption: non-numeric diameter
|
||||
if details['Units:'] == 'US':
|
||||
thread_diam = DataUSThreadSize.get_data_item(
|
||||
'Decimal',
|
||||
criteria=lambda i: i['Size'] == details['Diameter:'],
|
||||
cast=lambda v: unit2mm(v, 'us'),
|
||||
)
|
||||
else:
|
||||
raise
|
||||
|
||||
# pitch
|
||||
if details['Units:'].lower() == 'us':
|
||||
thread_pitch = unit2mm(1, 'us') / int(details['Thread count:'])
|
||||
elif details['Units:'].lower() == 'metric':
|
||||
thread_pitch = unit2mm(details['Thread pitch:'], details['Units:'])
|
||||
|
||||
# ISO 68 thread: not accurate for imperial bolts, but close enough
|
||||
# FIXME: imperial threads?
|
||||
thread = find_thread(name='iso68')(
|
||||
diameter=thread_diam,
|
||||
pitch=thread_pitch,
|
||||
lefthand=details['Thread direction:'] == 'Left hand',
|
||||
inner=True,
|
||||
)
|
||||
|
||||
# --- build nut
|
||||
try:
|
||||
nut_width = unit2mm(details['Width across the flats:'], details['Units:'])
|
||||
except KeyError: # assumption: 'Width across the flats:' not supplied
|
||||
if details['Units:'] == 'US':
|
||||
try:
|
||||
nut_width = DataUSNutSize.get_data_item(
|
||||
'Diameter*:Hex Nut',
|
||||
criteria=lambda i: i['Size:Size'] == details['Diameter:'],
|
||||
cast=lambda v: unit2mm(v, 'us'),
|
||||
)
|
||||
except ValueError:
|
||||
nut_width = DataUSNutSize.get_data_item(
|
||||
'Diameter*:Machine Screw Nut', # only use if 'Hex Nut' not avaliable
|
||||
criteria=lambda i: i['Size:Size'] == details['Diameter:'],
|
||||
cast=lambda v: unit2mm(v, 'us'),
|
||||
)
|
||||
else:
|
||||
raise
|
||||
|
||||
# height
|
||||
try:
|
||||
nut_height = unit2mm(details['Height:'], details['Units:'])
|
||||
except KeyError: # assumption: 'Height:' not specified
|
||||
if details['Units:'] == 'US':
|
||||
try:
|
||||
nut_height = DataUSNutSize.get_data_item(
|
||||
'Height:Hex Nut',
|
||||
criteria=lambda i: i['Size:Size'] == details['Diameter:'],
|
||||
cast=lambda v: unit2mm(v, 'us'),
|
||||
)
|
||||
except ValueError:
|
||||
nut_height = DataUSNutSize.get_data_item(
|
||||
'Height:Machine Screw Nut', # only use if 'Hex Nut' not avaliable
|
||||
criteria=lambda i: i['Size:Size'] == details['Diameter:'],
|
||||
cast=lambda v: unit2mm(v, 'us'),
|
||||
)
|
||||
else:
|
||||
raise
|
||||
|
||||
if details['Subcategory:'] == 'Hex nuts':
|
||||
nut_class = cqparts_fasteners.nuts.HexNut
|
||||
elif details['Subcategory:'] == 'Square nuts':
|
||||
nut_class = cqparts_fasteners.nuts.SquareNut
|
||||
else:
|
||||
raise ValueError("unsupported nut class %r" % details['Subcategory:'])
|
||||
|
||||
nut = nut_class(
|
||||
thread=thread,
|
||||
width=nut_width,
|
||||
height=nut_height,
|
||||
washer=False,
|
||||
)
|
||||
|
||||
return nut
|
||||
|
||||
|
||||
SPIDERS = [
|
||||
WoodScrewSpider,
|
||||
BoltSpider,
|
||||
NutSpider,
|
||||
]
|
||||
SPIDER_MAP = {
|
||||
cls.name: cls
|
||||
for cls in SPIDERS
|
||||
}
|
||||
|
||||
|
||||
class GrowingList(list):
|
||||
"""
|
||||
A list that will automatically expand if indexed beyond its limit.
|
||||
(the list equivalent of collections.defaultdict)
|
||||
"""
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
self._default_type = kwargs.pop('default_type', lambda: None)
|
||||
super(GrowingList, self).__init__(*args, **kwargs)
|
||||
|
||||
def __getitem__(self, index):
|
||||
if index >= len(self):
|
||||
self.extend([self._default_type() for i in range(index + 1 - len(self))])
|
||||
return super(GrowingList, self).__getitem__(index)
|
||||
|
||||
def __setitem__(self, index, value):
|
||||
if index >= len(self):
|
||||
self.extend([self._default_type() for i in range(index + 1 - len(self))])
|
||||
super(GrowingList, self).__setitem__(index, value)
|
||||
|
||||
|
||||
class BoltDepotDataSpider(BoltDepotSpider):
|
||||
|
||||
# set to True if the last header row does not uniquely identify each column
|
||||
merge_headers = False
|
||||
|
||||
@staticmethod
|
||||
def table_data(table):
|
||||
# Pull data out of a table into a 2d list.
|
||||
# Merged Cells:
|
||||
# any merged cells (using rowspan / colspan) will have duplicate
|
||||
# data over each cell.
|
||||
# "merging cells does not a database make" said me, just now
|
||||
|
||||
def push_data(row, i, val):
|
||||
# push data into next available slot in the given list
|
||||
# return the index used (will be >= i)
|
||||
assert isinstance(row, GrowingList), "%r" % row
|
||||
assert val is not None
|
||||
try:
|
||||
while row[i] is not None:
|
||||
i += 1
|
||||
except IndexError:
|
||||
pass
|
||||
row[i] = val
|
||||
return i
|
||||
|
||||
data = GrowingList(default_type=GrowingList) # nested growing list
|
||||
header_count = 0
|
||||
for (i, row) in enumerate(table.css('tr')):
|
||||
j = 0
|
||||
is_header_row = True
|
||||
for cell in row.css('th, td'):
|
||||
# cell data
|
||||
value = ' '.join([v.strip() for v in cell.css('::text').extract()])
|
||||
if value is None:
|
||||
value = ''
|
||||
value = value.rstrip('\r\n\t ')
|
||||
rowspan = int(cell.css('::attr("rowspan")').extract_first() or 1)
|
||||
colspan = int(cell.css('::attr("colspan")').extract_first() or 1)
|
||||
# is header row?
|
||||
if cell.root.tag != 'th':
|
||||
is_header_row = False
|
||||
# populate data (duplicate merged content)
|
||||
j = push_data(data[i], j, value)
|
||||
for di in range(rowspan):
|
||||
for dj in range(colspan):
|
||||
data[i + di][j + dj] = value
|
||||
j += 1
|
||||
if is_header_row:
|
||||
header_count += 1
|
||||
|
||||
return (data, header_count)
|
||||
|
||||
def parse(self, response):
|
||||
table = response.css('table.fastener-info-table')
|
||||
(data, header_count) = self.table_data(table)
|
||||
|
||||
if self.merge_headers:
|
||||
header = [ # join all headers per column
|
||||
':'.join(data[i][j] for i in range(header_count))
|
||||
for j in range(len(data[0]))
|
||||
]
|
||||
else:
|
||||
header = data[header_count - 1] # last header row
|
||||
for row in data[header_count:]:
|
||||
row_data = dict(zip(header, row))
|
||||
if any(v for v in row_data.values()):
|
||||
# don't yield if there's no data
|
||||
yield row_data
|
||||
|
||||
|
||||
class DataWoodScrewDiam(BoltDepotDataSpider):
|
||||
name = 'd-woodscrew-diam'
|
||||
start_urls = [
|
||||
'https://www.boltdepot.com/fastener-information/Wood-Screws/Wood-Screw-Diameter.aspx',
|
||||
]
|
||||
|
||||
class DataUSBoltThreadLen(BoltDepotDataSpider):
|
||||
name = 'd-us-bolt-thread-len'
|
||||
start_urls = [
|
||||
'https://www.boltdepot.com/fastener-information/Bolts/US-Thread-Length.aspx',
|
||||
]
|
||||
|
||||
class DataUSThreadPerInch(BoltDepotDataSpider):
|
||||
name = 'd-us-tpi'
|
||||
start_urls = [
|
||||
'https://www.boltdepot.com/fastener-information/Measuring/US-TPI.aspx',
|
||||
]
|
||||
|
||||
class DataUSBoltHeadSize(BoltDepotDataSpider):
|
||||
name = 'd-us-boltheadsize'
|
||||
start_urls = [
|
||||
'https://www.boltdepot.com/fastener-information/Bolts/US-Bolt-Head-Size.aspx',
|
||||
]
|
||||
|
||||
@staticmethod
|
||||
def unit_cast(value):
|
||||
# special case for the '7/16" or 3/8"' cell
|
||||
return unit2mm(re.split('\s*or\s*', value)[-1], 'us') # last value
|
||||
|
||||
class DataUSNutSize(BoltDepotDataSpider):
|
||||
name = 'd-us-nutsize'
|
||||
start_urls = [
|
||||
'https://www.boltdepot.com/fastener-information/Nuts-Washers/US-Nut-Dimensions.aspx',
|
||||
]
|
||||
merge_headers = True # header 'Hex Nut' is repeated
|
||||
|
||||
class DataUSThreadSize(BoltDepotDataSpider):
|
||||
name = 'd-us-threadsize'
|
||||
start_urls = [
|
||||
'https://www.boltdepot.com/fastener-information/Machine-Screws/Machine-Screw-Diameter.aspx',
|
||||
]
|
||||
|
||||
class DataMetricThreadPitch(BoltDepotDataSpider):
|
||||
name = 'd-met-threadpitch'
|
||||
start_urls = [
|
||||
'https://www.boltdepot.com/fastener-information/Measuring/Metric-Thread-Pitch.aspx',
|
||||
]
|
||||
|
||||
class DataMetricBoltHeadSize(BoltDepotDataSpider):
|
||||
name = 'd-met-boltheadsize'
|
||||
start_urls = [
|
||||
'https://www.boltdepot.com/fastener-information/Bolts/Metric-Bolt-Head-Size.aspx',
|
||||
]
|
||||
|
||||
class DataPhillipsDriveSizes(BoltDepotDataSpider):
|
||||
name = 'd-drivesizes-phillips'
|
||||
start_urls = [
|
||||
'https://www.boltdepot.com/fastener-information/Driver-Bits/Phillips-Driver-Sizes.aspx',
|
||||
]
|
||||
|
||||
|
||||
METRICS_SPIDERS = [
|
||||
DataWoodScrewDiam,
|
||||
DataUSBoltThreadLen,
|
||||
DataUSThreadPerInch,
|
||||
DataUSBoltHeadSize,
|
||||
DataUSNutSize,
|
||||
DataUSThreadSize,
|
||||
DataMetricThreadPitch,
|
||||
DataMetricBoltHeadSize,
|
||||
DataPhillipsDriveSizes,
|
||||
]
|
||||
|
||||
# ---------- Command-line Arguments Parser ----------
|
||||
DEFAULT_PREFIX = os.path.splitext(os.path.basename(
|
||||
os.path.abspath(inspect.getfile(inspect.currentframe()))
|
||||
))[0] + '-'
|
||||
|
||||
parser = argparse.ArgumentParser(
|
||||
description='Build Bolt Depot catalogue by crawling their website',
|
||||
epilog="""
|
||||
Actions:
|
||||
scrape scrape product details from website
|
||||
csv convert scraped output to csv [optional]
|
||||
build builds catalogue from scraped data
|
||||
all (run all above actions)
|
||||
|
||||
Note: Actions will always be performed in the order shown above,
|
||||
even if they're not listed in that order on commandline.
|
||||
""",
|
||||
formatter_class=argparse.RawTextHelpFormatter,
|
||||
)
|
||||
|
||||
VALID_ACTIONS = set(['scrape', 'csv', 'build', 'all'])
|
||||
def action_type(value):
|
||||
value = value.lower()
|
||||
if value not in VALID_ACTIONS:
|
||||
raise argparse.ArgumentError()
|
||||
return value
|
||||
|
||||
parser.add_argument(
|
||||
'actions', metavar='action', type=action_type, nargs='*',
|
||||
help='action(s) to perform'
|
||||
)
|
||||
|
||||
# Scraper arguments
|
||||
parser.add_argument(
|
||||
'--prefix', '-p', dest='prefix', default=DEFAULT_PREFIX,
|
||||
help="scraper file prefix (default: '%s')" % DEFAULT_PREFIX,
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
'--onlymetrics', '-om', dest='onlymetrics',
|
||||
action='store_const', const=True, default=False,
|
||||
help="if set, when scraping, only metrics data is scraped"
|
||||
)
|
||||
|
||||
# Catalogues
|
||||
parser.add_argument(
|
||||
'--list', '-l', dest='list',
|
||||
default=False, action='store_const', const=True,
|
||||
help="list catalogues to build",
|
||||
)
|
||||
|
||||
def catalogues_list_type(value):
|
||||
catalogues_all = set(SPIDER_MAP.keys())
|
||||
catalogues = set()
|
||||
for filter_str in value.split(','):
|
||||
catalogues |= set(fnmatch.filter(catalogues_all, filter_str))
|
||||
return sorted(catalogues)
|
||||
|
||||
parser.add_argument(
|
||||
'--catalogues', '-c', dest='catalogues',
|
||||
type=catalogues_list_type, default=catalogues_list_type('*'),
|
||||
help="csv list of catalogues to act on",
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
'--strict', '-s', dest='strict',
|
||||
default=False, action='store_const', const=True,
|
||||
help="if set, exceptions during a build stop progress",
|
||||
)
|
||||
|
||||
args = parser.parse_args()
|
||||
args.actions = set(args.actions) # convert to set
|
||||
|
||||
BoltDepotSpider.prefix = args.prefix
|
||||
|
||||
|
||||
# list catalogues & exit
|
||||
if args.list:
|
||||
print("Catalogues:")
|
||||
for name in args.catalogues:
|
||||
print(" - %s" % name)
|
||||
exit(0)
|
||||
|
||||
# no actions, print help & exit
|
||||
if not args.actions:
|
||||
parser.print_help()
|
||||
exit(1)
|
||||
|
||||
|
||||
# ----- Start Crawl -----
|
||||
|
||||
if {'all', 'scrape'} & args.actions:
|
||||
print("----- Scrape: %s (+ metrics)" % (', '.join(args.catalogues)))
|
||||
sys.stdout.flush()
|
||||
|
||||
# --- Clear feed files
|
||||
feed_names = []
|
||||
if not args.onlymetrics:
|
||||
feed_names += args.catalogues
|
||||
feed_names += [cls.name for cls in METRICS_SPIDERS]
|
||||
|
||||
for name in feed_names:
|
||||
feed_filename = BoltDepotSpider.FEED_URI % {
|
||||
'prefix': args.prefix, 'name': name,
|
||||
}
|
||||
if os.path.exists(feed_filename):
|
||||
os.unlink(feed_filename) # remove feed file to populate from scratch
|
||||
|
||||
|
||||
# --- Create Crawlers
|
||||
process = scrapy.crawler.CrawlerProcess(
|
||||
settings={
|
||||
'LOG_LEVEL': logging.INFO,
|
||||
'FEED_FORMAT': "json",
|
||||
'FEED_URI': BoltDepotSpider.FEED_URI,
|
||||
},
|
||||
)
|
||||
|
||||
# product crawlers
|
||||
if not args.onlymetrics:
|
||||
for name in args.catalogues:
|
||||
process.crawl(SPIDER_MAP[name])
|
||||
# metrics crawlers
|
||||
for metrics_spider in METRICS_SPIDERS:
|
||||
process.crawl(metrics_spider)
|
||||
|
||||
# --- Start Scraping
|
||||
process.start()
|
||||
|
||||
|
||||
# ----- Convert to CSV -----
|
||||
# Conversion of json files to csv is optional, csv's are easy to open
|
||||
# in a 3rd party application to visualise the data that was scraped.
|
||||
|
||||
if {'all', 'csv'} & args.actions:
|
||||
|
||||
def flatten_dict(dict_in):
|
||||
# flatten nested dicts using '.' separated keys
|
||||
def inner(d, key_prefix=''):
|
||||
for (k, v) in d.items():
|
||||
if isinstance(v, dict):
|
||||
for (k1, v1) in inner(v, k + '.'):
|
||||
yield (k1, v1)
|
||||
else:
|
||||
yield (key_prefix + k, v)
|
||||
|
||||
return dict(inner(dict_in))
|
||||
|
||||
for cls in itertools.chain([SPIDER_MAP[n] for n in args.catalogues], METRICS_SPIDERS):
|
||||
print("----- CSV: %s" % cls.name)
|
||||
feed_json = cls.get_feed_uri()
|
||||
feed_csv = "%s.csv" % os.path.splitext(feed_json)[0]
|
||||
print(" %s --> %s" % (feed_json, feed_csv))
|
||||
data = cls.get_data()
|
||||
|
||||
# pull out all possible keys to build header row
|
||||
headers = set(itertools.chain(*[
|
||||
tuple(str(k) for (k, v) in flatten_dict(row).items())
|
||||
for row in data
|
||||
]))
|
||||
|
||||
# Write row by row
|
||||
with open(feed_csv, 'w') as csv_file:
|
||||
writer = csv.DictWriter(csv_file, fieldnames=headers)
|
||||
writer.writeheader()
|
||||
for rowdata in data:
|
||||
writer.writerow(utf8encoded(flatten_dict(rowdata)))
|
||||
|
||||
|
||||
# ----- Build Catalogues -----
|
||||
|
||||
if {'all', 'build'} & args.actions:
|
||||
for name in args.catalogues:
|
||||
cls = SPIDER_MAP[name]
|
||||
print("----- Build: %s" % name)
|
||||
catalogue_file = os.path.join(
|
||||
'..', "%s.json" % os.path.splitext(cls.get_feed_uri())[0]
|
||||
)
|
||||
catalogue = cls.get_catalogue(clean=True)
|
||||
data = cls.get_data()
|
||||
|
||||
sys.stdout.flush() # make sure prints come through before bar renders
|
||||
bar = progressbar.ProgressBar()
|
||||
|
||||
for item_data in bar(data):
|
||||
try:
|
||||
cls.add_to_catalogue(item_data, catalogue)
|
||||
except Exception as e:
|
||||
print("couldn't add: %s" % cls.get_item_str(item_data))
|
||||
print("%s: %s" % (type(e).__name__, e))
|
||||
sys.stdout.flush()
|
||||
if args.strict:
|
||||
raise
|
313
ThirdParty/cqparts_fasteners/catalogue/scripts/bunnings.py
vendored
Executable file
313
ThirdParty/cqparts_fasteners/catalogue/scripts/bunnings.py
vendored
Executable file
|
@ -0,0 +1,313 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
import os
|
||||
import inspect
|
||||
import scrapy
|
||||
import scrapy.crawler
|
||||
import scrapy.exporters
|
||||
import re
|
||||
import argparse
|
||||
import logging
|
||||
import fnmatch
|
||||
import json
|
||||
import csv
|
||||
|
||||
|
||||
# ---------- Utilities ----------
|
||||
|
||||
def split_url(url):
|
||||
match = re.search(r'^(?P<base>.*)\?(?P<params>.*)$', url, flags=re.I)
|
||||
return (
|
||||
match.group('base'),
|
||||
{k: v for (k, v) in (p.split('=') for p in match.group('params').split('&'))}
|
||||
)
|
||||
|
||||
def join_url(base, params):
|
||||
return "{base}?{params}".format(
|
||||
base=base,
|
||||
params='&'.join('%s=%s' % (k, v) for (k, v) in params.items()),
|
||||
)
|
||||
|
||||
|
||||
# ---------- Scraper Spiders ----------
|
||||
|
||||
class BunningsProductSpider(scrapy.Spider):
|
||||
|
||||
def parse(self, response):
|
||||
"""Parse pagenated list of products"""
|
||||
|
||||
# Check if page is out of range
|
||||
no_more_products = re.search(
|
||||
r'No matching products were found',
|
||||
response.css('div.paged-results').extract_first(),
|
||||
flags=re.I
|
||||
)
|
||||
if no_more_products:
|
||||
pass # no more pages to populate, stop scraping
|
||||
|
||||
else:
|
||||
# Scrape products list
|
||||
for product in response.css('article.product-list__item'):
|
||||
product_url = product.css('a::attr("href")').extract_first()
|
||||
yield response.follow(product_url, self.parse_detail)
|
||||
|
||||
(base, params) = split_url(response.url)
|
||||
params.update({'page': int(params.get('page', '1')) + 1})
|
||||
next_page_url = join_url(base, params)
|
||||
self.logger.info(next_page_url)
|
||||
yield response.follow(next_page_url, self.parse)
|
||||
|
||||
def parse_detail(self, response):
|
||||
"""Parse individual product's detail"""
|
||||
# Product Information (a start)
|
||||
product_data = {
|
||||
'url': response.url,
|
||||
'name': response.css('div.page-title h1::text').extract_first(),
|
||||
}
|
||||
|
||||
# Inventory Number
|
||||
inventory_number = re.search(
|
||||
r'(?P<inv_num>\d+)$',
|
||||
response.css('span.product-in::text').extract_first(),
|
||||
).group('inv_num')
|
||||
product_data.update({'in': inventory_number})
|
||||
|
||||
# Specifications (arbitrary key:value pairs)
|
||||
specs_table = response.css('#tab-specs dl')
|
||||
for row in specs_table.css('div.spec-row'):
|
||||
keys = row.css('dt::text').extract()
|
||||
values = row.css('dd::text').extract()
|
||||
product_data.update({
|
||||
key: value
|
||||
for (key, value) in zip(keys, values)
|
||||
})
|
||||
|
||||
self.logger.info(product_data['name'])
|
||||
yield product_data
|
||||
|
||||
class ScrewSpider(BunningsProductSpider):
|
||||
name = 'screws'
|
||||
start_urls = [
|
||||
'https://www.bunnings.com.au/our-range/building-hardware/fixings-fasteners/screws/decking?page=1',
|
||||
'https://www.bunnings.com.au/our-range/building-hardware/fixings-fasteners/screws/batten?page=1',
|
||||
'https://www.bunnings.com.au/our-range/building-hardware/fixings-fasteners/screws/wood?page=1',
|
||||
'https://www.bunnings.com.au/our-range/building-hardware/fixings-fasteners/screws/metal-fix?page=1',
|
||||
'https://www.bunnings.com.au/our-range/building-hardware/fixings-fasteners/screws/chipboard?page=1',
|
||||
'https://www.bunnings.com.au/our-range/building-hardware/fixings-fasteners/screws/treated-pine?page=1',
|
||||
'https://www.bunnings.com.au/our-range/building-hardware/fixings-fasteners/screws/plasterboard?page=1',
|
||||
'https://www.bunnings.com.au/our-range/building-hardware/fixings-fasteners/screws/roofing?page=1',
|
||||
'https://www.bunnings.com.au/our-range/building-hardware/fixings-fasteners/screws/general-purpose?page=1',
|
||||
]
|
||||
|
||||
class BoltSpider(BunningsProductSpider):
|
||||
name = 'bolts'
|
||||
start_urls = [
|
||||
'https://www.bunnings.com.au/our-range/building-hardware/fixings-fasteners/bolts/cup-head-bolts?page=1',
|
||||
'https://www.bunnings.com.au/our-range/building-hardware/fixings-fasteners/bolts/hex-head-bolts?page=1',
|
||||
]
|
||||
|
||||
class NutSpider(BunningsProductSpider):
|
||||
name = 'nuts'
|
||||
start_urls = [
|
||||
'https://www.bunnings.com.au/our-range/building-hardware/fixings-fasteners/bolts/nuts?page=1',
|
||||
]
|
||||
|
||||
class ThreadedRodSpider(BunningsProductSpider):
|
||||
name = 'threaded-rods'
|
||||
start_urls = [
|
||||
'https://www.bunnings.com.au/our-range/building-hardware/fixings-fasteners/bolts/threaded-rod?page=1',
|
||||
]
|
||||
|
||||
class WasherSpider(BunningsProductSpider):
|
||||
name = 'washers'
|
||||
start_urls = [
|
||||
'https://www.bunnings.com.au/our-range/building-hardware/fixings-fasteners/bolts/washers?page=1',
|
||||
]
|
||||
|
||||
SPIDERS = [
|
||||
ScrewSpider,
|
||||
BoltSpider,
|
||||
NutSpider,
|
||||
ThreadedRodSpider,
|
||||
WasherSpider,
|
||||
]
|
||||
SPIDER_MAP = {
|
||||
cls.name: cls
|
||||
for cls in SPIDERS
|
||||
}
|
||||
|
||||
# ---------- Command-line Arguments Parser ----------
|
||||
DEFAULT_PREFIX = os.path.splitext(os.path.basename(
|
||||
os.path.abspath(inspect.getfile(inspect.currentframe()))
|
||||
))[0] + '-'
|
||||
|
||||
parser = argparse.ArgumentParser(
|
||||
description='Build Bunnings catalogue by crawling their website',
|
||||
epilog="""
|
||||
WORK IN PROGRESS
|
||||
At this time, this script will scrape the Bunnings website for fasteners,
|
||||
however it will not create a catalogue.
|
||||
This is because there is not enough information on the website to accurately
|
||||
determine fastener geometry.
|
||||
|
||||
Actions:
|
||||
scrape scrape product details from website
|
||||
csv convert scraped output to csv [optional]
|
||||
build builds catalogue from scraped data
|
||||
|
||||
Note: Actions will always be performed in the order shown above,
|
||||
even if they're not listed in that order on commandline.
|
||||
""",
|
||||
formatter_class=argparse.RawTextHelpFormatter,
|
||||
)
|
||||
|
||||
VALID_ACTIONS = set(['scrape', 'csv', 'build'])
|
||||
def action_type(value):
|
||||
value = value.lower()
|
||||
if value not in VALID_ACTIONS:
|
||||
raise argparse.ArgumentError()
|
||||
return value
|
||||
|
||||
parser.add_argument(
|
||||
'actions', metavar='action', type=action_type, nargs='*',
|
||||
help='action(s) to perform'
|
||||
)
|
||||
|
||||
# Scraper arguments
|
||||
parser.add_argument(
|
||||
'--prefix', '-p', dest='prefix', default=DEFAULT_PREFIX,
|
||||
help="scraper file prefix (default: '%s')" % DEFAULT_PREFIX,
|
||||
)
|
||||
|
||||
# Catalogues
|
||||
parser.add_argument(
|
||||
'--list', '-l', dest='list',
|
||||
default=False, action='store_const', const=True,
|
||||
help="list catalogues to build",
|
||||
)
|
||||
|
||||
def catalogues_list_type(value):
|
||||
catalogues_all = set(SPIDER_MAP.keys())
|
||||
catalogues = set()
|
||||
for filter_str in value.split(','):
|
||||
catalogues |= set(fnmatch.filter(catalogues_all, filter_str))
|
||||
return sorted(catalogues)
|
||||
|
||||
parser.add_argument(
|
||||
'--catalogues', '-c', dest='catalogues',
|
||||
type=catalogues_list_type, default=catalogues_list_type('*'),
|
||||
help="csv list of catalogues to act on",
|
||||
)
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
BunningsProductSpider.prefix = args.prefix
|
||||
|
||||
# list catalogues & exit
|
||||
if args.list:
|
||||
for name in args.catalogues:
|
||||
print(name)
|
||||
exit(0)
|
||||
|
||||
# no actions, print help & exit
|
||||
if not args.actions:
|
||||
parser.print_help()
|
||||
exit(1)
|
||||
|
||||
|
||||
FEED_URI = "%(prefix)sscrape-%(name)s.json"
|
||||
|
||||
# ----- Start Crawl -----
|
||||
|
||||
if 'scrape' in args.actions:
|
||||
print("----- Scrape: %s" % (', '.join(args.catalogues)))
|
||||
|
||||
|
||||
# Clear feed files
|
||||
for name in args.catalogues:
|
||||
feed_filename = FEED_URI % {
|
||||
'prefix': args.prefix, 'name': name,
|
||||
}
|
||||
if os.path.exists(feed_filename):
|
||||
os.unlink(feed_filename) # remove feed file to populate from scratch
|
||||
|
||||
# Create Crawlers
|
||||
process = scrapy.crawler.CrawlerProcess(
|
||||
settings={
|
||||
'LOG_LEVEL': logging.INFO,
|
||||
'FEED_FORMAT': "json",
|
||||
'FEED_URI': FEED_URI,
|
||||
},
|
||||
)
|
||||
|
||||
for name in args.catalogues:
|
||||
process.crawl(SPIDER_MAP[name])
|
||||
|
||||
# Start Scraping
|
||||
process.start()
|
||||
|
||||
|
||||
# ----- Convert to CSV -----
|
||||
|
||||
if 'csv' in args.actions:
|
||||
for name in args.catalogues:
|
||||
print("----- CSV: %s" % name)
|
||||
feed_json = FEED_URI % {
|
||||
'prefix': args.prefix, 'name': name,
|
||||
}
|
||||
with open(feed_json, 'r') as json_file:
|
||||
data = json.load(json_file)
|
||||
|
||||
# Pull out headers
|
||||
headers = set()
|
||||
for item in data:
|
||||
headers |= set(item.keys())
|
||||
|
||||
# Write Output
|
||||
def utf8encoded(d):
|
||||
return {k.encode('utf-8'): v.encode('utf-8') for (k, v) in d.items()}
|
||||
feed_csv = "%s.csv" % os.path.splitext(feed_json)[0]
|
||||
with open(feed_csv, 'w') as csv_file:
|
||||
writer = csv.DictWriter(csv_file, fieldnames=headers)
|
||||
writer.writeheader()
|
||||
for item in data:
|
||||
writer.writerow(utf8encoded(item))
|
||||
|
||||
|
||||
# ----- Build Catalogues -----
|
||||
|
||||
def build_screw(row):
|
||||
|
||||
# Required Parameters:
|
||||
# - drive
|
||||
# -
|
||||
# - head
|
||||
# - <countersunk>
|
||||
# - <>
|
||||
# - thread <triangular>
|
||||
# - diameter
|
||||
# - diameter_core (defaults to 2/3 diameter)
|
||||
# - pitch
|
||||
# - angle (defaults to 30deg)
|
||||
# - length
|
||||
# - neck_diam
|
||||
# - neck_length
|
||||
# - neck_taper
|
||||
# - tip_diameter
|
||||
# - tip_length
|
||||
|
||||
pass
|
||||
|
||||
|
||||
if 'build' in args.actions:
|
||||
print("BUILD ACTION NOT IMPLEMENTED")
|
||||
print('\n'.join([
|
||||
"The information on conventional commercial web-pages is too iratic and",
|
||||
"innacurate to formulate a quality catalogue.",
|
||||
"At the time of writing this, I've abandoned this idea, (at least for the",
|
||||
"bunnings.com.au website anyway)"
|
||||
]) + '\n')
|
||||
raise NotImplementedError("'build' action")
|
||||
|
||||
#for name in args.catalogues:
|
||||
# print("----- Build: %s" % name)
|
2
ThirdParty/cqparts_fasteners/catalogue/scripts/requirements.txt
vendored
Normal file
2
ThirdParty/cqparts_fasteners/catalogue/scripts/requirements.txt
vendored
Normal file
|
@ -0,0 +1,2 @@
|
|||
scrapy
|
||||
progressbar2
|
|
@ -0,0 +1,5 @@
|
|||
__all__ = [
|
||||
'Fastener',
|
||||
]
|
||||
|
||||
from .base import Fastener
|
1
ThirdParty/cqparts_fasteners/requirements.txt
vendored
Normal file
1
ThirdParty/cqparts_fasteners/requirements.txt
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
cqparts
|
19
ThirdParty/cqparts_fasteners/solidtypes/threads/README.md
vendored
Normal file
19
ThirdParty/cqparts_fasteners/solidtypes/threads/README.md
vendored
Normal file
|
@ -0,0 +1,19 @@
|
|||
|
||||
# Threads
|
||||
|
||||
Threads are built from a manually build profile wire, which is converted into
|
||||
a closed cross-sectional face, which is swept through a helix to create a solid.
|
||||
|
||||
If you're interested in the development process, read:
|
||||
https://forum.freecadweb.org/viewtopic.php?f=22&t=24628
|
||||
|
||||
|
||||
# Making a Custom Thread Type
|
||||
|
||||
It's recommended you adapt something simple, like `TriangularThread`.
|
||||
|
||||
TODO: make guide on how to customize a thread
|
||||
|
||||
# Research
|
||||
|
||||
* https://www.freecadweb.org/wiki/index.php?title=Macro_screw_maker1_2
|
|
@ -52,11 +52,13 @@ def profile_to_cross_section(profile, lefthand=False, start_count=1, min_vertice
|
|||
vertices to set for each wire.
|
||||
where: len(min_vertices) == number of edges in profile
|
||||
|
||||
**Example**::
|
||||
**Example**
|
||||
|
||||
.. doctest::
|
||||
|
||||
import cadquery
|
||||
from cqparts.solidtypes.threads.base import profile_to_cross_section
|
||||
from Helpers import show
|
||||
from cqparts_fasteners.solidtypes.threads.base import profile_to_cross_section
|
||||
from Helpers import show # doctest: +SKIP
|
||||
|
||||
profile = cadquery.Workplane("XZ") \
|
||||
.moveTo(1, 0) \
|
||||
|
@ -64,8 +66,8 @@ def profile_to_cross_section(profile, lefthand=False, start_count=1, min_vertice
|
|||
.wire()
|
||||
cross_section = profile_to_cross_section(profile)
|
||||
|
||||
show(profile)
|
||||
show(cross_section)
|
||||
show(profile) # doctest: +SKIP
|
||||
show(cross_section) # doctest: +SKIP
|
||||
|
||||
Will result in:
|
||||
|
||||
|
|
60
ThirdParty/cqparts_fasteners/utils/README.md
vendored
Normal file
60
ThirdParty/cqparts_fasteners/utils/README.md
vendored
Normal file
|
@ -0,0 +1,60 @@
|
|||
# Applying a Fastener
|
||||
|
||||
This `fasteners` collection has some utilities to automatically apply and select
|
||||
an apropriate fastener. What they do, and how to use them is documented below.
|
||||
|
||||
Using these tools is **not mandatory**; you'll always have the option to
|
||||
explicitly select your fastener with the placement and orientation of your
|
||||
choosing.
|
||||
|
||||
|
||||
## Evaluation
|
||||
|
||||
An evaluation is an assessment of the workpieces intended to be fastened along
|
||||
a given vector.
|
||||
An evaluation is required for a fastener selector, and an applicator.
|
||||
If a fastener selector is used to fine an appropriate fastener, that same evaluation
|
||||
can be passed to the applicator.
|
||||
|
||||
Evaluations are given, the _what_, and the _where_:
|
||||
- _what_: list of parts (those that may be effected, should be as short as possible)
|
||||
- _where_: linear edge, a vector along which the fastener is intended to be applied
|
||||
|
||||
A successful evaluation will yield:
|
||||
- list of parts effected (in order)
|
||||
- start & finish points on each effected part
|
||||
(the start being closer to the head)
|
||||
|
||||
There are 2 methods of evaluation
|
||||
- vector : faster, but may miss something
|
||||
- cylindrical : slower, but will find all interfacing solids
|
||||
|
||||
|
||||
```python
|
||||
# TODO: sample eval code
|
||||
```
|
||||
|
||||
|
||||
## Fastener Selector
|
||||
|
||||
An evaluation can be used to determine which fastener you need.
|
||||
Or simply, how long the thread on your chosen fastener needs to be.
|
||||
|
||||
```python
|
||||
# TODO: sample selector code
|
||||
```
|
||||
|
||||
|
||||
## Fastener Application
|
||||
|
||||
So you have the fastener to apply, and the workpieces to attach, the workpieces
|
||||
just need holes.
|
||||
|
||||
```python
|
||||
from cqparts.search import find
|
||||
screw = find('10g_30mm_CS_PHIL')()
|
||||
# TODO:
|
||||
box = Box() # FIXME
|
||||
plate = Plate() # FIXME
|
||||
screw.apply()
|
||||
```
|
1
ThirdParty/cqparts_gearboxes/LICENSE
vendored
Symbolic link
1
ThirdParty/cqparts_gearboxes/LICENSE
vendored
Symbolic link
|
@ -0,0 +1 @@
|
|||
../../LICENSE
|
17
ThirdParty/cqparts_gearboxes/__init__.py
vendored
Normal file
17
ThirdParty/cqparts_gearboxes/__init__.py
vendored
Normal file
|
@ -0,0 +1,17 @@
|
|||
"""
|
||||
Copyright 2018 Peter Boin
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
"""
|
||||
|
||||
__release_ready__ = False # TODO: remove to stop blocking build
|
1
ThirdParty/cqparts_gearboxes/requirements.txt
vendored
Normal file
1
ThirdParty/cqparts_gearboxes/requirements.txt
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
cqparts
|
1
ThirdParty/cqparts_gears/LICENSE
vendored
Symbolic link
1
ThirdParty/cqparts_gears/LICENSE
vendored
Symbolic link
|
@ -0,0 +1 @@
|
|||
../../LICENSE
|
26
ThirdParty/cqparts_gears/README.md
vendored
Normal file
26
ThirdParty/cqparts_gears/README.md
vendored
Normal file
|
@ -0,0 +1,26 @@
|
|||
# Involute Gear Profile
|
||||
|
||||
this may be a bit tricky
|
||||
|
||||
## Exiting Scripts
|
||||
|
||||
Existing scripts:
|
||||
* [DXF generator for involute gears](https://www.thingiverse.com/thing:829)
|
||||
* [Cnc25D Gear Profile Function](http://pythonhosted.org/Cnc25D/gear_profile_function.html) ([source](https://github.com/charlyoleg/Cnc25D/blob/master/cnc25d/gear_profile_outline.py))
|
||||
|
||||
I can't use them directly, but I can learn from them.
|
||||
|
||||
## More Reading
|
||||
|
||||
Some helpful descriptions for generating a gear profile:
|
||||
* http://khkgears.net/gear-knowledge/gear-technical-reference/involute-gear-profile/
|
||||
* http://lcamtuf.coredump.cx/gcnc/ch6/
|
||||
* http://khkgears.net/gear-knowledge/gear-technical-reference/calculation-gear-dimensions/
|
||||
|
||||
## Undercutting
|
||||
|
||||
> Question:
|
||||
> What's the formula for the undercut region
|
||||
|
||||
yeah, I've forgotten all this stuff from uni... at least,
|
||||
I assume I learnt it at uni... who knows!?
|
21
ThirdParty/cqparts_gears/__init__.py
vendored
Normal file
21
ThirdParty/cqparts_gears/__init__.py
vendored
Normal file
|
@ -0,0 +1,21 @@
|
|||
"""
|
||||
Copyright 2018 Peter Boin
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
"""
|
||||
|
||||
__all__ = [
|
||||
'trapezoidal',
|
||||
]
|
||||
|
||||
from . import trapezoidal
|
13
ThirdParty/cqparts_gears/base.py
vendored
Normal file
13
ThirdParty/cqparts_gears/base.py
vendored
Normal file
|
@ -0,0 +1,13 @@
|
|||
import cadquery
|
||||
|
||||
import cqparts
|
||||
from cqparts.params import *
|
||||
|
||||
class Gear(cqparts.Part):
|
||||
effective_radius = PositiveFloat(25, doc="designed equivalent wheel radius")
|
||||
tooth_count = PositiveInt(12, doc="number of teeth")
|
||||
width = PositiveFloat(10, doc="gear thickness")
|
||||
|
||||
def make_simple(self):
|
||||
return cadquery.Workplane('XY', origin=(0, 0, -self.width)) \
|
||||
.circle(self.effective_radius).extrude(self.width)
|
1
ThirdParty/cqparts_gears/requirements.txt
vendored
Normal file
1
ThirdParty/cqparts_gears/requirements.txt
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
cqparts
|
101
ThirdParty/cqparts_gears/trapezoidal.py
vendored
Normal file
101
ThirdParty/cqparts_gears/trapezoidal.py
vendored
Normal file
|
@ -0,0 +1,101 @@
|
|||
|
||||
from math import pi, radians, sin, cos, acos
|
||||
|
||||
import cadquery
|
||||
from cqparts.params import *
|
||||
from cqparts.utils import CoordSystem
|
||||
|
||||
from cqparts.constraint import Mate
|
||||
|
||||
from .base import Gear
|
||||
|
||||
|
||||
class TrapezoidalGear(Gear):
|
||||
"""
|
||||
Basic gear with trapezoidal tooth shape.
|
||||
|
||||
.. image:: /_static/img/gears/trapezoidal.png
|
||||
"""
|
||||
tooth_height = PositiveFloat(None, doc="radial height of teeth")
|
||||
|
||||
face_angle = PositiveFloat(30, doc="angle of tooth edge radial edge (unit: degrees)")
|
||||
spacing_ratio = FloatRange(0, 1, 0.5, doc="tooth thickness as a ratio of the distance between them")
|
||||
|
||||
flat_top = Boolean(False, doc="if ``True`` the tops of teeth are flat")
|
||||
|
||||
def initialize_parameters(self):
|
||||
super(TrapezoidalGear, self).initialize_parameters()
|
||||
if self.tooth_height is None:
|
||||
self.tooth_height = 0.2 * self.effective_radius # default: 20% effective radius
|
||||
|
||||
def _make_tooth_template(self):
|
||||
"""
|
||||
Builds a single tooth including the cylinder with tooth faces
|
||||
tangential to its circumference.
|
||||
"""
|
||||
# parameters
|
||||
period_arc = (2 * pi) / self.tooth_count
|
||||
tooth_arc = period_arc * self.spacing_ratio # the arc between faces at effective_radius
|
||||
outer_radius = self.effective_radius + (self.tooth_height / 2)
|
||||
face_angle_rad = radians(self.face_angle)
|
||||
|
||||
# cartesian isosceles trapezoid dimensions
|
||||
side_angle = face_angle_rad - (tooth_arc / 2)
|
||||
side_tangent_radius = sin(face_angle_rad) * self.effective_radius
|
||||
extra_side_angle = side_angle + acos(side_tangent_radius / outer_radius)
|
||||
|
||||
tooth = cadquery.Workplane('XY', origin=(0, 0, -self.width / 2)) \
|
||||
.moveTo(
|
||||
side_tangent_radius * cos(side_angle),
|
||||
side_tangent_radius * sin(side_angle)
|
||||
)
|
||||
opposite_point = (
|
||||
-side_tangent_radius * cos(side_angle),
|
||||
side_tangent_radius * sin(side_angle)
|
||||
)
|
||||
if self.face_angle:
|
||||
tooth = tooth.lineTo(*opposite_point)
|
||||
#tooth = tooth.threePointArc(
|
||||
# (0, -side_tangent_radius),
|
||||
# opposite_point
|
||||
#)
|
||||
tooth = tooth.lineTo(
|
||||
-cos(extra_side_angle) * outer_radius,
|
||||
sin(extra_side_angle) * outer_radius
|
||||
)
|
||||
opposite_point = (
|
||||
cos(extra_side_angle) * outer_radius,
|
||||
sin(extra_side_angle) * outer_radius
|
||||
)
|
||||
if self.flat_top:
|
||||
tooth = tooth.lineTo(*opposite_point)
|
||||
else:
|
||||
tooth = tooth.threePointArc((0, outer_radius), opposite_point)
|
||||
tooth = tooth.close().extrude(self.width)
|
||||
|
||||
return tooth
|
||||
|
||||
def make(self):
|
||||
# create inside cylinder
|
||||
inner_radius = self.effective_radius - (self.tooth_height / 2)
|
||||
gear = cadquery.Workplane('XY', origin=(0, 0, -self.width / 2)) \
|
||||
.circle(inner_radius).extrude(self.width)
|
||||
|
||||
# copy & rotate once per tooth
|
||||
tooth_template = self._make_tooth_template()
|
||||
|
||||
period_arc = 360. / self.tooth_count
|
||||
for i in range(self.tooth_count):
|
||||
gear = gear.union(
|
||||
CoordSystem().rotated((0, 0, i * period_arc)) + tooth_template
|
||||
)
|
||||
|
||||
return gear
|
||||
|
||||
@property
|
||||
def mate_top(self):
|
||||
return Mate(self, CoordSystem((0, 0, self.width / 2)))
|
||||
|
||||
@property
|
||||
def mate_bottom(self):
|
||||
return Mate(self, CoordSystem((0, 0, -self.width / 2)))
|
674
ThirdParty/cqparts_misc/LICENSE
vendored
674
ThirdParty/cqparts_misc/LICENSE
vendored
|
@ -1,674 +0,0 @@
|
|||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 3, 29 June 2007
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The GNU General Public License is a free, copyleft license for
|
||||
software and other kinds of works.
|
||||
|
||||
The licenses for most software and other practical works are designed
|
||||
to take away your freedom to share and change the works. By contrast,
|
||||
the GNU General Public License is intended to guarantee your freedom to
|
||||
share and change all versions of a program--to make sure it remains free
|
||||
software for all its users. We, the Free Software Foundation, use the
|
||||
GNU General Public License for most of our software; it applies also to
|
||||
any other work released this way by its authors. You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
them if you wish), that you receive source code or can get it if you
|
||||
want it, that you can change the software or use pieces of it in new
|
||||
free programs, and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to prevent others from denying you
|
||||
these rights or asking you to surrender the rights. Therefore, you have
|
||||
certain responsibilities if you distribute copies of the software, or if
|
||||
you modify it: responsibilities to respect the freedom of others.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must pass on to the recipients the same
|
||||
freedoms that you received. You must make sure that they, too, receive
|
||||
or can get the source code. And you must show them these terms so they
|
||||
know their rights.
|
||||
|
||||
Developers that use the GNU GPL protect your rights with two steps:
|
||||
(1) assert copyright on the software, and (2) offer you this License
|
||||
giving you legal permission to copy, distribute and/or modify it.
|
||||
|
||||
For the developers' and authors' protection, the GPL clearly explains
|
||||
that there is no warranty for this free software. For both users' and
|
||||
authors' sake, the GPL requires that modified versions be marked as
|
||||
changed, so that their problems will not be attributed erroneously to
|
||||
authors of previous versions.
|
||||
|
||||
Some devices are designed to deny users access to install or run
|
||||
modified versions of the software inside them, although the manufacturer
|
||||
can do so. This is fundamentally incompatible with the aim of
|
||||
protecting users' freedom to change the software. The systematic
|
||||
pattern of such abuse occurs in the area of products for individuals to
|
||||
use, which is precisely where it is most unacceptable. Therefore, we
|
||||
have designed this version of the GPL to prohibit the practice for those
|
||||
products. If such problems arise substantially in other domains, we
|
||||
stand ready to extend this provision to those domains in future versions
|
||||
of the GPL, as needed to protect the freedom of users.
|
||||
|
||||
Finally, every program is threatened constantly by software patents.
|
||||
States should not allow patents to restrict development and use of
|
||||
software on general-purpose computers, but in those that do, we wish to
|
||||
avoid the special danger that patents applied to a free program could
|
||||
make it effectively proprietary. To prevent this, the GPL assures that
|
||||
patents cannot be used to render the program non-free.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
TERMS AND CONDITIONS
|
||||
|
||||
0. Definitions.
|
||||
|
||||
"This License" refers to version 3 of the GNU General Public License.
|
||||
|
||||
"Copyright" also means copyright-like laws that apply to other kinds of
|
||||
works, such as semiconductor masks.
|
||||
|
||||
"The Program" refers to any copyrightable work licensed under this
|
||||
License. Each licensee is addressed as "you". "Licensees" and
|
||||
"recipients" may be individuals or organizations.
|
||||
|
||||
To "modify" a work means to copy from or adapt all or part of the work
|
||||
in a fashion requiring copyright permission, other than the making of an
|
||||
exact copy. The resulting work is called a "modified version" of the
|
||||
earlier work or a work "based on" the earlier work.
|
||||
|
||||
A "covered work" means either the unmodified Program or a work based
|
||||
on the Program.
|
||||
|
||||
To "propagate" a work means to do anything with it that, without
|
||||
permission, would make you directly or secondarily liable for
|
||||
infringement under applicable copyright law, except executing it on a
|
||||
computer or modifying a private copy. Propagation includes copying,
|
||||
distribution (with or without modification), making available to the
|
||||
public, and in some countries other activities as well.
|
||||
|
||||
To "convey" a work means any kind of propagation that enables other
|
||||
parties to make or receive copies. Mere interaction with a user through
|
||||
a computer network, with no transfer of a copy, is not conveying.
|
||||
|
||||
An interactive user interface displays "Appropriate Legal Notices"
|
||||
to the extent that it includes a convenient and prominently visible
|
||||
feature that (1) displays an appropriate copyright notice, and (2)
|
||||
tells the user that there is no warranty for the work (except to the
|
||||
extent that warranties are provided), that licensees may convey the
|
||||
work under this License, and how to view a copy of this License. If
|
||||
the interface presents a list of user commands or options, such as a
|
||||
menu, a prominent item in the list meets this criterion.
|
||||
|
||||
1. Source Code.
|
||||
|
||||
The "source code" for a work means the preferred form of the work
|
||||
for making modifications to it. "Object code" means any non-source
|
||||
form of a work.
|
||||
|
||||
A "Standard Interface" means an interface that either is an official
|
||||
standard defined by a recognized standards body, or, in the case of
|
||||
interfaces specified for a particular programming language, one that
|
||||
is widely used among developers working in that language.
|
||||
|
||||
The "System Libraries" of an executable work include anything, other
|
||||
than the work as a whole, that (a) is included in the normal form of
|
||||
packaging a Major Component, but which is not part of that Major
|
||||
Component, and (b) serves only to enable use of the work with that
|
||||
Major Component, or to implement a Standard Interface for which an
|
||||
implementation is available to the public in source code form. A
|
||||
"Major Component", in this context, means a major essential component
|
||||
(kernel, window system, and so on) of the specific operating system
|
||||
(if any) on which the executable work runs, or a compiler used to
|
||||
produce the work, or an object code interpreter used to run it.
|
||||
|
||||
The "Corresponding Source" for a work in object code form means all
|
||||
the source code needed to generate, install, and (for an executable
|
||||
work) run the object code and to modify the work, including scripts to
|
||||
control those activities. However, it does not include the work's
|
||||
System Libraries, or general-purpose tools or generally available free
|
||||
programs which are used unmodified in performing those activities but
|
||||
which are not part of the work. For example, Corresponding Source
|
||||
includes interface definition files associated with source files for
|
||||
the work, and the source code for shared libraries and dynamically
|
||||
linked subprograms that the work is specifically designed to require,
|
||||
such as by intimate data communication or control flow between those
|
||||
subprograms and other parts of the work.
|
||||
|
||||
The Corresponding Source need not include anything that users
|
||||
can regenerate automatically from other parts of the Corresponding
|
||||
Source.
|
||||
|
||||
The Corresponding Source for a work in source code form is that
|
||||
same work.
|
||||
|
||||
2. Basic Permissions.
|
||||
|
||||
All rights granted under this License are granted for the term of
|
||||
copyright on the Program, and are irrevocable provided the stated
|
||||
conditions are met. This License explicitly affirms your unlimited
|
||||
permission to run the unmodified Program. The output from running a
|
||||
covered work is covered by this License only if the output, given its
|
||||
content, constitutes a covered work. This License acknowledges your
|
||||
rights of fair use or other equivalent, as provided by copyright law.
|
||||
|
||||
You may make, run and propagate covered works that you do not
|
||||
convey, without conditions so long as your license otherwise remains
|
||||
in force. You may convey covered works to others for the sole purpose
|
||||
of having them make modifications exclusively for you, or provide you
|
||||
with facilities for running those works, provided that you comply with
|
||||
the terms of this License in conveying all material for which you do
|
||||
not control copyright. Those thus making or running the covered works
|
||||
for you must do so exclusively on your behalf, under your direction
|
||||
and control, on terms that prohibit them from making any copies of
|
||||
your copyrighted material outside their relationship with you.
|
||||
|
||||
Conveying under any other circumstances is permitted solely under
|
||||
the conditions stated below. Sublicensing is not allowed; section 10
|
||||
makes it unnecessary.
|
||||
|
||||
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
|
||||
|
||||
No covered work shall be deemed part of an effective technological
|
||||
measure under any applicable law fulfilling obligations under article
|
||||
11 of the WIPO copyright treaty adopted on 20 December 1996, or
|
||||
similar laws prohibiting or restricting circumvention of such
|
||||
measures.
|
||||
|
||||
When you convey a covered work, you waive any legal power to forbid
|
||||
circumvention of technological measures to the extent such circumvention
|
||||
is effected by exercising rights under this License with respect to
|
||||
the covered work, and you disclaim any intention to limit operation or
|
||||
modification of the work as a means of enforcing, against the work's
|
||||
users, your or third parties' legal rights to forbid circumvention of
|
||||
technological measures.
|
||||
|
||||
4. Conveying Verbatim Copies.
|
||||
|
||||
You may convey verbatim copies of the Program's source code as you
|
||||
receive it, in any medium, provided that you conspicuously and
|
||||
appropriately publish on each copy an appropriate copyright notice;
|
||||
keep intact all notices stating that this License and any
|
||||
non-permissive terms added in accord with section 7 apply to the code;
|
||||
keep intact all notices of the absence of any warranty; and give all
|
||||
recipients a copy of this License along with the Program.
|
||||
|
||||
You may charge any price or no price for each copy that you convey,
|
||||
and you may offer support or warranty protection for a fee.
|
||||
|
||||
5. Conveying Modified Source Versions.
|
||||
|
||||
You may convey a work based on the Program, or the modifications to
|
||||
produce it from the Program, in the form of source code under the
|
||||
terms of section 4, provided that you also meet all of these conditions:
|
||||
|
||||
a) The work must carry prominent notices stating that you modified
|
||||
it, and giving a relevant date.
|
||||
|
||||
b) The work must carry prominent notices stating that it is
|
||||
released under this License and any conditions added under section
|
||||
7. This requirement modifies the requirement in section 4 to
|
||||
"keep intact all notices".
|
||||
|
||||
c) You must license the entire work, as a whole, under this
|
||||
License to anyone who comes into possession of a copy. This
|
||||
License will therefore apply, along with any applicable section 7
|
||||
additional terms, to the whole of the work, and all its parts,
|
||||
regardless of how they are packaged. This License gives no
|
||||
permission to license the work in any other way, but it does not
|
||||
invalidate such permission if you have separately received it.
|
||||
|
||||
d) If the work has interactive user interfaces, each must display
|
||||
Appropriate Legal Notices; however, if the Program has interactive
|
||||
interfaces that do not display Appropriate Legal Notices, your
|
||||
work need not make them do so.
|
||||
|
||||
A compilation of a covered work with other separate and independent
|
||||
works, which are not by their nature extensions of the covered work,
|
||||
and which are not combined with it such as to form a larger program,
|
||||
in or on a volume of a storage or distribution medium, is called an
|
||||
"aggregate" if the compilation and its resulting copyright are not
|
||||
used to limit the access or legal rights of the compilation's users
|
||||
beyond what the individual works permit. Inclusion of a covered work
|
||||
in an aggregate does not cause this License to apply to the other
|
||||
parts of the aggregate.
|
||||
|
||||
6. Conveying Non-Source Forms.
|
||||
|
||||
You may convey a covered work in object code form under the terms
|
||||
of sections 4 and 5, provided that you also convey the
|
||||
machine-readable Corresponding Source under the terms of this License,
|
||||
in one of these ways:
|
||||
|
||||
a) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by the
|
||||
Corresponding Source fixed on a durable physical medium
|
||||
customarily used for software interchange.
|
||||
|
||||
b) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by a
|
||||
written offer, valid for at least three years and valid for as
|
||||
long as you offer spare parts or customer support for that product
|
||||
model, to give anyone who possesses the object code either (1) a
|
||||
copy of the Corresponding Source for all the software in the
|
||||
product that is covered by this License, on a durable physical
|
||||
medium customarily used for software interchange, for a price no
|
||||
more than your reasonable cost of physically performing this
|
||||
conveying of source, or (2) access to copy the
|
||||
Corresponding Source from a network server at no charge.
|
||||
|
||||
c) Convey individual copies of the object code with a copy of the
|
||||
written offer to provide the Corresponding Source. This
|
||||
alternative is allowed only occasionally and noncommercially, and
|
||||
only if you received the object code with such an offer, in accord
|
||||
with subsection 6b.
|
||||
|
||||
d) Convey the object code by offering access from a designated
|
||||
place (gratis or for a charge), and offer equivalent access to the
|
||||
Corresponding Source in the same way through the same place at no
|
||||
further charge. You need not require recipients to copy the
|
||||
Corresponding Source along with the object code. If the place to
|
||||
copy the object code is a network server, the Corresponding Source
|
||||
may be on a different server (operated by you or a third party)
|
||||
that supports equivalent copying facilities, provided you maintain
|
||||
clear directions next to the object code saying where to find the
|
||||
Corresponding Source. Regardless of what server hosts the
|
||||
Corresponding Source, you remain obligated to ensure that it is
|
||||
available for as long as needed to satisfy these requirements.
|
||||
|
||||
e) Convey the object code using peer-to-peer transmission, provided
|
||||
you inform other peers where the object code and Corresponding
|
||||
Source of the work are being offered to the general public at no
|
||||
charge under subsection 6d.
|
||||
|
||||
A separable portion of the object code, whose source code is excluded
|
||||
from the Corresponding Source as a System Library, need not be
|
||||
included in conveying the object code work.
|
||||
|
||||
A "User Product" is either (1) a "consumer product", which means any
|
||||
tangible personal property which is normally used for personal, family,
|
||||
or household purposes, or (2) anything designed or sold for incorporation
|
||||
into a dwelling. In determining whether a product is a consumer product,
|
||||
doubtful cases shall be resolved in favor of coverage. For a particular
|
||||
product received by a particular user, "normally used" refers to a
|
||||
typical or common use of that class of product, regardless of the status
|
||||
of the particular user or of the way in which the particular user
|
||||
actually uses, or expects or is expected to use, the product. A product
|
||||
is a consumer product regardless of whether the product has substantial
|
||||
commercial, industrial or non-consumer uses, unless such uses represent
|
||||
the only significant mode of use of the product.
|
||||
|
||||
"Installation Information" for a User Product means any methods,
|
||||
procedures, authorization keys, or other information required to install
|
||||
and execute modified versions of a covered work in that User Product from
|
||||
a modified version of its Corresponding Source. The information must
|
||||
suffice to ensure that the continued functioning of the modified object
|
||||
code is in no case prevented or interfered with solely because
|
||||
modification has been made.
|
||||
|
||||
If you convey an object code work under this section in, or with, or
|
||||
specifically for use in, a User Product, and the conveying occurs as
|
||||
part of a transaction in which the right of possession and use of the
|
||||
User Product is transferred to the recipient in perpetuity or for a
|
||||
fixed term (regardless of how the transaction is characterized), the
|
||||
Corresponding Source conveyed under this section must be accompanied
|
||||
by the Installation Information. But this requirement does not apply
|
||||
if neither you nor any third party retains the ability to install
|
||||
modified object code on the User Product (for example, the work has
|
||||
been installed in ROM).
|
||||
|
||||
The requirement to provide Installation Information does not include a
|
||||
requirement to continue to provide support service, warranty, or updates
|
||||
for a work that has been modified or installed by the recipient, or for
|
||||
the User Product in which it has been modified or installed. Access to a
|
||||
network may be denied when the modification itself materially and
|
||||
adversely affects the operation of the network or violates the rules and
|
||||
protocols for communication across the network.
|
||||
|
||||
Corresponding Source conveyed, and Installation Information provided,
|
||||
in accord with this section must be in a format that is publicly
|
||||
documented (and with an implementation available to the public in
|
||||
source code form), and must require no special password or key for
|
||||
unpacking, reading or copying.
|
||||
|
||||
7. Additional Terms.
|
||||
|
||||
"Additional permissions" are terms that supplement the terms of this
|
||||
License by making exceptions from one or more of its conditions.
|
||||
Additional permissions that are applicable to the entire Program shall
|
||||
be treated as though they were included in this License, to the extent
|
||||
that they are valid under applicable law. If additional permissions
|
||||
apply only to part of the Program, that part may be used separately
|
||||
under those permissions, but the entire Program remains governed by
|
||||
this License without regard to the additional permissions.
|
||||
|
||||
When you convey a copy of a covered work, you may at your option
|
||||
remove any additional permissions from that copy, or from any part of
|
||||
it. (Additional permissions may be written to require their own
|
||||
removal in certain cases when you modify the work.) You may place
|
||||
additional permissions on material, added by you to a covered work,
|
||||
for which you have or can give appropriate copyright permission.
|
||||
|
||||
Notwithstanding any other provision of this License, for material you
|
||||
add to a covered work, you may (if authorized by the copyright holders of
|
||||
that material) supplement the terms of this License with terms:
|
||||
|
||||
a) Disclaiming warranty or limiting liability differently from the
|
||||
terms of sections 15 and 16 of this License; or
|
||||
|
||||
b) Requiring preservation of specified reasonable legal notices or
|
||||
author attributions in that material or in the Appropriate Legal
|
||||
Notices displayed by works containing it; or
|
||||
|
||||
c) Prohibiting misrepresentation of the origin of that material, or
|
||||
requiring that modified versions of such material be marked in
|
||||
reasonable ways as different from the original version; or
|
||||
|
||||
d) Limiting the use for publicity purposes of names of licensors or
|
||||
authors of the material; or
|
||||
|
||||
e) Declining to grant rights under trademark law for use of some
|
||||
trade names, trademarks, or service marks; or
|
||||
|
||||
f) Requiring indemnification of licensors and authors of that
|
||||
material by anyone who conveys the material (or modified versions of
|
||||
it) with contractual assumptions of liability to the recipient, for
|
||||
any liability that these contractual assumptions directly impose on
|
||||
those licensors and authors.
|
||||
|
||||
All other non-permissive additional terms are considered "further
|
||||
restrictions" within the meaning of section 10. If the Program as you
|
||||
received it, or any part of it, contains a notice stating that it is
|
||||
governed by this License along with a term that is a further
|
||||
restriction, you may remove that term. If a license document contains
|
||||
a further restriction but permits relicensing or conveying under this
|
||||
License, you may add to a covered work material governed by the terms
|
||||
of that license document, provided that the further restriction does
|
||||
not survive such relicensing or conveying.
|
||||
|
||||
If you add terms to a covered work in accord with this section, you
|
||||
must place, in the relevant source files, a statement of the
|
||||
additional terms that apply to those files, or a notice indicating
|
||||
where to find the applicable terms.
|
||||
|
||||
Additional terms, permissive or non-permissive, may be stated in the
|
||||
form of a separately written license, or stated as exceptions;
|
||||
the above requirements apply either way.
|
||||
|
||||
8. Termination.
|
||||
|
||||
You may not propagate or modify a covered work except as expressly
|
||||
provided under this License. Any attempt otherwise to propagate or
|
||||
modify it is void, and will automatically terminate your rights under
|
||||
this License (including any patent licenses granted under the third
|
||||
paragraph of section 11).
|
||||
|
||||
However, if you cease all violation of this License, then your
|
||||
license from a particular copyright holder is reinstated (a)
|
||||
provisionally, unless and until the copyright holder explicitly and
|
||||
finally terminates your license, and (b) permanently, if the copyright
|
||||
holder fails to notify you of the violation by some reasonable means
|
||||
prior to 60 days after the cessation.
|
||||
|
||||
Moreover, your license from a particular copyright holder is
|
||||
reinstated permanently if the copyright holder notifies you of the
|
||||
violation by some reasonable means, this is the first time you have
|
||||
received notice of violation of this License (for any work) from that
|
||||
copyright holder, and you cure the violation prior to 30 days after
|
||||
your receipt of the notice.
|
||||
|
||||
Termination of your rights under this section does not terminate the
|
||||
licenses of parties who have received copies or rights from you under
|
||||
this License. If your rights have been terminated and not permanently
|
||||
reinstated, you do not qualify to receive new licenses for the same
|
||||
material under section 10.
|
||||
|
||||
9. Acceptance Not Required for Having Copies.
|
||||
|
||||
You are not required to accept this License in order to receive or
|
||||
run a copy of the Program. Ancillary propagation of a covered work
|
||||
occurring solely as a consequence of using peer-to-peer transmission
|
||||
to receive a copy likewise does not require acceptance. However,
|
||||
nothing other than this License grants you permission to propagate or
|
||||
modify any covered work. These actions infringe copyright if you do
|
||||
not accept this License. Therefore, by modifying or propagating a
|
||||
covered work, you indicate your acceptance of this License to do so.
|
||||
|
||||
10. Automatic Licensing of Downstream Recipients.
|
||||
|
||||
Each time you convey a covered work, the recipient automatically
|
||||
receives a license from the original licensors, to run, modify and
|
||||
propagate that work, subject to this License. You are not responsible
|
||||
for enforcing compliance by third parties with this License.
|
||||
|
||||
An "entity transaction" is a transaction transferring control of an
|
||||
organization, or substantially all assets of one, or subdividing an
|
||||
organization, or merging organizations. If propagation of a covered
|
||||
work results from an entity transaction, each party to that
|
||||
transaction who receives a copy of the work also receives whatever
|
||||
licenses to the work the party's predecessor in interest had or could
|
||||
give under the previous paragraph, plus a right to possession of the
|
||||
Corresponding Source of the work from the predecessor in interest, if
|
||||
the predecessor has it or can get it with reasonable efforts.
|
||||
|
||||
You may not impose any further restrictions on the exercise of the
|
||||
rights granted or affirmed under this License. For example, you may
|
||||
not impose a license fee, royalty, or other charge for exercise of
|
||||
rights granted under this License, and you may not initiate litigation
|
||||
(including a cross-claim or counterclaim in a lawsuit) alleging that
|
||||
any patent claim is infringed by making, using, selling, offering for
|
||||
sale, or importing the Program or any portion of it.
|
||||
|
||||
11. Patents.
|
||||
|
||||
A "contributor" is a copyright holder who authorizes use under this
|
||||
License of the Program or a work on which the Program is based. The
|
||||
work thus licensed is called the contributor's "contributor version".
|
||||
|
||||
A contributor's "essential patent claims" are all patent claims
|
||||
owned or controlled by the contributor, whether already acquired or
|
||||
hereafter acquired, that would be infringed by some manner, permitted
|
||||
by this License, of making, using, or selling its contributor version,
|
||||
but do not include claims that would be infringed only as a
|
||||
consequence of further modification of the contributor version. For
|
||||
purposes of this definition, "control" includes the right to grant
|
||||
patent sublicenses in a manner consistent with the requirements of
|
||||
this License.
|
||||
|
||||
Each contributor grants you a non-exclusive, worldwide, royalty-free
|
||||
patent license under the contributor's essential patent claims, to
|
||||
make, use, sell, offer for sale, import and otherwise run, modify and
|
||||
propagate the contents of its contributor version.
|
||||
|
||||
In the following three paragraphs, a "patent license" is any express
|
||||
agreement or commitment, however denominated, not to enforce a patent
|
||||
(such as an express permission to practice a patent or covenant not to
|
||||
sue for patent infringement). To "grant" such a patent license to a
|
||||
party means to make such an agreement or commitment not to enforce a
|
||||
patent against the party.
|
||||
|
||||
If you convey a covered work, knowingly relying on a patent license,
|
||||
and the Corresponding Source of the work is not available for anyone
|
||||
to copy, free of charge and under the terms of this License, through a
|
||||
publicly available network server or other readily accessible means,
|
||||
then you must either (1) cause the Corresponding Source to be so
|
||||
available, or (2) arrange to deprive yourself of the benefit of the
|
||||
patent license for this particular work, or (3) arrange, in a manner
|
||||
consistent with the requirements of this License, to extend the patent
|
||||
license to downstream recipients. "Knowingly relying" means you have
|
||||
actual knowledge that, but for the patent license, your conveying the
|
||||
covered work in a country, or your recipient's use of the covered work
|
||||
in a country, would infringe one or more identifiable patents in that
|
||||
country that you have reason to believe are valid.
|
||||
|
||||
If, pursuant to or in connection with a single transaction or
|
||||
arrangement, you convey, or propagate by procuring conveyance of, a
|
||||
covered work, and grant a patent license to some of the parties
|
||||
receiving the covered work authorizing them to use, propagate, modify
|
||||
or convey a specific copy of the covered work, then the patent license
|
||||
you grant is automatically extended to all recipients of the covered
|
||||
work and works based on it.
|
||||
|
||||
A patent license is "discriminatory" if it does not include within
|
||||
the scope of its coverage, prohibits the exercise of, or is
|
||||
conditioned on the non-exercise of one or more of the rights that are
|
||||
specifically granted under this License. You may not convey a covered
|
||||
work if you are a party to an arrangement with a third party that is
|
||||
in the business of distributing software, under which you make payment
|
||||
to the third party based on the extent of your activity of conveying
|
||||
the work, and under which the third party grants, to any of the
|
||||
parties who would receive the covered work from you, a discriminatory
|
||||
patent license (a) in connection with copies of the covered work
|
||||
conveyed by you (or copies made from those copies), or (b) primarily
|
||||
for and in connection with specific products or compilations that
|
||||
contain the covered work, unless you entered into that arrangement,
|
||||
or that patent license was granted, prior to 28 March 2007.
|
||||
|
||||
Nothing in this License shall be construed as excluding or limiting
|
||||
any implied license or other defenses to infringement that may
|
||||
otherwise be available to you under applicable patent law.
|
||||
|
||||
12. No Surrender of Others' Freedom.
|
||||
|
||||
If conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot convey a
|
||||
covered work so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you may
|
||||
not convey it at all. For example, if you agree to terms that obligate you
|
||||
to collect a royalty for further conveying from those to whom you convey
|
||||
the Program, the only way you could satisfy both those terms and this
|
||||
License would be to refrain entirely from conveying the Program.
|
||||
|
||||
13. Use with the GNU Affero General Public License.
|
||||
|
||||
Notwithstanding any other provision of this License, you have
|
||||
permission to link or combine any covered work with a work licensed
|
||||
under version 3 of the GNU Affero General Public License into a single
|
||||
combined work, and to convey the resulting work. The terms of this
|
||||
License will continue to apply to the part which is the covered work,
|
||||
but the special requirements of the GNU Affero General Public License,
|
||||
section 13, concerning interaction through a network will apply to the
|
||||
combination as such.
|
||||
|
||||
14. Revised Versions of this License.
|
||||
|
||||
The Free Software Foundation may publish revised and/or new versions of
|
||||
the GNU General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the
|
||||
Program specifies that a certain numbered version of the GNU General
|
||||
Public License "or any later version" applies to it, you have the
|
||||
option of following the terms and conditions either of that numbered
|
||||
version or of any later version published by the Free Software
|
||||
Foundation. If the Program does not specify a version number of the
|
||||
GNU General Public License, you may choose any version ever published
|
||||
by the Free Software Foundation.
|
||||
|
||||
If the Program specifies that a proxy can decide which future
|
||||
versions of the GNU General Public License can be used, that proxy's
|
||||
public statement of acceptance of a version permanently authorizes you
|
||||
to choose that version for the Program.
|
||||
|
||||
Later license versions may give you additional or different
|
||||
permissions. However, no additional obligations are imposed on any
|
||||
author or copyright holder as a result of your choosing to follow a
|
||||
later version.
|
||||
|
||||
15. Disclaimer of Warranty.
|
||||
|
||||
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
|
||||
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
|
||||
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
|
||||
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
|
||||
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
|
||||
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
|
||||
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||
|
||||
16. Limitation of Liability.
|
||||
|
||||
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
|
||||
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
|
||||
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
|
||||
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
|
||||
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
|
||||
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
|
||||
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
|
||||
SUCH DAMAGES.
|
||||
|
||||
17. Interpretation of Sections 15 and 16.
|
||||
|
||||
If the disclaimer of warranty and limitation of liability provided
|
||||
above cannot be given local legal effect according to their terms,
|
||||
reviewing courts shall apply local law that most closely approximates
|
||||
an absolute waiver of all civil liability in connection with the
|
||||
Program, unless a warranty or assumption of liability accompanies a
|
||||
copy of the Program in return for a fee.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
state the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
{one line to give the program's name and a brief idea of what it does.}
|
||||
Copyright (C) {year} {name of author}
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program does terminal interaction, make it output a short
|
||||
notice like this when it starts in an interactive mode:
|
||||
|
||||
{project} Copyright (C) {year} {fullname}
|
||||
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, your program's commands
|
||||
might be different; for a GUI interface, you would use an "about box".
|
||||
|
||||
You should also get your employer (if you work as a programmer) or school,
|
||||
if any, to sign a "copyright disclaimer" for the program, if necessary.
|
||||
For more information on this, and how to apply and follow the GNU GPL, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
|
||||
The GNU General Public License does not permit incorporating your program
|
||||
into proprietary programs. If your program is a subroutine library, you
|
||||
may consider it more useful to permit linking proprietary applications with
|
||||
the library. If this is what you want to do, use the GNU Lesser General
|
||||
Public License instead of this License. But first, please read
|
||||
<http://www.gnu.org/philosophy/why-not-lgpl.html>.
|
1
ThirdParty/cqparts_misc/LICENSE
vendored
Symbolic link
1
ThirdParty/cqparts_misc/LICENSE
vendored
Symbolic link
|
@ -0,0 +1 @@
|
|||
../../LICENSE
|
72
ThirdParty/cqparts_misc/README.rst
vendored
Normal file
72
ThirdParty/cqparts_misc/README.rst
vendored
Normal file
|
@ -0,0 +1,72 @@
|
|||
|
||||
====================================================
|
||||
`cqparts` Content Library : Miscellaneous
|
||||
====================================================
|
||||
|
||||
Components
|
||||
-------------------------
|
||||
|
||||
Primative Shapes
|
||||
^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Primative shapes to build or test ideas quickly
|
||||
|
||||
* Cube
|
||||
* Box
|
||||
* Sphere
|
||||
* Cylinder
|
||||
|
||||
Indicators
|
||||
^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
These components can be used in assemblies during development as a means
|
||||
to debug your part placement, and to demonstrate ``Mate`` coordinate systems.
|
||||
|
||||
* Coordinate System Indicator
|
||||
* Planar Indicator
|
||||
|
||||
.. image:: https://fragmuffin.github.io/cqparts/media/img/misc/indicators.png
|
||||
|
||||
|
||||
Examples
|
||||
-------------------------
|
||||
|
||||
Use indicator on a primative
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
To illustrate how an inciator can be used to show where a ``Mate`` is on a
|
||||
``Part``, we'll create a simple ``Assembly``::
|
||||
|
||||
import cqparts
|
||||
from cqparts.constraint import Fixed, Coincident
|
||||
|
||||
from cqparts_misc.basic.indicators import CoordSysIndicator
|
||||
from cqparts_misc.basic.primatives import Box
|
||||
|
||||
|
||||
class MyAsm(cqparts.Assembly):
|
||||
def make_components(self):
|
||||
return {
|
||||
'box': Box(length=30, width=20, height=10),
|
||||
'indicator': CoordSysIndicator(),
|
||||
}
|
||||
|
||||
def make_constraints(self):
|
||||
return [
|
||||
Fixed(self.components['box'].mate_origin), # fix at world origin
|
||||
Coincident(
|
||||
self.components['indicator'].mate_origin,
|
||||
self.components['box'].mate_neg_y,
|
||||
),
|
||||
]
|
||||
|
||||
|
||||
from cqparts.display import display
|
||||
display(MyAsm())
|
||||
|
||||
.. image:: https://fragmuffin.github.io/cqparts/media/img/misc/example-coordsys-indicator.png
|
||||
|
||||
From this we can see that the ``mate_neg_y`` mate has:
|
||||
|
||||
* its Z-axis along the world -Y-axis, and
|
||||
* its X-axis along the world Z-axis.
|
18
ThirdParty/cqparts_misc/__init__.py
vendored
18
ThirdParty/cqparts_misc/__init__.py
vendored
|
@ -1,3 +1,19 @@
|
|||
"""
|
||||
Copyright 2018 Peter Boin
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
"""
|
||||
|
||||
# =========================== Package Information ===========================
|
||||
# Version Planning:
|
||||
# 0.1.x - Development Status :: 2 - Pre-Alpha
|
||||
|
@ -15,7 +31,7 @@ __url__ = 'https://github.com/fragmuffin/cqparts/tree/master/src/cqparts_misc'
|
|||
__author__ = 'Peter Boin'
|
||||
__email__ = 'peter.boin+cqparts@gmail.com'
|
||||
|
||||
__license__ = 'GPLv3'
|
||||
__license__ = 'Apache Public License 2.0'
|
||||
|
||||
__keywords__ = ['cadquery', 'cad', '3d', 'modeling']
|
||||
|
||||
|
|
1
ThirdParty/cqparts_misc/requirements.txt
vendored
Normal file
1
ThirdParty/cqparts_misc/requirements.txt
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
cqparts
|
1
ThirdParty/cqparts_motors/LICENSE
vendored
Symbolic link
1
ThirdParty/cqparts_motors/LICENSE
vendored
Symbolic link
|
@ -0,0 +1 @@
|
|||
../../LICENSE
|
17
ThirdParty/cqparts_motors/__init__.py
vendored
Normal file
17
ThirdParty/cqparts_motors/__init__.py
vendored
Normal file
|
@ -0,0 +1,17 @@
|
|||
"""
|
||||
Copyright 2018 Peter Boin
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
"""
|
||||
|
||||
__release_ready__ = False # TODO: remove to stop blocking build
|
1
ThirdParty/cqparts_motors/catalogue/dcmotor.json
vendored
Normal file
1
ThirdParty/cqparts_motors/catalogue/dcmotor.json
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
{"items": {"1": {"obj": {"params": {"profile": "rect", "diam": 23.0, "shaft_length": 8.0, "cover_height": 0.0, "step_height": 0.0, "thickness": 15.4, "bush_height": 1.6, "shaft_diam": 2.0, "step_diam": 12.0, "height": 17.0, "bush_diam": 4.0}, "class": {"name": "DCMotor", "module": "cqparts_motors.dc"}, "lib": {"version": "0.2.2.dev1", "name": "cqparts"}}, "id": "slotcar", "criteria": {"diam": 23, "type": "motor", "class": "dc"}}, "2": {"obj": {"params": {"profile": "flat", "diam": 20.4, "shaft_length": 11.55, "cover_height": 0.0, "step_diam": 12.0, "thickness": 15.4, "bush_height": 1.6, "step_height": 0.0, "shaft_diam": 2.0, "bush_diam": 6.15, "height": 25.1}, "class": {"name": "DCMotor", "module": "cqparts_motors.dc"}, "lib": {"version": "0.2.2.dev1", "name": "cqparts"}}, "id": "130", "criteria": {"diam": 20.4, "type": "motor", "class": "dc"}}, "3": {"obj": {"params": {"profile": "circle", "diam": 20.4, "shaft_length": 6.0, "cover_height": 0.0, "step_height": 0.0, "thickness": 15.4, "height": 10.0, "bush_height": 0.4, "shaft_diam": 2.0, "bush_diam": 6.15, "step_diam": 12.0}, "class": {"name": "DCMotor", "module": "cqparts_motors.dc"}, "lib": {"version": "0.2.2.dev1", "name": "cqparts"}}, "id": "flat", "criteria": {"diam": 20.4, "type": "motor", "class": "dc"}}, "4": {"obj": {"params": {"profile": "circle", "diam": 20.4, "shaft_length": 11.55, "cover_height": 0.0, "bush_diam": 6.15, "height": 25.1, "bush_height": 1.6, "step_height": 1.0, "shaft_diam": 2.0, "step_diam": 12.0, "thickness": 15.4}, "class": {"name": "DCMotor", "module": "cqparts_motors.dc"}, "lib": {"version": "0.2.2.dev1", "name": "cqparts"}}, "id": "R140", "criteria": {"diam": 20.4, "type": "motor", "class": "dc"}}}, "_dbinfo": {"1": {"lib": "cqparts", "ver": "0.1", "name": "JSONCatalogue", "module": "cqparts.catalogue.json", "lib_version": "0.2.2.dev1"}}}
|
102
ThirdParty/cqparts_motors/catalogue/scripts/dc-hobby.py
vendored
Executable file
102
ThirdParty/cqparts_motors/catalogue/scripts/dc-hobby.py
vendored
Executable file
|
@ -0,0 +1,102 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
# Catalogue Usage example:
|
||||
# >>> from cqparts.catalogue import JSONCatalogue
|
||||
# >>> import cqparts_motors
|
||||
# >>> filename = os.path.join(
|
||||
# ... os.path.dirname(cqparts_motors.__file__),
|
||||
# ... 'catalogue', 'dcmotor.json',
|
||||
# ... )
|
||||
# >>> catalogue = JSONCatalogue(filename)
|
||||
# >>> item = catalogue.get_query()
|
||||
# >>> dc = catalogue.get(item.criteria.size == 304)
|
||||
# >>> from cqparts.display import display
|
||||
# >>> display(dc)
|
||||
|
||||
import os
|
||||
|
||||
import cqparts
|
||||
from cqparts.catalogue import JSONCatalogue
|
||||
|
||||
# DC Motor
|
||||
from cqparts_motors.dc import DCMotor
|
||||
|
||||
|
||||
CATALOGUE_NAME = 'dcmotor.json'
|
||||
|
||||
# DC Motor hobby examples
|
||||
# example only
|
||||
DC_HOBBY = {
|
||||
'130':
|
||||
{
|
||||
"profile": "flat",
|
||||
"diam": 20.4,
|
||||
"shaft_length": 11.55,
|
||||
"cover_height": 0.0,
|
||||
"thickness": 15.4,
|
||||
"bush_height": 1.6,
|
||||
"shaft_diam": 2.0,
|
||||
"bush_diam": 6.15,
|
||||
"height": 25.1
|
||||
},
|
||||
'R140':
|
||||
{
|
||||
"profile": "circle",
|
||||
"diam": 20.4,
|
||||
"shaft_length": 11.55,
|
||||
"cover_height": 0.0,
|
||||
"step_diam": 12.0,
|
||||
"thickness": 15.4,
|
||||
"bush_height": 1.6,
|
||||
"step_height": 1,
|
||||
"shaft_diam": 2.0,
|
||||
"bush_diam": 6.15,
|
||||
"height": 25.1
|
||||
},
|
||||
'slotcar':
|
||||
{
|
||||
"profile": "rect",
|
||||
"diam": 23,
|
||||
"shaft_length": 8,
|
||||
"cover_height": 0.0,
|
||||
"step_diam": 12.0,
|
||||
"thickness": 15.4,
|
||||
"bush_height": 1.6,
|
||||
"step_height": 0.0,
|
||||
"shaft_diam": 2.0,
|
||||
"bush_diam": 4,
|
||||
"height": 17
|
||||
},
|
||||
'flat':
|
||||
{
|
||||
"profile": "circle",
|
||||
"diam": 20.4,
|
||||
"shaft_length": 6,
|
||||
"cover_height": 0.0,
|
||||
"step_diam": 12.0,
|
||||
"thickness": 15.4,
|
||||
"bush_height": 0.4,
|
||||
"step_height": 0.0,
|
||||
"shaft_diam": 2.0,
|
||||
"bush_diam": 6.15,
|
||||
"height": 10
|
||||
}
|
||||
}
|
||||
|
||||
# Generate Catalogue
|
||||
catalogue = JSONCatalogue(
|
||||
filename=os.path.join('..', CATALOGUE_NAME),
|
||||
clean=True, # starts fresh
|
||||
)
|
||||
|
||||
# Create Motors
|
||||
for (name, params) in DC_HOBBY.items():
|
||||
catalogue.add(
|
||||
id= name,
|
||||
obj=DCMotor(**params),
|
||||
criteria={
|
||||
'type': 'motor',
|
||||
'class': 'dc',
|
||||
'diam': params['diam'],
|
||||
},
|
||||
)
|
102
ThirdParty/cqparts_motors/catalogue/scripts/stepper-nema.py
vendored
Executable file
102
ThirdParty/cqparts_motors/catalogue/scripts/stepper-nema.py
vendored
Executable file
|
@ -0,0 +1,102 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
# Catalogue Usage example:
|
||||
# >>> from cqparts.catalogue import JSONCatalogue
|
||||
# >>> import cqparts_motors
|
||||
# >>> filename = os.path.join(
|
||||
# ... os.path.dirname(cqparts_motors.__file__),
|
||||
# ... 'catalogue', 'stepper-nema.json',
|
||||
# ... )
|
||||
# >>> catalogue = JSONCatalogue(filename)
|
||||
# >>> item = catalogue.get_query()
|
||||
# >>> stepper = catalogue.get(item.criteria.size == 17)
|
||||
# >>> from cqparts.display import display
|
||||
# >>> display(stepper)
|
||||
|
||||
import os
|
||||
|
||||
import cqparts
|
||||
from cqparts.catalogue import JSONCatalogue
|
||||
|
||||
# Stepper
|
||||
from cqparts_motors.stepper import Stepper
|
||||
|
||||
|
||||
CATALOGUE_NAME = 'stepper-nema.json'
|
||||
|
||||
# Sized motors , build into collection
|
||||
# http://www.osmtec.com/stepper_motors.htm is a good reference
|
||||
# sizes 8, 11, 14, 16, 17, 23, 24, 34, 42
|
||||
# Stepper.class_params().keys()
|
||||
|
||||
NEMA_SIZES = {
|
||||
8 : {
|
||||
'shaft_length': 10.0,
|
||||
'hole_spacing': 15.4,
|
||||
'hole_size': 2.0,
|
||||
'length': 28.0,
|
||||
'width': 20.3,
|
||||
'boss_size': 16.0,
|
||||
'shaft_diam': 4.0,
|
||||
'boss_length': 1.5,
|
||||
},
|
||||
11 : {
|
||||
'shaft_length': 20.0,
|
||||
'hole_spacing': 23.0,
|
||||
'hole_size': 2.5,
|
||||
'length': 31.5,
|
||||
'width': 28.2,
|
||||
'boss_size': 22.0,
|
||||
'shaft_diam': 4.0,
|
||||
'boss_length': 2.0,
|
||||
},
|
||||
14 : {
|
||||
'shaft_length': 24.0,
|
||||
'hole_spacing': 26.0,
|
||||
'hole_size': 3.0,
|
||||
'length': 28.0,
|
||||
'width': 35.2,
|
||||
'boss_size': 22.0,
|
||||
'shaft_diam': 5.0,
|
||||
'boss_length': 2.0,
|
||||
},
|
||||
17 : {
|
||||
'shaft_length': 24.0,
|
||||
'hole_spacing': 31.0,
|
||||
'hole_size': 3.0,
|
||||
'length': 50.0,
|
||||
'width': 42.0,
|
||||
'boss_size': 22.0,
|
||||
'shaft_diam': 5.0,
|
||||
'boss_length': 2.0,
|
||||
},
|
||||
23 : {
|
||||
'shaft_length': 21.0,
|
||||
'hole_spacing': 47.0,
|
||||
'hole_size': 5.0,
|
||||
'length': 56.0,
|
||||
'width': 57.0,
|
||||
'boss_size': 38.0,
|
||||
'shaft_diam': 6.35,
|
||||
'boss_length': 1.6,
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
# Generate Catalogue
|
||||
catalogue = JSONCatalogue(
|
||||
filename=os.path.join('..', CATALOGUE_NAME),
|
||||
clean=True, # starts fresh
|
||||
)
|
||||
|
||||
# Create Steppers
|
||||
for (size, params) in NEMA_SIZES.items():
|
||||
catalogue.add(
|
||||
id='NEMA_Stepper_%i' % size,
|
||||
obj=Stepper(**params),
|
||||
criteria={
|
||||
'type': 'motor',
|
||||
'class': 'stepper',
|
||||
'size': size,
|
||||
},
|
||||
)
|
1
ThirdParty/cqparts_motors/catalogue/stepper-nema.json
vendored
Normal file
1
ThirdParty/cqparts_motors/catalogue/stepper-nema.json
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
{"items": {"1": {"obj": {"params": {"boss_length": 1.5, "shaft_length": 10.0, "hole_spacing": 15.4, "hole_size": 2.0, "boss_size": 16.0, "length": 28.0, "shaft_diam": 4.0, "width": 20.3}, "class": {"name": "Stepper", "module": "cqparts_motors.stepper"}, "lib": {"version": "0.2.2.dev1", "name": "cqparts"}}, "id": "NEMA_Stepper_8", "criteria": {"type": "motor", "class": "stepper", "size": 8}}, "2": {"obj": {"params": {"boss_length": 2.0, "shaft_length": 24.0, "hole_spacing": 31.0, "hole_size": 3.0, "boss_size": 22.0, "length": 50.0, "shaft_diam": 5.0, "width": 42.0}, "class": {"name": "Stepper", "module": "cqparts_motors.stepper"}, "lib": {"version": "0.2.2.dev1", "name": "cqparts"}}, "id": "NEMA_Stepper_17", "criteria": {"type": "motor", "class": "stepper", "size": 17}}, "3": {"obj": {"params": {"boss_length": 2.0, "shaft_length": 20.0, "hole_spacing": 23.0, "hole_size": 2.5, "boss_size": 22.0, "length": 31.5, "shaft_diam": 4.0, "width": 28.2}, "class": {"name": "Stepper", "module": "cqparts_motors.stepper"}, "lib": {"version": "0.2.2.dev1", "name": "cqparts"}}, "id": "NEMA_Stepper_11", "criteria": {"type": "motor", "class": "stepper", "size": 11}}, "4": {"obj": {"params": {"boss_length": 2.0, "shaft_length": 24.0, "hole_spacing": 26.0, "hole_size": 3.0, "boss_size": 22.0, "length": 28.0, "shaft_diam": 5.0, "width": 35.2}, "class": {"name": "Stepper", "module": "cqparts_motors.stepper"}, "lib": {"version": "0.2.2.dev1", "name": "cqparts"}}, "id": "NEMA_Stepper_14", "criteria": {"type": "motor", "class": "stepper", "size": 14}}, "5": {"obj": {"params": {"boss_length": 1.6, "shaft_length": 21.0, "hole_spacing": 47.0, "hole_size": 5.0, "boss_size": 38.0, "length": 56.0, "shaft_diam": 6.35, "width": 57.0}, "class": {"name": "Stepper", "module": "cqparts_motors.stepper"}, "lib": {"version": "0.2.2.dev1", "name": "cqparts"}}, "id": "NEMA_Stepper_23", "criteria": {"type": "motor", "class": "stepper", "size": 23}}}, "_dbinfo": {"1": {"module": "cqparts.catalogue.json", "ver": "0.1", "name": "JSONCatalogue", "lib": "cqparts", "lib_version": "0.2.2.dev1"}}}
|
170
ThirdParty/cqparts_motors/dc.py
vendored
Normal file
170
ThirdParty/cqparts_motors/dc.py
vendored
Normal file
|
@ -0,0 +1,170 @@
|
|||
"""
|
||||
DC motor cqparts model
|
||||
2018 Simon Kirkby obeygiantrobot@gmail.com
|
||||
"""
|
||||
|
||||
import math
|
||||
import cadquery as cq
|
||||
|
||||
import cqparts
|
||||
from cqparts.params import PositiveFloat, String
|
||||
from cqparts.display import render_props
|
||||
from cqparts.constraint import Fixed, Coincident
|
||||
from cqparts.constraint import Mate
|
||||
from cqparts.utils.geometry import CoordSystem
|
||||
|
||||
from cqparts_motors import shaft, motor
|
||||
|
||||
|
||||
# defines the profile of the motor , returns a wire
|
||||
def _profile(shape, diam, thickness):
|
||||
work_plane = cq.Workplane("XY")
|
||||
if shape == "circle":
|
||||
profile = work_plane.circle(diam/2)
|
||||
|
||||
if shape == "flat":
|
||||
radius = diam / 2
|
||||
half_thickness = thickness / 2
|
||||
intersect = math.sqrt(radius*radius-half_thickness*half_thickness)
|
||||
profile = work_plane.moveTo(0, half_thickness)\
|
||||
.lineTo(intersect, half_thickness)\
|
||||
.threePointArc((radius, 0), (intersect, -half_thickness))\
|
||||
.lineTo(0, -half_thickness)\
|
||||
.mirrorY()
|
||||
|
||||
if shape == "rect":
|
||||
profile = work_plane.rect(thickness/2, diam/2)
|
||||
return profile
|
||||
|
||||
# the motor cup
|
||||
class _Cup(cqparts.Part):
|
||||
height = PositiveFloat(25.1, doc="cup length")
|
||||
diam = PositiveFloat(20.4, doc="cup diameter")
|
||||
thickness = PositiveFloat(15.4, doc="cup thickness for flat profile")
|
||||
hole_spacing = PositiveFloat(12.4, doc="distance between the holes")
|
||||
hole_size = PositiveFloat(2, doc="hole size")
|
||||
step_diam = PositiveFloat(12, doc="step diameter")
|
||||
step_height = PositiveFloat(0, doc="height if step, if zero no step")
|
||||
bush_diam = PositiveFloat(6.15, doc="diameter of the bush")
|
||||
bush_height = PositiveFloat(1.6, doc="height of the bush")
|
||||
|
||||
profile = String("flat", doc="profile shape (circle|flat|rect)")
|
||||
|
||||
def make(self):
|
||||
# grab the correct profile
|
||||
work_plane = cq.Workplane("XY")
|
||||
cup = _profile(self.profile, self.diam, self.thickness)\
|
||||
.extrude(-self.height)
|
||||
if self.step_height > 0:
|
||||
step = work_plane.circle(self.step_diam/2).extrude(self.step_height)
|
||||
cup = cup.union(step)
|
||||
bush = work_plane.workplane(
|
||||
offset=self.step_height)\
|
||||
.circle(self.bush_diam/2)\
|
||||
.extrude(self.bush_height)
|
||||
cup = cup.union(bush)
|
||||
return cup
|
||||
|
||||
def get_cutout(self, clearance=0):
|
||||
" get the cutout for the shaft"
|
||||
return cq.Workplane('XY', origin=(0, 0, 0)) \
|
||||
.circle((self.diam / 2) + clearance) \
|
||||
.extrude(10)
|
||||
|
||||
@property
|
||||
def mate_bottom(self):
|
||||
" connect to the bottom of the cup"
|
||||
return Mate(self, CoordSystem(\
|
||||
origin=(0, 0, -self.height),\
|
||||
xDir=(1, 0, 0),\
|
||||
normal=(0, 0, 1)))
|
||||
|
||||
|
||||
class _BackCover(cqparts.Part):
|
||||
height = PositiveFloat(6, doc="back length")
|
||||
diam = PositiveFloat(20.4, doc="back diameter")
|
||||
thickness = PositiveFloat(15.4, doc="back thickness for flat profile")
|
||||
profile = String("flat", doc="profile shape (circle|flat|rect)")
|
||||
bush_diam = PositiveFloat(6.15, doc="diameter of the bush")
|
||||
bush_height = PositiveFloat(1.6, doc="height of the bush")
|
||||
|
||||
_render = render_props(color=(50, 255, 255))
|
||||
|
||||
def make(self):
|
||||
# grab the correct profile
|
||||
work_plane = cq.Workplane("XY")
|
||||
back = work_plane.workplane(offset=-self.height)\
|
||||
.circle(self.bush_diam/2)\
|
||||
.extrude(-self.bush_height)
|
||||
if self.height > 0:
|
||||
back = _profile(self.profile, self.diam, self.thickness)\
|
||||
.extrude(-self.height)
|
||||
back = back.union(back)
|
||||
return back
|
||||
|
||||
|
||||
class DCMotor(motor.Motor):
|
||||
"""
|
||||
DC motors for models
|
||||
|
||||
.. image:: /_static/img/motors/DCMotor.png
|
||||
"""
|
||||
height = PositiveFloat(25.1, doc="motor length")
|
||||
diam = PositiveFloat(20.4, doc="motor diameter")
|
||||
thickness = PositiveFloat(15.4, doc="back thickness for flat profile")
|
||||
profile = String("flat", doc="profile shape (circle|flat|rect)")
|
||||
|
||||
bush_diam = PositiveFloat(6.15, doc="diameter of the bush")
|
||||
bush_height = PositiveFloat(1.6, doc="height of the bush")
|
||||
|
||||
shaft_type = shaft.Shaft #replace with other shaft
|
||||
shaft_length = PositiveFloat(11.55, doc="length of the shaft")
|
||||
shaft_diam = PositiveFloat(2, doc="diameter of the shaft")
|
||||
|
||||
cover_height = PositiveFloat(0, doc="back cover height")
|
||||
|
||||
# a step on the top surface
|
||||
step_height = PositiveFloat(0, doc="height if step, if zero no step")
|
||||
step_diam = PositiveFloat(12, doc="step diameter")
|
||||
|
||||
def get_shaft(self):
|
||||
return self.shaft_type
|
||||
|
||||
def mount_points(self):
|
||||
# TODO handle mount points
|
||||
pass
|
||||
|
||||
def make_components(self):
|
||||
return {
|
||||
'body': _Cup(
|
||||
height=self.height,
|
||||
thickness=self.thickness,
|
||||
diam=self.diam,
|
||||
profile=self.profile,
|
||||
bush_diam=self.bush_diam,
|
||||
bush_height=self.bush_height,
|
||||
step_height=self.step_height
|
||||
),
|
||||
'shaft': self.shaft_type(length=self.shaft_length, diam=self.shaft_diam),
|
||||
'back': _BackCover(
|
||||
height=self.cover_height,
|
||||
thickness=self.thickness,
|
||||
diam=self.diam,
|
||||
profile=self.profile,
|
||||
bush_diam=self.bush_diam,
|
||||
bush_height=self.bush_height
|
||||
)
|
||||
}
|
||||
|
||||
def make_constraints(self):
|
||||
return [
|
||||
Fixed(self.components['body'].mate_origin),
|
||||
Coincident(
|
||||
self.components['shaft'].mate_origin,
|
||||
self.components['body'].mate_origin,
|
||||
),
|
||||
Coincident(
|
||||
self.components['back'].mate_origin,
|
||||
self.components['body'].mate_bottom,
|
||||
)
|
||||
]
|
18
ThirdParty/cqparts_motors/motor.py
vendored
Normal file
18
ThirdParty/cqparts_motors/motor.py
vendored
Normal file
|
@ -0,0 +1,18 @@
|
|||
# base motor class
|
||||
#
|
||||
|
||||
# 2018 Simon Kirkby obeygiantrobot@gmail.com
|
||||
|
||||
import cqparts
|
||||
|
||||
# base motor class
|
||||
# TODO lift all motor things up to here
|
||||
|
||||
class Motor(cqparts.Assembly):
|
||||
|
||||
def mount_points(self):
|
||||
raise NotImplementedError("mount_points function not implemented")
|
||||
|
||||
def get_shaft(self):
|
||||
raise NotImplementedError("get_shaft function not implemented")
|
||||
|
1
ThirdParty/cqparts_motors/requirements.txt
vendored
Normal file
1
ThirdParty/cqparts_motors/requirements.txt
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
cqparts
|
48
ThirdParty/cqparts_motors/shaft.py
vendored
Normal file
48
ThirdParty/cqparts_motors/shaft.py
vendored
Normal file
|
@ -0,0 +1,48 @@
|
|||
"""
|
||||
cp parts
|
||||
base shaft collection
|
||||
# 2018 Simon Kirkby obeygiantrobot@gmail.com
|
||||
"""
|
||||
|
||||
# TODO
|
||||
# need tip , base and offset mate points
|
||||
# maybe shaft needs to go into it's own module
|
||||
#
|
||||
# there are lots of types of shafts and extras
|
||||
# need a clean way to build shafts
|
||||
|
||||
import cadquery as cq
|
||||
|
||||
import cqparts
|
||||
from cqparts.params import PositiveFloat
|
||||
from cqparts.display import render_props
|
||||
|
||||
# base shaft type
|
||||
class Shaft(cqparts.Part):
|
||||
" base shaft , override ME"
|
||||
length = PositiveFloat(24, doc="shaft length")
|
||||
diam = PositiveFloat(5, doc="shaft diameter")
|
||||
|
||||
_render = render_props(color=(50, 255, 255))
|
||||
|
||||
def make(self):
|
||||
shft = cq.Workplane("XY")\
|
||||
.circle(self.diam/2)\
|
||||
.extrude(self.length)\
|
||||
.faces(">Z")\
|
||||
.chamfer(0.4)
|
||||
return shft
|
||||
|
||||
def cut_out(self):
|
||||
cutout = cq.Workplane("XY")\
|
||||
.circle(self.diam/2)\
|
||||
.extrude(self.length)
|
||||
return cutout
|
||||
|
||||
# TODO , mate for shafts
|
||||
|
||||
def get_cutout(self, clearance=0):
|
||||
" clearance cut out for shaft "
|
||||
return cq.Workplane('XY', origin=(0, 0, 0)) \
|
||||
.circle((self.diam / 2) + clearance) \
|
||||
.extrude(self.length*2)
|
225
ThirdParty/cqparts_motors/stepper.py
vendored
Normal file
225
ThirdParty/cqparts_motors/stepper.py
vendored
Normal file
|
@ -0,0 +1,225 @@
|
|||
|
||||
""" cqparts motors
|
||||
2018 Simon Kirkby obeygiantrobot@gmail.com
|
||||
stepper motor generic
|
||||
"""
|
||||
|
||||
# TODO
|
||||
# even 4 fasteners so it auto mounts to whatever it is parented to.
|
||||
|
||||
import cadquery as cq
|
||||
|
||||
import cqparts
|
||||
from cqparts.params import PositiveFloat
|
||||
from cqparts.constraint import Fixed, Coincident
|
||||
from cqparts.constraint import Mate
|
||||
from cqparts.display import render_props
|
||||
from cqparts.utils.geometry import CoordSystem
|
||||
|
||||
import shaft
|
||||
import motor
|
||||
|
||||
class _EndCap(cqparts.Part):
|
||||
# Parameters
|
||||
width = PositiveFloat(42.3, doc="Motor Size")
|
||||
length = PositiveFloat(10, doc="End length")
|
||||
cham = PositiveFloat(3, doc="chamfer")
|
||||
|
||||
# _render = render_props(color=(50, 50, 50),alpha=0.4)
|
||||
def make(self):
|
||||
base = cq.Workplane("XY")\
|
||||
.box(self.width, self.width, self.length)\
|
||||
.edges("|Z")\
|
||||
.chamfer(self.cham)
|
||||
return base
|
||||
|
||||
@property
|
||||
def mate_top(self):
|
||||
" connect to the end of the top cap"
|
||||
return Mate(self, CoordSystem(
|
||||
origin=(0, 0, -self.length/2),
|
||||
xDir=(0, 1, 0),
|
||||
normal=(0, 0, -1)
|
||||
))
|
||||
|
||||
@property
|
||||
def mate_bottom(self):
|
||||
" bottom of the top cap"
|
||||
return Mate(self, CoordSystem(
|
||||
origin=(0, 0, -self.length/2),
|
||||
xDir=(0, 1, 0),
|
||||
normal=(0, 0, 1)
|
||||
))
|
||||
|
||||
|
||||
class _Stator(cqparts.Part):
|
||||
# Parameters
|
||||
width = PositiveFloat(40.0, doc="Motor Size")
|
||||
length = PositiveFloat(20, doc="stator length")
|
||||
cham = PositiveFloat(3, doc="chamfer")
|
||||
|
||||
_render = render_props(color=(50, 50, 50))
|
||||
|
||||
def make(self):
|
||||
base = cq.Workplane("XY")\
|
||||
.box(self.width, self.width, self.length,centered=(True,True,True))\
|
||||
.edges("|Z")\
|
||||
.chamfer(self.cham)
|
||||
return base
|
||||
|
||||
@property
|
||||
def mate_top(self):
|
||||
" top of the stator"
|
||||
return Mate(self, CoordSystem(
|
||||
origin=(0, 0, self.length/2),
|
||||
xDir=(0, 1, 0),
|
||||
normal=(0, 0, 1)
|
||||
))
|
||||
|
||||
@property
|
||||
def mate_bottom(self):
|
||||
" bottom of the stator"
|
||||
return Mate(self, CoordSystem(
|
||||
origin=(0, 0, -self.length/2),
|
||||
xDir=(1, 0, 0),
|
||||
normal=(0, 0, -1)
|
||||
))
|
||||
|
||||
|
||||
class _StepperMount(_EndCap):
|
||||
spacing = PositiveFloat(31, doc="hole spacing")
|
||||
hole_size = PositiveFloat(3, doc="hole size")
|
||||
boss = PositiveFloat(22, doc="boss size")
|
||||
boss_length = PositiveFloat(2, doc="boss_length")
|
||||
|
||||
def make(self):
|
||||
obj = super(_StepperMount, self).make()
|
||||
obj.faces(">Z").workplane() \
|
||||
.rect(self.spacing, self.spacing, forConstruction=True)\
|
||||
.vertices() \
|
||||
.hole(self.hole_size)
|
||||
obj.faces(">Z").workplane()\
|
||||
.circle(self.boss/2).extrude(self.boss_length)
|
||||
return obj
|
||||
|
||||
@property
|
||||
def mate_top(self):
|
||||
" top of the mount"
|
||||
return Mate(self, CoordSystem(
|
||||
origin=(0, 0, self.length/2),
|
||||
xDir=(0, 1, 0),
|
||||
normal=(0, 0, 1)
|
||||
))
|
||||
|
||||
@property
|
||||
def mate_bottom(self):
|
||||
" bottom of the mount"
|
||||
return Mate(self, CoordSystem(
|
||||
origin=(0, 0,-self.length/2),
|
||||
xDir=(0, 1, 0),
|
||||
normal=(0, 0, 1)
|
||||
))
|
||||
|
||||
|
||||
class _Back(_EndCap):
|
||||
spacing = PositiveFloat(31, doc="hole spacing")
|
||||
hole_size = PositiveFloat(3, doc="hole size")
|
||||
|
||||
def make(self):
|
||||
obj = super(_Back, self).make()
|
||||
obj.faces(">Z").workplane() \
|
||||
.rect(self.spacing, self.spacing, forConstruction=True)\
|
||||
.vertices() \
|
||||
.hole(self.hole_size)
|
||||
return obj
|
||||
|
||||
|
||||
class Stepper(motor.Motor):
|
||||
" Stepper Motor , simple rendering "
|
||||
shaft_type = shaft.Shaft
|
||||
|
||||
width = PositiveFloat(42.3, doc="width and depth of the stepper")
|
||||
length = PositiveFloat(50, doc="length of the stepper")
|
||||
hole_spacing = PositiveFloat(31.0, doc="distance between centers")
|
||||
hole_size = PositiveFloat(3, doc="hole diameter , select screw with this")
|
||||
boss_size = PositiveFloat(22, doc="diameter of the raise circle")
|
||||
boss_length = PositiveFloat(2, doc="length away from the top surface")
|
||||
|
||||
shaft_diam = PositiveFloat(5, doc="diameter of the the shaft ")
|
||||
shaft_length = PositiveFloat(24, doc="length from top surface")
|
||||
|
||||
def get_shaft(self):
|
||||
return self.components['shaft']
|
||||
|
||||
def mount_points(self):
|
||||
" return mount points"
|
||||
wp = cq.Workplane("XY")
|
||||
h = wp.rect(self.hole_spacing,self.hole_spacing
|
||||
,forConstruction=True).vertices()
|
||||
return h.objects
|
||||
|
||||
def make_components(self):
|
||||
sec = self.length / 6
|
||||
return {
|
||||
'topcap': _StepperMount(
|
||||
width=self.width,
|
||||
length=sec,
|
||||
spacing=self.hole_spacing,
|
||||
hole_size=self.hole_size,
|
||||
boss=self.boss_size
|
||||
),
|
||||
'stator': _Stator(width=self.width-3, length=sec*4),
|
||||
'botcap': _Back(
|
||||
width=self.width,
|
||||
length=sec,
|
||||
spacing=self.hole_spacing,
|
||||
hole_size=self.hole_size,
|
||||
),
|
||||
'shaft': self.shaft_type(
|
||||
length=self.shaft_length,
|
||||
diam=self.shaft_diam)
|
||||
}
|
||||
|
||||
def make_constraints(self):
|
||||
return [
|
||||
Fixed(self.components['topcap'].mate_top),
|
||||
Coincident(
|
||||
self.components['stator'].mate_top,
|
||||
self.components['topcap'].mate_bottom,
|
||||
),
|
||||
Coincident(
|
||||
self.components['botcap'].mate_bottom,
|
||||
self.components['stator'].mate_bottom
|
||||
),
|
||||
Coincident(
|
||||
self.components['shaft'].mate_origin,
|
||||
self.components['topcap'].mate_top
|
||||
),
|
||||
]
|
||||
|
||||
def apply_cutout(self):
|
||||
" shaft cutout "
|
||||
stepper_shaft = self.components['shaft']
|
||||
top = self.components['topcap']
|
||||
local_obj = top.local_obj
|
||||
local_obj = local_obj.cut(stepper_shaft.get_cutout(clearance=0.5))
|
||||
|
||||
def make_alterations(self):
|
||||
self.apply_cutout()
|
||||
|
||||
def boss_cutout(self,clearance=0):
|
||||
bc = cq.Workplane("XY")\
|
||||
.circle(self.boss_size/2)\
|
||||
.extrude(self.shaft_length)
|
||||
return bc
|
||||
|
||||
def cut_boss(self,part,clearance=0):
|
||||
co = self.boss_cutout(clearance=clearance)
|
||||
lo = part.local_obj\
|
||||
.cut((self.world_coords - part.world_coords)+co)
|
||||
|
||||
if __name__ == "__main__":
|
||||
from cqparts.display import display
|
||||
st = Stepper()
|
||||
display(st)
|
||||
|
1
ThirdParty/cqparts_springs/LICENSE
vendored
Symbolic link
1
ThirdParty/cqparts_springs/LICENSE
vendored
Symbolic link
|
@ -0,0 +1 @@
|
|||
../../LICENSE
|
17
ThirdParty/cqparts_springs/__init__.py
vendored
Normal file
17
ThirdParty/cqparts_springs/__init__.py
vendored
Normal file
|
@ -0,0 +1,17 @@
|
|||
"""
|
||||
Copyright 2018 Peter Boin
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
"""
|
||||
|
||||
__release_ready__ = False # TODO: remove to stop blocking build
|
1
ThirdParty/cqparts_springs/requirements.txt
vendored
Normal file
1
ThirdParty/cqparts_springs/requirements.txt
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
cqparts
|
1
ThirdParty/cqparts_template/LICENSE
vendored
Symbolic link
1
ThirdParty/cqparts_template/LICENSE
vendored
Symbolic link
|
@ -0,0 +1 @@
|
|||
../../LICENSE
|
25
ThirdParty/cqparts_template/README.md
vendored
Normal file
25
ThirdParty/cqparts_template/README.md
vendored
Normal file
|
@ -0,0 +1,25 @@
|
|||
# `cqparts` library template
|
||||
|
||||
This is a library template intended to be copied then modified to contain your
|
||||
created components.
|
||||
|
||||
This library has a number of examples intended to illustrate the following:
|
||||
|
||||
* End user buildable components
|
||||
* `Part` and `Assembly` classes
|
||||
* Registration with `cqparts.search` [optional]
|
||||
* Intermediate sub-components used for building
|
||||
* `Part` and `Assembly` classes prefixed with `_`
|
||||
* Sphinx documentation practices
|
||||
* Creating a `Catalogue` of your component variants.
|
||||
|
||||
# Steps to Creating a New Library
|
||||
|
||||
The following steps should give you an idea of how to proceed:
|
||||
|
||||
1. **Copy**: Make a copy of this folder, and re-name it to
|
||||
`cqparts_<your-lib-name>`.
|
||||
1. **Create**: Create your _components_.
|
||||
1. **TODO**: search for occurances of `TODO`, and addres each item.
|
||||
1. **`README.md`**: `TODO`: remember to rename `README.tmp.md` to `README.md`,
|
||||
replacing this file.
|
20
ThirdParty/cqparts_template/README.tmp.md
vendored
Normal file
20
ThirdParty/cqparts_template/README.tmp.md
vendored
Normal file
|
@ -0,0 +1,20 @@
|
|||
# `cqparts_TODO` Components
|
||||
|
||||
TODO: brief description of your library, include an image
|
||||
|
||||
## Components
|
||||
|
||||
TODO: List components by group, give a user an idea of the breadth of the
|
||||
library's content
|
||||
|
||||
## Utilities
|
||||
|
||||
TODO: List anything that isn't strictly a `Component` that may be used as part
|
||||
of this library.
|
||||
|
||||
## Example
|
||||
|
||||
TODO: A brief example of your library, include fully qualified code and an image
|
||||
of the resulting model
|
||||
For more detailed documentation, consider using sphinx, that way cross-linking
|
||||
of components in documentation is easy.
|
41
ThirdParty/cqparts_template/__init__.py
vendored
Normal file
41
ThirdParty/cqparts_template/__init__.py
vendored
Normal file
|
@ -0,0 +1,41 @@
|
|||
"""
|
||||
Copyright 2018 Peter Boin
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
"""
|
||||
|
||||
__release_ready__ = False # TODO: remove to stop blocking build
|
||||
|
||||
__title__ = "cqparts_<lib_name>" # TODO
|
||||
__description__ = "<brief description>" # TODO
|
||||
__url__ = "<library url>" # TODO
|
||||
|
||||
__version__ = "0.1.0"
|
||||
__author__ = "<your name>" # TODO
|
||||
|
||||
|
||||
# ------ Registration
|
||||
from cqparts.search import (
|
||||
find as _find,
|
||||
search as _search,
|
||||
register as _register,
|
||||
)
|
||||
from cqparts.search import common_criteria
|
||||
|
||||
module_criteria = {
|
||||
'library': __name__,
|
||||
}
|
||||
|
||||
register = common_criteria(**module_criteria)(_register)
|
||||
search = common_criteria(**module_criteria)(_search)
|
||||
find = common_criteria(**module_criteria)(_find)
|
1
ThirdParty/cqparts_template/catalogue/pegs.json
vendored
Normal file
1
ThirdParty/cqparts_template/catalogue/pegs.json
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
{"items": {"1": {"obj": {"params": {"spring_wire_diam": 1.3, "minor_radius": 1.0, "spring_arm_length": 17.5, "tip_chamfer": 5.0, "minor_depth": 1.0, "handle_length": 35.0, "depth": 7.0, "width": 10.0, "handle_tip_depth": 2.0, "minor_offset": 31.0, "major_depth": 2.0, "spring_diam": 5.0, "major_radius": 10.0, "length": 90.0, "major_offset": 17.0}, "class": {"name": "ClothesPeg", "module": "cqparts_template.clamp.peg"}, "lib": {"version": "0.1.0", "name": "cqparts"}}, "id": "PEG01", "criteria": {"style": "long"}}, "2": {"obj": {"params": {"spring_wire_diam": 1.3, "minor_radius": 1.0, "spring_arm_length": 17.5, "tip_chamfer": 5.0, "minor_depth": 1.0, "handle_length": 30.0, "handle_tip_depth": 2.0, "width": 10.0, "depth": 7.0, "minor_offset": 31.0, "major_depth": 2.0, "spring_diam": 5.0, "major_radius": 10.0, "length": 75.0, "major_offset": 17.0}, "class": {"name": "ClothesPeg", "module": "cqparts_template.clamp.peg"}, "lib": {"version": "0.1.0", "name": "cqparts"}}, "id": "PEG02", "criteria": {"style": "norm"}}, "3": {"obj": {"params": {"depth": 7.0, "spring_wire_diam": 1.3, "minor_radius": 1.0, "spring_arm_length": 17.5, "tip_chamfer": 5.0, "minor_depth": 1.0, "handle_length": 20.0, "handle_tip_depth": 2.0, "width": 10.0, "spring_diam": 5.0, "minor_offset": 31.0, "major_depth": 2.0, "major_radius": 10.0, "length": 60.0, "major_offset": 17.0}, "class": {"name": "ClothesPeg", "module": "cqparts_template.clamp.peg"}, "lib": {"version": "0.1.0", "name": "cqparts"}}, "id": "PEG03", "criteria": {"style": "short"}}}, "_dbinfo": {"1": {"lib_version": "0.1.0", "ver": "0.1", "name": "JSONCatalogue", "module": "cqparts.catalogue.json", "lib": "cqparts"}}}
|
9
ThirdParty/cqparts_template/catalogue/scripts/README.md
vendored
Normal file
9
ThirdParty/cqparts_template/catalogue/scripts/README.md
vendored
Normal file
|
@ -0,0 +1,9 @@
|
|||
# Catalogue Scripts
|
||||
|
||||
Scripts, and input files in this folder are used to build catalogues for the
|
||||
parent directory.
|
||||
|
||||
This folder is not a sub-module so it should **not** contain a `__init__.py`
|
||||
file.
|
||||
|
||||
TODO: remove this file, or replace it with content relevant to the scripts.
|
78
ThirdParty/cqparts_template/catalogue/scripts/build.py
vendored
Executable file
78
ThirdParty/cqparts_template/catalogue/scripts/build.py
vendored
Executable file
|
@ -0,0 +1,78 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
import argparse
|
||||
import os
|
||||
import inspect
|
||||
import csv
|
||||
|
||||
import cqparts
|
||||
from cqparts.catalogue import JSONCatalogue
|
||||
|
||||
# TODO: import your library
|
||||
# TODO: if you don't offer a catalogue for your library, then
|
||||
# remove this `scripts` folder.
|
||||
import cqparts_template
|
||||
|
||||
from cqparts_template.clamp.peg import ClothesPeg
|
||||
|
||||
# ---------- Parameter Defaults ----------
|
||||
_this_path = os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe())))
|
||||
|
||||
def _relative_path_to(path_list, filename):
|
||||
"""Get a neat relative path to files relative to the CWD"""
|
||||
return os.path.join(
|
||||
os.path.relpath(os.path.join(*path_list), os.getcwd()),
|
||||
filename
|
||||
)
|
||||
|
||||
DEFAULT_OUTPUT = _relative_path_to([_this_path, '..'], 'pegs.json')
|
||||
DEFAULT_INPUT = _relative_path_to([_this_path], 'pegs.csv')
|
||||
|
||||
parser = argparse.ArgumentParser(
|
||||
prog='Build catalogue', # TODO: change program name
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
'-o', '--output', dest='output',
|
||||
default=DEFAULT_OUTPUT, metavar="FILE",
|
||||
help='catalogue file to write',
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
'-i', '--input', dest='input',
|
||||
default=DEFAULT_INPUT, metavar="FILE",
|
||||
help='component parameters file',
|
||||
)
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
|
||||
# ---------- Component Builders ----------
|
||||
# TODO: build your own objects in whatever way suits your application.
|
||||
|
||||
def build_obj(cls, **kwargs):
|
||||
# Take any parameters relevent to the given class from kwargs
|
||||
# (all other parameters ignored)
|
||||
class_params = cls.class_params()
|
||||
obj_kwargs = {
|
||||
key: kwargs.pop(key, param.default)
|
||||
for (key, param) in class_params.items()
|
||||
}
|
||||
|
||||
return cls(**obj_kwargs)
|
||||
|
||||
|
||||
# ---------- Create Catalogue ----------
|
||||
|
||||
catalogue = JSONCatalogue(args.output, clean=True)
|
||||
|
||||
with open(args.input, "rb" ) as csv_fileio:
|
||||
csv_reader = csv.DictReader(csv_fileio)
|
||||
for line in csv_reader:
|
||||
obj = build_obj(ClothesPeg, **line)
|
||||
criteria = {
|
||||
key: line[key]
|
||||
for key in line.keys()
|
||||
if (not hasattr(obj, key)) and (key not in ('ID',))
|
||||
}
|
||||
catalogue.add(id=line['ID'], obj=obj, criteria=criteria)
|
4
ThirdParty/cqparts_template/catalogue/scripts/pegs.csv
vendored
Normal file
4
ThirdParty/cqparts_template/catalogue/scripts/pegs.csv
vendored
Normal file
|
@ -0,0 +1,4 @@
|
|||
ID,length,handle_length,style
|
||||
PEG01,90,35,long
|
||||
PEG02,75,30,norm
|
||||
PEG03,60,20,short
|
|
5
ThirdParty/cqparts_template/clamp/__init__.py
vendored
Normal file
5
ThirdParty/cqparts_template/clamp/__init__.py
vendored
Normal file
|
@ -0,0 +1,5 @@
|
|||
__all__ = [
|
||||
'ClothesPeg',
|
||||
]
|
||||
|
||||
from .peg import ClothesPeg
|
182
ThirdParty/cqparts_template/clamp/peg.py
vendored
Normal file
182
ThirdParty/cqparts_template/clamp/peg.py
vendored
Normal file
|
@ -0,0 +1,182 @@
|
|||
|
||||
# TODO: illustrative model only; remove this file
|
||||
|
||||
import cadquery
|
||||
|
||||
import cqparts
|
||||
from cqparts.params import *
|
||||
from cqparts.display import render_props
|
||||
from cqparts import constraint
|
||||
from cqparts.utils import CoordSystem
|
||||
|
||||
from .. import register
|
||||
|
||||
|
||||
class _PegSide(cqparts.Part):
|
||||
"""
|
||||
One side of a wooden clothes peg.
|
||||
|
||||
Note that this docstring does not get rendered in the sphinx automated
|
||||
documentation, this is because the class is prefixed with a ``_``.
|
||||
|
||||
Also: idiomatic Python dictates that components with a ``_`` prefix are not
|
||||
intended for an end-user, which is why they're not documented.
|
||||
"""
|
||||
|
||||
length = PositiveFloat()
|
||||
width = PositiveFloat()
|
||||
depth = PositiveFloat()
|
||||
|
||||
tip_chamfer = PositiveFloat()
|
||||
handle_tip_depth = PositiveFloat()
|
||||
handle_length = PositiveFloat()
|
||||
|
||||
# spring
|
||||
spring_diam = PositiveFloat()
|
||||
spring_arm_length = PositiveFloat()
|
||||
spring_wire_diam = PositiveFloat()
|
||||
|
||||
# major indent
|
||||
major_radius = PositiveFloat()
|
||||
major_depth = PositiveFloat()
|
||||
major_offset = PositiveFloat()
|
||||
|
||||
# minor indent
|
||||
minor_radius = PositiveFloat()
|
||||
minor_depth = PositiveFloat()
|
||||
minor_offset = PositiveFloat()
|
||||
|
||||
# Default material to render
|
||||
_render = render_props(template='wood')
|
||||
|
||||
def make(self):
|
||||
# Main profile shape of peg
|
||||
points = [
|
||||
(0, 0), (self.length, 0),
|
||||
(self.length, self.handle_tip_depth),
|
||||
(self.length - self.handle_length, self.depth),
|
||||
(self.tip_chamfer, self.depth),
|
||||
(0, self.depth - self.tip_chamfer),
|
||||
]
|
||||
|
||||
side = cadquery.Workplane('XY') \
|
||||
.moveTo(*points[0]).polyline(points[1:]).close() \
|
||||
.extrude(self.width)
|
||||
|
||||
# cut spring
|
||||
side = side.cut(cadquery.Workplane('XY') \
|
||||
.moveTo(self.length - self.handle_length, self.depth) \
|
||||
.circle(self.spring_diam / 2).extrude(self.width)
|
||||
)
|
||||
|
||||
# cut indents
|
||||
def cut_indent(obj, radius, depth, offset):
|
||||
return obj.cut(cadquery.Workplane('XY') \
|
||||
.moveTo(offset, self.depth + (radius - depth)) \
|
||||
.circle(radius).extrude(self.width)
|
||||
)
|
||||
side = cut_indent(
|
||||
obj=side,
|
||||
radius=self.major_radius,
|
||||
depth=self.major_depth,
|
||||
offset=self.major_offset,
|
||||
)
|
||||
side = cut_indent(
|
||||
obj=side,
|
||||
radius=self.minor_radius,
|
||||
depth=self.minor_depth,
|
||||
offset=self.minor_offset,
|
||||
)
|
||||
|
||||
return side
|
||||
|
||||
@property
|
||||
def mate_spring_center(self):
|
||||
# mate in the center of the spring, z-axis along spring center
|
||||
return constraint.Mate(self, CoordSystem(
|
||||
origin=(self.length - self.handle_length, self.depth, self.width / 2),
|
||||
))
|
||||
|
||||
@property
|
||||
def mate_side(self):
|
||||
# mate in middle of outside edge, z-axis into peg
|
||||
return constraint.Mate(self, CoordSystem(
|
||||
origin=(self.length / 2, 0, self.width / 2),
|
||||
xDir=(0, 0, -1),
|
||||
normal=(0, 1, 0),
|
||||
))
|
||||
|
||||
|
||||
class _Spring(cqparts.Part):
|
||||
diam = PositiveFloat()
|
||||
arm_length = PositiveFloat()
|
||||
wire_diam = PositiveFloat()
|
||||
width = PositiveFloat()
|
||||
|
||||
def make(self):
|
||||
spring = cadquery.Workplane('XY', origin=(0, 0, -(self.width / 2 + self.wire_diam))) \
|
||||
.circle(self.diam / 2).circle((self.diam / 2) - self.wire_diam) \
|
||||
.extrude(self.width + (2 * self.wire_diam))
|
||||
|
||||
return spring
|
||||
|
||||
|
||||
@register(module=__name__, name='clothespeg', type='peg_clamp')
|
||||
class ClothesPeg(cqparts.Assembly):
|
||||
"""
|
||||
A common household clothes-peg
|
||||
|
||||
.. image:: /_static/img/template/peg.png
|
||||
"""
|
||||
|
||||
length = PositiveFloat(75, doc="length of peg side")
|
||||
width = PositiveFloat(10, doc="peg width")
|
||||
depth = PositiveFloat(7, doc="depth of peg side, half peg's full depth")
|
||||
|
||||
tip_chamfer = PositiveFloat(5, doc="chamfer at tip")
|
||||
handle_tip_depth = PositiveFloat(2, doc="depth at handle's tip")
|
||||
handle_length = PositiveFloat(30, doc="length of tapered handle")
|
||||
|
||||
# spring
|
||||
spring_diam = PositiveFloat(5, doc="diameter of spring's core")
|
||||
spring_arm_length = PositiveFloat(17.5, doc="length of spring's arm converting torque to closing force")
|
||||
spring_wire_diam = PositiveFloat(1.3, doc="diamter of spring's wire")
|
||||
|
||||
# major indent
|
||||
major_radius = PositiveFloat(10, doc="large indentation's radius")
|
||||
major_depth = PositiveFloat(2, doc="large indentation's depth")
|
||||
major_offset = PositiveFloat(17, doc="large indentation center's distance from tip")
|
||||
|
||||
# minor indent
|
||||
minor_radius = PositiveFloat(1, doc="small indentation's radius")
|
||||
minor_depth = PositiveFloat(1, doc="small indentation's depth")
|
||||
minor_offset = PositiveFloat(31, doc="small indentation center's distance from tip")
|
||||
|
||||
def make_components(self):
|
||||
params = self.params(hidden=False) # common to _PegSide
|
||||
return {
|
||||
'bottom': _PegSide(**params),
|
||||
'top': _PegSide(**params),
|
||||
'spring': _Spring(
|
||||
diam=self.spring_diam,
|
||||
arm_length=self.spring_arm_length,
|
||||
wire_diam=self.spring_wire_diam,
|
||||
width=self.width,
|
||||
),
|
||||
}
|
||||
|
||||
def make_constraints(self):
|
||||
bottom = self.components['bottom']
|
||||
top = self.components['top']
|
||||
spring = self.components['spring']
|
||||
return [
|
||||
constraint.Fixed(bottom.mate_side),
|
||||
constraint.Coincident(
|
||||
top.mate_spring_center,
|
||||
bottom.mate_spring_center + CoordSystem(normal=(0, 0, -1))
|
||||
),
|
||||
constraint.Coincident(
|
||||
spring.mate_origin,
|
||||
bottom.mate_spring_center
|
||||
),
|
||||
]
|
1
ThirdParty/cqparts_template/requirements.txt
vendored
Normal file
1
ThirdParty/cqparts_template/requirements.txt
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
cqparts
|
15
ThirdParty/cqparts_template/search.py
vendored
Normal file
15
ThirdParty/cqparts_template/search.py
vendored
Normal file
|
@ -0,0 +1,15 @@
|
|||
|
||||
from cqparts.search import (
|
||||
find as _find,
|
||||
search as _search,
|
||||
register as _register,
|
||||
)
|
||||
from cqparts.search import common_criteria
|
||||
|
||||
module_criteria = {
|
||||
'module': __name__,
|
||||
}
|
||||
|
||||
register = common_criteria(**module_criteria)(_register)
|
||||
search = common_criteria(**module_criteria)(_search)
|
||||
find = common_criteria(**module_criteria)(_find)
|
1
ThirdParty/cqparts_torquelimiters/LICENSE
vendored
Symbolic link
1
ThirdParty/cqparts_torquelimiters/LICENSE
vendored
Symbolic link
|
@ -0,0 +1 @@
|
|||
../../LICENSE
|
17
ThirdParty/cqparts_torquelimiters/__init__.py
vendored
Normal file
17
ThirdParty/cqparts_torquelimiters/__init__.py
vendored
Normal file
|
@ -0,0 +1,17 @@
|
|||
"""
|
||||
Copyright 2018 Peter Boin
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
"""
|
||||
|
||||
__release_ready__ = False # TODO: remove to stop blocking build
|
0
ThirdParty/cqparts_torquelimiters/ball_detent.py
vendored
Normal file
0
ThirdParty/cqparts_torquelimiters/ball_detent.py
vendored
Normal file
1
ThirdParty/cqparts_torquelimiters/requirements.txt
vendored
Normal file
1
ThirdParty/cqparts_torquelimiters/requirements.txt
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
cqparts
|
0
ThirdParty/cqparts_torquelimiters/sheer_pin.py
vendored
Normal file
0
ThirdParty/cqparts_torquelimiters/sheer_pin.py
vendored
Normal file
1
ThirdParty/cqparts_toys/LICENSE
vendored
Symbolic link
1
ThirdParty/cqparts_toys/LICENSE
vendored
Symbolic link
|
@ -0,0 +1 @@
|
|||
../../LICENSE
|
17
ThirdParty/cqparts_toys/__init__.py
vendored
Normal file
17
ThirdParty/cqparts_toys/__init__.py
vendored
Normal file
|
@ -0,0 +1,17 @@
|
|||
"""
|
||||
Copyright 2018 Peter Boin
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
"""
|
||||
|
||||
__release_ready__ = False # TODO: remove to stop blocking build
|
1
ThirdParty/cqparts_toys/requirements.txt
vendored
Normal file
1
ThirdParty/cqparts_toys/requirements.txt
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
cqparts
|
0
ThirdParty/cqparts_toys/train/__init__.py
vendored
Normal file
0
ThirdParty/cqparts_toys/train/__init__.py
vendored
Normal file
188
ThirdParty/cqparts_toys/train/track.py
vendored
Normal file
188
ThirdParty/cqparts_toys/train/track.py
vendored
Normal file
|
@ -0,0 +1,188 @@
|
|||
import cadquery
|
||||
|
||||
import cqparts
|
||||
from cqparts.params import *
|
||||
|
||||
from cqparts.utils import property_buffered
|
||||
from cqparts.display.material import render_props
|
||||
from cqparts.constraint import Mate
|
||||
from cqparts.utils import CoordSystem
|
||||
|
||||
|
||||
class _Track(cqparts.Part):
|
||||
|
||||
double_sided = Boolean(True, doc="if set, track is cut from both sides")
|
||||
|
||||
# Profile Metrics
|
||||
width = PositiveFloat(30, doc="track width")
|
||||
depth = PositiveFloat(8, doc="track thickness")
|
||||
track_guage = PositiveFloat(None, doc="distance between wheel centers")
|
||||
track_width = PositiveFloat(None, doc="wheel's width")
|
||||
track_depth = PositiveFloat(2, doc="depth each track is cut")
|
||||
track_chamfer = PositiveFloat(None, doc="chamfer at wheel's edges")
|
||||
|
||||
# Connector
|
||||
conn_diam = PositiveFloat(None, doc="diameter of connector circle")
|
||||
conn_neck_width = PositiveFloat(None, doc="connector neck width")
|
||||
conn_neck_length = PositiveFloat(None, doc="connector neck length")
|
||||
conn_clearance = PositiveFloat(0.5, doc="clearance ")
|
||||
|
||||
_render = render_props(template='wood')
|
||||
|
||||
def initialize_parameters(self):
|
||||
super(_Track, self).initialize_parameters()
|
||||
|
||||
if self.track_guage is None:
|
||||
self.track_guage = self.width * (2. / 3)
|
||||
if self.track_width is None:
|
||||
self.track_width = self.track_guage / 4
|
||||
if self.track_depth is None:
|
||||
self.track_depth = self.track_width / 2
|
||||
if self.track_chamfer is None:
|
||||
self.track_chamfer = self.track_depth / 3
|
||||
|
||||
if self.conn_diam is None:
|
||||
self.conn_diam = self.depth
|
||||
if self.conn_neck_width is None:
|
||||
self.conn_neck_width = self.conn_diam / 3
|
||||
if self.conn_neck_length is None:
|
||||
self.conn_neck_length = self.conn_diam * 0.6
|
||||
|
||||
@property
|
||||
def _wheel_profile(self):
|
||||
|
||||
if self.track_chamfer:
|
||||
|
||||
left_side = (self.track_guage / 2) - (self.track_width / 2)
|
||||
points = [
|
||||
(left_side - (self.track_chamfer * 2), (self.depth / 2) + self.track_depth),
|
||||
(left_side - (self.track_chamfer * 2), (self.depth / 2) + self.track_chamfer),
|
||||
(left_side, (self.depth / 2) - self.track_chamfer), # remove if self.track_chamfer == 0
|
||||
(left_side, (self.depth / 2) - self.track_depth),
|
||||
]
|
||||
# mirror over x = self.track_guage / 2 plane
|
||||
points += [(self.track_guage - x, y) for (x, y) in reversed(points)]
|
||||
|
||||
else:
|
||||
# no chamfer, just plot the points for a rectangle
|
||||
points = [
|
||||
((self.track_guage / 2) - (self.track_width / 2), (self.depth / 2) + self.track_depth),
|
||||
((self.track_guage / 2) - (self.track_width / 2), (self.depth / 2) - self.track_depth),
|
||||
((self.track_guage / 2) + (self.track_width / 2), (self.depth / 2) - self.track_depth),
|
||||
((self.track_guage / 2) + (self.track_width / 2), (self.depth / 2) + self.track_depth),
|
||||
]
|
||||
|
||||
flip = lambda p, xf, yf: (p[0] * xf, p[1] * yf)
|
||||
|
||||
profile = cadquery.Workplane('XZ') \
|
||||
.moveTo(*flip(points[0], 1, 1)).polyline([flip(p, 1, 1) for p in points[1:]]).close() \
|
||||
.moveTo(*flip(points[0], -1, 1)).polyline([flip(p, -1, 1) for p in points[1:]]).close()
|
||||
if self.double_sided:
|
||||
profile = profile \
|
||||
.moveTo(*flip(points[0], 1, -1)).polyline([flip(p, 1, -1) for p in points[1:]]).close() \
|
||||
.moveTo(*flip(points[0], -1, -1)).polyline([flip(p, -1, -1) for p in points[1:]]).close()
|
||||
|
||||
return profile
|
||||
|
||||
@property
|
||||
def _track_profile(self):
|
||||
return cadquery.Workplane('XZ').rect(self.width, self.depth)
|
||||
|
||||
def _get_connector(self, clearance=False):
|
||||
clear_dist = self.conn_clearance if clearance else 0.
|
||||
return cadquery.Workplane('XY').box(
|
||||
self.conn_neck_width + (clear_dist * 2),
|
||||
self.conn_neck_length + self.conn_diam / 2,
|
||||
self.depth,
|
||||
centered=(True, False, True),
|
||||
).union(cadquery.Workplane('XY', origin=(
|
||||
0, self.conn_neck_length + self.conn_diam / 2, -self.depth / 2
|
||||
)).circle((self.conn_diam / 2) + clear_dist).extrude(self.depth))
|
||||
|
||||
@property
|
||||
def conn_length(self):
|
||||
return self.conn_neck_length + self.conn_diam
|
||||
|
||||
|
||||
class StraightTrack(_Track):
|
||||
"""
|
||||
.. image:: /_static/img/toys/track-straight.png
|
||||
"""
|
||||
|
||||
length = PositiveFloat(100, doc="track length")
|
||||
|
||||
def make(self):
|
||||
track = self._track_profile.extrude(self.length) \
|
||||
.translate((0, self.length / 2, 0)) \
|
||||
.union(self._get_connector().translate((0, self.length / 2, 0))) \
|
||||
.cut(self._get_connector(True).translate((0, -self.length / 2, 0)))
|
||||
|
||||
# cut tracks
|
||||
track = track.cut(
|
||||
self._wheel_profile \
|
||||
.extrude(self.length + self.conn_length) \
|
||||
.translate((0, self.length / 2 + self.conn_length, 0))
|
||||
)
|
||||
|
||||
return track
|
||||
|
||||
def make_simple(self):
|
||||
return self._track_profile.extrude(self.length) \
|
||||
.translate((0, self.length / 2, 0))
|
||||
|
||||
@property
|
||||
def mate_start(self):
|
||||
return Mate(self, CoordSystem((0, -self.length / 2, 0)))
|
||||
|
||||
@property
|
||||
def mate_end(self):
|
||||
return Mate(self, CoordSystem((0, self.length / 2, 0)))
|
||||
|
||||
|
||||
class CurvedTrack(_Track):
|
||||
"""
|
||||
.. image:: /_static/img/toys/track-curved.png
|
||||
"""
|
||||
|
||||
turn_radius = Float(100, doc="radius of turn")
|
||||
turn_angle = FloatRange(0, 360, 45, doc="arc angle covered by track (unit: degrees)")
|
||||
|
||||
def make(self):
|
||||
revolve_params = {
|
||||
'angleDegrees': self.turn_angle,
|
||||
'axisStart': (self.turn_radius, 0),
|
||||
'axisEnd': (self.turn_radius, 1 if (self.turn_radius > 0) else -1),
|
||||
}
|
||||
|
||||
track = self._track_profile.revolve(**revolve_params) \
|
||||
.translate((-self.turn_radius, 0, 0)) \
|
||||
.cut(self.mate_start.local_coords + self._get_connector(True)) \
|
||||
.union(self.mate_end.local_coords + self._get_connector(False))
|
||||
|
||||
# cut tracks
|
||||
track = track.cut(
|
||||
self._wheel_profile.revolve(**revolve_params) \
|
||||
.translate((-self.turn_radius, 0, 0))
|
||||
)
|
||||
track = track.cut(
|
||||
self.mate_end.local_coords + self._wheel_profile.extrude(-self.conn_length)
|
||||
)
|
||||
|
||||
return track
|
||||
#return self._wheel_profile.extrude(self.conn_length)
|
||||
|
||||
def make_simple(self):
|
||||
return self._track_profile.revolve(
|
||||
angleDegrees=self.turn_angle,
|
||||
axisStart=(self.turn_radius, 0),
|
||||
axisEnd=(self.turn_radius, 1),
|
||||
).translate((-self.turn_radius, 0, 0)) \
|
||||
|
||||
@property
|
||||
def mate_start(self):
|
||||
return Mate(self, CoordSystem((-self.turn_radius, 0, 0)))
|
||||
|
||||
@property
|
||||
def mate_end(self):
|
||||
angle = self.turn_angle if (self.turn_radius < 0) else -self.turn_angle
|
||||
return Mate(self, CoordSystem().rotated((0, 0, angle)) + self.mate_start.local_coords)
|
Loading…
Reference in New Issue
Block a user