@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.
@@ -55,6 +55,8 @@ function initJscadutils(_CSG, options = {}) {
55
55
  enabled: [],
56
56
  disabled: []
57
57
  });
58
+ var jscadUtilsAssertValidCSGWarnings = options.assertValidCSGWarnings || false;
59
+ var jscadUtilsAssertValidCSG = options.assertValidCSG || false;
58
60
  var jscadUtils = function(exports, jsCadCSG, scadApi) {
59
61
  "use strict";
60
62
  function _interopDefaultLegacy(e) {
@@ -288,6 +290,51 @@ function initJscadutils(_CSG, options = {}) {
288
290
  function _arrayWithHoles(r) {
289
291
  if (Array.isArray(r)) return r;
290
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
+ }
291
338
  function _defineProperty(e, r, t) {
292
339
  return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, {
293
340
  value: t,
@@ -708,6 +755,219 @@ function initJscadutils(_CSG, options = {}) {
708
755
  c[3] = g || 1;
709
756
  return o.setColor(c);
710
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
+ }
711
971
  function init(proto) {
712
972
  if (proto.prototype._jscadutilsinit) return;
713
973
  proto.prototype.color = function(r, g, b, a) {
@@ -801,6 +1061,9 @@ function initJscadutils(_CSG, options = {}) {
801
1061
  proto.prototype.subtractIf = function subtractIf(object, condition) {
802
1062
  return condition ? this.subtract(result(this, object)) : this;
803
1063
  };
1064
+ proto.prototype.validate = function validate(options) {
1065
+ return validateCSG(this, options);
1066
+ };
804
1067
  proto.prototype._translate = proto.prototype.translate;
805
1068
  proto.prototype.translate = function translate() {
806
1069
  if (arguments.length === 1) {
@@ -833,12 +1096,13 @@ function initJscadutils(_CSG, options = {}) {
833
1096
  __proto__: null,
834
1097
  default: init
835
1098
  });
836
- var CSG = jsCadCSG__default["default"].CSG, CAG = jsCadCSG__default["default"].CAG;
1099
+ var CSG$1 = jsCadCSG__default["default"].CSG, CAG = jsCadCSG__default["default"].CAG;
837
1100
  var rectangular_extrude = scadApi__default["default"].extrusions.rectangular_extrude;
838
1101
  var _scadApi$text = scadApi__default["default"].text, vector_text = _scadApi$text.vector_text, vector_char = _scadApi$text.vector_char;
839
1102
  var union = scadApi__default["default"].booleanOps.union;
840
- init(CSG);
1103
+ init(CSG$1);
841
1104
  var debug$3 = Debug("jscadUtils:group");
1105
+ var assertValidCSG$2 = AssertValidCSG("group");
842
1106
  function JsCadUtilsGroup() {
843
1107
  var names = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];
844
1108
  var parts = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
@@ -889,7 +1153,7 @@ function initJscadutils(_CSG, options = {}) {
889
1153
  debug$3("combine mapPick", value, key, object);
890
1154
  return map ? map(value, key, index, object) : identity(value);
891
1155
  }, self.name));
892
- 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");
893
1157
  } catch (err) {
894
1158
  debug$3("combine error", this, pieces, options, err);
895
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");
@@ -930,7 +1194,7 @@ function initJscadutils(_CSG, options = {}) {
930
1194
  });
931
1195
  if (self.holes) {
932
1196
  group.holes = toArray(self.holes).map(function(part) {
933
- return map(CSG.fromPolygons(part.toPolygons()), "holes");
1197
+ return assertValidCSG$2(map(CSG$1.fromPolygons(part.toPolygons()), "holes"), "clone");
934
1198
  });
935
1199
  }
936
1200
  return group;
@@ -949,7 +1213,7 @@ function initJscadutils(_CSG, options = {}) {
949
1213
  var rotationCenter = solid.centroid();
950
1214
  var rotationAxis = axes[axis];
951
1215
  self.map(function(part) {
952
- return part.rotate(rotationCenter, rotationAxis, angle);
1216
+ return assertValidCSG$2(part.rotate(rotationCenter, rotationAxis, angle), "rotate");
953
1217
  });
954
1218
  return self;
955
1219
  };
@@ -962,7 +1226,7 @@ function initJscadutils(_CSG, options = {}) {
962
1226
  var self = this;
963
1227
  var t = calcSnap(self.combine(part), to, axis, orientation, delta);
964
1228
  self.map(function(part) {
965
- return part.translate(t);
1229
+ return assertValidCSG$2(part.translate(t), "snap");
966
1230
  });
967
1231
  return self;
968
1232
  } catch (err) {
@@ -977,7 +1241,7 @@ function initJscadutils(_CSG, options = {}) {
977
1241
  noholes: true
978
1242
  }), axis, to, delta);
979
1243
  self.map(function(part) {
980
- return part.translate(t);
1244
+ return assertValidCSG$2(part.translate(t), "align");
981
1245
  });
982
1246
  return self;
983
1247
  } catch (err) {
@@ -1009,14 +1273,14 @@ function initJscadutils(_CSG, options = {}) {
1009
1273
  var myConnector = connectorName.split(".").reduce(function(a, v) {
1010
1274
  return a[v];
1011
1275
  }, self.parts[partName].properties);
1012
- debug$3("toConnector", to instanceof CSG.Connector);
1276
+ debug$3("toConnector", to instanceof CSG$1.Connector);
1013
1277
  var toConnector = toConnectorName.split(".").reduce(function(a, v) {
1014
1278
  return a[v];
1015
1279
  }, to.properties);
1016
1280
  var matrix = myConnector.getTransformationTo(toConnector, mirror, normalrotation);
1017
1281
  debug$3("connectTo", matrix);
1018
1282
  self.map(function(part) {
1019
- return part.transform(matrix);
1283
+ return assertValidCSG$2(part.transform(matrix), "connectTo");
1020
1284
  });
1021
1285
  return self;
1022
1286
  };
@@ -1027,7 +1291,7 @@ function initJscadutils(_CSG, options = {}) {
1027
1291
  return to - size[a] / 2;
1028
1292
  });
1029
1293
  self.map(function(part) {
1030
- return part.translate(t);
1294
+ return assertValidCSG$2(part.translate(t), "midlineTo");
1031
1295
  });
1032
1296
  return self;
1033
1297
  };
@@ -1036,7 +1300,7 @@ function initJscadutils(_CSG, options = {}) {
1036
1300
  var t = Array.isArray(x) ? x : [ x, y, z ];
1037
1301
  debug$3("translate", t);
1038
1302
  self.map(function(part) {
1039
- return part.translate(t);
1303
+ return assertValidCSG$2(part.translate(t), "translate");
1040
1304
  });
1041
1305
  return self;
1042
1306
  };
@@ -1046,7 +1310,7 @@ function initJscadutils(_CSG, options = {}) {
1046
1310
  if (!map) map = identity;
1047
1311
  var g = Group();
1048
1312
  p.forEach(function(name) {
1049
- 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);
1050
1314
  });
1051
1315
  return g;
1052
1316
  };
@@ -1061,7 +1325,7 @@ function initJscadutils(_CSG, options = {}) {
1061
1325
  debug$3("array error", _this, parts);
1062
1326
  throw error('group::array error "'.concat(name, '" not found.\nthis: ').concat(_this, '\nparts: "').concat(parts, '"\n'), "JSCAD_UTILS_GROUP_ERROR");
1063
1327
  }
1064
- 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"));
1065
1329
  });
