@jwc/jscad-utils 5.2.0 → 5.5.0

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.
@@ -1,14 +1,15 @@
1
1
  function main() {
2
- util.init(CSG);
2
+ util.init(CSG, { debug: 'jscadUtils:boxes' });
3
+
4
+ var cyl = Parts.Cylinder(20, 20)
5
+ var cbox = Boxes.Hollow(cyl, 3, function (box) {
6
+ return box
7
+ .fillet(2, 'z+')
8
+ .fillet(2, 'z-');
9
+ });
10
+ var box = Boxes.Rabett(cbox, 3, 0.5, 11, 2)
11
+ return box.parts.top.translate([0, 0, 10]).union(box.parts.bottom);
3
12
 
4
- var cyl = Parts.Cylinder(20, 20)
5
- var cbox = Boxes.Hollow(cyl, 3, function (box) {
6
- return box
7
- .fillet(2, 'z+')
8
- .fillet(2, 'z-');
9
- });
10
- var box = Boxes.Rabett(cbox, 3, 0.5, 11, 2)
11
- return box.parts.top.translate([0, 0, 10]).union(box.parts.bottom);
12
13
  }
13
14
 
14
15
  // include:js
@@ -54,6 +55,8 @@ function initJscadutils(_CSG, options = {}) {
54
55
  enabled: [],
55
56
  disabled: []
56
57
  });
