@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.
Files changed (75) hide show
  1. package/CHANGELOG.md +32 -0
  2. package/css/demo.css +5 -1
  3. package/dist/jscad-web.min.js +861 -1999
  4. package/examples/CHANGELOG.md +30 -0
  5. package/examples/README.md +0 -4
  6. package/examples/core/extrusions/nutsAndBolts.js +94 -0
  7. package/examples/examples.json +1 -1
  8. package/examples/package.json +1 -1
  9. package/examples/parameters/gear.js +1 -1
  10. package/package.json +7 -7
  11. package/postInstall.js +0 -1
  12. package/src/sideEffects/worker/index.js +12 -9
  13. package/src/ui/flow/design.js +23 -305
  14. package/src/ui/flow/reducers.js +304 -0
  15. package/src/ui/views/parameterControls.js +3 -3
  16. package/src/ui/views/status.js +21 -14
  17. package/examples/old/benchmark-cag.jscad +0 -27
  18. package/examples/old/benchmark-csg.jscad +0 -29
  19. package/examples/old/benchmark.jscad +0 -25
  20. package/examples/old/bunch-cubes.jscad +0 -17
  21. package/examples/old/complex/example001.jscad +0 -31
  22. package/examples/old/complex/example002.jscad +0 -25
  23. package/examples/old/complex/example003.jscad +0 -25
  24. package/examples/old/complex/example004.jscad +0 -16
  25. package/examples/old/complex/example005.jscad +0 -27
  26. package/examples/old/complex/globe.js +0 -235
  27. package/examples/old/complex/iphone4-case.js +0 -213
  28. package/examples/old/complex/umbilical_torus.js +0 -43
  29. package/examples/old/complex/umbilical_torus.scad +0 -37
  30. package/examples/old/core/cncCutout.js +0 -16
  31. package/examples/old/core/connectors/servo.js +0 -185
  32. package/examples/old/core/extrusions/extrudeLinear.js +0 -24
  33. package/examples/old/core/extrusions/extrudeRectangular.js +0 -21
  34. package/examples/old/core/extrusions/extrudeRotate.js +0 -43
  35. package/examples/old/core/extrusions/slices/four2three-round.js +0 -62
  36. package/examples/old/core/extrusions/slices/four2three.js +0 -53
  37. package/examples/old/core/extrusions/slices/jar-barrel.js +0 -60
  38. package/examples/old/core/extrusions/slices/jar.js +0 -69
  39. package/examples/old/core/extrusions/slices/non-aff.js +0 -72
  40. package/examples/old/core/extrusions/slices/rose.js +0 -52
  41. package/examples/old/core/extrusions/slices/screw.js +0 -34
  42. package/examples/old/core/extrusions/slices/screwDouble.js +0 -34
  43. package/examples/old/core/extrusions/slices/slices.js +0 -43
  44. package/examples/old/core/extrusions/slices/spring.js +0 -41
  45. package/examples/old/core/extrusions/slices/three2four.js +0 -42
  46. package/examples/old/core/extrusions/slices/tor.js +0 -30
  47. package/examples/old/core/hulls/hullChain.js +0 -58
  48. package/examples/old/core/lookup.js +0 -19
  49. package/examples/old/core/platonics/main.jscad +0 -42
  50. package/examples/old/core/platonics/maths_geodesic.jscad +0 -192
  51. package/examples/old/core/platonics/origv07/dualdodeca_difference.stl +0 -1962
  52. package/examples/old/core/platonics/origv07/dualdodeca_intersection.stl +0 -1374
  53. package/examples/old/core/platonics/origv07/dualdodeca_union.stl +0 -1822
  54. package/examples/old/core/platonics/origv07/maths_geodesic.scad +0 -162
  55. package/examples/old/core/platonics/origv07/platonic.scad +0 -483
  56. package/examples/old/core/platonics/origv07/test_platonic.scad +0 -616
  57. package/examples/old/core/platonics/platonic.jscad +0 -528
  58. package/examples/old/core/text/textSimplex.js +0 -625
  59. package/examples/old/core/transforms/transformations.js +0 -29
  60. package/examples/old/echo.jscad +0 -7
  61. package/examples/old/formats/scad/example001.scad +0 -26
  62. package/examples/old/formats/scad/example002.scad +0 -23
  63. package/examples/old/formats/scad/example003.scad +0 -20
  64. package/examples/old/formats/scad/example004.scad +0 -11
  65. package/examples/old/formats/scad/example005.scad +0 -20
  66. package/examples/old/json_logo.json +0 -1
  67. package/examples/old/parameters/axis-coupler.js +0 -149
  68. package/examples/old/parameters/celtic-knot-ring.js +0 -300
  69. package/examples/old/parameters/grille.js +0 -257
  70. package/examples/old/parameters/lamp-shade.js +0 -369
  71. package/examples/old/parameters/name-plate.js +0 -46
  72. package/examples/old/parameters/s-hook.js +0 -131
  73. package/examples/old/parameters/stepper-motor.js +0 -127
  74. package/examples/old/various/logo.js +0 -32
  75. package/examples/old/voxel.json +0 -1
@@ -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
@@ -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 }
@@ -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&#39;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&#39;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,6 +1,6 @@
1
1
  {
2
2
  "name": "@jscad/examples",
3
- "version": "2.3.3",
3
+ "version": "2.4.1",
4
4
  "description": "Example Files for JSCAD",
5
5
  "homepage": "https://openjscad.xyz/",
6
6
  "repository": "https://github.com/jscad/OpenJSCAD.org",
@@ -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.9",
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.5.9",
40
- "@jscad/examples": "2.3.4",
41
- "@jscad/io": "2.3.2",
42
- "@jscad/modeling": "2.9.3",
43
- "@jscad/regl-renderer": "2.5.9",
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": "85fa1fcdfb2d516a201ecf31da242e64b5b3274e"
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
- let _worker = WebWorkify(workerPath)
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((_) => _worker.terminate())
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((message) => {
19
- _worker.terminate()// FIXME: sub optimal ! worker recreation is SLOW and should not be systematic
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
 
@@ -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 { applyParameterDefinitions, getParameterValuesFromUIControls } = require('@jscad/core').parameters
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 jsonCompare = (first, second) => JSON.stringify(first) === JSON.stringify(second)
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
- // ui/toggles
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 emmiting to storage only AFTER initial settings have been loaded
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 actualy have design data
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 , the timeout is irrelevant
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 retrived from local storage
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 retrived from titleBar
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 , why ?
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$,