1066
1330
  return a;
1067
1331
  };
@@ -1094,7 +1358,7 @@ function initJscadutils(_CSG, options = {}) {
1094
1358
  self.names = names && names.length > 0 && names.split(",") || [];
1095
1359
  if (Array.isArray(objects)) {
1096
1360
  self.parts = zipObject(self.names, objects);
1097
- } else if (objects instanceof CSG) {
1361
+ } else if (objects instanceof CSG$1) {
1098
1362
  self.parts = zipObject(self.names, [ objects ]);
1099
1363
  } else {
1100
1364
  self.parts = objects || {};
@@ -1115,6 +1379,7 @@ function initJscadutils(_CSG, options = {}) {
1115
1379
  return new JsCadUtilsGroup(self.names, self.parts, self.holes);
1116
1380
  }
1117
1381
  var debug$2 = Debug("jscadUtils:util");
1382
+ var assertValidCSG$1 = AssertValidCSG("util");
1118
1383
  var NOZZEL_SIZE = .4;
1119
1384
  var nearest = {
1120
1385
  under: function under(desired) {
@@ -1191,12 +1456,12 @@ function initJscadutils(_CSG, options = {}) {
1191
1456
  h: height || 2
1192
1457
  }));
1193
1458
  });
1194
- return center(union(o));
1459
+ return assertValidCSG$1(center(union(o)), "label");
1195
1460
  }