58
+ var jscadUtilsAssertValidCSGWarnings = options.assertValidCSGWarnings || false;
59
+ var jscadUtilsAssertValidCSG = options.assertValidCSG || false;
57
60
  var jscadUtils = function(exports, jsCadCSG, scadApi) {
58
61
  "use strict";
59
62
  function _interopDefaultLegacy(e) {
@@ -287,6 +290,51 @@ function initJscadutils(_CSG, options = {}) {
287
290
  function _arrayWithHoles(r) {
288
291
  if (Array.isArray(r)) return r;
289
292
  }
293
+ function _createForOfIteratorHelper(r, e) {
294
+ var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"];
295
+ if (!t) {
296
+ if (Array.isArray(r) || (t = _unsupportedIterableToArray(r)) || e && r && "number" == typeof r.length) {
297
+ t && (r = t);
298
+ var n = 0, F = function() {};
299
+ return {
300
+ s: F,
301
+ n: function() {
302
+ return n >= r.length ? {
303
+ done: !0
304
+ } : {
305
+ done: !1,
306
+ value: r[n++]
307
+ };
308
+ },
309
+ e: function(r) {
310
+ throw r;
311
+ },
312
+ f: F
313
+ };
314
+ }
315
+ throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
316
+ }
317
+ var o, a = !0, u = !1;
318
+ return {
319
+ s: function() {
320
+ t = t.call(r);
321
+ },
322
+ n: function() {
323
+ var r = t.next();
324
+ return a = r.done, r;
325
+ },
326
+ e: function(r) {
327
+ u = !0, o = r;
328
+ },
329
+ f: function() {
330
+ try {
331
+ a || null == t.return || t.return();
332
+ } finally {
333
+ if (u) throw o;
334
+ }
335
+ }
336
+ };
337
+ }
290
338
  function _defineProperty(e, r, t) {
291
339
  return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, {
292
340
  value: t,
@@ -707,6 +755,219 @@ function initJscadutils(_CSG, options = {}) {
707
755
  c[3] = g || 1;
708
756
  return o.setColor(c);
709
757
  }
758
+ function validateCSG(csg, options) {
759
+ var errors = [];
760
+ var warnings = [];
761
+ if (!csg || !csg.polygons || csg.polygons.length === 0) {
762
+ errors.push("Empty mesh: no polygons");
763
+ return {
764
+ ok: false,
765
+ errors,
766
+ warnings
767
+ };
768
+ }
769
+ var opts = _objectSpread2({
770
+ fixTJunctions: true
771
+ }, options);
772
+ if (opts.fixTJunctions && typeof csg.canonicalized === "function") {
773
+ csg = csg.canonicalized();
774
+ if (typeof csg.reTesselated === "function") {
775
+ csg = csg.reTesselated();
776
+ }
777
+ if (typeof csg.fixTJunctions === "function") {
778
+ csg = csg.fixTJunctions();
779
+ }
780
+ }
781
+ var AREA_EPS = 1e-10;
782
+ var KEY_EPS = 1e-5;
783
+ var degenerateCount = 0;
784
+ var invalidVertexCount = 0;
785
+ var _iterator = _createForOfIteratorHelper(csg.polygons), _step;
786
+ try {
787
+ for (_iterator.s(); !(_step = _iterator.n()).done; ) {
788
+ var npoly = _step.value;
789
+ var _iterator4 = _createForOfIteratorHelper(npoly.vertices), _step4;
790
+ try {
791
+ for (_iterator4.s(); !(_step4 = _iterator4.n()).done; ) {
792
+ var nvert = _step4.value;
793
+ var np = nvert.pos;
794
+ if (!Number.isFinite(np.x) || !Number.isFinite(np.y) || !Number.isFinite(np.z) || Number.isNaN(np.x) || Number.isNaN(np.y) || Number.isNaN(np.z)) {
795
+ invalidVertexCount++;
796
+ break;
797
+ }
798
+ }
799
+ } catch (err) {
800
+ _iterator4.e(err);
801
+ } finally {
802
+ _iterator4.f();
803
+ }
804
+ }
805
+ } catch (err) {
806
+ _iterator.e(err);
807
+ } finally {
808
+ _iterator.f();
809
+ }
810
+ if (invalidVertexCount > 0) {
811
+ errors.push(invalidVertexCount + " polygon(s) with invalid vertex coordinates (NaN or Infinity)");
812
+ }
813
+ function vtxKey(v) {
814
+ var p = v.pos;
815
+ return Math.round(p.x / KEY_EPS) + "," + Math.round(p.y / KEY_EPS) + "," + Math.round(p.z / KEY_EPS);
816
+ }
817
+ var validPolygons = [];
818
+ var _iterator2 = _createForOfIteratorHelper(csg.polygons), _step2;
819
+ try {
820
+ for (_iterator2.s(); !(_step2 = _iterator2.n()).done; ) {
821
+ var poly = _step2.value;
822
+ var verts = poly.vertices;
823
+ var nv = verts.length;
824
+ if (nv < 3) {
825
+ degenerateCount++;
826
+ continue;
827
+ }
828
+ var hasInvalid = false;
829
+ var _iterator5 = _createForOfIteratorHelper(verts), _step5;
830
+ try {
831
+ for (_iterator5.s(); !(_step5 = _iterator5.n()).done; ) {
832
+ var vert = _step5.value;
833
+ var ip = vert.pos;
834
+ if (!Number.isFinite(ip.x) || !Number.isFinite(ip.y) || !Number.isFinite(ip.z)) {
835
+ hasInvalid = true;
836
+ break;
837
+ }
838
+ }
839
+ } catch (err) {
840
+ _iterator5.e(err);
841
+ } finally {
842
+ _iterator5.f();
843
+ }
844
+ if (hasInvalid) continue;
845
+ var area = 0;
846
+ for (var ai = 0; ai < nv - 2; ai++) {
847
+ area += verts[ai + 1].pos.minus(verts[0].pos).cross(verts[ai + 2].pos.minus(verts[ai + 1].pos)).length();
848
+ }
849
+ area *= .5;
850
+ if (area < AREA_EPS) {
851
+ degenerateCount++;
852
+ continue;
853
+ }
854
+ validPolygons.push(poly);
855
+ }
856
+ } catch (err) {
857
+ _iterator2.e(err);
858
+ } finally {
859
+ _iterator2.f();
860
+ }
861
+ if (degenerateCount > 0) {
862
+ warnings.push(degenerateCount + " degenerate polygon(s) (fewer than 3 vertices or near-zero area)");
863
+ if (opts.fixTJunctions && typeof CSG !== "undefined") {
864
+ var cleaned = CSG.fromPolygons(validPolygons);
865
+ cleaned = cleaned.canonicalized();
866
+ if (typeof cleaned.reTesselated === "function") {
867
+ cleaned = cleaned.reTesselated();
868
+ }
869
+ if (typeof cleaned.fixTJunctions === "function") {
870
+ cleaned = cleaned.fixTJunctions();
871
+ }
872
+ validPolygons = [];
873
+ var _iterator3 = _createForOfIteratorHelper(cleaned.polygons), _step3;
874
+ try {
875
+ for (_iterator3.s(); !(_step3 = _iterator3.n()).done; ) {
876
+ var cpoly = _step3.value;
877
+ var cverts = cpoly.vertices;
878
+ var cnv = cverts.length;
879
+ if (cnv < 3) continue;
880
+ var carea = 0;
881
+ for (var cai = 0; cai < cnv - 2; cai++) {
882
+ carea += cverts[cai + 1].pos.minus(cverts[0].pos).cross(cverts[cai + 2].pos.minus(cverts[cai + 1].pos)).length();
883
+ }
884
+ carea *= .5;
885
+ if (carea < AREA_EPS) continue;
886
+ validPolygons.push(cpoly);
887
+ }
888
+ } catch (err) {
889
+ _iterator3.e(err);
890
+ } finally {
891
+ _iterator3.f();
892
+ }
893
+ }
894
+ }
895
+ var edgeCounts = {};
896
+ for (var _i = 0, _validPolygons = validPolygons; _i < _validPolygons.length; _i++) {
897
+ var vpoly = _validPolygons[_i];
898
+ var vverts = vpoly.vertices;
899
+ var vnv = vverts.length;
900
+ for (var ei = 0; ei < vnv; ei++) {
901
+ var v0 = vverts[ei];
902
+ var v1 = vverts[(ei + 1) % vnv];
903
+ var edgeKey = vtxKey(v0) + "/" + vtxKey(v1);
904
+ edgeCounts[edgeKey] = (edgeCounts[edgeKey] || 0) + 1;
905
+ }
906
+ }
907
+ var unmatchedEdges = 0;
908
+ var nonManifoldEdges = 0;
909
+ var checked = {};
910
+ for (var _i2 = 0, _Object$keys = Object.keys(edgeCounts); _i2 < _Object$keys.length; _i2++) {
911
+ var _edgeKey = _Object$keys[_i2];
912
+ if (checked[_edgeKey]) continue;
913
+ var parts = _edgeKey.split("/");
914
+ var reverseKey = parts[1] + "/" + parts[0];
915
+ var forwardCount = edgeCounts[_edgeKey] || 0;
916
+ var reverseCount = edgeCounts[reverseKey] || 0;
917
+ checked[_edgeKey] = true;
918
+ checked[reverseKey] = true;
919
+ if (forwardCount !== reverseCount) {
920
+ unmatchedEdges += Math.abs(forwardCount - reverseCount);
921
+ }
922
+ if (forwardCount > 1 || reverseCount > 1) {
923
+ nonManifoldEdges++;
924
+ }
925
+ }
926
+ if (unmatchedEdges > 0) {
927
+ errors.push(unmatchedEdges + " unmatched edge(s): mesh is not watertight");
928
+ }
929
+ if (nonManifoldEdges > 0) {
930
+ errors.push(nonManifoldEdges + " non-manifold edge(s): edge shared by more than 2 polygons");
931
+ }
932
+ return {
933
+ ok: errors.length === 0,
934
+ errors,
935
+ warnings
936
+ };
937
+ }
938
+ function _noOp(csg) {
939
+ return csg;
940
+ }
941
+ function _makeAssertFn(warnEnabled) {
942
+ return function _assert(csg) {
943
+ var functionName = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : "unknown";
944
+ var moduleName = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : "unknown";
945
+ if (!csg || csg.polygons === undefined) return csg;
946
+ var result = validateCSG(csg);
947
+ if (!result.ok) {
948
+ throw new Error(moduleName + ":" + functionName + ": " + "invalid CSG: " + result.errors.join(", "));
949
+ }
950
+ if (warnEnabled && result.warnings.length > 0) {
951
+ throw new Error(moduleName + ":" + functionName + ": " + "CSG warnings: " + result.warnings.join(", "));
952
+ }
953
+ return csg;
954
+ };
955
+ }
956
+ var _assertFn = _noOp;
957
+ function _resolveFromGlobals() {
958
+ var enabled = typeof jscadUtilsAssertValidCSG !== "undefined" && !!jscadUtilsAssertValidCSG;
959
+ var warnEnabled = typeof jscadUtilsAssertValidCSGWarnings !== "undefined" && !!jscadUtilsAssertValidCSGWarnings;
960
+ return enabled ? _makeAssertFn(warnEnabled) : _noOp;
961
+ }
962
+ function AssertValidCSG() {
963
+ var moduleName = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : "unknown";
964
+ {
965
+ _assertFn = _resolveFromGlobals();
966
+ }
967
+ return function(csg, name) {
968
+ return _assertFn(csg, name, moduleName);
969
+ };
970
+ }
710
971
  function init(proto) {
711
972
  if (proto.prototype._jscadutilsinit) return;
712
973
  proto.prototype.color = function(r, g, b, a) {
@@ -800,6 +1061,9 @@ function initJscadutils(_CSG, options = {}) {
800
1061
  proto.prototype.subtractIf = function subtractIf(object, condition) {
801
1062
  return condition ? this.subtract(result(this, object)) : this;
802
1063
  };
1064
+ proto.prototype.validate = function validate(options) {
1065
+ return validateCSG(this, options);
1066
+ };
803
1067
  proto.prototype._translate = proto.prototype.translate;
804
1068
  proto.prototype.translate = function translate() {
805
1069
  if (arguments.length === 1) {
@@ -832,12 +1096,13 @@ function initJscadutils(_CSG, options = {}) {
832
1096
  __proto__: null,
833
1097
  default: init
834
1098
  });
835
- var CSG = jsCadCSG__default["default"].CSG, CAG = jsCadCSG__default["default"].CAG;
1099
+ var CSG$1 = jsCadCSG__default["default"].CSG, CAG = jsCadCSG__default["default"].CAG;
836
1100
  var rectangular_extrude = scadApi__default["default"].extrusions.rectangular_extrude;
837
1101
  var _scadApi$text = scadApi__default["default"].text, vector_text = _scadApi$text.vector_text, vector_char = _scadApi$text.vector_char;
838
1102
  var union = scadApi__default["default"].booleanOps.union;
839
- init(CSG);
1103
+ init(CSG$1);
840
1104
  var debug$3 = Debug("jscadUtils:group");
1105
+ var assertValidCSG$2 = AssertValidCSG("group");
841
1106
  function JsCadUtilsGroup() {
842
1107
  var names = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];
843
1108
  var parts = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
@@ -888,7 +1153,7 @@ function initJscadutils(_CSG, options = {}) {
888
1153
  debug$3("combine mapPick", value, key, object);
889
1154
  return map ? map(value, key, index, object) : identity(value);
890
1155
  }, self.name));
891
- return g.subtractIf(self.holes && Array.isArray(self.holes) ? union(self.holes) : self.holes, self.holes && !options.noholes);
1156
+ return assertValidCSG$2(g.subtractIf(self.holes && Array.isArray(self.holes) ? union(self.holes) : self.holes, self.holes && !options.noholes), "combine");
892
1157
  } catch (err) {
893
1158
  debug$3("combine error", this, pieces, options, err);
894
1159
  throw error('group::combine error "'.concat(err.message || err.toString(), '"\nthis: ').concat(this, '\npieces: "').concat(pieces, '"\noptions: ').concat(JSON.stringify(options, null, 2), "\nstack: ").concat(err.stack, "\n"), "JSCAD_UTILS_GROUP_ERROR");
@@ -929,7 +1194,7 @@ function initJscadutils(_CSG, options = {}) {
929
1194
  });
930
1195
  if (self.holes) {
931
1196
  group.holes = toArray(self.holes).map(function(part) {
932
- return map(CSG.fromPolygons(part.toPolygons()), "holes");
1197
+ return assertValidCSG$2(map(CSG$1.fromPolygons(part.toPolygons()), "holes"), "clone");
933
1198
  });
934
1199
  }
935
1200
  return group;
@@ -948,7 +1213,7 @@ function initJscadutils(_CSG, options = {}) {
948
1213
  var rotationCenter = solid.centroid();
949
1214
  var rotationAxis = axes[axis];
950
1215
  self.map(function(part) {
951
- return part.rotate(rotationCenter, rotationAxis, angle);
1216
+ return assertValidCSG$2(part.rotate(rotationCenter, rotationAxis, angle), "rotate");
952
1217
  });
953
1218
  return self;
954
1219
  };
@@ -961,7 +1226,7 @@ function initJscadutils(_CSG, options = {}) {
961
1226
  var self = this;
962
1227
  var t = calcSnap(self.combine(part), to, axis, orientation, delta);
963
1228
  self.map(function(part) {
964
- return part.translate(t);
1229
+ return assertValidCSG$2(part.translate(t), "snap");
965
1230
  });
966
1231
  return self;
967
1232
  } catch (err) {
@@ -976,7 +1241,7 @@ function initJscadutils(_CSG, options = {}) {
976
1241
  noholes: true
977
1242
  }), axis, to, delta);
978
1243
  self.map(function(part) {
979
- return part.translate(t);
1244
+ return assertValidCSG$2(part.translate(t), "align");
980
1245
  });
981
1246
  return self;
982
1247
  } catch (err) {
@@ -1008,14 +1273,14 @@ function initJscadutils(_CSG, options = {}) {
1008
1273
  var myConnector = connectorName.split(".").reduce(function(a, v) {
1009
1274
  return a[v];
1010
1275
  }, self.parts[partName].properties);
1011
- debug$3("toConnector", to instanceof CSG.Connector);
1276
+ debug$3("toConnector", to instanceof CSG$1.Connector);
1012
1277
  var toConnector = toConnectorName.split(".").reduce(function(a, v) {
1013
1278
  return a[v];
1014
1279
  }, to.properties);
1015
1280
  var matrix = myConnector.getTransformationTo(toConnector, mirror, normalrotation);
1016
1281
  debug$3("connectTo", matrix);
1017
1282
  self.map(function(part) {
1018
- return part.transform(matrix);
1283
+ return assertValidCSG$2(part.transform(matrix), "connectTo");
1019
1284
  });
1020
1285
  return self;
1021
1286
  };
@@ -1026,7 +1291,7 @@ function initJscadutils(_CSG, options = {}) {
1026
1291
  return to - size[a] / 2;
1027
1292
  });
1028
1293
  self.map(function(part) {
1029
- return part.translate(t);
1294
+ return assertValidCSG$2(part.translate(t), "midlineTo");
1030
1295
  });
1031
1296
  return self;
1032
1297
  };
@@ -1035,7 +1300,7 @@ function initJscadutils(_CSG, options = {}) {
1035
1300
  var t = Array.isArray(x) ? x : [ x, y, z ];
1036
1301
  debug$3("translate", t);
1037
1302
  self.map(function(part) {
1038
- return part.translate(t);
1303
+ return assertValidCSG$2(part.translate(t), "translate");
1039
1304
  });
1040
1305
  return self;
1041
1306
  };
@@ -1045,7 +1310,7 @@ function initJscadutils(_CSG, options = {}) {
1045
1310
  if (!map) map = identity;
1046
1311
  var g = Group();
1047
1312
  p.forEach(function(name) {
1048
- g.add(map(CSG.fromPolygons(self.parts[name].toPolygons()), name), name);
1313
+ g.add(assertValidCSG$2(map(CSG$1.fromPolygons(self.parts[name].toPolygons()), name), "pick"), name);
1049
1314
  });
1050
1315
  return g;
1051
1316
  };
@@ -1060,7 +1325,7 @@ function initJscadutils(_CSG, options = {}) {
1060
1325
  debug$3("array error", _this, parts);
1061
1326
  throw error('group::array error "'.concat(name, '" not found.\nthis: ').concat(_this, '\nparts: "').concat(parts, '"\n'), "JSCAD_UTILS_GROUP_ERROR");
1062
1327
  }
1063
- a.push(map(CSG.fromPolygons(self.parts[name].toPolygons()), name));
1328
+ a.push(assertValidCSG$2(map(CSG$1.fromPolygons(self.parts[name].toPolygons()), name), "array"));
1064
1329
  });
1065
1330
  return a;
1066
1331
  };
