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