1196
1461
  function text(text) {
1197
1462
  var l = vector_char(0, 0, text);
1198
1463
  var _char = l.segments.reduce(function(result, segment) {
1199
- var path = new CSG.Path2D(segment);
1464
+ var path = new CSG$1.Path2D(segment);
1200
1465
  var cag = path.expandToCAG(2);
1201
1466
  return result ? result.union(cag) : cag;
1202
1467
  }, undefined);
@@ -1204,17 +1469,17 @@ function initJscadutils(_CSG, options = {}) {
1204
1469
  }
1205
1470
  function unitCube(length, radius) {
1206
1471
  radius = radius || .5;
1207
- return CSG.cube({
1472
+ return assertValidCSG$1(CSG$1.cube({
1208
1473
  center: [ 0, 0, 0 ],
1209
1474
  radius: [ radius, radius, length || .5 ]
1210
- });
1475
+ }), "unitCube");
1211
1476
  }
1212
1477
  function unitAxis(length, radius, centroid) {
1213
1478
  debug$2("unitAxis", length, radius, centroid);
1214
1479
  centroid = centroid || [ 0, 0, 0 ];
1215
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) ]);
1216
- unitaxis.properties.origin = new CSG.Connector([ 0, 0, 0 ], [ 1, 0, 0 ], [ 0, 1, 0 ]);
1217
- 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");
1218
1483
  }