@@ -1093,7 +1358,7 @@ function initJscadutils(_CSG, options = {}) {
1093
1358
  self.names = names && names.length > 0 && names.split(",") || [];
1094
1359
  if (Array.isArray(objects)) {
1095
1360
  self.parts = zipObject(self.names, objects);
1096
- } else if (objects instanceof CSG) {
1361
+ } else if (objects instanceof CSG$1) {
1097
1362
  self.parts = zipObject(self.names, [ objects ]);
1098
1363
  } else {
1099
1364
  self.parts = objects || {};
@@ -1114,6 +1379,7 @@ function initJscadutils(_CSG, options = {}) {
1114
1379
  return new JsCadUtilsGroup(self.names, self.parts, self.holes);
1115
1380
  }
1116
1381
  var debug$2 = Debug("jscadUtils:util");
1382
+ var assertValidCSG$1 = AssertValidCSG("util");
1117
1383
  var NOZZEL_SIZE = .4;
1118
1384
  var nearest = {
1119
1385
  under: function under(desired) {
@@ -1190,12 +1456,12 @@ function initJscadutils(_CSG, options = {}) {
1190
1456
  h: height || 2
1191
1457
  }));
1192
1458
  });
1193
- return center(union(o));
1459
+ return assertValidCSG$1(center(union(o)), "label");
1194
1460
  }
