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