1219
1484
  function toArray(a) {
1220
1485
  return Array.isArray(a) ? a : [ a ];
@@ -1304,15 +1569,15 @@ function initJscadutils(_CSG, options = {}) {
1304
1569
  }
1305
1570
  function center(object, objectSize) {
1306
1571
  objectSize = objectSize || size(object.getBounds());
1307
- return centerY(centerX(object, objectSize), objectSize);
1572
+ return assertValidCSG$1(centerY(centerX(object, objectSize), objectSize), "center");
1308
1573
  }
1309
1574
  function centerY(object, objectSize) {
1310
1575
  objectSize = objectSize || size(object.getBounds());
1311
- return object.translate([ 0, -objectSize.y / 2, 0 ]);
1576
+ return assertValidCSG$1(object.translate([ 0, -objectSize.y / 2, 0 ]), "centerY");
1312
1577
  }
1313
1578
  function centerX(object, objectSize) {
1314
1579
  objectSize = objectSize || size(object.getBounds());
1315
- return object.translate([ -objectSize.x / 2, 0, 0 ]);
1580
+ return assertValidCSG$1(object.translate([ -objectSize.x / 2, 0, 0 ]), "centerX");
1316
1581
  }
1317
1582
  function enlarge(object, x, y, z) {
1318
1583
  var a;
@@ -1330,7 +1595,7 @@ function initJscadutils(_CSG, options = {}) {
1330
1595
  var new_object = object.scale(t);
1331
1596
  var new_centroid = centroid(new_object);
1332
1597
  var delta = new_centroid.minus(objectCentroid).times(-1);
1333
- return new_object.translate(delta);
1598
+ return assertValidCSG$1(new_object.translate(delta), "enlarge");
1334
1599
  }
1335
1600
  function fit(object, x, y, z, keep_aspect_ratio) {
1336
1601
  var a;
@@ -1350,10 +1615,10 @@ function initJscadutils(_CSG, options = {}) {
1350
1615
  }
1351
1616
  var s = [ scale(objectSize.x, x), scale(objectSize.y, y), scale(objectSize.z, z) ];
1352
1617
  var min$1 = min(s);
1353
- return centerWith(object.scale(s.map(function(d, i) {
1618
+ return assertValidCSG$1(centerWith(object.scale(s.map(function(d, i) {
1354
1619
  if (a[i] === 0) return 1;
1355
1620
  return keep_aspect_ratio ? min$1 : d;
1356
- })), "xyz", object);
1621
+ })), "xyz", object), "fit");
1357
1622
  }
1358
1623
  function shift(object, x, y, z) {
1359
1624
  var hsize = this.div(this.size(object.getBounds()), 2);
@@ -1361,10 +1626,10 @@ function initJscadutils(_CSG, options = {}) {
1361
1626
  }
1362
1627
  function zero(object) {
1363
1628
  var bounds = object.getBounds();
1364
- return object.translate([ 0, 0, -bounds[0].z ]);
1629
+ return assertValidCSG$1(object.translate([ 0, 0, -bounds[0].z ]), "zero");
1365
1630
  }
1366
1631
  function mirrored4(x) {
1367
- 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");
1368
1633
  }
1369
1634
  var flushSide = {
1370
1635
  "above-outside": [ 1, 0 ],
@@ -1425,10 +1690,10 @@ function initJscadutils(_CSG, options = {}) {
1425
1690
  function snap(moveobj, withobj, axis, orientation, delta) {
1426
1691
  debug$2("snap", moveobj, withobj, axis, orientation, delta);
1427
1692
  var t = calcSnap(moveobj, withobj, axis, orientation, delta);
1428
- return moveobj.translate(t);
1693
+ return assertValidCSG$1(moveobj.translate(t), "snap");
1429
1694
  }
1430
1695
  function flush(moveobj, withobj, axis, mside, wside) {
1431
- return moveobj.translate(calcFlush(moveobj, withobj, axis, mside, wside));
1696
+ return assertValidCSG$1(moveobj.translate(calcFlush(moveobj, withobj, axis, mside, wside)), "flush");
1432
1697
  }
1433
1698
  function axisApply(axes, valfun, a) {
1434
1699
  debug$2("axisApply", axes, valfun, a);
@@ -1444,7 +1709,7 @@ function initJscadutils(_CSG, options = {}) {
1444
1709
  return retval;
1445
1710
  }
1446
1711
  function axis2array(axes, valfun) {
1447
- depreciated("axis2array");
1712
+ depreciated("axis2array", false, "Use axisApply instead.");
1448
1713
  var a = [ 0, 0, 0 ];
1449
1714
  var lookup = {
1450
1715
  x: 0,
@@ -1474,7 +1739,7 @@ function initJscadutils(_CSG, options = {}) {
1474
1739
  });
1475
1740
  }
1476
1741
  function midlineTo(o, axis, to) {
1477
- return o.translate(calcmidlineTo(o, axis, to));
1742
+ return assertValidCSG$1(o.translate(calcmidlineTo(o, axis, to)), "midlineTo");
1478
1743
  }
1479
1744
  function translator(o, axis, withObj) {
1480
1745
  var objectCentroid = centroid(o);
@@ -1494,7 +1759,7 @@ function initJscadutils(_CSG, options = {}) {
1494
1759
  return delta ? add(t, delta) : t;
1495
1760
  }
1496
1761
  function centerWith(o, axis, withObj) {
1497
- return o.translate(calcCenterWith(o, axis, withObj));
1762
+ return assertValidCSG$1(o.translate(calcCenterWith(o, axis, withObj)), "centerWith");
1498
1763
  }
1499
1764
  function getDelta(size, bounds, axis, offset, nonzero) {
1500
1765
  if (!isEmpty(offset) && nonzero) {
@@ -1507,6 +1772,95 @@ function initJscadutils(_CSG, options = {}) {
1507
1772
  return bounds[0][a] + (isEmpty(dist) ? size[axis] / 2 : dist);
1508
1773
  });
1509
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
+ }
1510
1864
  function bisect() {
1511
1865
  for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
1512
1866
  args[_key] = arguments[_key];
@@ -1568,13 +1922,13 @@ function initJscadutils(_CSG, options = {}) {
1568
1922
  }[[ axis, rotateaxis ].sort().join("")];
1569
1923
  var centroid = object.centroid();
1570
1924
  var rotateDelta = getDelta(objectSize, bounds, rotateOffsetAxis, rotateoffset);
1571
- 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) {
1572
1926
  if (a == axis) return cutDelta[i];
1573
1927
  if (a == rotateOffsetAxis) return rotateDelta[i];
1574
1928
  return centroid[a];
1575
1929
  }));
1576
1930
  var theRotationAxis = rotationAxes[rotateaxis];
1577
- 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);
1578
1932
  debug$2("bisect", debug$2.enabled && {
1579
1933
  axis,
1580
1934
  offset,
@@ -1587,7 +1941,26 @@ function initJscadutils(_CSG, options = {}) {
1587
1941
  cutplane,
1588
1942
  options
1589
1943
  });
1590
- 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") ]);
1591
1964
  if (options.addRotationCenter) g.add(unitAxis(objectSize.length() + 10, .1, rotationCenter), "rotationCenter");
1592
1965
  return g;
1593
1966
  }
@@ -1600,9 +1973,9 @@ function initJscadutils(_CSG, options = {}) {
1600
1973
  addRotationCenter: true
1601
1974
  };
1602
1975
  var info = normalVector(axis);
1603
- var rotationCenter = options.rotationCenter || new CSG.Vector3D(0, 0, 0);
1976
+ var rotationCenter = options.rotationCenter || new CSG$1.Vector3D(0, 0, 0);
1604
1977
  var theRotationAxis = rotationAxes[rotateaxis];
1605
- 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);
1606
1979
  var g = Group("negative,positive", [ object.cutByPlane(cutplane.plane).color(options.color && "red"), object.cutByPlane(cutplane.plane.flipped()).color(options.color && "blue") ]);
1607
1980
  if (options.addRotationCenter) {
1608
1981
  var objectSize = size(object);
@@ -1627,14 +2000,14 @@ function initJscadutils(_CSG, options = {}) {
1627
2000
  var bounds = object.getBounds();
1628
2001
  var objectSize = size(object);
1629
2002
  var cutDelta = getDelta(objectSize, bounds, axis, offset, true);
1630
- return object.stretchAtPlane(normal[axis], cutDelta, distance);
2003
+ return assertValidCSG$1(object.stretchAtPlane(normal[axis], cutDelta, distance), "stretch");
1631
2004
  }
1632
2005
  function poly2solid(top, bottom, height) {
1633
2006
  if (top.sides.length == 0) {
1634
- return new CSG;
2007
+ return new CSG$1;
1635
2008
  }
1636
- var offsetVector = CSG.Vector3D.Create(0, 0, height);
1637
- 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);
1638
2011
  var polygons = [];
1639
2012
  polygons = polygons.concat(bottom._toPlanePolygons({
1640
2013
  translation: [ 0, 0, 0 ],
@@ -1646,14 +2019,14 @@ function initJscadutils(_CSG, options = {}) {
1646
2019
  normalVector,
1647
2020
  flipped: offsetVector.z < 0
1648
2021
  }));
1649
- var c1 = new CSG.Connector(offsetVector.times(0), [ 0, 0, offsetVector.z ], normalVector);
1650
- 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);
1651
2024
  polygons = polygons.concat(bottom._toWallPolygons({
1652
2025
  cag: top,
1653
2026
  toConnector1: c1,
1654
2027
  toConnector2: c2
1655
2028
  }));
1656
- return CSG.fromPolygons(polygons);
2029
+ return assertValidCSG$1(CSG$1.fromPolygons(polygons), "poly2solid");
1657
2030
  }
1658
2031
  function slices2poly(slices, options, axis) {
1659
2032
  debug$2("slices2poly", slices, options, axis);
@@ -1662,7 +2035,7 @@ function initJscadutils(_CSG, options = {}) {
1662
2035
  twiststeps: 0
1663
2036
  }, options);
1664
2037
  var twistangle = options && parseFloat(options.twistangle) || 0;
1665
- options && parseInt(options.twiststeps) || CSG.defaultResolution3D;
2038
+ options && parseInt(options.twiststeps) || CSG$1.defaultResolution3D;
1666
2039
  var normalVector = options.si.normalVector;
1667
2040
  var polygons = [];
1668
2041
  var first$1 = first(slices);
@@ -1691,8 +2064,8 @@ function initJscadutils(_CSG, options = {}) {
1691
2064
  var nextidx = idx + 1;
1692
2065
  var top = !up ? slices[nextidx] : slice;
1693
2066
  var bottom = up ? slices[nextidx] : slice;
1694
- var c1 = new CSG.Connector(bottom.offset, connectorAxis, rotate(normalVector, twistangle, idx / slices.length));
1695
- 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));
1696
2069
  polygons = polygons.concat(bottom.poly._toWallPolygons({
1697
2070
  cag: top.poly,
1698
2071
  toConnector1: c1,
@@ -1700,21 +2073,21 @@ function initJscadutils(_CSG, options = {}) {
1700
2073
  }));
1701
2074
  }
1702
2075
  });
