piecad 1.0.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- piecad-1.0.0/.gitignore +2 -0
- piecad-1.0.0/.gitmodules +0 -0
- piecad-1.0.0/LICENSE +30 -0
- piecad-1.0.0/Makefile +22 -0
- piecad-1.0.0/PKG-INFO +12 -0
- piecad-1.0.0/README.md +23 -0
- piecad-1.0.0/doc_examples/cone.example +1 -0
- piecad-1.0.0/doc_examples/cube.example +1 -0
- piecad-1.0.0/doc_examples/cuboid.example +1 -0
- piecad-1.0.0/doc_examples/difference2d.example +3 -0
- piecad-1.0.0/doc_examples/difference3d.example +3 -0
- piecad-1.0.0/doc_examples/ellipsoid.example +1 -0
- piecad-1.0.0/doc_examples/elliptical_cylinder.example +1 -0
- piecad-1.0.0/doc_examples/extrude.example +1 -0
- piecad-1.0.0/doc_examples/extrude_chaining.example +19 -0
- piecad-1.0.0/doc_examples/extrude_transforming.example +4 -0
- piecad-1.0.0/doc_examples/geodesic_sphere.example +1 -0
- piecad-1.0.0/doc_examples/hull2d.example +4 -0
- piecad-1.0.0/doc_examples/hull3d.example +4 -0
- piecad-1.0.0/doc_examples/intersect2d.example +3 -0
- piecad-1.0.0/doc_examples/intersect3d.example +3 -0
- piecad-1.0.0/doc_examples/mk_doc_examples +26 -0
- piecad-1.0.0/doc_examples/polygon.example +6 -0
- piecad-1.0.0/doc_examples/process_example.py +82 -0
- piecad-1.0.0/doc_examples/pyramid.example +1 -0
- piecad-1.0.0/doc_examples/revolve.example +1 -0
- piecad-1.0.0/doc_examples/rounded_cuboid.example +1 -0
- piecad-1.0.0/doc_examples/rounded_cylinder.example +1 -0
- piecad-1.0.0/doc_examples/sphere.example +1 -0
- piecad-1.0.0/doc_examples/torus.example +1 -0
- piecad-1.0.0/doc_examples/union2d.example +3 -0
- piecad-1.0.0/doc_examples/union3d.example +3 -0
- piecad-1.0.0/docs/bulk_ops.html +294 -0
- piecad-1.0.0/docs/examples/cone.html +51 -0
- piecad-1.0.0/docs/examples/cube.html +51 -0
- piecad-1.0.0/docs/examples/cuboid.html +51 -0
- piecad-1.0.0/docs/examples/difference2d.html +53 -0
- piecad-1.0.0/docs/examples/difference3d.html +53 -0
- piecad-1.0.0/docs/examples/ellipsoid.html +51 -0
- piecad-1.0.0/docs/examples/elliptical_cylinder.html +51 -0
- piecad-1.0.0/docs/examples/extrude.html +51 -0
- piecad-1.0.0/docs/examples/extrude_chaining.html +69 -0
- piecad-1.0.0/docs/examples/extrude_transforming.html +54 -0
- piecad-1.0.0/docs/examples/geodesic_sphere.html +51 -0
- piecad-1.0.0/docs/examples/hull2d.html +54 -0
- piecad-1.0.0/docs/examples/hull3d.html +54 -0
- piecad-1.0.0/docs/examples/intersect2d.html +53 -0
- piecad-1.0.0/docs/examples/intersect3d.html +53 -0
- piecad-1.0.0/docs/examples/polygon.html +56 -0
- piecad-1.0.0/docs/examples/pyramid.html +51 -0
- piecad-1.0.0/docs/examples/revolve.html +51 -0
- piecad-1.0.0/docs/examples/rounded_cuboid.html +51 -0
- piecad-1.0.0/docs/examples/rounded_cylinder.html +51 -0
- piecad-1.0.0/docs/examples/sphere.html +51 -0
- piecad-1.0.0/docs/examples/torus.html +51 -0
- piecad-1.0.0/docs/examples/union2d.html +53 -0
- piecad-1.0.0/docs/examples/union3d.html +53 -0
- piecad-1.0.0/docs/index.html +1740 -0
- piecad-1.0.0/docs/models/cone.glb +0 -0
- piecad-1.0.0/docs/models/cube.glb +0 -0
- piecad-1.0.0/docs/models/cuboid.glb +0 -0
- piecad-1.0.0/docs/models/difference2d.glb +0 -0
- piecad-1.0.0/docs/models/difference3d.glb +0 -0
- piecad-1.0.0/docs/models/ellipsoid.glb +0 -0
- piecad-1.0.0/docs/models/elliptical_cylinder.glb +0 -0
- piecad-1.0.0/docs/models/extrude.glb +0 -0
- piecad-1.0.0/docs/models/extrude_chaining.glb +0 -0
- piecad-1.0.0/docs/models/extrude_transforming.glb +0 -0
- piecad-1.0.0/docs/models/geodesic_sphere.glb +0 -0
- piecad-1.0.0/docs/models/hull2d.glb +0 -0
- piecad-1.0.0/docs/models/hull3d.glb +0 -0
- piecad-1.0.0/docs/models/intersect2d.glb +0 -0
- piecad-1.0.0/docs/models/intersect3d.glb +0 -0
- piecad-1.0.0/docs/models/polygon.glb +0 -0
- piecad-1.0.0/docs/models/pyramid.glb +0 -0
- piecad-1.0.0/docs/models/revolve.glb +0 -0
- piecad-1.0.0/docs/models/rounded_cuboid.glb +0 -0
- piecad-1.0.0/docs/models/rounded_cylinder.glb +0 -0
- piecad-1.0.0/docs/models/sphere.glb +0 -0
- piecad-1.0.0/docs/models/torus.glb +0 -0
- piecad-1.0.0/docs/models/union2d.glb +0 -0
- piecad-1.0.0/docs/models/union3d.glb +0 -0
- piecad-1.0.0/docs/primitives_2d.html +493 -0
- piecad-1.0.0/docs/primitives_3d.html +902 -0
- piecad-1.0.0/docs/trigonometry.html +310 -0
- piecad-1.0.0/docs/utilities.html +371 -0
- piecad-1.0.0/examples/NeilMedDrainStandv1.py +71 -0
- piecad-1.0.0/examples/NeilMedDrainStandv2.py +91 -0
- piecad-1.0.0/examples/kid_n_b.py +124 -0
- piecad-1.0.0/examples/kid_nail.py +48 -0
- piecad-1.0.0/examples/name_plate.py +39 -0
- piecad-1.0.0/examples/piecad +1 -0
- piecad-1.0.0/piecad/__init__.py +665 -0
- piecad-1.0.0/piecad/_color.py +202 -0
- piecad-1.0.0/piecad/_poly_point_isect.py +1391 -0
- piecad-1.0.0/piecad/_text.py +114 -0
- piecad-1.0.0/piecad/bulk_ops.py +159 -0
- piecad-1.0.0/piecad/fonts/Hack-Regular-License.txt +45 -0
- piecad-1.0.0/piecad/fonts/Hack-Regular.ttf +0 -0
- piecad-1.0.0/piecad/fonts/Roboto-Regular-License.txt +93 -0
- piecad-1.0.0/piecad/fonts/Roboto-Regular.ttf +0 -0
- piecad-1.0.0/piecad/primitives_2d.py +306 -0
- piecad-1.0.0/piecad/primitives_3d.py +590 -0
- piecad-1.0.0/piecad/trigonometry.py +152 -0
- piecad-1.0.0/piecad/utilities.py +272 -0
- piecad-1.0.0/pyproject.toml +28 -0
- piecad-1.0.0/serve_docs +4 -0
- piecad-1.0.0/setup +5 -0
- piecad-1.0.0/tests/piecad +1 -0
- piecad-1.0.0/tests/summary.py +53 -0
- piecad-1.0.0/tests/test_2d.py +294 -0
- piecad-1.0.0/tests/test_3d.py +245 -0
- piecad-1.0.0/tests/test_bulk_ops.py +94 -0
- piecad-1.0.0/tests/test_color.py +55 -0
- piecad-1.0.0/tests/test_m_direct.py +220 -0
- piecad-1.0.0/tests/test_methods.py +185 -0
- piecad-1.0.0/tests/test_text.py +48 -0
- piecad-1.0.0/tests/test_trig.py +159 -0
piecad-1.0.0/.gitignore
ADDED
piecad-1.0.0/.gitmodules
ADDED
|
File without changes
|
piecad-1.0.0/LICENSE
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
The bulk of the code is covered by this license:
|
|
2
|
+
|
|
3
|
+
The MIT License (MIT)
|
|
4
|
+
|
|
5
|
+
Copyright (c) 2025 Brian Sturgill
|
|
6
|
+
|
|
7
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
8
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
9
|
+
in the Software without restriction, including without limitation the rights
|
|
10
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
11
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
12
|
+
furnished to do so, subject to the following conditions:
|
|
13
|
+
|
|
14
|
+
The above copyright notice and this permission notice shall be included in
|
|
15
|
+
all copies or substantial portions of the Software.
|
|
16
|
+
|
|
17
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
18
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
19
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
20
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
21
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
22
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
23
|
+
THE SOFTWARE.
|
|
24
|
+
----
|
|
25
|
+
|
|
26
|
+
The file `piecad/_poly_point_isect.py` has it's own license (located at the top of the file).
|
|
27
|
+
|
|
28
|
+
----
|
|
29
|
+
|
|
30
|
+
Fonts are covered by a separate license, see the License files in piecad/fonts for details.
|
piecad-1.0.0/Makefile
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
|
|
2
|
+
all: test docs
|
|
3
|
+
|
|
4
|
+
docs:
|
|
5
|
+
black piecad/*.py tests/*.py doc_examples/*.example examples/*.py
|
|
6
|
+
rm -rf docs/*
|
|
7
|
+
pdoc3 --html piecad --force
|
|
8
|
+
(cd doc_examples; ./mk_doc_examples)
|
|
9
|
+
mv html/piecad docs
|
|
10
|
+
rmdir html
|
|
11
|
+
|
|
12
|
+
test:
|
|
13
|
+
pytest tests --benchmark-disable
|
|
14
|
+
|
|
15
|
+
benchmark:
|
|
16
|
+
pytest tests --benchmark-only
|
|
17
|
+
|
|
18
|
+
savebenchmark:
|
|
19
|
+
(read -p "Benchmark Name: " -r NAME ; pytest tests --benchmark-only --benchmark-save=`date +%F`"$${NAME}" --benchmark-name=short)
|
|
20
|
+
|
|
21
|
+
clean:
|
|
22
|
+
rm -f examples/*.obj
|
piecad-1.0.0/PKG-INFO
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: piecad
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: "Easy as Pie" CAD (Piecad)
|
|
5
|
+
Author-email: Brian Sturgill <codersnext@gmail.com>
|
|
6
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
7
|
+
Requires-Dist: trimesh >= 1.26.4
|
|
8
|
+
Requires-Dist: fontPens >= 0.2.4
|
|
9
|
+
Requires-Dist: fontTools >= 4.57.0
|
|
10
|
+
Requires-Dist: manifold3d >= 3.0.1
|
|
11
|
+
Requires-Dist: skia-pathops >= 0.8.0
|
|
12
|
+
Project-URL: Home, https://github.com/briansturgill/Piecad
|
piecad-1.0.0/README.md
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# "Easy as Pie" CAD (Piecad)
|
|
2
|
+
|
|
3
|
+
For many years I used [OpenSCAD](https://www.openscad.org),
|
|
4
|
+
but the functional language it uses was often a hinderance and its speed
|
|
5
|
+
was poor. **Piecad** is my opinionted view of what a good, simple CAD API should look like.
|
|
6
|
+
Its primary focus is the creation of models for 3D printing.
|
|
7
|
+
|
|
8
|
+
[Documentation](https://briansturgill.github.io/Piecad)
|
|
9
|
+
|
|
10
|
+
INSTALLATION IS STILL IN PROGRESS -- FINISHED SOON
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
## CREDITS
|
|
14
|
+
|
|
15
|
+
Piecad is based on [Manifold](https://github.com/elalish/manifold), a 3D CAD package written in C++.
|
|
16
|
+
Manifold incorporates [Clipper2](https://github.com/AngusJohnson/Clipper2) for 2D objects.
|
|
17
|
+
It also uses [`quickhull`](https://github.com/akuukka/quickhull) for 3d convex hulls.
|
|
18
|
+
You can see Manifold's web site for other packages that are used.
|
|
19
|
+
|
|
20
|
+
Piecad also uses [isect_segments-bentley_ottmann](https://github.com/ideasman42/isect_segments-bentley_ottmann)
|
|
21
|
+
to check for polygon self intersections. Also, [fontTools](https://github.com/fonttools/fonttools) and [fontPens](https://github.com/robotools/fontPens) are used to support text.
|
|
22
|
+
|
|
23
|
+
We include two fonts: `Hack-Regular.tts` and `Roboto-Regular.tts`, see `piecad/fonts` for the licenses.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
out = cone(10, 5, 0, 100)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
out = cube(10)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
out = cube([10, 5, 8])
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
out = ellipsoid((10, 5, 8), 100)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
out = elliptical_cylinder(18, (8, 5), 100)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
out = extrude(star(5, 4), 10)
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
def sphere_from_chaining(radius, segs):
|
|
2
|
+
deg_per_seg = 180.0 / segs
|
|
3
|
+
hs = (3.141592653589793 * radius) / segs
|
|
4
|
+
l = []
|
|
5
|
+
l.append((-radius, circle(0.3, segs)))
|
|
6
|
+
h_sum = -radius
|
|
7
|
+
for i in range(1, segs - 1):
|
|
8
|
+
factor = sin(i * deg_per_seg)
|
|
9
|
+
r = radius * factor
|
|
10
|
+
h = hs * factor
|
|
11
|
+
h_sum += h
|
|
12
|
+
l.append((h_sum, circle(r, segs)))
|
|
13
|
+
l.append((radius, circle(0.3, segs)))
|
|
14
|
+
|
|
15
|
+
s = extrude_chaining(l, is_convex=True)
|
|
16
|
+
return s
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
out = sphere_from_chaining(10, 60)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
out = geodesic_sphere(17)
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
#!/bin/sh
|
|
2
|
+
models="../html/piecad/models"
|
|
3
|
+
examples="../html/piecad/examples"
|
|
4
|
+
if [ ! -d $models ]; then
|
|
5
|
+
mkdir $models
|
|
6
|
+
fi
|
|
7
|
+
if [ ! -d $examples ]; then
|
|
8
|
+
mkdir $examples
|
|
9
|
+
fi
|
|
10
|
+
if [ ! -d tmp ]; then
|
|
11
|
+
mkdir tmp
|
|
12
|
+
fi
|
|
13
|
+
if [ ! -L tmp/piecad ]; then
|
|
14
|
+
ln -s ../../piecad tmp/piecad
|
|
15
|
+
fi
|
|
16
|
+
for f in *.example; do
|
|
17
|
+
echo $f
|
|
18
|
+
python process_example.py $f
|
|
19
|
+
if [ $? -ne 0 ]; then
|
|
20
|
+
exit $?
|
|
21
|
+
fi
|
|
22
|
+
done
|
|
23
|
+
mv tmp/*.glb $models
|
|
24
|
+
mv tmp/*.html $examples
|
|
25
|
+
rm tmp/*.py
|
|
26
|
+
rm tmp/piecad
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import sys
|
|
2
|
+
import os
|
|
3
|
+
|
|
4
|
+
if len(sys.argv) != 2:
|
|
5
|
+
print("Should have 1 argument.")
|
|
6
|
+
sys.exit(1)
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
idx = sys.argv[1].rindex(".example")
|
|
10
|
+
example_name=sys.argv[1][:idx]
|
|
11
|
+
|
|
12
|
+
with open(sys.argv[1], "r") as f:
|
|
13
|
+
example_code = f.readlines()
|
|
14
|
+
|
|
15
|
+
example_model = f"tmp/{example_name}.glb"
|
|
16
|
+
example_creator = f"tmp/{example_name}.py"
|
|
17
|
+
example_html = f"tmp/{example_name}.html"
|
|
18
|
+
|
|
19
|
+
template = f"""
|
|
20
|
+
<html>
|
|
21
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
22
|
+
<head>
|
|
23
|
+
<style>
|
|
24
|
+
body {{
|
|
25
|
+
background-color: lightblue;
|
|
26
|
+
color: black;
|
|
27
|
+
}}
|
|
28
|
+
pre {{
|
|
29
|
+
margin: 0;
|
|
30
|
+
text-align: left;
|
|
31
|
+
}}
|
|
32
|
+
.cd {{
|
|
33
|
+
padding-top: 0px;
|
|
34
|
+
}}
|
|
35
|
+
.mv {{
|
|
36
|
+
display: block;
|
|
37
|
+
margin-left: auto;
|
|
38
|
+
margin-right: auto;
|
|
39
|
+
width: 300px;
|
|
40
|
+
}}
|
|
41
|
+
</style>
|
|
42
|
+
</head>
|
|
43
|
+
<body>
|
|
44
|
+
<script type="module" src="https://ajax.googleapis.com/ajax/libs/model-viewer/3.4.0/model-viewer.min.js"></script>
|
|
45
|
+
<!--link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/default.min.css">-->
|
|
46
|
+
<!--script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/highlight.min.js"></script>-->
|
|
47
|
+
<!--script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/languages/python.min.js"></script>-->
|
|
48
|
+
<!--script>hljs.highlightAll();</script>-->
|
|
49
|
+
<table width="100%">
|
|
50
|
+
<tr>
|
|
51
|
+
<td class="cd">
|
|
52
|
+
<code>
|
|
53
|
+
<pre>
|
|
54
|
+
{"".join(example_code)}
|
|
55
|
+
</pre>
|
|
56
|
+
</code>
|
|
57
|
+
</td>
|
|
58
|
+
</tr>
|
|
59
|
+
<tr>
|
|
60
|
+
<td>
|
|
61
|
+
<div class="mv">
|
|
62
|
+
<model-viewer src="../models/{example_name}.glb" ar ar-scale="fixed" interaction-prompt="none" camera-controls touch-action="pan-y" disable-zoom alt="Output of code example." shadow-intensity="2" camera-orbit="0deg 180deg 0" xr-environment></model-viewer>
|
|
63
|
+
</div>
|
|
64
|
+
</td>
|
|
65
|
+
</tr>
|
|
66
|
+
</table>
|
|
67
|
+
</body>
|
|
68
|
+
</html>
|
|
69
|
+
"""
|
|
70
|
+
|
|
71
|
+
with open(example_html, "w") as f:
|
|
72
|
+
f.write(template)
|
|
73
|
+
|
|
74
|
+
with open(example_creator, "w") as f:
|
|
75
|
+
f.write("from piecad import *\n")
|
|
76
|
+
f.write("".join(example_code))
|
|
77
|
+
f.write("if type(out) == Obj2d: out = out.extrude(0.2)\n")
|
|
78
|
+
f.write("out = out.color(\"khaki\")\n")
|
|
79
|
+
f.write(f"save(\"{example_model}\", out)\n")
|
|
80
|
+
|
|
81
|
+
ret = os.system(f"python {example_creator}")
|
|
82
|
+
sys.exit(0 if ret == 0 else 1)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
out = pyramid(height=15, num_sides=4, radius=10)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
out = star(10, 5).translate([10, 0]).revolve(segments=100)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
out = rounded_cuboid((20, 16, 18), rounding_radius=3.0, segments=100)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
out = rounded_cylinder(18, 8, rounding_radius=3.0, segments=100)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
out = sphere(17, 100)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
out = torus(outer_radius=10, inner_radius=6, segments=100)
|
|
@@ -0,0 +1,294 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="utf-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1">
|
|
6
|
+
<meta name="generator" content="pdoc3 0.11.6">
|
|
7
|
+
<title>piecad.bulk_ops API documentation</title>
|
|
8
|
+
<meta name="description" content="Miscellaneous bulk operations that work on multiple objects.">
|
|
9
|
+
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/13.0.0/sanitize.min.css" integrity="sha512-y1dtMcuvtTMJc1yPgEqF0ZjQbhnc/bFhyvIyVNb9Zk5mIGtqVaAB1Ttl28su8AvFMOY0EwRbAe+HCLqj6W7/KA==" crossorigin>
|
|
10
|
+
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/13.0.0/typography.min.css" integrity="sha512-Y1DYSb995BAfxobCkKepB1BqJJTPrOp3zPL74AWFugHHmmdcvO+C48WLrUOlhGMc0QG7AE3f7gmvvcrmX2fDoA==" crossorigin>
|
|
11
|
+
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/default.min.css" crossorigin>
|
|
12
|
+
<style>:root{--highlight-color:#fe9}.flex{display:flex !important}body{line-height:1.5em}#content{padding:20px}#sidebar{padding:1.5em;overflow:hidden}#sidebar > *:last-child{margin-bottom:2cm}.http-server-breadcrumbs{font-size:130%;margin:0 0 15px 0}#footer{font-size:.75em;padding:5px 30px;border-top:1px solid #ddd;text-align:right}#footer p{margin:0 0 0 1em;display:inline-block}#footer p:last-child{margin-right:30px}h1,h2,h3,h4,h5{font-weight:300}h1{font-size:2.5em;line-height:1.1em}h2{font-size:1.75em;margin:2em 0 .50em 0}h3{font-size:1.4em;margin:1.6em 0 .7em 0}h4{margin:0;font-size:105%}h1:target,h2:target,h3:target,h4:target,h5:target,h6:target{background:var(--highlight-color);padding:.2em 0}a{color:#058;text-decoration:none;transition:color .2s ease-in-out}a:visited{color:#503}a:hover{color:#b62}.title code{font-weight:bold}h2[id^="header-"]{margin-top:2em}.ident{color:#900;font-weight:bold}pre code{font-size:.8em;line-height:1.4em;padding:1em;display:block}code{background:#f3f3f3;font-family:"DejaVu Sans Mono",monospace;padding:1px 4px;overflow-wrap:break-word}h1 code{background:transparent}pre{border-top:1px solid #ccc;border-bottom:1px solid #ccc;margin:1em 0}#http-server-module-list{display:flex;flex-flow:column}#http-server-module-list div{display:flex}#http-server-module-list dt{min-width:10%}#http-server-module-list p{margin-top:0}.toc ul,#index{list-style-type:none;margin:0;padding:0}#index code{background:transparent}#index h3{border-bottom:1px solid #ddd}#index ul{padding:0}#index h4{margin-top:.6em;font-weight:bold}@media (min-width:200ex){#index .two-column{column-count:2}}@media (min-width:300ex){#index .two-column{column-count:3}}dl{margin-bottom:2em}dl dl:last-child{margin-bottom:4em}dd{margin:0 0 1em 3em}#header-classes + dl > dd{margin-bottom:3em}dd dd{margin-left:2em}dd p{margin:10px 0}.name{background:#eee;font-size:.85em;padding:5px 10px;display:inline-block;min-width:40%}.name:hover{background:#e0e0e0}dt:target .name{background:var(--highlight-color)}.name > span:first-child{white-space:nowrap}.name.class > span:nth-child(2){margin-left:.4em}.inherited{color:#999;border-left:5px solid #eee;padding-left:1em}.inheritance em{font-style:normal;font-weight:bold}.desc h2{font-weight:400;font-size:1.25em}.desc h3{font-size:1em}.desc dt code{background:inherit}.source > summary,.git-link-div{color:#666;text-align:right;font-weight:400;font-size:.8em;text-transform:uppercase}.source summary > *{white-space:nowrap;cursor:pointer}.git-link{color:inherit;margin-left:1em}.source pre{max-height:500px;overflow:auto;margin:0}.source pre code{font-size:12px;overflow:visible;min-width:max-content}.hlist{list-style:none}.hlist li{display:inline}.hlist li:after{content:',\2002'}.hlist li:last-child:after{content:none}.hlist .hlist{display:inline;padding-left:1em}img{max-width:100%}td{padding:0 .5em}.admonition{padding:.1em 1em;margin:1em 0}.admonition-title{font-weight:bold}.admonition.note,.admonition.info,.admonition.important{background:#aef}.admonition.todo,.admonition.versionadded,.admonition.tip,.admonition.hint{background:#dfd}.admonition.warning,.admonition.versionchanged,.admonition.deprecated{background:#fd4}.admonition.error,.admonition.danger,.admonition.caution{background:lightpink}</style>
|
|
13
|
+
<style media="screen and (min-width: 700px)">@media screen and (min-width:700px){#sidebar{width:30%;height:100vh;overflow:auto;position:sticky;top:0}#content{width:70%;max-width:100ch;padding:3em 4em;border-left:1px solid #ddd}pre code{font-size:1em}.name{font-size:1em}main{display:flex;flex-direction:row-reverse;justify-content:flex-end}.toc ul ul,#index ul ul{padding-left:1em}.toc > ul > li{margin-top:.5em}}</style>
|
|
14
|
+
<style media="print">@media print{#sidebar h1{page-break-before:always}.source{display:none}}@media print{*{background:transparent !important;color:#000 !important;box-shadow:none !important;text-shadow:none !important}a[href]:after{content:" (" attr(href) ")";font-size:90%}a[href][title]:after{content:none}abbr[title]:after{content:" (" attr(title) ")"}.ir a:after,a[href^="javascript:"]:after,a[href^="#"]:after{content:""}pre,blockquote{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}tr,img{page-break-inside:avoid}img{max-width:100% !important}@page{margin:0.5cm}p,h2,h3{orphans:3;widows:3}h1,h2,h3,h4,h5,h6{page-break-after:avoid}}</style>
|
|
15
|
+
<script defer src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/highlight.min.js" integrity="sha512-D9gUyxqja7hBtkWpPWGt9wfbfaMGVt9gnyCvYa+jojwwPHLCzUm5i8rpk7vD7wNee9bA35eYIjobYPaQuKS1MQ==" crossorigin></script>
|
|
16
|
+
<script>window.addEventListener('DOMContentLoaded', () => {
|
|
17
|
+
hljs.configure({languages: ['bash', 'css', 'diff', 'graphql', 'ini', 'javascript', 'json', 'plaintext', 'python', 'python-repl', 'rust', 'shell', 'sql', 'typescript', 'xml', 'yaml']});
|
|
18
|
+
hljs.highlightAll();
|
|
19
|
+
/* Collapse source docstrings */
|
|
20
|
+
setTimeout(() => {
|
|
21
|
+
[...document.querySelectorAll('.hljs.language-python > .hljs-string')]
|
|
22
|
+
.filter(el => el.innerHTML.length > 200 && ['"""', "'''"].includes(el.innerHTML.substring(0, 3)))
|
|
23
|
+
.forEach(el => {
|
|
24
|
+
let d = document.createElement('details');
|
|
25
|
+
d.classList.add('hljs-string');
|
|
26
|
+
d.innerHTML = '<summary>"""</summary>' + el.innerHTML.substring(3);
|
|
27
|
+
el.replaceWith(d);
|
|
28
|
+
});
|
|
29
|
+
}, 100);
|
|
30
|
+
})</script>
|
|
31
|
+
</head>
|
|
32
|
+
<body>
|
|
33
|
+
<main>
|
|
34
|
+
<article id="content">
|
|
35
|
+
<header>
|
|
36
|
+
<h1 class="title">Module <code>piecad.bulk_ops</code></h1>
|
|
37
|
+
</header>
|
|
38
|
+
<section id="section-intro">
|
|
39
|
+
<h2 id="miscellaneous-bulk-operations-that-work-on-multiple-objects">Miscellaneous bulk operations that work on multiple objects.</h2>
|
|
40
|
+
</section>
|
|
41
|
+
<section>
|
|
42
|
+
</section>
|
|
43
|
+
<section>
|
|
44
|
+
</section>
|
|
45
|
+
<section>
|
|
46
|
+
<h2 class="section-title" id="header-functions">Functions</h2>
|
|
47
|
+
<dl>
|
|
48
|
+
<dt id="piecad.bulk_ops.compose"><code class="name flex">
|
|
49
|
+
<span>def <span class="ident">compose</span></span>(<span>*objs: <a title="piecad.Obj2d" href="index.html#piecad.Obj2d">Obj2d</a> | <a title="piecad.Obj3d" href="index.html#piecad.Obj3d">Obj3d</a>) ‑> <a title="piecad.Obj2d" href="index.html#piecad.Obj2d">Obj2d</a> | <a title="piecad.Obj3d" href="index.html#piecad.Obj3d">Obj3d</a></span>
|
|
50
|
+
</code></dt>
|
|
51
|
+
<dd>
|
|
52
|
+
<details class="source">
|
|
53
|
+
<summary>
|
|
54
|
+
<span>Expand source code</span>
|
|
55
|
+
</summary>
|
|
56
|
+
<pre><code class="python">def compose(*objs: Obj2d | Obj3d) -> Obj2d | Obj3d:
|
|
57
|
+
"""
|
|
58
|
+
Returns a single object containing all the disjoint objects.
|
|
59
|
+
|
|
60
|
+
It is important that the objects not overlap.
|
|
61
|
+
This is for making a scene of a group of objects that can be saved as a single model.
|
|
62
|
+
|
|
63
|
+
If you want to combine two models into one model, see `union` below.
|
|
64
|
+
|
|
65
|
+
See the `decompose` method on `Obj2d` and `Obj3d` for the inverse operation.
|
|
66
|
+
|
|
67
|
+
"""
|
|
68
|
+
ty = type(objs[0])
|
|
69
|
+
_chkGOTY("objs", ty)
|
|
70
|
+
if len(objs) == 0:
|
|
71
|
+
return Obj2d(_m.CrossSection()) if ty == Obj2d else Obj3d(_m.Manifold())
|
|
72
|
+
for o in objs:
|
|
73
|
+
if type(o) != ty:
|
|
74
|
+
raise ValidationError("Mixed types in parameter: objs.")
|
|
75
|
+
l = []
|
|
76
|
+
for o in objs:
|
|
77
|
+
l.append(o.mo)
|
|
78
|
+
|
|
79
|
+
if ty == Obj2d:
|
|
80
|
+
return Obj2d(_m.CrossSection.compose(l))
|
|
81
|
+
else:
|
|
82
|
+
return Obj3d(_m.Manifold.compose(l))</code></pre>
|
|
83
|
+
</details>
|
|
84
|
+
<div class="desc"><p>Returns a single object containing all the disjoint objects.</p>
|
|
85
|
+
<p>It is important that the objects not overlap.
|
|
86
|
+
This is for making a scene of a group of objects that can be saved as a single model.</p>
|
|
87
|
+
<p>If you want to combine two models into one model, see <code><a title="piecad.bulk_ops.union" href="#piecad.bulk_ops.union">union()</a></code> below.</p>
|
|
88
|
+
<p>See the <code>decompose</code> method on <code>Obj2d</code> and <code>Obj3d</code> for the inverse operation.</p></div>
|
|
89
|
+
</dd>
|
|
90
|
+
<dt id="piecad.bulk_ops.difference"><code class="name flex">
|
|
91
|
+
<span>def <span class="ident">difference</span></span>(<span>*objs: <a title="piecad.Obj2d" href="index.html#piecad.Obj2d">Obj2d</a> | <a title="piecad.Obj3d" href="index.html#piecad.Obj3d">Obj3d</a>) ‑> <a title="piecad.Obj2d" href="index.html#piecad.Obj2d">Obj2d</a> | <a title="piecad.Obj3d" href="index.html#piecad.Obj3d">Obj3d</a></span>
|
|
92
|
+
</code></dt>
|
|
93
|
+
<dd>
|
|
94
|
+
<details class="source">
|
|
95
|
+
<summary>
|
|
96
|
+
<span>Expand source code</span>
|
|
97
|
+
</summary>
|
|
98
|
+
<pre><code class="python">def difference(*objs: Obj2d | Obj3d) -> Obj2d | Obj3d:
|
|
99
|
+
"""
|
|
100
|
+
Returns the object removing the second through the last objects from the first object.
|
|
101
|
+
|
|
102
|
+
In some packages this function might be called subtract
|
|
103
|
+
|
|
104
|
+
<iframe width="100%" height="250" src="examples/difference2d.html"></iframe>
|
|
105
|
+
|
|
106
|
+
<iframe width="100%" height="250" src="examples/difference3d.html"></iframe>
|
|
107
|
+
"""
|
|
108
|
+
ty = type(objs[0])
|
|
109
|
+
_chkGOTY("objs", ty)
|
|
110
|
+
if len(objs) == 0:
|
|
111
|
+
return Obj2d(_m.CrossSection()) if ty == Obj2d else Obj3d(_m.Manifold())
|
|
112
|
+
for o in objs:
|
|
113
|
+
if type(o) != ty:
|
|
114
|
+
raise ValidationError("Mixed types in parameter: objs.")
|
|
115
|
+
if ty == Obj2d:
|
|
116
|
+
l = []
|
|
117
|
+
for o in objs:
|
|
118
|
+
l.append(o.mo)
|
|
119
|
+
return Obj2d(_m.CrossSection.batch_boolean(l, _m.OpType.Subtract))
|
|
120
|
+
elif ty == Obj3d:
|
|
121
|
+
l = []
|
|
122
|
+
for o in objs:
|
|
123
|
+
l.append(o.mo)
|
|
124
|
+
return Obj3d(_m.Manifold.batch_boolean(l, _m.OpType.Subtract))
|
|
125
|
+
else:
|
|
126
|
+
raise ValidationError("All objects must be of one type, Obj2d or Obj3d")</code></pre>
|
|
127
|
+
</details>
|
|
128
|
+
<div class="desc"><p>Returns the object removing the second through the last objects from the first object.</p>
|
|
129
|
+
<p>In some packages this function might be called subtract</p>
|
|
130
|
+
<iframe width="100%" height="250" src="examples/difference2d.html"></iframe>
|
|
131
|
+
<iframe width="100%" height="250" src="examples/difference3d.html"></iframe></div>
|
|
132
|
+
</dd>
|
|
133
|
+
<dt id="piecad.bulk_ops.hull"><code class="name flex">
|
|
134
|
+
<span>def <span class="ident">hull</span></span>(<span>*objs: <a title="piecad.Obj2d" href="index.html#piecad.Obj2d">Obj2d</a> | <a title="piecad.Obj3d" href="index.html#piecad.Obj3d">Obj3d</a>) ‑> <a title="piecad.Obj2d" href="index.html#piecad.Obj2d">Obj2d</a> | <a title="piecad.Obj3d" href="index.html#piecad.Obj3d">Obj3d</a></span>
|
|
135
|
+
</code></dt>
|
|
136
|
+
<dd>
|
|
137
|
+
<details class="source">
|
|
138
|
+
<summary>
|
|
139
|
+
<span>Expand source code</span>
|
|
140
|
+
</summary>
|
|
141
|
+
<pre><code class="python">def hull(*objs: Obj2d | Obj3d) -> Obj2d | Obj3d:
|
|
142
|
+
"""
|
|
143
|
+
Return a convex hull of the given objects.
|
|
144
|
+
|
|
145
|
+
All objects must be of the same type (Obj2d or Obj3d).
|
|
146
|
+
|
|
147
|
+
The corresponding hull that is returned will be of the same type
|
|
148
|
+
as the input objects.
|
|
149
|
+
|
|
150
|
+
<iframe width="100%" height="250" src="examples/hull2d.html"></iframe>
|
|
151
|
+
|
|
152
|
+
<iframe width="100%" height="250" src="examples/hull3d.html"></iframe>
|
|
153
|
+
"""
|
|
154
|
+
ty = type(objs[0])
|
|
155
|
+
_chkGOTY("objs", ty)
|
|
156
|
+
if len(objs) == 0:
|
|
157
|
+
return Obj2d(_m.CrossSection()) if ty == Obj2d else Obj3d(_m.Manifold())
|
|
158
|
+
for o in objs:
|
|
159
|
+
if type(o) != ty:
|
|
160
|
+
raise ValidationError("Mixed types in parameter: objs.")
|
|
161
|
+
if ty == Obj2d:
|
|
162
|
+
l = []
|
|
163
|
+
for o in objs:
|
|
164
|
+
l.append(o.mo)
|
|
165
|
+
return Obj2d(_m.CrossSection.batch_hull(l))
|
|
166
|
+
elif ty == Obj3d:
|
|
167
|
+
l = []
|
|
168
|
+
for o in objs:
|
|
169
|
+
l.append(o.mo)
|
|
170
|
+
return Obj3d(_m.Manifold.batch_hull(l))
|
|
171
|
+
else:
|
|
172
|
+
raise ValidationError("All objects must be of one type, Obj2d or Obj3d")</code></pre>
|
|
173
|
+
</details>
|
|
174
|
+
<div class="desc"><p>Return a convex hull of the given objects.</p>
|
|
175
|
+
<p>All objects must be of the same type (Obj2d or Obj3d).</p>
|
|
176
|
+
<p>The corresponding hull that is returned will be of the same type
|
|
177
|
+
as the input objects.</p>
|
|
178
|
+
<iframe width="100%" height="250" src="examples/hull2d.html"></iframe>
|
|
179
|
+
<iframe width="100%" height="250" src="examples/hull3d.html"></iframe></div>
|
|
180
|
+
</dd>
|
|
181
|
+
<dt id="piecad.bulk_ops.intersect"><code class="name flex">
|
|
182
|
+
<span>def <span class="ident">intersect</span></span>(<span>*objs: <a title="piecad.Obj2d" href="index.html#piecad.Obj2d">Obj2d</a> | <a title="piecad.Obj3d" href="index.html#piecad.Obj3d">Obj3d</a>) ‑> <a title="piecad.Obj2d" href="index.html#piecad.Obj2d">Obj2d</a> | <a title="piecad.Obj3d" href="index.html#piecad.Obj3d">Obj3d</a></span>
|
|
183
|
+
</code></dt>
|
|
184
|
+
<dd>
|
|
185
|
+
<details class="source">
|
|
186
|
+
<summary>
|
|
187
|
+
<span>Expand source code</span>
|
|
188
|
+
</summary>
|
|
189
|
+
<pre><code class="python">def intersect(*objs: Obj2d | Obj3d) -> Obj2d | Obj3d:
|
|
190
|
+
"""
|
|
191
|
+
Returns the object made by adding those portions that occur only in all `objs` together.
|
|
192
|
+
|
|
193
|
+
<iframe width="100%" height="250" src="examples/intersect2d.html"></iframe>
|
|
194
|
+
|
|
195
|
+
<iframe width="100%" height="250" src="examples/intersect3d.html"></iframe>
|
|
196
|
+
"""
|
|
197
|
+
ty = type(objs[0])
|
|
198
|
+
_chkGOTY("objs", ty)
|
|
199
|
+
if len(objs) == 0:
|
|
200
|
+
return Obj2d(_m.CrossSection()) if ty == Obj2d else Obj3d(_m.Manifold())
|
|
201
|
+
for o in objs:
|
|
202
|
+
if type(o) != ty:
|
|
203
|
+
raise ValidationError("Mixed types in parameter: objs.")
|
|
204
|
+
if ty == Obj2d:
|
|
205
|
+
l = []
|
|
206
|
+
for o in objs:
|
|
207
|
+
l.append(o.mo)
|
|
208
|
+
return Obj2d(_m.CrossSection.batch_boolean(l, _m.OpType.Intersect))
|
|
209
|
+
elif ty == Obj3d:
|
|
210
|
+
l = []
|
|
211
|
+
for o in objs:
|
|
212
|
+
l.append(o.mo)
|
|
213
|
+
return Obj3d(_m.Manifold.batch_boolean(l, _m.OpType.Intersect))
|
|
214
|
+
else:
|
|
215
|
+
raise ValidationError("All objects must be of one type, Obj2d or Obj3d")</code></pre>
|
|
216
|
+
</details>
|
|
217
|
+
<div class="desc"><p>Returns the object made by adding those portions that occur only in all <code>objs</code> together.</p>
|
|
218
|
+
<iframe width="100%" height="250" src="examples/intersect2d.html"></iframe>
|
|
219
|
+
<iframe width="100%" height="250" src="examples/intersect3d.html"></iframe></div>
|
|
220
|
+
</dd>
|
|
221
|
+
<dt id="piecad.bulk_ops.union"><code class="name flex">
|
|
222
|
+
<span>def <span class="ident">union</span></span>(<span>*objs: <a title="piecad.Obj2d" href="index.html#piecad.Obj2d">Obj2d</a> | <a title="piecad.Obj3d" href="index.html#piecad.Obj3d">Obj3d</a>) ‑> <a title="piecad.Obj2d" href="index.html#piecad.Obj2d">Obj2d</a> | <a title="piecad.Obj3d" href="index.html#piecad.Obj3d">Obj3d</a></span>
|
|
223
|
+
</code></dt>
|
|
224
|
+
<dd>
|
|
225
|
+
<details class="source">
|
|
226
|
+
<summary>
|
|
227
|
+
<span>Expand source code</span>
|
|
228
|
+
</summary>
|
|
229
|
+
<pre><code class="python">def union(*objs: Obj2d | Obj3d) -> Obj2d | Obj3d:
|
|
230
|
+
"""
|
|
231
|
+
Returns the object made by adding all the `objs` together.
|
|
232
|
+
|
|
233
|
+
<iframe width="100%" height="250" src="examples/union2d.html"></iframe>
|
|
234
|
+
|
|
235
|
+
<iframe width="100%" height="250" src="examples/union3d.html"></iframe>
|
|
236
|
+
"""
|
|
237
|
+
ty = type(objs[0])
|
|
238
|
+
_chkGOTY("objs", ty)
|
|
239
|
+
if len(objs) == 0:
|
|
240
|
+
return Obj2d(_m.CrossSection()) if ty == Obj2d else Obj3d(_m.Manifold())
|
|
241
|
+
for o in objs:
|
|
242
|
+
if type(o) != ty:
|
|
243
|
+
raise ValidationError("Mixed types in parameter: objs.")
|
|
244
|
+
if ty == Obj2d:
|
|
245
|
+
l = []
|
|
246
|
+
for o in objs:
|
|
247
|
+
l.append(o.mo)
|
|
248
|
+
return Obj2d(_m.CrossSection.batch_boolean(l, _m.OpType.Add))
|
|
249
|
+
elif ty == Obj3d:
|
|
250
|
+
l = []
|
|
251
|
+
for o in objs:
|
|
252
|
+
l.append(o.mo)
|
|
253
|
+
return Obj3d(_m.Manifold.batch_boolean(l, _m.OpType.Add))
|
|
254
|
+
else:
|
|
255
|
+
raise ValidationError("All objects must be of one type, Obj2d or Obj3d")</code></pre>
|
|
256
|
+
</details>
|
|
257
|
+
<div class="desc"><p>Returns the object made by adding all the <code>objs</code> together.</p>
|
|
258
|
+
<iframe width="100%" height="250" src="examples/union2d.html"></iframe>
|
|
259
|
+
<iframe width="100%" height="250" src="examples/union3d.html"></iframe></div>
|
|
260
|
+
</dd>
|
|
261
|
+
</dl>
|
|
262
|
+
</section>
|
|
263
|
+
<section>
|
|
264
|
+
</section>
|
|
265
|
+
</article>
|
|
266
|
+
<nav id="sidebar">
|
|
267
|
+
<div class="toc">
|
|
268
|
+
<ul>
|
|
269
|
+
<li><a href="#miscellaneous-bulk-operations-that-work-on-multiple-objects">Miscellaneous bulk operations that work on multiple objects.</a></li>
|
|
270
|
+
</ul>
|
|
271
|
+
</div>
|
|
272
|
+
<ul id="index">
|
|
273
|
+
<li><h3>Super-module</h3>
|
|
274
|
+
<ul>
|
|
275
|
+
<li><code><a title="piecad" href="index.html">piecad</a></code></li>
|
|
276
|
+
</ul>
|
|
277
|
+
</li>
|
|
278
|
+
<li><h3><a href="#header-functions">Functions</a></h3>
|
|
279
|
+
<ul class="">
|
|
280
|
+
<li><code><a title="piecad.bulk_ops.compose" href="#piecad.bulk_ops.compose">compose</a></code></li>
|
|
281
|
+
<li><code><a title="piecad.bulk_ops.difference" href="#piecad.bulk_ops.difference">difference</a></code></li>
|
|
282
|
+
<li><code><a title="piecad.bulk_ops.hull" href="#piecad.bulk_ops.hull">hull</a></code></li>
|
|
283
|
+
<li><code><a title="piecad.bulk_ops.intersect" href="#piecad.bulk_ops.intersect">intersect</a></code></li>
|
|
284
|
+
<li><code><a title="piecad.bulk_ops.union" href="#piecad.bulk_ops.union">union</a></code></li>
|
|
285
|
+
</ul>
|
|
286
|
+
</li>
|
|
287
|
+
</ul>
|
|
288
|
+
</nav>
|
|
289
|
+
</main>
|
|
290
|
+
<footer id="footer">
|
|
291
|
+
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.11.6</a>.</p>
|
|
292
|
+
</footer>
|
|
293
|
+
</body>
|
|
294
|
+
</html>
|