@jscad/web 2.5.9 → 2.5.12
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.
- package/CHANGELOG.md +32 -0
- package/css/demo.css +5 -1
- package/dist/jscad-web.min.js +861 -1999
- package/examples/CHANGELOG.md +30 -0
- package/examples/README.md +0 -4
- package/examples/core/extrusions/nutsAndBolts.js +94 -0
- package/examples/examples.json +1 -1
- package/examples/package.json +1 -1
- package/examples/parameters/gear.js +1 -1
- package/package.json +7 -7
- package/postInstall.js +0 -1
- package/src/sideEffects/worker/index.js +12 -9
- package/src/ui/flow/design.js +23 -305
- package/src/ui/flow/reducers.js +304 -0
- package/src/ui/views/parameterControls.js +3 -3
- package/src/ui/views/status.js +21 -14
- package/examples/old/benchmark-cag.jscad +0 -27
- package/examples/old/benchmark-csg.jscad +0 -29
- package/examples/old/benchmark.jscad +0 -25
- package/examples/old/bunch-cubes.jscad +0 -17
- package/examples/old/complex/example001.jscad +0 -31
- package/examples/old/complex/example002.jscad +0 -25
- package/examples/old/complex/example003.jscad +0 -25
- package/examples/old/complex/example004.jscad +0 -16
- package/examples/old/complex/example005.jscad +0 -27
- package/examples/old/complex/globe.js +0 -235
- package/examples/old/complex/iphone4-case.js +0 -213
- package/examples/old/complex/umbilical_torus.js +0 -43
- package/examples/old/complex/umbilical_torus.scad +0 -37
- package/examples/old/core/cncCutout.js +0 -16
- package/examples/old/core/connectors/servo.js +0 -185
- package/examples/old/core/extrusions/extrudeLinear.js +0 -24
- package/examples/old/core/extrusions/extrudeRectangular.js +0 -21
- package/examples/old/core/extrusions/extrudeRotate.js +0 -43
- package/examples/old/core/extrusions/slices/four2three-round.js +0 -62
- package/examples/old/core/extrusions/slices/four2three.js +0 -53
- package/examples/old/core/extrusions/slices/jar-barrel.js +0 -60
- package/examples/old/core/extrusions/slices/jar.js +0 -69
- package/examples/old/core/extrusions/slices/non-aff.js +0 -72
- package/examples/old/core/extrusions/slices/rose.js +0 -52
- package/examples/old/core/extrusions/slices/screw.js +0 -34
- package/examples/old/core/extrusions/slices/screwDouble.js +0 -34
- package/examples/old/core/extrusions/slices/slices.js +0 -43
- package/examples/old/core/extrusions/slices/spring.js +0 -41
- package/examples/old/core/extrusions/slices/three2four.js +0 -42
- package/examples/old/core/extrusions/slices/tor.js +0 -30
- package/examples/old/core/hulls/hullChain.js +0 -58
- package/examples/old/core/lookup.js +0 -19
- package/examples/old/core/platonics/main.jscad +0 -42
- package/examples/old/core/platonics/maths_geodesic.jscad +0 -192
- package/examples/old/core/platonics/origv07/dualdodeca_difference.stl +0 -1962
- package/examples/old/core/platonics/origv07/dualdodeca_intersection.stl +0 -1374
- package/examples/old/core/platonics/origv07/dualdodeca_union.stl +0 -1822
- package/examples/old/core/platonics/origv07/maths_geodesic.scad +0 -162
- package/examples/old/core/platonics/origv07/platonic.scad +0 -483
- package/examples/old/core/platonics/origv07/test_platonic.scad +0 -616
- package/examples/old/core/platonics/platonic.jscad +0 -528
- package/examples/old/core/text/textSimplex.js +0 -625
- package/examples/old/core/transforms/transformations.js +0 -29
- package/examples/old/echo.jscad +0 -7
- package/examples/old/formats/scad/example001.scad +0 -26
- package/examples/old/formats/scad/example002.scad +0 -23
- package/examples/old/formats/scad/example003.scad +0 -20
- package/examples/old/formats/scad/example004.scad +0 -11
- package/examples/old/formats/scad/example005.scad +0 -20
- package/examples/old/json_logo.json +0 -1
- package/examples/old/parameters/axis-coupler.js +0 -149
- package/examples/old/parameters/celtic-knot-ring.js +0 -300
- package/examples/old/parameters/grille.js +0 -257
- package/examples/old/parameters/lamp-shade.js +0 -369
- package/examples/old/parameters/name-plate.js +0 -46
- package/examples/old/parameters/s-hook.js +0 -131
- package/examples/old/parameters/stepper-motor.js +0 -127
- package/examples/old/various/logo.js +0 -32
- package/examples/old/voxel.json +0 -1
package/examples/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,36 @@
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
5
5
|
|
|
6
|
+
## [2.4.1](https://github.com/jscad/OpenJSCAD.org/compare/@jscad/examples@2.4.0...@jscad/examples@2.4.1) (2022-06-12)
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
### Bug Fixes
|
|
10
|
+
|
|
11
|
+
* **examples:** create uniform segments for involute gear example ([#1093](https://github.com/jscad/OpenJSCAD.org/issues/1093)) ([0b234f3](https://github.com/jscad/OpenJSCAD.org/commit/0b234f3f8ff6b39a967900089e2d939295163b68))
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
# [2.4.0](https://github.com/jscad/OpenJSCAD.org/compare/@jscad/examples@2.3.4...@jscad/examples@2.4.0) (2022-05-15)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
### Features
|
|
21
|
+
|
|
22
|
+
* **examples:** new Nuts and Bolts example ([#1081](https://github.com/jscad/OpenJSCAD.org/issues/1081)) ([cd78003](https://github.com/jscad/OpenJSCAD.org/commit/cd7800351e56f7cd75f0add07cf068df328b7839))
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
## [2.3.4](https://github.com/jscad/OpenJSCAD.org/compare/@jscad/examples@2.3.3...@jscad/examples@2.3.4) (2022-04-24)
|
|
29
|
+
|
|
30
|
+
**Note:** Version bump only for package @jscad/examples
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
|
|
6
36
|
## [2.3.3](https://github.com/jscad/OpenJSCAD.org/compare/@jscad/examples@2.3.2...@jscad/examples@2.3.3) (2022-04-03)
|
|
7
37
|
|
|
8
38
|
**Note:** Version bump only for package @jscad/examples
|
package/examples/README.md
CHANGED
|
@@ -63,9 +63,5 @@ See for more details
|
|
|
63
63
|
(unless specified otherwise)
|
|
64
64
|
|
|
65
65
|
Some content released under different licence:
|
|
66
|
-
- thing_7-Zomboe.stl: CC-BY-NC-SA
|
|
67
66
|
- 3d_sculpture-VernonBussler.stl: CC-BY-SA
|
|
68
67
|
- frog-OwenCollins.stl: CC-BY-NC-SA
|
|
69
|
-
- organic_flower-Bogoboy23.stl: CC-BY
|
|
70
|
-
- treefrog-Jerrill.stl: CC-BY-NC-SA
|
|
71
|
-
- yoda-RichRap.stl: CC-BY-SA
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Nuts and Bolts
|
|
3
|
+
* @category Creating Shapes
|
|
4
|
+
* @skillLevel 8
|
|
5
|
+
* @description Demonstrating the advanced extrusion using slices to generate screw threads.
|
|
6
|
+
* @tags extrude, slice, slices, extrudefromslices, callback
|
|
7
|
+
* @authors platypii
|
|
8
|
+
* @licence MIT License
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
const jscad = require('@jscad/modeling')
|
|
12
|
+
const { cylinder } = jscad.primitives
|
|
13
|
+
const { subtract, union } = jscad.booleans
|
|
14
|
+
const { colorize } = jscad.colors
|
|
15
|
+
const { extrudeFromSlices, slice } = jscad.extrusions
|
|
16
|
+
const { translate } = jscad.transforms
|
|
17
|
+
|
|
18
|
+
const options = {
|
|
19
|
+
hexWidth: 10,
|
|
20
|
+
hexHeight: 8,
|
|
21
|
+
threadLength: 32,
|
|
22
|
+
threadSize: 4,
|
|
23
|
+
innerRadius: 4,
|
|
24
|
+
outerRadius: 5.6,
|
|
25
|
+
slicesPerRevolution: 12,
|
|
26
|
+
segments: 32
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const main = () => {
|
|
30
|
+
return [
|
|
31
|
+
colorize([0.9, 0.6, 0.2], bolt(options)),
|
|
32
|
+
colorize([0.4, 0.4, 0.4], translate([30, 0, 0], nut(options)))
|
|
33
|
+
]
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// generate bolt by attaching threads to a hex head
|
|
37
|
+
const bolt = (options) => {
|
|
38
|
+
return union(
|
|
39
|
+
translate([0, 0, options.threadLength], hex(options)),
|
|
40
|
+
threads(options)
|
|
41
|
+
)
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// generate nut by subtracting threads from a hex block
|
|
45
|
+
const nut = (options) => {
|
|
46
|
+
return subtract(
|
|
47
|
+
hex(options),
|
|
48
|
+
threads({ ...options, threadLength: options.hexHeight })
|
|
49
|
+
)
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// generate hexagonal block
|
|
53
|
+
const hex = (options) => {
|
|
54
|
+
const radius = options.hexWidth * 1.1547005 // hexagon outer radius
|
|
55
|
+
const height = options.hexHeight
|
|
56
|
+
return cylinder({ center: [0, 0, height / 2], height, radius, segments: 6 })
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// generate a threaded shaft using extrudeFromSlices
|
|
60
|
+
const threads = (options) => {
|
|
61
|
+
const { innerRadius, outerRadius, segments, threadLength } = options
|
|
62
|
+
const revolutions = threadLength / options.threadSize
|
|
63
|
+
const numberOfSlices = options.slicesPerRevolution * revolutions
|
|
64
|
+
return extrudeFromSlices({
|
|
65
|
+
numberOfSlices,
|
|
66
|
+
callback: (progress, index, base) => {
|
|
67
|
+
// generate each slice manually
|
|
68
|
+
const points = []
|
|
69
|
+
for (let i = 0; i < segments; i++) {
|
|
70
|
+
const pointAngle = Math.PI * 2 * i / segments
|
|
71
|
+
const threadAngle = (2 * Math.PI * revolutions * progress) % (Math.PI * 2)
|
|
72
|
+
|
|
73
|
+
// define the shape of the threads
|
|
74
|
+
const phase = angleDiff(threadAngle, pointAngle) / Math.PI
|
|
75
|
+
const radius = lerp(innerRadius, outerRadius, 1.4 * phase - 0.2)
|
|
76
|
+
|
|
77
|
+
const x = radius * Math.cos(pointAngle)
|
|
78
|
+
const y = radius * Math.sin(pointAngle)
|
|
79
|
+
points.push([x, y, threadLength * progress])
|
|
80
|
+
}
|
|
81
|
+
return slice.fromPoints(points)
|
|
82
|
+
}
|
|
83
|
+
}, {})
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// linear interpolation with bounding
|
|
87
|
+
const lerp = (a, b, t) => Math.max(a, Math.min(b, a + (b - a) * t))
|
|
88
|
+
|
|
89
|
+
const angleDiff = (angle1, angle2) => {
|
|
90
|
+
const diff = Math.abs((angle1 - angle2) % (Math.PI * 2))
|
|
91
|
+
return diff > Math.PI ? Math.PI * 2 - diff : diff
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
module.exports = { main }
|
package/examples/examples.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"Creating Shapes":[{"title":"2D Primitives Demonstration","filePath":"examples/core/primitives/primitives2D.js","sort":1,"description":"Demonstrating the basics of a variety of 2D primitives"},{"title":"3D Primitives Demonstration","filePath":"examples/core/primitives/primitives3D.js","sort":1,"description":"Demonstrating the basics of a variety of 3D primitives"},{"title":"Rounded Cuboid","filePath":"examples/core/primitives/roundedCuboid.js","sort":1,"description":"Demonstrating the roundedCuboid() functiom"},{"title":"Spheres of all sorts","filePath":"examples/core/primitives/sphere.js","sort":1,"description":"Demonstrating the sphere() and geodesicSphere() functions"},{"title":"Building a Dodecahedron","filePath":"examples/core/primitives/dodecahedron.js","sort":2,"description":"building dodecahedron() from cuboids"},{"title":"Torus Variety","filePath":"examples/core/primitives/torus.js","sort":2,"description":"Demonstrating the capabilities and variations of the torus() primitive"},{"title":"Building a Polyhedron from scratch","filePath":"examples/core/primitives/polyhedron.js","sort":4,"description":"Demonstrating the polyhedron() function"},{"title":"Basic Extrude Functions","filePath":"examples/core/extrusions/basicExtrusions.js","sort":5,"description":"Demonstrating the basic types of extrusions, and the variety of objects they can create."},{"title":"Extrude Along a Bezier Path","filePath":"examples/core/curves/bezier/extrudeAlongPath.js","sort":5,"description":"Using a 3D bezier path to create a solid tube"},{"title":"Extrude From Slices","filePath":"examples/core/extrusions/extrudeFromSlices.js","sort":5,"description":"Demonstrating the advanced extrusion using slices with varying numbers of points."},{"title":"Simple Bezier Extrude","filePath":"examples/core/curves/bezier/simpleExtrude.js","sort":5,"description":"Using a 1D bezier function to create a non-uniform extrusion"},{"title":"Hull and HullChain 2D example","filePath":"examples/core/hulls/hull2D.js","sort":8,"description":"Demonstrating the basics of Hulls in two dimensions"},{"title":"Hull and HullChain 3D example","filePath":"examples/core/hulls/hull3D.js","sort":8,"description":"Demonstrating the basics of Hulls in three dimensions"},{"title":"Basic Text Creation","filePath":"examples/core/text/text.js","sort":10,"description":"Demonstrating methods of building 3D text"}],"Manipulating Shapes":[{"title":"Basic Booleans Demonstration","filePath":"examples/core/booleans/basicBooleans.js","sort":2,"description":"Demonstrating the basics of boolean shape combinations"},{"title":"Align function demonstration","filePath":"examples/core/transforms/align.js","sort":3,"description":"Demonstrating aligning shapes using the align function"},{"title":"Expanding 2D and 3D Shapes","filePath":"examples/core/expansions/expand.js","sort":5,"description":"Exploring the expand() function on 2D and 3D geometries"},{"title":"Offsetting 2D Shapes","filePath":"examples/core/expansions/offset.js","sort":5,"description":"Demonstrating the offset() function. Moves all points in a 2d path or 2D geometry perpendicular to the line's tangent."},{"title":"Center function demonstration","filePath":"examples/core/transforms/center.js","sort":10,"description":"Using center() to translate objects"},{"title":"Measure Aggregate Bounding Box","filePath":"examples/core/measurements/measureAggregateBounds.js","sort":10,"description":"Examples of measureAggregateBoundingBox function"},{"title":"Measure Area and Volume","filePath":"examples/core/measurements/measureAreaAndVolume.js","sort":10,"description":"Examples of measureArea() and measureVolume() function"},{"title":"Measure Bounding Box","filePath":"examples/core/measurements/measureBounds.js","sort":10,"description":"Examples of measureBoundingBox function"}],"Colors":[{"title":"Basic Colors","filePath":"examples/core/colors/basicColors.js","sort":1,"description":"showing various color functions"},{"title":"Color Cube","filePath":"examples/core/colors/colorCube.js","sort":2,"description":"looking at the different ways to specify a color"},{"title":"Transparency","filePath":"examples/core/colors/transparency.js","sort":2,"description":"showing transparent objects"}],"Parameters":[{"title":"All Parameter Types Demo","filePath":"examples/parameters/allParamTypes.js","sort":1,"description":"Example of interactive parameters"},{"title":"Birthday Balloons","filePath":"examples/parameters/balloons.js","sort":1,"description":"Example of building models from interactive parameters"},{"title":"Parametric Involute Gear","filePath":"examples/parameters/gear.js","sort":1,"description":"Build a proper involute gear, demonstrating parameters, and how they can be used in complex math."}],"Other":[{"title":"Coordinate system and Rotation demonstration","filePath":"examples/core/other/orientation.js","sort":1,"description":"Demonstrating rotation about the three axes."}]}
|
|
1
|
+
{"Creating Shapes":[{"title":"2D Primitives Demonstration","filePath":"examples/core/primitives/primitives2D.js","sort":1,"description":"Demonstrating the basics of a variety of 2D primitives"},{"title":"3D Primitives Demonstration","filePath":"examples/core/primitives/primitives3D.js","sort":1,"description":"Demonstrating the basics of a variety of 3D primitives"},{"title":"Rounded Cuboid","filePath":"examples/core/primitives/roundedCuboid.js","sort":1,"description":"Demonstrating the roundedCuboid() functiom"},{"title":"Spheres of all sorts","filePath":"examples/core/primitives/sphere.js","sort":1,"description":"Demonstrating the sphere() and geodesicSphere() functions"},{"title":"Building a Dodecahedron","filePath":"examples/core/primitives/dodecahedron.js","sort":2,"description":"building dodecahedron() from cuboids"},{"title":"Torus Variety","filePath":"examples/core/primitives/torus.js","sort":2,"description":"Demonstrating the capabilities and variations of the torus() primitive"},{"title":"Building a Polyhedron from scratch","filePath":"examples/core/primitives/polyhedron.js","sort":4,"description":"Demonstrating the polyhedron() function"},{"title":"Basic Extrude Functions","filePath":"examples/core/extrusions/basicExtrusions.js","sort":5,"description":"Demonstrating the basic types of extrusions, and the variety of objects they can create."},{"title":"Extrude Along a Bezier Path","filePath":"examples/core/curves/bezier/extrudeAlongPath.js","sort":5,"description":"Using a 3D bezier path to create a solid tube"},{"title":"Extrude From Slices","filePath":"examples/core/extrusions/extrudeFromSlices.js","sort":5,"description":"Demonstrating the advanced extrusion using slices with varying numbers of points."},{"title":"Simple Bezier Extrude","filePath":"examples/core/curves/bezier/simpleExtrude.js","sort":5,"description":"Using a 1D bezier function to create a non-uniform extrusion"},{"title":"Hull and HullChain 2D example","filePath":"examples/core/hulls/hull2D.js","sort":8,"description":"Demonstrating the basics of Hulls in two dimensions"},{"title":"Hull and HullChain 3D example","filePath":"examples/core/hulls/hull3D.js","sort":8,"description":"Demonstrating the basics of Hulls in three dimensions"},{"title":"Nuts and Bolts","filePath":"examples/core/extrusions/nutsAndBolts.js","sort":8,"description":"Demonstrating the advanced extrusion using slices to generate screw threads."},{"title":"Basic Text Creation","filePath":"examples/core/text/text.js","sort":10,"description":"Demonstrating methods of building 3D text"}],"Manipulating Shapes":[{"title":"Basic Booleans Demonstration","filePath":"examples/core/booleans/basicBooleans.js","sort":2,"description":"Demonstrating the basics of boolean shape combinations"},{"title":"Align function demonstration","filePath":"examples/core/transforms/align.js","sort":3,"description":"Demonstrating aligning shapes using the align function"},{"title":"Expanding 2D and 3D Shapes","filePath":"examples/core/expansions/expand.js","sort":5,"description":"Exploring the expand() function on 2D and 3D geometries"},{"title":"Offsetting 2D Shapes","filePath":"examples/core/expansions/offset.js","sort":5,"description":"Demonstrating the offset() function. Moves all points in a 2d path or 2D geometry perpendicular to the line's tangent."},{"title":"Center function demonstration","filePath":"examples/core/transforms/center.js","sort":10,"description":"Using center() to translate objects"},{"title":"Measure Aggregate Bounding Box","filePath":"examples/core/measurements/measureAggregateBounds.js","sort":10,"description":"Examples of measureAggregateBoundingBox function"},{"title":"Measure Area and Volume","filePath":"examples/core/measurements/measureAreaAndVolume.js","sort":10,"description":"Examples of measureArea() and measureVolume() function"},{"title":"Measure Bounding Box","filePath":"examples/core/measurements/measureBounds.js","sort":10,"description":"Examples of measureBoundingBox function"}],"Colors":[{"title":"Basic Colors","filePath":"examples/core/colors/basicColors.js","sort":1,"description":"showing various color functions"},{"title":"Color Cube","filePath":"examples/core/colors/colorCube.js","sort":2,"description":"looking at the different ways to specify a color"},{"title":"Transparency","filePath":"examples/core/colors/transparency.js","sort":2,"description":"showing transparent objects"}],"Parameters":[{"title":"All Parameter Types Demo","filePath":"examples/parameters/allParamTypes.js","sort":1,"description":"Example of interactive parameters"},{"title":"Birthday Balloons","filePath":"examples/parameters/balloons.js","sort":1,"description":"Example of building models from interactive parameters"},{"title":"Parametric Involute Gear","filePath":"examples/parameters/gear.js","sort":1,"description":"Build a proper involute gear, demonstrating parameters, and how they can be used in complex math."}],"Other":[{"title":"Coordinate system and Rotation demonstration","filePath":"examples/core/other/orientation.js","sort":1,"description":"Demonstrating rotation about the three axes."}]}
|
package/examples/package.json
CHANGED
|
@@ -50,7 +50,7 @@ const createSingleToothPolygon = (maxAngle, baseRadius, angularToothWidthAtBase)
|
|
|
50
50
|
const points = [[0, 0]]
|
|
51
51
|
for (let i = 0; i <= toothCurveResolution; i++) {
|
|
52
52
|
// first side of the tooth:
|
|
53
|
-
const angle = maxAngle * i / toothCurveResolution
|
|
53
|
+
const angle = maxAngle * Math.pow(i / toothCurveResolution, 2 / 3)
|
|
54
54
|
const tanLength = angle * baseRadius
|
|
55
55
|
let radiantVector = vec2.fromAngleRadians(vec2.create(), angle)
|
|
56
56
|
let tangentVector = vec2.scale(vec2.create(), vec2.normal(vec2.create(), radiantVector), -tanLength)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jscad/web",
|
|
3
|
-
"version": "2.5.
|
|
3
|
+
"version": "2.5.12",
|
|
4
4
|
"description": "Web Application for JSCAD",
|
|
5
5
|
"homepage": "https://openjscad.xyz/",
|
|
6
6
|
"repository": "https://github.com/jscad/OpenJSCAD.org",
|
|
@@ -36,11 +36,11 @@
|
|
|
36
36
|
"license": "MIT",
|
|
37
37
|
"dependencies": {
|
|
38
38
|
"@jscad/array-utils": "2.1.4",
|
|
39
|
-
"@jscad/core": "2.
|
|
40
|
-
"@jscad/examples": "2.
|
|
41
|
-
"@jscad/io": "2.
|
|
42
|
-
"@jscad/modeling": "2.9.
|
|
43
|
-
"@jscad/regl-renderer": "2.
|
|
39
|
+
"@jscad/core": "2.6.2",
|
|
40
|
+
"@jscad/examples": "2.4.2",
|
|
41
|
+
"@jscad/io": "2.4.1",
|
|
42
|
+
"@jscad/modeling": "2.9.6",
|
|
43
|
+
"@jscad/regl-renderer": "2.6.2",
|
|
44
44
|
"@most/create": "2.0.1",
|
|
45
45
|
"brace": "0.11.1",
|
|
46
46
|
"codemirror": "5.65.2",
|
|
@@ -67,5 +67,5 @@
|
|
|
67
67
|
"url": "https://opencollective.com/openjscad",
|
|
68
68
|
"logo": "https://opencollective.com/openjscad/logo.txt"
|
|
69
69
|
},
|
|
70
|
-
"gitHead": "
|
|
70
|
+
"gitHead": "9768af96e5da00cd113c00ddeb0f6046707819b1"
|
|
71
71
|
}
|
package/postInstall.js
CHANGED
|
@@ -29,7 +29,6 @@ const processExamplesInDirectory = (dir, examples) => {
|
|
|
29
29
|
files.forEach((fileName) => {
|
|
30
30
|
const filePath = path.join(dir, fileName)
|
|
31
31
|
if (fs.lstatSync(filePath).isDirectory()) {
|
|
32
|
-
if (fileName === 'old') return
|
|
33
32
|
processExamplesInDirectory(filePath, examples)
|
|
34
33
|
} else if (filePath.endsWith('.js')) {
|
|
35
34
|
processExamplesFile(filePath, examples)
|
|
@@ -3,24 +3,27 @@ const WebWorkify = require('webworkify')
|
|
|
3
3
|
const callBackToStream = require('../../most-utils/callbackToObservable')
|
|
4
4
|
|
|
5
5
|
const makeWorkerEffect = (workerPath) => {
|
|
6
|
-
|
|
6
|
+
const workerEventsCb = callBackToStream()
|
|
7
|
+
|
|
8
|
+
let _worker = WebWorkify(workerPath, {})
|
|
7
9
|
_worker.onerror = (error) => workerEventsCb.callback({ error })
|
|
8
10
|
_worker.onmessage = (message) => workerEventsCb.callback(message)
|
|
9
|
-
const workerEventsCb = callBackToStream()
|
|
10
11
|
|
|
11
12
|
const workerSink = (outToWorker$) => {
|
|
12
13
|
// cancel whatever is going on in the worker by terminating it
|
|
13
14
|
outToWorker$.filter(({ cmd }) => cmd === 'cancel')
|
|
14
|
-
.forEach((
|
|
15
|
+
.forEach((task) => {
|
|
16
|
+
_worker.terminate()
|
|
17
|
+
_worker = WebWorkify(workerPath)
|
|
18
|
+
_worker.onerror = (error) => workerEventsCb.callback({ error })
|
|
19
|
+
_worker.onmessage = (message) => workerEventsCb.callback(message)
|
|
20
|
+
})
|
|
21
|
+
|
|
15
22
|
// send other messages to the worker
|
|
16
23
|
outToWorker$
|
|
17
24
|
.filter(({ cmd }) => cmd !== 'cancel')
|
|
18
|
-
.forEach((
|
|
19
|
-
_worker.
|
|
20
|
-
_worker = WebWorkify(workerPath)// new Worker(workerPath)
|
|
21
|
-
_worker.onerror = (error) => workerEventsCb.callback({ error })
|
|
22
|
-
_worker.onmessage = (message) => workerEventsCb.callback(message)
|
|
23
|
-
_worker.postMessage(message)
|
|
25
|
+
.forEach((task) => {
|
|
26
|
+
_worker.postMessage(task)
|
|
24
27
|
})
|
|
25
28
|
}
|
|
26
29
|
|
package/src/ui/flow/design.js
CHANGED
|
@@ -1,309 +1,14 @@
|
|
|
1
|
-
const path = require('path')
|
|
2
1
|
const most = require('most')
|
|
3
2
|
|
|
4
3
|
const { delayFromObservable, holdUntil, withLatestFrom } = require('../../most-utils')
|
|
5
4
|
|
|
6
|
-
const {
|
|
7
|
-
const { getDesignEntryPoint, getDesignName } = require('@jscad/core').loading.requireDesignUtilsFs
|
|
8
|
-
const { makeFakeFs } = require('@jscad/core').loading
|
|
5
|
+
const { getParameterValuesFromUIControls } = require('@jscad/core').parameters
|
|
9
6
|
|
|
10
|
-
const { keep } = require('../../utils/object')
|
|
11
7
|
const { fetchUriParams, getAllUriParams } = require('../../utils/urlUtils')
|
|
12
|
-
const { availableExportFormatsFromSolids, exportFilePathFromFormatAndDesign } = require('../../core/io/exportUtils')
|
|
13
|
-
const packageMetadata = require('../../../package.json')
|
|
14
8
|
|
|
15
|
-
const
|
|
16
|
-
|
|
17
|
-
// what fields should we check to determine if two designs are the same
|
|
18
|
-
const designEqualityFields = [
|
|
19
|
-
'parameterDefinitions',
|
|
20
|
-
'parameterValues',
|
|
21
|
-
'mainPath',
|
|
22
|
-
'filesAndFolders',
|
|
23
|
-
'vtreeMode' // also trigger a recompute when vtree mode is enabled/ disabled
|
|
24
|
-
]
|
|
25
|
-
|
|
26
|
-
// what fields we want to de/serialize
|
|
27
|
-
const serializableFields = [
|
|
28
|
-
'name',
|
|
29
|
-
'mainPath',
|
|
30
|
-
'origin',
|
|
31
|
-
'parameterValues',
|
|
32
|
-
'vtreeMode',
|
|
33
|
-
'autoReload',
|
|
34
|
-
'instantUpdate',
|
|
35
|
-
'solidsTimeOut'
|
|
36
|
-
]
|
|
37
|
-
|
|
38
|
-
const reducers = {
|
|
39
|
-
/** initialise the design's state
|
|
40
|
-
* @returns {Object} the default state for designs
|
|
41
|
-
*/
|
|
42
|
-
initialize: (state) => {
|
|
43
|
-
const design = {
|
|
44
|
-
// metadata
|
|
45
|
-
name: '',
|
|
46
|
-
path: '',
|
|
47
|
-
mainPath: '',
|
|
48
|
-
origin: undefined, // where the design came from : http, local etc
|
|
49
|
-
filesAndFolders: [], // file tree, of sorts
|
|
50
|
-
// code
|
|
51
|
-
instantUpdate: false,
|
|
52
|
-
autoReload: false,
|
|
53
|
-
// parameters
|
|
54
|
-
parameterDefinitions: [],
|
|
55
|
-
parameterValues: {},
|
|
56
|
-
parameterDefaults: {},
|
|
57
|
-
// solids
|
|
58
|
-
solidsTimeOut: 80000,
|
|
59
|
-
solids: [],
|
|
60
|
-
// geometry caching
|
|
61
|
-
vtreeMode: false,
|
|
62
|
-
lookup: {},
|
|
63
|
-
lookupCounts: {},
|
|
64
|
-
debug: {
|
|
65
|
-
startTime: 0,
|
|
66
|
-
endTime: 0,
|
|
67
|
-
totalTime: 0
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
return { design }
|
|
71
|
-
},
|
|
72
|
-
|
|
73
|
-
/** reset the content of the design
|
|
74
|
-
* @param {Object} state
|
|
75
|
-
* @param {String} payload
|
|
76
|
-
* @returns {Object} the updated state
|
|
77
|
-
*/
|
|
78
|
-
resetDesign: (state, origin) => {
|
|
79
|
-
// we reset only the given fields: mostly all except design specific things
|
|
80
|
-
const fieldsToReset = [
|
|
81
|
-
'name', 'path', 'mainPath', 'origin', 'filesAndFolders',
|
|
82
|
-
'parameterDefinitions', 'parameterValues', 'parameterDefaults',
|
|
83
|
-
'lookup', 'lookupCounts', 'debug', 'solids'
|
|
84
|
-
]
|
|
85
|
-
const design = Object.assign({},
|
|
86
|
-
state.design, keep(fieldsToReset, reducers.initialize().design)
|
|
87
|
-
)
|
|
88
|
-
// ugh
|
|
89
|
-
design.origin = origin
|
|
90
|
-
return { design }
|
|
91
|
-
},
|
|
92
|
-
|
|
93
|
-
/** set the content of the design usually after a reset
|
|
94
|
-
* bulk of the data is set here
|
|
95
|
-
* @param {Object} state
|
|
96
|
-
* @param {String} payload
|
|
97
|
-
* @returns {Object} the updated state
|
|
98
|
-
*/
|
|
99
|
-
setDesignContent: (state, payload) => {
|
|
100
|
-
// all our available data (specific to web)
|
|
101
|
-
const { filesAndFolders } = payload
|
|
102
|
-
const fakeFs = makeFakeFs(filesAndFolders)
|
|
103
|
-
const rootPath = filesAndFolders[0].fullPath
|
|
104
|
-
const mainPath = getDesignEntryPoint(fakeFs, rootPath)
|
|
105
|
-
const designName = getDesignName(fakeFs, rootPath)
|
|
106
|
-
const designPath = path.dirname(rootPath)
|
|
107
|
-
|
|
108
|
-
let design = state.design
|
|
109
|
-
// to track computation time
|
|
110
|
-
const debug = Object.assign({ }, state.design.debug, { startTime: new Date() })
|
|
111
|
-
|
|
112
|
-
design = Object.assign({}, design, {
|
|
113
|
-
name: designName,
|
|
114
|
-
path: designPath,
|
|
115
|
-
mainPath,
|
|
116
|
-
filesAndFolders,
|
|
117
|
-
debug
|
|
118
|
-
})
|
|
119
|
-
|
|
120
|
-
const appTitle = `jscad v ${packageMetadata.version}: ${state.design.name}`
|
|
121
|
-
|
|
122
|
-
// FIXME: this is the same as clear errors ?
|
|
123
|
-
const status = Object.assign({}, state.status, { busy: true, error: undefined })
|
|
124
|
-
return {
|
|
125
|
-
design,
|
|
126
|
-
appTitle,
|
|
127
|
-
status
|
|
128
|
-
}
|
|
129
|
-
},
|
|
130
|
-
|
|
131
|
-
/** set the solids (2d/ 3D /csg/cag data), and the geometry cache if applicable
|
|
132
|
-
* @param {} state
|
|
133
|
-
* @param {} {solids
|
|
134
|
-
* @param {} lookup
|
|
135
|
-
* @param {} lookupCounts}
|
|
136
|
-
* @returns {Object} the updated state
|
|
137
|
-
*/
|
|
138
|
-
setDesignSolids: (state, { solids, lookup, lookupCounts }) => {
|
|
139
|
-
solids = solids || []
|
|
140
|
-
lookup = lookup || {}
|
|
141
|
-
lookupCounts = lookupCounts || {}
|
|
142
|
-
|
|
143
|
-
// should debug be part of status ?
|
|
144
|
-
const endTime = new Date()
|
|
145
|
-
const totalTime = endTime - state.design.debug.startTime
|
|
146
|
-
const debug = Object.assign({ }, state.design.debug, {
|
|
147
|
-
endTime,
|
|
148
|
-
totalTime
|
|
149
|
-
})
|
|
150
|
-
console.warn('total time for design regeneration', totalTime, new Date().getSeconds())
|
|
151
|
-
|
|
152
|
-
const design = Object.assign({}, state.design, {
|
|
153
|
-
solids,
|
|
154
|
-
lookup,
|
|
155
|
-
lookupCounts,
|
|
156
|
-
debug
|
|
157
|
-
})
|
|
158
|
-
|
|
159
|
-
// TODO: move this to IO ??
|
|
160
|
-
const { exportFormat, availableExportFormats } = availableExportFormatsFromSolids(solids)
|
|
161
|
-
const exportInfos = exportFilePathFromFormatAndDesign(design, exportFormat)
|
|
162
|
-
const io = {
|
|
163
|
-
exportFormat,
|
|
164
|
-
exportFilePath: exportInfos.exportFilePath, // default export file path
|
|
165
|
-
availableExportFormats
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
const status = Object.assign({}, state.status, { busy: false })
|
|
169
|
-
|
|
170
|
-
return {
|
|
171
|
-
design,
|
|
172
|
-
status,
|
|
173
|
-
io
|
|
174
|
-
}
|
|
175
|
-
},
|
|
176
|
-
|
|
177
|
-
setDesignParameterDefinitions: (state, data) => {
|
|
178
|
-
const parameterDefaults = data.parameterDefaults || state.design.parameterDefaults
|
|
179
|
-
const parameterDefinitions = data.parameterDefinitions || state.design.parameterDefinitions
|
|
180
|
-
const design = Object.assign({}, state.design, {
|
|
181
|
-
parameterDefaults,
|
|
182
|
-
parameterDefinitions,
|
|
183
|
-
parametersOrigin: data.origin
|
|
184
|
-
})
|
|
185
|
-
return { design }
|
|
186
|
-
},
|
|
187
|
-
|
|
188
|
-
/** set the parameters of this design
|
|
189
|
-
* @param {Object} state
|
|
190
|
-
* @param {} {parameterDefaults
|
|
191
|
-
* @param {} parameterValues
|
|
192
|
-
* @param {} parameterDefinitions}
|
|
193
|
-
* @returns {Object} the updated state
|
|
194
|
-
*/
|
|
195
|
-
setDesignParameterValues: (state, data) => {
|
|
196
|
-
let parameterValues = data.parameterValues
|
|
197
|
-
// one of many ways of filtering out data from instantUpdates
|
|
198
|
-
if (data.origin === 'instantUpdate' && !state.design.instantUpdate) {
|
|
199
|
-
parameterValues = state.design.parameterValues
|
|
200
|
-
}
|
|
201
|
-
parameterValues = parameterValues ? applyParameterDefinitions(parameterValues, state.design.parameterDefinitions) : parameterValues
|
|
202
|
-
parameterValues = Object.assign({}, state.design.parameterValues, parameterValues)
|
|
203
|
-
|
|
204
|
-
let design = Object.assign({}, state.design, {
|
|
205
|
-
parameterValues,
|
|
206
|
-
parametersOrigin: data.origin
|
|
207
|
-
})
|
|
208
|
-
// to track computation time
|
|
209
|
-
const debug = Object.assign({ }, state.design.debug, { startTime: new Date() })
|
|
210
|
-
design = Object.assign({}, design, { debug })
|
|
211
|
-
|
|
212
|
-
const status = Object.assign({}, state.status, { busy: true, error: undefined })
|
|
213
|
-
|
|
214
|
-
return {
|
|
215
|
-
design,
|
|
216
|
-
status
|
|
217
|
-
}
|
|
218
|
-
},
|
|
219
|
-
|
|
220
|
-
setSettings: (state, { data }) => {
|
|
221
|
-
const {
|
|
222
|
-
vtreeMode,
|
|
223
|
-
autoReload,
|
|
224
|
-
instantUpdate,
|
|
225
|
-
solidsTimeOut
|
|
226
|
-
} = data
|
|
227
|
-
// FIXME : clunky but needed to make sure we have no invalid settings
|
|
228
|
-
if (vtreeMode === undefined) {
|
|
229
|
-
return { design: state.design }
|
|
230
|
-
}
|
|
231
|
-
const design = Object.assign({}, state.design, { vtreeMode, autoReload, instantUpdate, solidsTimeOut })
|
|
232
|
-
return {
|
|
233
|
-
design
|
|
234
|
-
}
|
|
235
|
-
},
|
|
236
|
-
|
|
237
|
-
requestGeometryRecompute: ({ design }, _) => keep(['mainPath', 'parameterValues', 'filesAndFolders', 'vtreeMode', 'lookup', 'lookupCounts'], design),
|
|
238
|
-
|
|
239
|
-
timeoutGeometryRecompute: ({ status }, _) => {
|
|
240
|
-
if (status.isBusy) { // still computing... we can kill it
|
|
241
|
-
return Object.assign({}, status, {
|
|
242
|
-
busy: false,
|
|
243
|
-
error: new Error('Failed to generate design within an acceptable time, bailing out')
|
|
244
|
-
})
|
|
245
|
-
}
|
|
246
|
-
// no problem, just act as a no-op
|
|
247
|
-
return { status }
|
|
248
|
-
},
|
|
249
|
-
|
|
250
|
-
requestWriteCachedGeometry: ({ design }, cache) => {
|
|
251
|
-
const data = {}
|
|
252
|
-
Object.keys(cache).forEach((key) => {
|
|
253
|
-
data[key] = cache[key]
|
|
254
|
-
})
|
|
255
|
-
// we want to save the geometry cache under '.solidsCache'
|
|
256
|
-
return { path: '.solidsCache', options: { isRawData: true }, origin: design.origin }
|
|
257
|
-
},
|
|
258
|
-
|
|
259
|
-
// what do we want to save , return an object containing only that data?
|
|
260
|
-
requestSaveSettings: ({ design }) => keep(serializableFields, design),
|
|
261
|
-
|
|
262
|
-
// helpers
|
|
263
|
-
isDesignValid: (state) => (state.design && state.design.name && state.design.path !== ''),
|
|
264
|
-
|
|
265
|
-
// determine if a design has remained the same : does NOT include solids, as they are a result of all the other parameters
|
|
266
|
-
isDesignTheSame: (previousState, state) => {
|
|
267
|
-
if (!previousState.design) {
|
|
268
|
-
return false
|
|
269
|
-
}
|
|
270
|
-
const current = JSON.stringify(keep(designEqualityFields, state.design))
|
|
271
|
-
const previous = JSON.stringify(keep(designEqualityFields, previousState.design))
|
|
272
|
-
return previous === current
|
|
273
|
-
},
|
|
274
|
-
|
|
275
|
-
// same as above but with added fields for settings
|
|
276
|
-
isDesignTheSameForSerialization: (previousState, state) => {
|
|
277
|
-
if (!previousState.design) {
|
|
278
|
-
return false
|
|
279
|
-
}
|
|
280
|
-
// do a JSON compare of the previous & current fields to save if needed
|
|
281
|
-
const current = JSON.stringify(keep(serializableFields, state.design))
|
|
282
|
-
const previous = JSON.stringify(keep(serializableFields, previousState.design))
|
|
283
|
-
return previous === current
|
|
284
|
-
},
|
|
9
|
+
const reducers = require('./reducers')
|
|
285
10
|
|
|
286
|
-
|
|
287
|
-
toggleAutoReload: (state, autoReload) => {
|
|
288
|
-
const design = Object.assign({}, state.design, { autoReload })
|
|
289
|
-
return { design }
|
|
290
|
-
},
|
|
291
|
-
|
|
292
|
-
toggleInstantUpdate: (state, instantUpdate) => {
|
|
293
|
-
const design = Object.assign({}, state.design, { instantUpdate })
|
|
294
|
-
return { design }
|
|
295
|
-
},
|
|
296
|
-
|
|
297
|
-
toggleVtreeMode: (state, vtreeMode) => {
|
|
298
|
-
const design = Object.assign({}, state.design, { vtreeMode })
|
|
299
|
-
return { design }
|
|
300
|
-
},
|
|
301
|
-
|
|
302
|
-
setSolidsTimeout: (state, solidsTimeOut) => {
|
|
303
|
-
const design = Object.assign({}, state.design, { solidsTimeOut })
|
|
304
|
-
return { design }
|
|
305
|
-
}
|
|
306
|
-
} // end of reducers
|
|
11
|
+
const jsonCompare = (first, second) => JSON.stringify(first) === JSON.stringify(second)
|
|
307
12
|
|
|
308
13
|
const actions = ({ sources }) => {
|
|
309
14
|
const initialize$ = most.just({})
|
|
@@ -315,11 +20,11 @@ const actions = ({ sources }) => {
|
|
|
315
20
|
const requestLoadSettings$ = initialize$
|
|
316
21
|
.map((_) => ({ sink: 'store', key: 'design', type: 'read' }))
|
|
317
22
|
|
|
318
|
-
// starts
|
|
23
|
+
// starts emitting to storage only AFTER initial settings have been loaded
|
|
319
24
|
const requestSaveSettings$ = sources.state
|
|
320
25
|
.filter(reducers.isDesignValid)
|
|
321
26
|
.skipRepeatsWith(reducers.isDesignTheSameForSerialization)
|
|
322
|
-
// wait until we
|
|
27
|
+
// wait until we actually have design data
|
|
323
28
|
.thru(holdUntil(sources.store.filter((reply) => reply.key === 'design' && reply.type === 'read')))
|
|
324
29
|
.map(reducers.requestSaveSettings)
|
|
325
30
|
.map((data) => Object.assign({}, { data }, { sink: 'store', key: 'design', type: 'write' }))
|
|
@@ -446,7 +151,7 @@ const actions = ({ sources }) => {
|
|
|
446
151
|
const resetDesign$ = most.mergeArray([
|
|
447
152
|
requestLoadDesignContent$.map(({ sink }) => sink)
|
|
448
153
|
])
|
|
449
|
-
// .thru(holdUntil(setDesignSettings$))// only after FIXME : this does not seem to work
|
|
154
|
+
// .thru(holdUntil(setDesignSettings$)) // only after FIXME : this does not seem to work
|
|
450
155
|
.thru(withLatestFrom(reducers.resetDesign, sources.state))
|
|
451
156
|
.map((data) => ({ type: 'resetDesign', state: data, sink: 'state' }))
|
|
452
157
|
.multicast()
|
|
@@ -491,7 +196,7 @@ const actions = ({ sources }) => {
|
|
|
491
196
|
|
|
492
197
|
// we also re-use the timeout to send a signal to the worker to terminate the current geometry generation
|
|
493
198
|
const cancelGeometryRecompute$ = timeoutGeometryRecompute$
|
|
494
|
-
.filter(({ state }) => state.status.error !== undefined)// if there was no error
|
|
199
|
+
.filter(({ state }) => state.status.error !== undefined) // if there was no error, the timeout is irrelevant
|
|
495
200
|
.map((_) => Object.assign({}, { sink: 'geometryWorker', cmd: 'cancel' }))
|
|
496
201
|
.multicast()
|
|
497
202
|
|
|
@@ -539,13 +244,13 @@ const actions = ({ sources }) => {
|
|
|
539
244
|
.multicast()
|
|
540
245
|
.debounce(10)
|
|
541
246
|
|
|
542
|
-
// parameter values etc
|
|
247
|
+
// parameter values etc retrieved from local storage
|
|
543
248
|
const parametersFromStore$ = sources.store
|
|
544
249
|
.filter((reply) => reply.key === 'design' && reply.type === 'read' && reply.data.parameterValues !== undefined)
|
|
545
250
|
.map(({ data }) => ({ parameterValues: data.parameterValues, origin: 'store' }))
|
|
546
251
|
.multicast()
|
|
547
252
|
|
|
548
|
-
// parameter values
|
|
253
|
+
// parameter values retrieved from titleBar
|
|
549
254
|
const parametersFromTitleBar$ = sources.titleBar
|
|
550
255
|
.map((uri) => getAllUriParams(uri))
|
|
551
256
|
.filter((params) => Object.keys(params).length > 0)
|
|
@@ -573,7 +278,18 @@ const actions = ({ sources }) => {
|
|
|
573
278
|
.thru(withLatestFrom(reducers.setDesignParameterValues, sources.state))
|
|
574
279
|
.map((data) => ({ type: 'setDesignParameterValues', state: data, sink: 'state' }))
|
|
575
280
|
.multicast()
|
|
576
|
-
.delay(10) // needed
|
|
281
|
+
.delay(10) // needed, why?
|
|
282
|
+
|
|
283
|
+
// errors retrieved from worker
|
|
284
|
+
const errorsFromWorker$ = sources.solidWorker
|
|
285
|
+
.filter((event) => event.data instanceof Object && event.data.type === 'errors')
|
|
286
|
+
.map(({ data }) => ({ error: data, origin: 'worker' }))
|
|
287
|
+
|
|
288
|
+
const reportErrorsFromWorker$ = most.mergeArray([
|
|
289
|
+
errorsFromWorker$
|
|
290
|
+
])
|
|
291
|
+
.skipRepeatsWith(jsonCompare)
|
|
292
|
+
.tap((x) => console.log('errors', x))
|
|
577
293
|
|
|
578
294
|
// ui/toggles
|
|
579
295
|
const toggleAutoReload$ = most.mergeArray([
|
|
@@ -615,6 +331,8 @@ const actions = ({ sources }) => {
|
|
|
615
331
|
setDesignParameterDefinitions$,
|
|
616
332
|
setDesignParameterValues$,
|
|
617
333
|
|
|
334
|
+
reportErrorsFromWorker$,
|
|
335
|
+
|
|
618
336
|
requestGeometryRecompute$,
|
|
619
337
|
timeoutGeometryRecompute$,
|
|
620
338
|
cancelGeometryRecompute$,
|