1703
- return CSG.fromPolygons(polygons);
2076
+ return assertValidCSG$1(CSG$1.fromPolygons(polygons), "slices2poly");
1704
2077
  }
1705
2078
  function normalVector(axis) {
1706
2079
  var axisInfo = {
1707
2080
  z: {
1708
2081
  orthoNormalCartesian: [ "X", "Y" ],
1709
- normalVector: CSG.Vector3D.Create(0, 1, 0)
2082
+ normalVector: CSG$1.Vector3D.Create(0, 1, 0)
1710
2083
  },
1711
2084
  x: {
1712
2085
  orthoNormalCartesian: [ "Y", "Z" ],
1713
- normalVector: CSG.Vector3D.Create(0, 0, 1)
2086
+ normalVector: CSG$1.Vector3D.Create(0, 0, 1)
1714
2087
  },
1715
2088
  y: {
1716
- orthoNormalCartesian: [ "X", "Z" ],
1717
- normalVector: CSG.Vector3D.Create(0, 0, 1)
2089
+ orthoNormalCartesian: [ "Z", "X" ],
2090
+ normalVector: CSG$1.Vector3D.Create(0, 0, 1)
1718
2091
  }
1719
2092
  };
1720
2093
  if (!axisInfo[axis]) error("normalVector: invalid axis " + axis);
@@ -1755,7 +2128,7 @@ function initJscadutils(_CSG, options = {}) {
1755
2128
  var si = sliceParams(orientation, radius, b);
1756
2129
  debug$2("reShape", absoluteRadius, si);
1757
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.');
1758
- 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);
1759
2132
  var slice = object.sectionCut(cutplane);
1760
2133
  var first = axisApply(si.axis, function() {
1761
2134
  return si.positive ? 0 : absoluteRadius;
@@ -1770,25 +2143,25 @@ function initJscadutils(_CSG, options = {}) {
1770
2143
  si
1771
2144
  }), si.axis).color(options.color);
1772
2145
  var remainder = object.cutByPlane(plane);
1773
- return union([ options.unionOriginal ? object : remainder, delta.translate(si.moveDelta) ]);
2146
+ return assertValidCSG$1(union([ options.unionOriginal ? object : remainder, delta.translate(si.moveDelta) ]), "reShape");
1774
2147
  }