1195
1461
  function text(text) {
1196
1462
  var l = vector_char(0, 0, text);
1197
1463
  var _char = l.segments.reduce(function(result, segment) {
1198
- var path = new CSG.Path2D(segment);
1464
+ var path = new CSG$1.Path2D(segment);
1199
1465
  var cag = path.expandToCAG(2);
1200
1466
  return result ? result.union(cag) : cag;
1201
1467
  }, undefined);
@@ -1203,17 +1469,17 @@ function initJscadutils(_CSG, options = {}) {
1203
1469
  }
1204
1470
  function unitCube(length, radius) {
1205
1471
  radius = radius || .5;
1206
- return CSG.cube({
1472
+ return assertValidCSG$1(CSG$1.cube({
1207
1473
  center: [ 0, 0, 0 ],
1208
1474
  radius: [ radius, radius, length || .5 ]
1209
- });
1475
+ }), "unitCube");
1210
1476
  }
1211
1477
  function unitAxis(length, radius, centroid) {
1212
1478
  debug$2("unitAxis", length, radius, centroid);
1213
1479
  centroid = centroid || [ 0, 0, 0 ];
1214
1480
  var unitaxis = unitCube(length, radius).setColor(1, 0, 0).union([ unitCube(length, radius).rotateY(90).setColor(0, 1, 0), unitCube(length, radius).rotateX(90).setColor(0, 0, 1) ]);
1215
- unitaxis.properties.origin = new CSG.Connector([ 0, 0, 0 ], [ 1, 0, 0 ], [ 0, 1, 0 ]);
1216
- return unitaxis.translate(centroid);
1481
+ unitaxis.properties.origin = new CSG$1.Connector([ 0, 0, 0 ], [ 1, 0, 0 ], [ 0, 1, 0 ]);
1482
+ return assertValidCSG$1(unitaxis.translate(centroid), "unitAxis");
1217
1483
  }
1218
1484
  function toArray(a) {
1219
1485
  return Array.isArray(a) ? a : [ a ];
@@ -1303,15 +1569,15 @@ function initJscadutils(_CSG, options = {}) {
1303
1569
  }
1304
1570
  function center(object, objectSize) {
1305
1571
  objectSize = objectSize || size(object.getBounds());
1306
- return centerY(centerX(object, objectSize), objectSize);
1572
+ return assertValidCSG$1(centerY(centerX(object, objectSize), objectSize), "center");
1307
1573
  }
1308
1574
  function centerY(object, objectSize) {
1309
1575
  objectSize = objectSize || size(object.getBounds());
1310
- return object.translate([ 0, -objectSize.y / 2, 0 ]);
1576
+ return assertValidCSG$1(object.translate([ 0, -objectSize.y / 2, 0 ]), "centerY");
1311
1577
  }
1312
1578
  function centerX(object, objectSize) {
1313
1579
  objectSize = objectSize || size(object.getBounds());
1314
- return object.translate([ -objectSize.x / 2, 0, 0 ]);
1580
+ return assertValidCSG$1(object.translate([ -objectSize.x / 2, 0, 0 ]), "centerX");
1315
1581
  }
1316
1582
  function enlarge(object, x, y, z) {
1317
1583
  var a;
@@ -1329,7 +1595,7 @@ function initJscadutils(_CSG, options = {}) {
1329
1595
  var new_object = object.scale(t);
1330
1596
  var new_centroid = centroid(new_object);
1331
1597
  var delta = new_centroid.minus(objectCentroid).times(-1);
1332
- return new_object.translate(delta);
1598
+ return assertValidCSG$1(new_object.translate(delta), "enlarge");
1333
1599
  }
1334
1600
  function fit(object, x, y, z, keep_aspect_ratio) {
1335
1601
  var a;
@@ -1349,10 +1615,10 @@ function initJscadutils(_CSG, options = {}) {
1349
1615
  }
1350
1616
  var s = [ scale(objectSize.x, x), scale(objectSize.y, y), scale(objectSize.z, z) ];
1351
1617
  var min$1 = min(s);
1352
- return centerWith(object.scale(s.map(function(d, i) {
1618
+ return assertValidCSG$1(centerWith(object.scale(s.map(function(d, i) {
1353
1619
  if (a[i] === 0) return 1;
1354
1620
  return keep_aspect_ratio ? min$1 : d;
1355
- })), "xyz", object);
1621
+ })), "xyz", object), "fit");
1356
1622
  }
1357
1623
  function shift(object, x, y, z) {
1358
1624
  var hsize = this.div(this.size(object.getBounds()), 2);
@@ -1360,10 +1626,10 @@ function initJscadutils(_CSG, options = {}) {
1360
1626
  }
1361
1627
  function zero(object) {
1362
1628
  var bounds = object.getBounds();
1363
- return object.translate([ 0, 0, -bounds[0].z ]);
1629
+ return assertValidCSG$1(object.translate([ 0, 0, -bounds[0].z ]), "zero");
1364
1630
  }
1365
1631
  function mirrored4(x) {
1366
- return x.union([ x.mirroredY(90), x.mirroredX(90), x.mirroredY(90).mirroredX(90) ]);
1632
+ return assertValidCSG$1(x.union([ x.mirroredY(90), x.mirroredX(90), x.mirroredY(90).mirroredX(90) ]), "mirrored4");
1367
1633
  }
1368
1634
  var flushSide = {
1369
1635
  "above-outside": [ 1, 0 ],
@@ -1424,10 +1690,10 @@ function initJscadutils(_CSG, options = {}) {
1424
1690
  function snap(moveobj, withobj, axis, orientation, delta) {
1425
1691
  debug$2("snap", moveobj, withobj, axis, orientation, delta);
1426
1692
  var t = calcSnap(moveobj, withobj, axis, orientation, delta);
1427
- return moveobj.translate(t);
1693
+ return assertValidCSG$1(moveobj.translate(t), "snap");
1428
1694
  }
1429
1695
  function flush(moveobj, withobj, axis, mside, wside) {
1430
- return moveobj.translate(calcFlush(moveobj, withobj, axis, mside, wside));
1696
+ return assertValidCSG$1(moveobj.translate(calcFlush(moveobj, withobj, axis, mside, wside)), "flush");
1431
1697
  }
1432
1698
  function axisApply(axes, valfun, a) {
1433
1699
  debug$2("axisApply", axes, valfun, a);
@@ -1443,7 +1709,7 @@ function initJscadutils(_CSG, options = {}) {
1443
1709
  return retval;
1444
1710
  }
1445
1711
  function axis2array(axes, valfun) {
1446
- depreciated("axis2array");
1712
+ depreciated("axis2array", false, "Use axisApply instead.");
1447
1713
  var a = [ 0, 0, 0 ];
1448
1714
  var lookup = {
1449
1715
  x: 0,
@@ -1473,7 +1739,7 @@ function initJscadutils(_CSG, options = {}) {
1473
1739
  });
1474
1740
  }
1475
1741
  function midlineTo(o, axis, to) {
1476
- return o.translate(calcmidlineTo(o, axis, to));
1742
+ return assertValidCSG$1(o.translate(calcmidlineTo(o, axis, to)), "midlineTo");
1477
1743
  }
1478
1744
  function translator(o, axis, withObj) {
1479
1745
  var objectCentroid = centroid(o);
@@ -1493,7 +1759,7 @@ function initJscadutils(_CSG, options = {}) {
1493
1759
  return delta ? add(t, delta) : t;
1494
1760
  }
1495
1761
  function centerWith(o, axis, withObj) {
1496
- return o.translate(calcCenterWith(o, axis, withObj));
1762
+ return assertValidCSG$1(o.translate(calcCenterWith(o, axis, withObj)), "centerWith");
1497
1763
  }
1498
1764
  function getDelta(size, bounds, axis, offset, nonzero) {
1499
1765
  if (!isEmpty(offset) && nonzero) {
@@ -1506,6 +1772,95 @@ function initJscadutils(_CSG, options = {}) {
1506
1772
  return bounds[0][a] + (isEmpty(dist) ? size[axis] / 2 : dist);
1507
1773
  });
1508
1774
  }
1775
+ var EPS = 1e-5;
1776
+ function splitCSGByPlane(csg, plane) {
1777
+ var frontPolys = [];
1778
+ var backPolys = [];
1779
+ csg.polygons.forEach(function(poly) {
1780
+ var vertices = poly.vertices;
1781
+ var numVerts = vertices.length;
1782
+ var hasfront = false;
1783
+ var hasback = false;
1784
+ var vertexIsBack = [];
1785
+ for (var i = 0; i < numVerts; i++) {
1786
+ var t = plane.normal.dot(vertices[i].pos) - plane.w;
1787
+ vertexIsBack.push(t < 0);
1788
+ if (t > EPS) hasfront = true;
1789
+ if (t < -EPS) hasback = true;
1790
+ }
1791
+ if (!hasfront && !hasback) {
1792
+ var d = plane.normal.dot(poly.plane.normal);
1793
+ if (d >= 0) {
1794
+ frontPolys.push(poly);
1795
+ } else {
1796
+ backPolys.push(poly);
1797
+ }
1798
+ } else if (!hasback) {
1799
+ frontPolys.push(poly);
1800
+ } else if (!hasfront) {
1801
+ backPolys.push(poly);
1802
+ } else {
1803
+ var fv = [];
1804
+ var bv = [];
1805
+ for (var vi = 0; vi < numVerts; vi++) {
1806
+ var vertex = vertices[vi];
1807
+ var nextVi = (vi + 1) % numVerts;
1808
+ var isback = vertexIsBack[vi];
1809
+ var nextisback = vertexIsBack[nextVi];
1810
+ if (isback === nextisback) {
1811
+ if (isback) {
1812
+ bv.push(vertex);
1813
+ } else {
1814
+ fv.push(vertex);
1815
+ }
1816
+ } else {
1817
+ var point = vertex.pos;
1818
+ var nextpoint = vertices[nextVi].pos;
1819
+ var ip = plane.splitLineBetweenPoints(point, nextpoint);
1820
+ var iv = new CSG$1.Vertex(ip);
1821
+ if (isback) {
1822
+ bv.push(vertex);
1823
+ bv.push(iv);
1824
+ fv.push(iv);
1825
+ } else {
1826
+ fv.push(vertex);
1827
+ fv.push(iv);
1828
+ bv.push(iv);
1829
+ }
1830
+ }
1831
+ }
1832
+ var EPSEPS = EPS * EPS;
1833
+ if (fv.length >= 3) {
1834
+ var prev = fv[fv.length - 1];
1835
+ for (var fi = 0; fi < fv.length; fi++) {
1836
+ var curr = fv[fi];
1837
+ if (curr.pos.distanceToSquared(prev.pos) < EPSEPS) {
1838
+ fv.splice(fi, 1);
1839
+ fi--;
1840
+ }
1841
+ prev = curr;
1842
+ }
1843
+ }
1844
+ if (bv.length >= 3) {
1845
+ var prev = bv[bv.length - 1];
1846
+ for (var bi = 0; bi < bv.length; bi++) {
1847
+ var curr = bv[bi];
1848
+ if (curr.pos.distanceToSquared(prev.pos) < EPSEPS) {
1849
+ bv.splice(bi, 1);
1850
+ bi--;
1851
+ }
1852
+ prev = curr;
1853
+ }
1854
+ }
1855
+ if (fv.length >= 3) frontPolys.push(new CSG$1.Polygon(fv, poly.shared, poly.plane));
1856
+ if (bv.length >= 3) backPolys.push(new CSG$1.Polygon(bv, poly.shared, poly.plane));
1857
+ }
1858
+ });
1859
+ return {
1860
+ front: CSG$1.fromPolygons(frontPolys),
1861
+ back: CSG$1.fromPolygons(backPolys)
1862
+ };
1863
+ }
1509
1864
  function bisect() {
1510
1865
  for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
1511
1866
  args[_key] = arguments[_key];
@@ -1567,13 +1922,13 @@ function initJscadutils(_CSG, options = {}) {
1567
1922
  }[[ axis, rotateaxis ].sort().join("")];
1568
1923
  var centroid = object.centroid();
1569
1924
  var rotateDelta = getDelta(objectSize, bounds, rotateOffsetAxis, rotateoffset);
1570
- var rotationCenter = options.rotationCenter || new CSG.Vector3D(axisApply("xyz", function(i, a) {
1925
+ var rotationCenter = options.rotationCenter || new CSG$1.Vector3D(axisApply("xyz", function(i, a) {
1571
1926
  if (a == axis) return cutDelta[i];
1572
1927
  if (a == rotateOffsetAxis) return rotateDelta[i];
1573
1928
  return centroid[a];
1574
1929
  }));
1575
1930
  var theRotationAxis = rotationAxes[rotateaxis];
1576
- var cutplane = CSG.OrthoNormalBasis.GetCartesian(info.orthoNormalCartesian[0], info.orthoNormalCartesian[1]).translate(cutDelta).rotate(rotationCenter, theRotationAxis, angle);
1931
+ var cutplane = CSG$1.OrthoNormalBasis.GetCartesian(info.orthoNormalCartesian[0], info.orthoNormalCartesian[1]).translate(cutDelta).rotate(rotationCenter, theRotationAxis, angle);
1577
1932
  debug$2("bisect", debug$2.enabled && {
1578
1933
  axis,
1579
1934
  offset,
@@ -1586,7 +1941,26 @@ function initJscadutils(_CSG, options = {}) {
1586
1941
  cutplane,
1587
1942
  options
1588
1943
  });
1589
- var g = Group("negative,positive", [ object.cutByPlane(cutplane.plane).color(options.color && "red"), object.cutByPlane(cutplane.plane.flipped()).color(options.color && "blue") ]);
1944
+ var negative = object.cutByPlane(cutplane.plane);
1945
+ var positive = object.cutByPlane(cutplane.plane.flipped());
1946
+ var negSize = size(negative);
1947
+ var posSize = size(positive);
1948
+ if (negSize[axis] >= objectSize[axis] - EPS || posSize[axis] >= objectSize[axis] - EPS) {
1949
+ var halves = splitCSGByPlane(object, cutplane.plane);
1950
+ if (negSize[axis] >= objectSize[axis] - EPS) {
1951
+ negative = halves.back;
1952
+ try {
1953
+ negative = negative.cutByPlane(cutplane.plane);
1954
+ } catch (e) {}
1955
+ }
1956
+ if (posSize[axis] >= objectSize[axis] - EPS) {
1957
+ positive = halves.front;
1958
+ try {
1959
+ positive = positive.cutByPlane(cutplane.plane.flipped());
1960
+ } catch (e) {}
1961
+ }
1962
+ }
1963
+ var g = Group("negative,positive", [ negative.color(options.color && "red"), positive.color(options.color && "blue") ]);
1590
1964
  if (options.addRotationCenter) g.add(unitAxis(objectSize.length() + 10, .1, rotationCenter), "rotationCenter");
1591
1965
  return g;
1592
1966
  }
@@ -1599,9 +1973,9 @@ function initJscadutils(_CSG, options = {}) {
1599
1973
  addRotationCenter: true
1600
1974
  };
1601
1975
  var info = normalVector(axis);
1602
- var rotationCenter = options.rotationCenter || new CSG.Vector3D(0, 0, 0);
1976
+ var rotationCenter = options.rotationCenter || new CSG$1.Vector3D(0, 0, 0);
1603
1977
  var theRotationAxis = rotationAxes[rotateaxis];
1604
- var cutplane = CSG.OrthoNormalBasis.GetCartesian(info.orthoNormalCartesian[0], info.orthoNormalCartesian[1]).rotate(rotationCenter, theRotationAxis, angle);
1978
+ var cutplane = CSG$1.OrthoNormalBasis.GetCartesian(info.orthoNormalCartesian[0], info.orthoNormalCartesian[1]).rotate(rotationCenter, theRotationAxis, angle);
1605
1979
  var g = Group("negative,positive", [ object.cutByPlane(cutplane.plane).color(options.color && "red"), object.cutByPlane(cutplane.plane.flipped()).color(options.color && "blue") ]);
1606
1980
  if (options.addRotationCenter) {
1607
1981
  var objectSize = size(object);
@@ -1626,14 +2000,14 @@ function initJscadutils(_CSG, options = {}) {
1626
2000
  var bounds = object.getBounds();
1627
2001
  var objectSize = size(object);
1628
2002
  var cutDelta = getDelta(objectSize, bounds, axis, offset, true);
1629
- return object.stretchAtPlane(normal[axis], cutDelta, distance);
2003
+ return assertValidCSG$1(object.stretchAtPlane(normal[axis], cutDelta, distance), "stretch");
1630
2004
  }
1631
2005
  function poly2solid(top, bottom, height) {
1632
2006
  if (top.sides.length == 0) {
1633
- return new CSG;
2007
+ return new CSG$1;
1634
2008
  }
1635
- var offsetVector = CSG.Vector3D.Create(0, 0, height);
1636
- var normalVector = CSG.Vector3D.Create(0, 1, 0);
2009
+ var offsetVector = CSG$1.Vector3D.Create(0, 0, height);
2010
+ var normalVector = CSG$1.Vector3D.Create(0, 1, 0);
1637
2011
  var polygons = [];
1638
2012
  polygons = polygons.concat(bottom._toPlanePolygons({
1639
2013
  translation: [ 0, 0, 0 ],
@@ -1645,14 +2019,14 @@ function initJscadutils(_CSG, options = {}) {
1645
2019
  normalVector,
1646
2020
  flipped: offsetVector.z < 0
1647
2021
  }));
1648
- var c1 = new CSG.Connector(offsetVector.times(0), [ 0, 0, offsetVector.z ], normalVector);
1649
- var c2 = new CSG.Connector(offsetVector, [ 0, 0, offsetVector.z ], normalVector);
2022
+ var c1 = new CSG$1.Connector(offsetVector.times(0), [ 0, 0, offsetVector.z ], normalVector);
2023
+ var c2 = new CSG$1.Connector(offsetVector, [ 0, 0, offsetVector.z ], normalVector);
1650
2024
  polygons = polygons.concat(bottom._toWallPolygons({
1651
2025
  cag: top,
1652
2026
  toConnector1: c1,
1653
2027
  toConnector2: c2
1654
2028
  }));
1655
- return CSG.fromPolygons(polygons);
2029
+ return assertValidCSG$1(CSG$1.fromPolygons(polygons), "poly2solid");
1656
2030
  }
1657
2031
  function slices2poly(slices, options, axis) {
1658
2032
  debug$2("slices2poly", slices, options, axis);
@@ -1661,7 +2035,7 @@ function initJscadutils(_CSG, options = {}) {
1661
2035
  twiststeps: 0
1662
2036
  }, options);
1663
2037
  var twistangle = options && parseFloat(options.twistangle) || 0;
1664
- options && parseInt(options.twiststeps) || CSG.defaultResolution3D;
2038
+ options && parseInt(options.twiststeps) || CSG$1.defaultResolution3D;
1665
2039
  var normalVector = options.si.normalVector;
1666
2040
  var polygons = [];
1667
2041
  var first$1 = first(slices);
@@ -1690,8 +2064,8 @@ function initJscadutils(_CSG, options = {}) {
1690
2064
  var nextidx = idx + 1;
1691
2065
  var top = !up ? slices[nextidx] : slice;
1692
2066
  var bottom = up ? slices[nextidx] : slice;
1693
- var c1 = new CSG.Connector(bottom.offset, connectorAxis, rotate(normalVector, twistangle, idx / slices.length));
1694
- var c2 = new CSG.Connector(top.offset, connectorAxis, rotate(normalVector, twistangle, nextidx / slices.length));
2067
+ var c1 = new CSG$1.Connector(bottom.offset, connectorAxis, rotate(normalVector, twistangle, idx / slices.length));
2068
+ var c2 = new CSG$1.Connector(top.offset, connectorAxis, rotate(normalVector, twistangle, nextidx / slices.length));
1695
2069
  polygons = polygons.concat(bottom.poly._toWallPolygons({
1696
2070
  cag: top.poly,
1697
2071
  toConnector1: c1,
@@ -1699,21 +2073,21 @@ function initJscadutils(_CSG, options = {}) {
1699
2073
  }));
1700
2074
  }
1701
2075
  });
1702
- return CSG.fromPolygons(polygons);
2076
+ return assertValidCSG$1(CSG$1.fromPolygons(polygons), "slices2poly");
1703
2077
  }
1704
2078
  function normalVector(axis) {
1705
2079
  var axisInfo = {
1706
2080
  z: {
1707
2081
  orthoNormalCartesian: [ "X", "Y" ],
1708
- normalVector: CSG.Vector3D.Create(0, 1, 0)
2082
+ normalVector: CSG$1.Vector3D.Create(0, 1, 0)
1709
2083
  },
1710
2084
  x: {
1711
2085
  orthoNormalCartesian: [ "Y", "Z" ],
1712
- normalVector: CSG.Vector3D.Create(0, 0, 1)
2086
+ normalVector: CSG$1.Vector3D.Create(0, 0, 1)
1713
2087
  },
1714
2088
  y: {
1715
- orthoNormalCartesian: [ "X", "Z" ],
1716
- normalVector: CSG.Vector3D.Create(0, 0, 1)
2089
+ orthoNormalCartesian: [ "Z", "X" ],
2090
+ normalVector: CSG$1.Vector3D.Create(0, 0, 1)
1717
2091
  }
1718
2092
  };
1719
2093
  if (!axisInfo[axis]) error("normalVector: invalid axis " + axis);
@@ -1754,7 +2128,7 @@ function initJscadutils(_CSG, options = {}) {
1754
2128
  var si = sliceParams(orientation, radius, b);
1755
2129
  debug$2("reShape", absoluteRadius, si);
1756
2130
  if (si.axis !== "z") throw new Error('reShape error: CAG._toPlanePolygons only uses the "z" axis. You must use the "z" axis for now.');
1757
- var cutplane = CSG.OrthoNormalBasis.GetCartesian(si.orthoNormalCartesian[0], si.orthoNormalCartesian[1]).translate(si.cutDelta);
2131
+ var cutplane = CSG$1.OrthoNormalBasis.GetCartesian(si.orthoNormalCartesian[0], si.orthoNormalCartesian[1]).translate(si.cutDelta);
1758
2132
  var slice = object.sectionCut(cutplane);
1759
2133
  var first = axisApply(si.axis, function() {
1760
2134
  return si.positive ? 0 : absoluteRadius;
@@ -1769,25 +2143,25 @@ function initJscadutils(_CSG, options = {}) {
1769
2143
  si
1770
2144
  }), si.axis).color(options.color);
1771
2145
  var remainder = object.cutByPlane(plane);
1772
- return union([ options.unionOriginal ? object : remainder, delta.translate(si.moveDelta) ]);
2146
+ return assertValidCSG$1(union([ options.unionOriginal ? object : remainder, delta.translate(si.moveDelta) ]), "reShape");
1773
2147
  }
1774
2148
  function chamfer(object, radius, orientation, options) {
1775
- return reShape(object, radius, orientation, options, function(first, last, slice) {
2149
+ return assertValidCSG$1(reShape(object, radius, orientation, options, function(first, last, slice) {
1776
2150
  return [ {
1777
2151
  poly: slice,
1778
- offset: new CSG.Vector3D(first)
2152
+ offset: new CSG$1.Vector3D(first)
1779
2153
  }, {
1780
2154
  poly: enlarge(slice, [ -radius * 2, -radius * 2 ]),
1781
- offset: new CSG.Vector3D(last)
2155
+ offset: new CSG$1.Vector3D(last)
1782
2156
  } ];
1783
- });
2157
+ }), "chamfer");
1784
2158
  }
1785
2159
  function fillet(object, radius, orientation, options) {
1786
2160
  options = options || {};
1787
- return reShape(object, radius, orientation, options, function(first, last, slice) {
1788
- var v1 = new CSG.Vector3D(first);
1789
- var v2 = new CSG.Vector3D(last);
1790
- var res = options.resolution || CSG.defaultResolution3D;
2161
+ return assertValidCSG$1(reShape(object, radius, orientation, options, function(first, last, slice) {
2162
+ var v1 = new CSG$1.Vector3D(first);
2163
+ var v2 = new CSG$1.Vector3D(last);
2164
+ var res = options.resolution || CSG$1.defaultResolution3D;
1791
2165
  var slices = range(0, res).map(function(i) {
1792
2166
  var p = i > 0 ? i / (res - 1) : 0;
1793
2167
  var v = v1.lerp(v2, p);
@@ -1798,7 +2172,7 @@ function initJscadutils(_CSG, options = {}) {
1798
2172
  };
1799
2173
  });
1800
2174
  return slices;
1801
- });
2175
+ }), "fillet");
1802
2176
  }
1803
2177
  function calcRotate(part, solid, axis) {
1804
2178
  var axes = {
@@ -1815,7 +2189,7 @@ function initJscadutils(_CSG, options = {}) {
1815
2189
  }
1816
2190
  function rotateAround(part, solid, axis, angle) {
1817
2191
  var _calcRotate = calcRotate(part, solid, axis), rotationCenter = _calcRotate.rotationCenter, rotationAxis = _calcRotate.rotationAxis;
1818
- return part.rotate(rotationCenter, rotationAxis, angle);
2192
+ return assertValidCSG$1("rotateAround")(part.rotate(rotationCenter, rotationAxis, angle));
1819
2193
  }
1820
2194
  function cloneProperties(from, to) {
1821
2195
  return Object.entries(from).reduce(function(props, _ref) {
@@ -1825,19 +2199,20 @@ function initJscadutils(_CSG, options = {}) {
1825
2199
  }, to);
1826
2200
  }
1827
2201
  function clone(o) {
1828
- var c = CSG.fromPolygons(o.toPolygons());
2202
+ var c = CSG$1.fromPolygons(o.toPolygons());
1829
2203
  cloneProperties(o, c);
1830
- debug$2("clone", o, c, CSG);
1831
- return c;
2204
+ debug$2("clone", o, c, CSG$1);
2205
+ return assertValidCSG$1(c, "clone");
1832
2206
  }
1833
2207
  function addConnector(object, name) {
1834
2208
  var point = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : [ 0, 0, 0 ];
1835
2209
  var axis = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : [ 1, 0, 0 ];
1836
2210
  var normal = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : [ 0, 0, 1 ];
1837
- object.properties[name] = new CSG.Connector(point, axis, normal);
1838
- return object;
2211
+ object.properties[name] = new CSG$1.Connector(point, axis, normal);
2212
+ return assertValidCSG$1("addConnector")(object);
1839
2213
  }
1840
2214
  var debug$1 = Debug("jscadUtils:parts");
2215
+ var assertValidCSG = AssertValidCSG("parts");
1841
2216
  var parts = {
1842
2217
  BBox: BBox$1,
1843
2218
  Cube,
@@ -1847,7 +2222,7 @@ function initJscadutils(_CSG, options = {}) {
1847
2222
  };
1848
2223
  function BBox$1() {
1849
2224
  function box(object) {
1850
- return CSG.cube({
2225
+ return CSG$1.cube({
1851
2226
  center: object.centroid(),
1852
2227
  radius: object.size().dividedBy(2)
1853
2228
  });
@@ -1855,17 +2230,17 @@ function initJscadutils(_CSG, options = {}) {
1855
2230
  for (var _len = arguments.length, objects = new Array(_len), _key = 0; _key < _len; _key++) {
1856
2231
  objects[_key] = arguments[_key];
1857
2232
  }
1858
- return objects.reduce(function(bbox, part) {
2233
+ return assertValidCSG(objects.reduce(function(bbox, part) {
1859
2234
  var object = bbox ? union([ bbox, box(part) ]) : part;
1860
2235
  return box(object);
1861
- }, undefined);
2236
+ }, undefined), "BBox");
1862
2237
  }
1863
2238
  function Cube(width) {
1864
2239
  var r = div$1(fromxyz(width), 2);
1865
- return CSG.cube({
2240
+ return assertValidCSG(CSG$1.cube({
1866
2241
  center: r,
1867
2242
  radius: r
1868
- });
2243
+ }), "Cube");
1869
2244
  }
1870
2245
  function RoundedCube(x, y, thickness, corner_radius) {
1871
2246
  if (x.getBounds) {
@@ -1881,11 +2256,11 @@ function initJscadutils(_CSG, options = {}) {
1881
2256
  center: [ r[0], r[1], 0 ],
1882
2257
  radius: r,
1883
2258
  roundradius: corner_radius,
1884
- resolution: CSG.defaultResolution2D
2259
+ resolution: CSG$1.defaultResolution2D
1885
2260
  }).extrude({
1886
2261
  offset: [ 0, 0, thickness || 1.62 ]
1887
2262
  });
1888
- return roundedcube;
2263
+ return assertValidCSG(roundedcube, "RoundedCube");
1889
2264
  }
1890
2265
  function Cylinder(diameter, height) {
1891
2266
  var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
@@ -1894,39 +2269,39 @@ function initJscadutils(_CSG, options = {}) {
1894
2269
  start: [ 0, 0, 0 ],
1895
2270
  end: [ 0, 0, height ],
1896
2271
  radius: diameter / 2,
1897
- resolution: CSG.defaultResolution2D
2272
+ resolution: CSG$1.defaultResolution2D
1898
2273
  }, options);
1899
- return CSG.cylinder(options);
2274
+ return assertValidCSG(CSG$1.cylinder(options), "Cylinder");
1900
2275
  }
1901
2276
  function Cone(diameter1, diameter2, height) {
1902
2277
  var options = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {};
1903
2278
  debug$1("parts.Cone", diameter1, diameter2, height, options);
1904
- return CSG.cylinder(Object.assign({
2279
+ return assertValidCSG(CSG$1.cylinder(Object.assign({
1905
2280
  start: [ 0, 0, 0 ],
1906
2281
  end: [ 0, 0, height ],
1907
2282
  radiusStart: diameter1 / 2,
1908
2283
  radiusEnd: diameter2 / 2,
1909
- resolution: CSG.defaultResolution2D
1910
- }, options));
2284
+ resolution: CSG$1.defaultResolution2D
2285
+ }, options)), "Cone");
1911
2286
  }
1912
2287
  function Hexagon(diameter, height) {
1913
2288
  debug$1("hexagon", diameter, height);
1914
2289
  var radius = diameter / 2;
1915
2290
  var sqrt3 = Math.sqrt(3) / 2;
1916
2291
  var hex = CAG.fromPoints([ [ radius, 0 ], [ radius / 2, radius * sqrt3 ], [ -radius / 2, radius * sqrt3 ], [ -radius, 0 ], [ -radius / 2, -radius * sqrt3 ], [ radius / 2, -radius * sqrt3 ] ]);
1917
- return hex.extrude({
2292
+ return assertValidCSG(hex.extrude({
1918
2293
  offset: [ 0, 0, height ]
1919
- });
2294
+ }), "Hexagon");
1920
2295
  }
1921
2296
  function Triangle(base, height) {
1922
2297
  var radius = base / 2;
1923
2298
  var tri = CAG.fromPoints([ [ -radius, 0 ], [ radius, 0 ], [ 0, Math.sin(30) * radius ] ]);
1924
- return tri.extrude({
2299
+ return assertValidCSG(tri.extrude({
1925
2300
  offset: [ 0, 0, height ]
1926
- });
2301
+ }), "Triangle");
1927
2302
  }
1928
2303
  function Tube(outsideDiameter, insideDiameter, height, outsideOptions, insideOptions) {
1929
- return Cylinder(outsideDiameter, height, outsideOptions).subtract(Cylinder(insideDiameter, height, insideOptions || outsideOptions));
2304
+ return assertValidCSG(Cylinder(outsideDiameter, height, outsideOptions).subtract(Cylinder(insideDiameter, height, insideOptions || outsideOptions)), "Tube");
1930
2305
  }
1931
2306
  function Anchor() {
1932
2307
  var width = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 10;
@@ -1944,11 +2319,11 @@ function initJscadutils(_CSG, options = {}) {
1944
2319
  center: [ r[0], r[1], 0 ],
1945
2320
  radius: r,
1946
2321
  roundradius: corner_radius,
1947
- resolution: CSG.defaultResolution2D
2322
+ resolution: CSG$1.defaultResolution2D
1948
2323
  }).extrude({
1949
2324
  offset: [ 0, 0, thickness || 1.62 ]
1950
2325
  });
1951
- return board;
2326
+ return assertValidCSG(board, "Board");
1952
2327
  }
1953
2328
  var Hardware = {
1954
2329
  Orientation: {
@@ -2039,6 +2414,10 @@ function initJscadutils(_CSG, options = {}) {
2039
2414
  gap = gap || .25;
2040
2415
  var inside = thickness - gap;
2041
2416
  var outside = -thickness + gap;
2417
+ var boxHeight = box.size().z;
2418
+ if (Math.abs(height) >= boxHeight) {
2419
+ throw new Error("Rabett: height (".concat(height, ") must be less than the object height (").concat(boxHeight, ")"));
2420
+ }
2042
2421
  debug("inside", inside, "outside", outside);
2043
2422
  var group = Group();
2044
2423
  var _box$bisect$parts = box.bisect("z", height, options).parts, top = _box$bisect$parts.positive, lower2_3rd = _box$bisect$parts.negative;
@@ -2109,10 +2488,10 @@ function initJscadutils(_CSG, options = {}) {
2109
2488
  thickness = thickness || 2;
2110
2489
  var s = div$1(xyz2array(size), 2);
2111
2490
  var r = add(s, thickness);
2112
- var box = CSG.cube({
2491
+ var box = CSG$1.cube({
2113
2492
  center: r,
2114
2493
  radius: r
2115
- }).subtract(CSG.cube({
2494
+ }).subtract(CSG$1.cube({
2116
2495
  center: r,
2117
2496
  radius: s
2118
2497
  }));
@@ -2130,7 +2509,7 @@ function initJscadutils(_CSG, options = {}) {
2130
2509
  var BBox = function BBox(o) {
2131
2510
  depreciated("BBox", true, "Use 'parts.BBox' instead");
2132
2511
  var s = div$1(xyz2array(o.size()), 2);
2133
- return CSG.cube({
2512
+ return CSG$1.cube({
2134
2513
  center: s,
2135
2514
  radius: s
2136
2515
  }).align(o, "xyz");
@@ -2142,7 +2521,7 @@ function initJscadutils(_CSG, options = {}) {
2142
2521
  var gap = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : .25;
2143
2522
  var r = add(getRadius(box), -thickness / 2);
2144
2523
  r[2] = thickness / 2;
2145
- var cutter = CSG.cube({
2524
+ var cutter = CSG$1.cube({
2146
2525
  center: r,
2147
2526
  radius: r
2148
2527
  }).align(box, "xy").color("green");