1775
2148
  function chamfer(object, radius, orientation, options) {
1776
- return reShape(object, radius, orientation, options, function(first, last, slice) {
2149
+ return assertValidCSG$1(reShape(object, radius, orientation, options, function(first, last, slice) {
1777
2150
  return [ {
1778
2151
  poly: slice,
1779
- offset: new CSG.Vector3D(first)
2152
+ offset: new CSG$1.Vector3D(first)
1780
2153
  }, {
1781
2154
  poly: enlarge(slice, [ -radius * 2, -radius * 2 ]),
1782
- offset: new CSG.Vector3D(last)
2155
+ offset: new CSG$1.Vector3D(last)
1783
2156
  } ];
1784
- });
2157
+ }), "chamfer");
1785
2158
  }
1786
2159
  function fillet(object, radius, orientation, options) {
1787
2160
  options = options || {};
1788
- return reShape(object, radius, orientation, options, function(first, last, slice) {
1789
- var v1 = new CSG.Vector3D(first);
1790
- var v2 = new CSG.Vector3D(last);
1791
- 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;
1792
2165
  var slices = range(0, res).map(function(i) {
1793
2166
  var p = i > 0 ? i / (res - 1) : 0;
1794
2167
  var v = v1.lerp(v2, p);
@@ -1799,7 +2172,7 @@ function initJscadutils(_CSG, options = {}) {
1799
2172
  };
1800
2173
  });
1801
2174
  return slices;
1802
- });
2175
+ }), "fillet");
1803
2176
  }
1804
2177
  function calcRotate(part, solid, axis) {
1805
2178
  var axes = {
@@ -1816,7 +2189,7 @@ function initJscadutils(_CSG, options = {}) {
1816
2189
  }
1817
2190
  function rotateAround(part, solid, axis, angle) {
1818
2191
  var _calcRotate = calcRotate(part, solid, axis), rotationCenter = _calcRotate.rotationCenter, rotationAxis = _calcRotate.rotationAxis;
1819
- return part.rotate(rotationCenter, rotationAxis, angle);
2192
+ return assertValidCSG$1("rotateAround")(part.rotate(rotationCenter, rotationAxis, angle));
1820
2193
  }
1821
2194
  function cloneProperties(from, to) {
1822
2195
  return Object.entries(from).reduce(function(props, _ref) {
@@ -1826,19 +2199,20 @@ function initJscadutils(_CSG, options = {}) {
1826
2199
  }, to);
1827
2200
  }
1828
2201
  function clone(o) {
1829
- var c = CSG.fromPolygons(o.toPolygons());
2202
+ var c = CSG$1.fromPolygons(o.toPolygons());
1830
2203
  cloneProperties(o, c);
1831
- debug$2("clone", o, c, CSG);
1832
- return c;
2204
+ debug$2("clone", o, c, CSG$1);
2205
+ return assertValidCSG$1(c, "clone");
1833
2206
  }
1834
2207
  function addConnector(object, name) {
1835
2208
  var point = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : [ 0, 0, 0 ];
1836
2209
  var axis = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : [ 1, 0, 0 ];
1837
2210
  var normal = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : [ 0, 0, 1 ];
1838
- object.properties[name] = new CSG.Connector(point, axis, normal);
1839
- return object;
2211
+ object.properties[name] = new CSG$1.Connector(point, axis, normal);
2212
+ return assertValidCSG$1("addConnector")(object);
1840
2213
  }
1841
2214
  var debug$1 = Debug("jscadUtils:parts");
2215
+ var assertValidCSG = AssertValidCSG("parts");
1842
2216
  var parts = {
1843
2217
  BBox: BBox$1,
1844
2218
  Cube,
@@ -1848,7 +2222,7 @@ function initJscadutils(_CSG, options = {}) {
1848
2222
  };
1849
2223
  function BBox$1() {
1850
2224
  function box(object) {
1851
- return CSG.cube({
2225
+ return CSG$1.cube({
1852
2226
  center: object.centroid(),
1853
2227
  radius: object.size().dividedBy(2)
1854
2228
  });
@@ -1856,17 +2230,17 @@ function initJscadutils(_CSG, options = {}) {
1856
2230
  for (var _len = arguments.length, objects = new Array(_len), _key = 0; _key < _len; _key++) {
1857
2231
  objects[_key] = arguments[_key];
1858
2232
  }
1859
- return objects.reduce(function(bbox, part) {
2233
+ return assertValidCSG(objects.reduce(function(bbox, part) {
1860
2234
  var object = bbox ? union([ bbox, box(part) ]) : part;
1861
2235
  return box(object);
1862
- }, undefined);
2236
+ }, undefined), "BBox");
1863
2237
  }
1864
2238
  function Cube(width) {
1865
2239
  var r = div$1(fromxyz(width), 2);
1866
- return CSG.cube({
2240
+ return assertValidCSG(CSG$1.cube({
1867
2241
  center: r,
1868
2242
  radius: r
1869
- });
2243
+ }), "Cube");
1870
2244
  }
1871
2245
  function RoundedCube(x, y, thickness, corner_radius) {
1872
2246
  if (x.getBounds) {
@@ -1882,11 +2256,11 @@ function initJscadutils(_CSG, options = {}) {
1882
2256
  center: [ r[0], r[1], 0 ],
1883
2257
  radius: r,
1884
2258
  roundradius: corner_radius,
1885
- resolution: CSG.defaultResolution2D
2259
+ resolution: CSG$1.defaultResolution2D
1886
2260
  }).extrude({
1887
2261
  offset: [ 0, 0, thickness || 1.62 ]
1888
2262
  });
1889
- return roundedcube;
2263
+ return assertValidCSG(roundedcube, "RoundedCube");
1890
2264
  }
1891
2265
  function Cylinder(diameter, height) {
1892
2266
  var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
@@ -1895,39 +2269,39 @@ function initJscadutils(_CSG, options = {}) {
1895
2269
  start: [ 0, 0, 0 ],
1896
2270
  end: [ 0, 0, height ],
1897
2271
  radius: diameter / 2,
1898
- resolution: CSG.defaultResolution2D
2272
+ resolution: CSG$1.defaultResolution2D
1899
2273
  }, options);
1900
- return CSG.cylinder(options);
2274
+ return assertValidCSG(CSG$1.cylinder(options), "Cylinder");
1901
2275
  }
1902
2276
  function Cone(diameter1, diameter2, height) {
1903
2277
  var options = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {};
1904
2278
  debug$1("parts.Cone", diameter1, diameter2, height, options);
1905
- return CSG.cylinder(Object.assign({
2279
+ return assertValidCSG(CSG$1.cylinder(Object.assign({
1906
2280
  start: [ 0, 0, 0 ],
1907
2281
  end: [ 0, 0, height ],
1908
2282
  radiusStart: diameter1 / 2,
1909
2283
  radiusEnd: diameter2 / 2,
1910
- resolution: CSG.defaultResolution2D
1911
- }, options));
2284
+ resolution: CSG$1.defaultResolution2D
2285
+ }, options)), "Cone");
1912
2286
  }
1913
2287
  function Hexagon(diameter, height) {
1914
2288
  debug$1("hexagon", diameter, height);
1915
2289
  var radius = diameter / 2;
1916
2290
  var sqrt3 = Math.sqrt(3) / 2;
1917
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 ] ]);
1918
- return hex.extrude({
2292
+ return assertValidCSG(hex.extrude({
1919
2293
  offset: [ 0, 0, height ]
1920
- });
2294
+ }), "Hexagon");
1921
2295
  }
1922
2296
  function Triangle(base, height) {
1923
2297
  var radius = base / 2;
1924
2298
  var tri = CAG.fromPoints([ [ -radius, 0 ], [ radius, 0 ], [ 0, Math.sin(30) * radius ] ]);
1925
- return tri.extrude({
2299
+ return assertValidCSG(tri.extrude({
1926
2300
  offset: [ 0, 0, height ]
1927
- });
2301
+ }), "Triangle");
1928
2302
  }
1929
2303
  function Tube(outsideDiameter, insideDiameter, height, outsideOptions, insideOptions) {
1930
- 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");
1931
2305
  }
1932
2306
  function Anchor() {
1933
2307
  var width = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 10;
@@ -1945,11 +2319,11 @@ function initJscadutils(_CSG, options = {}) {
1945
2319
  center: [ r[0], r[1], 0 ],
1946
2320
  radius: r,
1947
2321
  roundradius: corner_radius,
1948
- resolution: CSG.defaultResolution2D
2322
+ resolution: CSG$1.defaultResolution2D
1949
2323
  }).extrude({
1950
2324
  offset: [ 0, 0, thickness || 1.62 ]
1951
2325
  });
1952
- return board;
2326
+ return assertValidCSG(board, "Board");
1953
2327
  }
1954
2328
  var Hardware = {
1955
2329
  Orientation: {
@@ -2040,6 +2414,10 @@ function initJscadutils(_CSG, options = {}) {
2040
2414
  gap = gap || .25;
2041
2415
  var inside = thickness - gap;
2042
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
+ }
2043
2421
  debug("inside", inside, "outside", outside);
2044
2422
  var group = Group();
2045
2423
  var _box$bisect$parts = box.bisect("z", height, options).parts, top = _box$bisect$parts.positive, lower2_3rd = _box$bisect$parts.negative;
@@ -2110,10 +2488,10 @@ function initJscadutils(_CSG, options = {}) {
2110
2488
  thickness = thickness || 2;
2111
2489
  var s = div$1(xyz2array(size), 2);
2112
2490
  var r = add(s, thickness);
2113
- var box = CSG.cube({
2491
+ var box = CSG$1.cube({
2114
2492
  center: r,
2115
2493
  radius: r
2116
- }).subtract(CSG.cube({
2494
+ }).subtract(CSG$1.cube({
2117
2495
  center: r,
2118
2496
  radius: s
2119
2497
  }));
@@ -2131,7 +2509,7 @@ function initJscadutils(_CSG, options = {}) {
2131
2509
  var BBox = function BBox(o) {
2132
2510
  depreciated("BBox", true, "Use 'parts.BBox' instead");
2133
2511
  var s = div$1(xyz2array(o.size()), 2);
2134
- return CSG.cube({
2512
+ return CSG$1.cube({
2135
2513
  center: s,
2136
2514
  radius: s
2137
2515
  }).align(o, "xyz");
@@ -2143,7 +2521,7 @@ function initJscadutils(_CSG, options = {}) {
2143
2521
  var gap = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : .25;
2144
2522
  var r = add(getRadius(box), -thickness / 2);
2145
2523
  r[2] = thickness / 2;
2146
- var cutter = CSG.cube({
2524
+ var cutter = CSG$1.cube({
2147
2525
  center: r,
2148
2526
  radius: r
2149
2527
  }).align(box, "xy").color("green");