@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.
@@ -60,6 +60,8 @@ function initJscadutils(_CSG, options = {}) {
60
60
  enabled: [],
61
61
  disabled: []
62
62
  });
63
+ var jscadUtilsAssertValidCSGWarnings = options.assertValidCSGWarnings || false;
64
+ var jscadUtilsAssertValidCSG = options.assertValidCSG || false;
63
65
  var jscadUtils = function(exports, jsCadCSG, scadApi) {
64
66
  "use strict";
65
67
  function _interopDefaultLegacy(e) {
@@ -293,6 +295,51 @@ function initJscadutils(_CSG, options = {}) {
293
295
  function _arrayWithHoles(r) {
294
296
  if (Array.isArray(r)) return r;
295
297
  }
298
+ function _createForOfIteratorHelper(r, e) {
299
+ var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"];
300
+ if (!t) {
301
+ if (Array.isArray(r) || (t = _unsupportedIterableToArray(r)) || e && r && "number" == typeof r.length) {
302
+ t && (r = t);
303
+ var n = 0, F = function() {};
304
+ return {
305
+ s: F,
306
+ n: function() {
307
+ return n >= r.length ? {
308
+ done: !0
309
+ } : {
310
+ done: !1,
311
+ value: r[n++]
312
+ };
313
+ },
314
+ e: function(r) {
315
+ throw r;
316
+ },
317
+ f: F
318
+ };
319
+ }
320
+ throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
321
+ }
322
+ var o, a = !0, u = !1;
323
+ return {
324
+ s: function() {
325
+ t = t.call(r);
326
+ },
327
+ n: function() {
328
+ var r = t.next();
329
+ return a = r.done, r;
330
+ },
331
+ e: function(r) {
332
+ u = !0, o = r;
333
+ },
334
+ f: function() {
335
+ try {
336
+ a || null == t.return || t.return();
337
+ } finally {
338
+ if (u) throw o;
339
+ }
340
+ }
341
+ };
342
+ }
296
343
  function _defineProperty(e, r, t) {
297
344
  return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, {
298
345
  value: t,
@@ -713,6 +760,219 @@ function initJscadutils(_CSG, options = {}) {
713
760
  c[3] = g || 1;
714
761
  return o.setColor(c);
715
762
  }
763
+ function validateCSG(csg, options) {
764
+ var errors = [];
765
+ var warnings = [];
766
+ if (!csg || !csg.polygons || csg.polygons.length === 0) {
767
+ errors.push("Empty mesh: no polygons");
768
+ return {
769
+ ok: false,
770
+ errors,
771
+ warnings
772
+ };
773
+ }
774
+ var opts = _objectSpread2({
775
+ fixTJunctions: true
776
+ }, options);
777
+ if (opts.fixTJunctions && typeof csg.canonicalized === "function") {
778
+ csg = csg.canonicalized();
779
+ if (typeof csg.reTesselated === "function") {
780
+ csg = csg.reTesselated();
781
+ }
782
+ if (typeof csg.fixTJunctions === "function") {
783
+ csg = csg.fixTJunctions();
784
+ }
785
+ }
786
+ var AREA_EPS = 1e-10;
787
+ var KEY_EPS = 1e-5;
788
+ var degenerateCount = 0;
789
+ var invalidVertexCount = 0;
790
+ var _iterator = _createForOfIteratorHelper(csg.polygons), _step;
791
+ try {
792
+ for (_iterator.s(); !(_step = _iterator.n()).done; ) {
793
+ var npoly = _step.value;
794
+ var _iterator4 = _createForOfIteratorHelper(npoly.vertices), _step4;
795
+ try {
796
+ for (_iterator4.s(); !(_step4 = _iterator4.n()).done; ) {
797
+ var nvert = _step4.value;
798
+ var np = nvert.pos;
799
+ 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)) {
800
+ invalidVertexCount++;
801
+ break;
802
+ }
803
+ }
804
+ } catch (err) {
805
+ _iterator4.e(err);
806
+ } finally {
807
+ _iterator4.f();
808
+ }
809
+ }
810
+ } catch (err) {
811
+ _iterator.e(err);
812
+ } finally {
813
+ _iterator.f();
814
+ }
815
+ if (invalidVertexCount > 0) {
816
+ errors.push(invalidVertexCount + " polygon(s) with invalid vertex coordinates (NaN or Infinity)");
817
+ }
818
+ function vtxKey(v) {
819
+ var p = v.pos;
820
+ return Math.round(p.x / KEY_EPS) + "," + Math.round(p.y / KEY_EPS) + "," + Math.round(p.z / KEY_EPS);
821
+ }
822
+ var validPolygons = [];
823
+ var _iterator2 = _createForOfIteratorHelper(csg.polygons), _step2;
824
+ try {
825
+ for (_iterator2.s(); !(_step2 = _iterator2.n()).done; ) {
826
+ var poly = _step2.value;
827
+ var verts = poly.vertices;
828
+ var nv = verts.length;
829
+ if (nv < 3) {
830
+ degenerateCount++;
831
+ continue;
832
+ }
833
+ var hasInvalid = false;
834
+ var _iterator5 = _createForOfIteratorHelper(verts), _step5;
835
+ try {
836
+ for (_iterator5.s(); !(_step5 = _iterator5.n()).done; ) {
837
+ var vert = _step5.value;
838
+ var ip = vert.pos;
839
+ if (!Number.isFinite(ip.x) || !Number.isFinite(ip.y) || !Number.isFinite(ip.z)) {
840
+ hasInvalid = true;
841
+ break;
842
+ }
843
+ }
844
+ } catch (err) {
845
+ _iterator5.e(err);
846
+ } finally {
847
+ _iterator5.f();
848
+ }
849
+ if (hasInvalid) continue;
850
+ var area = 0;
851
+ for (var ai = 0; ai < nv - 2; ai++) {
852
+ area += verts[ai + 1].pos.minus(verts[0].pos).cross(verts[ai + 2].pos.minus(verts[ai + 1].pos)).length();
853
+ }
854
+ area *= .5;
855
+ if (area < AREA_EPS) {
856
+ degenerateCount++;
857
+ continue;
858
+ }
859
+ validPolygons.push(poly);
860
+ }
861
+ } catch (err) {
862
+ _iterator2.e(err);
863
+ } finally {
864
+ _iterator2.f();
865
+ }
866
+ if (degenerateCount > 0) {
867
+ warnings.push(degenerateCount + " degenerate polygon(s) (fewer than 3 vertices or near-zero area)");
868
+ if (opts.fixTJunctions && typeof CSG !== "undefined") {
869
+ var cleaned = CSG.fromPolygons(validPolygons);
870
+ cleaned = cleaned.canonicalized();
871
+ if (typeof cleaned.reTesselated === "function") {
872
+ cleaned = cleaned.reTesselated();
873
+ }
874
+ if (typeof cleaned.fixTJunctions === "function") {
875
+ cleaned = cleaned.fixTJunctions();
876
+ }
877
+ validPolygons = [];
878
+ var _iterator3 = _createForOfIteratorHelper(cleaned.polygons), _step3;
879
+ try {
880
+ for (_iterator3.s(); !(_step3 = _iterator3.n()).done; ) {
881
+ var cpoly = _step3.value;
882
+ var cverts = cpoly.vertices;
883
+ var cnv = cverts.length;
884
+ if (cnv < 3) continue;
885
+ var carea = 0;
886
+ for (var cai = 0; cai < cnv - 2; cai++) {
887
+ carea += cverts[cai + 1].pos.minus(cverts[0].pos).cross(cverts[cai + 2].pos.minus(cverts[cai + 1].pos)).length();
888
+ }
889
+ carea *= .5;
890
+ if (carea < AREA_EPS) continue;
891
+ validPolygons.push(cpoly);
892
+ }
893
+ } catch (err) {
894
+ _iterator3.e(err);
895
+ } finally {
896
+ _iterator3.f();
897
+ }
898
+ }
899
+ }
900
+ var edgeCounts = {};
901
+ for (var _i = 0, _validPolygons = validPolygons; _i < _validPolygons.length; _i++) {
902
+ var vpoly = _validPolygons[_i];
903
+ var vverts = vpoly.vertices;
904
+ var vnv = vverts.length;
905
+ for (var ei = 0; ei < vnv; ei++) {
906
+ var v0 = vverts[ei];
907
+ var v1 = vverts[(ei + 1) % vnv];
908
+ var edgeKey = vtxKey(v0) + "/" + vtxKey(v1);
909
+ edgeCounts[edgeKey] = (edgeCounts[edgeKey] || 0) + 1;
910
+ }
911
+ }
912
+ var unmatchedEdges = 0;
913
+ var nonManifoldEdges = 0;
914
+ var checked = {};
915
+ for (var _i2 = 0, _Object$keys = Object.keys(edgeCounts); _i2 < _Object$keys.length; _i2++) {
916
+ var _edgeKey = _Object$keys[_i2];
917
+ if (checked[_edgeKey]) continue;
918
+ var parts = _edgeKey.split("/");
919
+ var reverseKey = parts[1] + "/" + parts[0];
920
+ var forwardCount = edgeCounts[_edgeKey] || 0;
921
+ var reverseCount = edgeCounts[reverseKey] || 0;
922
+ checked[_edgeKey] = true;
923
+ checked[reverseKey] = true;
924
+ if (forwardCount !== reverseCount) {
925
+ unmatchedEdges += Math.abs(forwardCount - reverseCount);
926
+ }
927
+ if (forwardCount > 1 || reverseCount > 1) {
928
+ nonManifoldEdges++;
929
+ }
930
+ }
931
+ if (unmatchedEdges > 0) {
932
+ errors.push(unmatchedEdges + " unmatched edge(s): mesh is not watertight");
933
+ }
934
+ if (nonManifoldEdges > 0) {
935
+ errors.push(nonManifoldEdges + " non-manifold edge(s): edge shared by more than 2 polygons");
936
+ }
937
+ return {
938
+ ok: errors.length === 0,
939
+ errors,
940
+ warnings
941
+ };
942
+ }
943
+ function _noOp(csg) {
944
+ return csg;
945
+ }
946
+ function _makeAssertFn(warnEnabled) {
947
+ return function _assert(csg) {
948
+ var functionName = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : "unknown";
949
+ var moduleName = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : "unknown";
950
+ if (!csg || csg.polygons === undefined) return csg;
951
+ var result = validateCSG(csg);
952
+ if (!result.ok) {
953
+ throw new Error(moduleName + ":" + functionName + ": " + "invalid CSG: " + result.errors.join(", "));
954
+ }
955
+ if (warnEnabled && result.warnings.length > 0) {
956
+ throw new Error(moduleName + ":" + functionName + ": " + "CSG warnings: " + result.warnings.join(", "));
957
+ }
958
+ return csg;
959
+ };
960
+ }
961
+ var _assertFn = _noOp;
962
+ function _resolveFromGlobals() {
963
+ var enabled = typeof jscadUtilsAssertValidCSG !== "undefined" && !!jscadUtilsAssertValidCSG;
964
+ var warnEnabled = typeof jscadUtilsAssertValidCSGWarnings !== "undefined" && !!jscadUtilsAssertValidCSGWarnings;
965
+ return enabled ? _makeAssertFn(warnEnabled) : _noOp;
966
+ }
967
+ function AssertValidCSG() {
968
+ var moduleName = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : "unknown";
969
+ {
970
+ _assertFn = _resolveFromGlobals();
971
+ }
972
+ return function(csg, name) {
973
+ return _assertFn(csg, name, moduleName);
974
+ };
975
+ }
716
976
  function init(proto) {
717
977
  if (proto.prototype._jscadutilsinit) return;
718
978
  proto.prototype.color = function(r, g, b, a) {
@@ -806,6 +1066,9 @@ function initJscadutils(_CSG, options = {}) {
806
1066
  proto.prototype.subtractIf = function subtractIf(object, condition) {
807
1067
  return condition ? this.subtract(result(this, object)) : this;
808
1068
  };
1069
+ proto.prototype.validate = function validate(options) {
1070
+ return validateCSG(this, options);
1071
+ };
809
1072
  proto.prototype._translate = proto.prototype.translate;
810
1073
  proto.prototype.translate = function translate() {
811
1074
  if (arguments.length === 1) {
@@ -838,12 +1101,13 @@ function initJscadutils(_CSG, options = {}) {
838
1101
  __proto__: null,
839
1102
  default: init
840
1103
  });
841
- var CSG = jsCadCSG__default["default"].CSG, CAG = jsCadCSG__default["default"].CAG;
1104
+ var CSG$1 = jsCadCSG__default["default"].CSG, CAG = jsCadCSG__default["default"].CAG;
842
1105
  var rectangular_extrude = scadApi__default["default"].extrusions.rectangular_extrude;
843
1106
  var _scadApi$text = scadApi__default["default"].text, vector_text = _scadApi$text.vector_text, vector_char = _scadApi$text.vector_char;
844
1107
  var union = scadApi__default["default"].booleanOps.union;
845
- init(CSG);
1108
+ init(CSG$1);
846
1109
  var debug$3 = Debug("jscadUtils:group");
1110
+ var assertValidCSG$2 = AssertValidCSG("group");
847
1111
  function JsCadUtilsGroup() {
848
1112
  var names = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];
849
1113
  var parts = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
@@ -894,7 +1158,7 @@ function initJscadutils(_CSG, options = {}) {
894
1158
  debug$3("combine mapPick", value, key, object);
895
1159
  return map ? map(value, key, index, object) : identity(value);
896
1160
  }, self.name));
897
- return g.subtractIf(self.holes && Array.isArray(self.holes) ? union(self.holes) : self.holes, self.holes && !options.noholes);
1161
+ return assertValidCSG$2(g.subtractIf(self.holes && Array.isArray(self.holes) ? union(self.holes) : self.holes, self.holes && !options.noholes), "combine");
898
1162
  } catch (err) {
899
1163
  debug$3("combine error", this, pieces, options, err);
900
1164
  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");
@@ -935,7 +1199,7 @@ function initJscadutils(_CSG, options = {}) {
935
1199
  });
936
1200
  if (self.holes) {
937
1201
  group.holes = toArray(self.holes).map(function(part) {
938
- return map(CSG.fromPolygons(part.toPolygons()), "holes");
1202
+ return assertValidCSG$2(map(CSG$1.fromPolygons(part.toPolygons()), "holes"), "clone");
939
1203
  });
940
1204
  }
941
1205
  return group;
@@ -954,7 +1218,7 @@ function initJscadutils(_CSG, options = {}) {
954
1218
  var rotationCenter = solid.centroid();
955
1219
  var rotationAxis = axes[axis];
956
1220
  self.map(function(part) {
957
- return part.rotate(rotationCenter, rotationAxis, angle);
1221
+ return assertValidCSG$2(part.rotate(rotationCenter, rotationAxis, angle), "rotate");
958
1222
  });
959
1223
  return self;
960
1224
  };
@@ -967,7 +1231,7 @@ function initJscadutils(_CSG, options = {}) {
967
1231
  var self = this;
968
1232
  var t = calcSnap(self.combine(part), to, axis, orientation, delta);
969
1233
  self.map(function(part) {
970
- return part.translate(t);
1234
+ return assertValidCSG$2(part.translate(t), "snap");
971
1235
  });
972
1236
  return self;
973
1237
  } catch (err) {
@@ -982,7 +1246,7 @@ function initJscadutils(_CSG, options = {}) {
982
1246
  noholes: true
983
1247
  }), axis, to, delta);
984
1248
  self.map(function(part) {
985
- return part.translate(t);
1249
+ return assertValidCSG$2(part.translate(t), "align");
986
1250
  });
987
1251
  return self;
988
1252
  } catch (err) {
@@ -1014,14 +1278,14 @@ function initJscadutils(_CSG, options = {}) {
1014
1278
  var myConnector = connectorName.split(".").reduce(function(a, v) {
1015
1279
  return a[v];
1016
1280
  }, self.parts[partName].properties);
1017
- debug$3("toConnector", to instanceof CSG.Connector);
1281
+ debug$3("toConnector", to instanceof CSG$1.Connector);
1018
1282
  var toConnector = toConnectorName.split(".").reduce(function(a, v) {
1019
1283
  return a[v];
1020
1284
  }, to.properties);
1021
1285
  var matrix = myConnector.getTransformationTo(toConnector, mirror, normalrotation);
1022
1286
  debug$3("connectTo", matrix);
1023
1287
  self.map(function(part) {
1024
- return part.transform(matrix);
1288
+ return assertValidCSG$2(part.transform(matrix), "connectTo");
1025
1289
  });
1026
1290
  return self;
1027
1291
  };
@@ -1032,7 +1296,7 @@ function initJscadutils(_CSG, options = {}) {
1032
1296
  return to - size[a] / 2;
1033
1297
  });
1034
1298
  self.map(function(part) {
1035
- return part.translate(t);
1299
+ return assertValidCSG$2(part.translate(t), "midlineTo");
1036
1300
  });
1037
1301
  return self;
1038
1302
  };
@@ -1041,7 +1305,7 @@ function initJscadutils(_CSG, options = {}) {
1041
1305
  var t = Array.isArray(x) ? x : [ x, y, z ];
1042
1306
  debug$3("translate", t);
1043
1307
  self.map(function(part) {
1044
- return part.translate(t);
1308
+ return assertValidCSG$2(part.translate(t), "translate");
1045
1309
  });
1046
1310
  return self;
1047
1311
  };
@@ -1051,7 +1315,7 @@ function initJscadutils(_CSG, options = {}) {
1051
1315
  if (!map) map = identity;
1052
1316
  var g = Group();
1053
1317
  p.forEach(function(name) {
1054
- g.add(map(CSG.fromPolygons(self.parts[name].toPolygons()), name), name);
1318
+ g.add(assertValidCSG$2(map(CSG$1.fromPolygons(self.parts[name].toPolygons()), name), "pick"), name);
1055
1319
  });
1056
1320
  return g;
1057
1321
  };
@@ -1066,7 +1330,7 @@ function initJscadutils(_CSG, options = {}) {
1066
1330
  debug$3("array error", _this, parts);
1067
1331
  throw error('group::array error "'.concat(name, '" not found.\nthis: ').concat(_this, '\nparts: "').concat(parts, '"\n'), "JSCAD_UTILS_GROUP_ERROR");
1068
1332
  }
1069
- a.push(map(CSG.fromPolygons(self.parts[name].toPolygons()), name));
1333
+ a.push(assertValidCSG$2(map(CSG$1.fromPolygons(self.parts[name].toPolygons()), name), "array"));
1070
1334
  });
1071
1335
  return a;
1072
1336
  };
@@ -1099,7 +1363,7 @@ function initJscadutils(_CSG, options = {}) {
1099
1363
  self.names = names && names.length > 0 && names.split(",") || [];
1100
1364
  if (Array.isArray(objects)) {
1101
1365
  self.parts = zipObject(self.names, objects);
1102
- } else if (objects instanceof CSG) {
1366
+ } else if (objects instanceof CSG$1) {
1103
1367
  self.parts = zipObject(self.names, [ objects ]);
1104
1368
  } else {
1105
1369
  self.parts = objects || {};
@@ -1120,6 +1384,7 @@ function initJscadutils(_CSG, options = {}) {
1120
1384
  return new JsCadUtilsGroup(self.names, self.parts, self.holes);
1121
1385
  }
1122
1386
  var debug$2 = Debug("jscadUtils:util");
1387
+ var assertValidCSG$1 = AssertValidCSG("util");
1123
1388
  var NOZZEL_SIZE = .4;
1124
1389
  var nearest = {
1125
1390
  under: function under(desired) {
@@ -1196,12 +1461,12 @@ function initJscadutils(_CSG, options = {}) {
1196
1461
  h: height || 2
1197
1462
  }));
1198
1463
  });
1199
- return center(union(o));
1464
+ return assertValidCSG$1(center(union(o)), "label");
1200
1465
  }
1201
1466
  function text(text) {
1202
1467
  var l = vector_char(0, 0, text);
1203
1468
  var _char = l.segments.reduce(function(result, segment) {
1204
- var path = new CSG.Path2D(segment);
1469
+ var path = new CSG$1.Path2D(segment);
1205
1470
  var cag = path.expandToCAG(2);
1206
1471
  return result ? result.union(cag) : cag;
1207
1472
  }, undefined);
@@ -1209,17 +1474,17 @@ function initJscadutils(_CSG, options = {}) {
1209
1474
  }
1210
1475
  function unitCube(length, radius) {
1211
1476
  radius = radius || .5;
1212
- return CSG.cube({
1477
+ return assertValidCSG$1(CSG$1.cube({
1213
1478
  center: [ 0, 0, 0 ],
1214
1479
  radius: [ radius, radius, length || .5 ]
1215
- });
1480
+ }), "unitCube");
1216
1481
  }
1217
1482
  function unitAxis(length, radius, centroid) {
1218
1483
  debug$2("unitAxis", length, radius, centroid);
1219
1484
  centroid = centroid || [ 0, 0, 0 ];
1220
1485
  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) ]);
1221
- unitaxis.properties.origin = new CSG.Connector([ 0, 0, 0 ], [ 1, 0, 0 ], [ 0, 1, 0 ]);
1222
- return unitaxis.translate(centroid);
1486
+ unitaxis.properties.origin = new CSG$1.Connector([ 0, 0, 0 ], [ 1, 0, 0 ], [ 0, 1, 0 ]);
1487
+ return assertValidCSG$1(unitaxis.translate(centroid), "unitAxis");
1223
1488
  }
1224
1489
  function toArray(a) {
1225
1490
  return Array.isArray(a) ? a : [ a ];
@@ -1309,15 +1574,15 @@ function initJscadutils(_CSG, options = {}) {
1309
1574
  }
1310
1575
  function center(object, objectSize) {
1311
1576
  objectSize = objectSize || size(object.getBounds());
1312
- return centerY(centerX(object, objectSize), objectSize);
1577
+ return assertValidCSG$1(centerY(centerX(object, objectSize), objectSize), "center");
1313
1578
  }
1314
1579
  function centerY(object, objectSize) {
1315
1580
  objectSize = objectSize || size(object.getBounds());
1316
- return object.translate([ 0, -objectSize.y / 2, 0 ]);
1581
+ return assertValidCSG$1(object.translate([ 0, -objectSize.y / 2, 0 ]), "centerY");
1317
1582
  }
1318
1583
  function centerX(object, objectSize) {
1319
1584
  objectSize = objectSize || size(object.getBounds());
1320
- return object.translate([ -objectSize.x / 2, 0, 0 ]);
1585
+ return assertValidCSG$1(object.translate([ -objectSize.x / 2, 0, 0 ]), "centerX");
1321
1586
  }
1322
1587
  function enlarge(object, x, y, z) {
1323
1588
  var a;
@@ -1335,7 +1600,7 @@ function initJscadutils(_CSG, options = {}) {
1335
1600
  var new_object = object.scale(t);
1336
1601
  var new_centroid = centroid(new_object);
1337
1602
  var delta = new_centroid.minus(objectCentroid).times(-1);
1338
- return new_object.translate(delta);
1603
+ return assertValidCSG$1(new_object.translate(delta), "enlarge");
1339
1604
  }
1340
1605
  function fit(object, x, y, z, keep_aspect_ratio) {
1341
1606
  var a;
@@ -1355,10 +1620,10 @@ function initJscadutils(_CSG, options = {}) {
1355
1620
  }
1356
1621
  var s = [ scale(objectSize.x, x), scale(objectSize.y, y), scale(objectSize.z, z) ];
1357
1622
  var min$1 = min(s);
1358
- return centerWith(object.scale(s.map(function(d, i) {
1623
+ return assertValidCSG$1(centerWith(object.scale(s.map(function(d, i) {
1359
1624
  if (a[i] === 0) return 1;
1360
1625
  return keep_aspect_ratio ? min$1 : d;
1361
- })), "xyz", object);
1626
+ })), "xyz", object), "fit");
1362
1627
  }
1363
1628
  function shift(object, x, y, z) {
1364
1629
  var hsize = this.div(this.size(object.getBounds()), 2);
@@ -1366,10 +1631,10 @@ function initJscadutils(_CSG, options = {}) {
1366
1631
  }
1367
1632
  function zero(object) {
1368
1633
  var bounds = object.getBounds();
1369
- return object.translate([ 0, 0, -bounds[0].z ]);
1634
+ return assertValidCSG$1(object.translate([ 0, 0, -bounds[0].z ]), "zero");
1370
1635
  }
1371
1636
  function mirrored4(x) {
1372
- return x.union([ x.mirroredY(90), x.mirroredX(90), x.mirroredY(90).mirroredX(90) ]);
1637
+ return assertValidCSG$1(x.union([ x.mirroredY(90), x.mirroredX(90), x.mirroredY(90).mirroredX(90) ]), "mirrored4");
1373
1638
  }
1374
1639
  var flushSide = {
1375
1640
  "above-outside": [ 1, 0 ],
@@ -1430,10 +1695,10 @@ function initJscadutils(_CSG, options = {}) {
1430
1695
  function snap(moveobj, withobj, axis, orientation, delta) {
1431
1696
  debug$2("snap", moveobj, withobj, axis, orientation, delta);
1432
1697
  var t = calcSnap(moveobj, withobj, axis, orientation, delta);
1433
- return moveobj.translate(t);
1698
+ return assertValidCSG$1(moveobj.translate(t), "snap");
1434
1699
  }
1435
1700
  function flush(moveobj, withobj, axis, mside, wside) {
1436
- return moveobj.translate(calcFlush(moveobj, withobj, axis, mside, wside));
1701
+ return assertValidCSG$1(moveobj.translate(calcFlush(moveobj, withobj, axis, mside, wside)), "flush");
1437
1702
  }
1438
1703
  function axisApply(axes, valfun, a) {
1439
1704
  debug$2("axisApply", axes, valfun, a);
@@ -1449,7 +1714,7 @@ function initJscadutils(_CSG, options = {}) {
1449
1714
  return retval;
1450
1715
  }
1451
1716
  function axis2array(axes, valfun) {
1452
- depreciated("axis2array");
1717
+ depreciated("axis2array", false, "Use axisApply instead.");
1453
1718
  var a = [ 0, 0, 0 ];
1454
1719
  var lookup = {
1455
1720
  x: 0,
@@ -1479,7 +1744,7 @@ function initJscadutils(_CSG, options = {}) {
1479
1744
  });
1480
1745
  }
1481
1746
  function midlineTo(o, axis, to) {
1482
- return o.translate(calcmidlineTo(o, axis, to));
1747
+ return assertValidCSG$1(o.translate(calcmidlineTo(o, axis, to)), "midlineTo");
1483
1748
  }
1484
1749
  function translator(o, axis, withObj) {
1485
1750
  var objectCentroid = centroid(o);
@@ -1499,7 +1764,7 @@ function initJscadutils(_CSG, options = {}) {
1499
1764
  return delta ? add(t, delta) : t;
1500
1765
  }
1501
1766
  function centerWith(o, axis, withObj) {
1502
- return o.translate(calcCenterWith(o, axis, withObj));
1767
+ return assertValidCSG$1(o.translate(calcCenterWith(o, axis, withObj)), "centerWith");
1503
1768
  }
1504
1769
  function getDelta(size, bounds, axis, offset, nonzero) {
1505
1770
  if (!isEmpty(offset) && nonzero) {
@@ -1512,6 +1777,95 @@ function initJscadutils(_CSG, options = {}) {
1512
1777
  return bounds[0][a] + (isEmpty(dist) ? size[axis] / 2 : dist);
1513
1778
  });
1514
1779
  }
1780
+ var EPS = 1e-5;
1781
+ function splitCSGByPlane(csg, plane) {
1782
+ var frontPolys = [];
1783
+ var backPolys = [];
1784
+ csg.polygons.forEach(function(poly) {
1785
+ var vertices = poly.vertices;
1786
+ var numVerts = vertices.length;
1787
+ var hasfront = false;
1788
+ var hasback = false;
1789
+ var vertexIsBack = [];
1790
+ for (var i = 0; i < numVerts; i++) {
1791
+ var t = plane.normal.dot(vertices[i].pos) - plane.w;
1792
+ vertexIsBack.push(t < 0);
1793
+ if (t > EPS) hasfront = true;
1794
+ if (t < -EPS) hasback = true;
1795
+ }
1796
+ if (!hasfront && !hasback) {
1797
+ var d = plane.normal.dot(poly.plane.normal);
1798
+ if (d >= 0) {
1799
+ frontPolys.push(poly);
1800
+ } else {
1801
+ backPolys.push(poly);
1802
+ }
1803
+ } else if (!hasback) {
1804
+ frontPolys.push(poly);
1805
+ } else if (!hasfront) {
1806
+ backPolys.push(poly);
1807
+ } else {
1808
+ var fv = [];
1809
+ var bv = [];
1810
+ for (var vi = 0; vi < numVerts; vi++) {
1811
+ var vertex = vertices[vi];
1812
+ var nextVi = (vi + 1) % numVerts;
1813
+ var isback = vertexIsBack[vi];
1814
+ var nextisback = vertexIsBack[nextVi];
1815
+ if (isback === nextisback) {
1816
+ if (isback) {
1817
+ bv.push(vertex);
1818
+ } else {
1819
+ fv.push(vertex);
1820
+ }
1821
+ } else {
1822
+ var point = vertex.pos;
1823
+ var nextpoint = vertices[nextVi].pos;
1824
+ var ip = plane.splitLineBetweenPoints(point, nextpoint);
1825
+ var iv = new CSG$1.Vertex(ip);
1826
+ if (isback) {
1827
+ bv.push(vertex);
1828
+ bv.push(iv);
1829
+ fv.push(iv);
1830
+ } else {
1831
+ fv.push(vertex);
1832
+ fv.push(iv);
1833
+ bv.push(iv);
1834
+ }
1835
+ }
1836
+ }
1837
+ var EPSEPS = EPS * EPS;
1838
+ if (fv.length >= 3) {
1839
+ var prev = fv[fv.length - 1];
1840
+ for (var fi = 0; fi < fv.length; fi++) {
1841
+ var curr = fv[fi];
1842
+ if (curr.pos.distanceToSquared(prev.pos) < EPSEPS) {
1843
+ fv.splice(fi, 1);
1844
+ fi--;
1845
+ }
1846
+ prev = curr;
1847
+ }
1848
+ }
1849
+ if (bv.length >= 3) {
1850
+ var prev = bv[bv.length - 1];
1851
+ for (var bi = 0; bi < bv.length; bi++) {
1852
+ var curr = bv[bi];
1853
+ if (curr.pos.distanceToSquared(prev.pos) < EPSEPS) {
1854
+ bv.splice(bi, 1);
1855
+ bi--;
1856
+ }
1857
+ prev = curr;
1858
+ }
1859
+ }
1860
+ if (fv.length >= 3) frontPolys.push(new CSG$1.Polygon(fv, poly.shared, poly.plane));
1861
+ if (bv.length >= 3) backPolys.push(new CSG$1.Polygon(bv, poly.shared, poly.plane));
1862
+ }
1863
+ });
1864
+ return {
1865
+ front: CSG$1.fromPolygons(frontPolys),
1866
+ back: CSG$1.fromPolygons(backPolys)
1867
+ };
1868
+ }
1515
1869
  function bisect() {
1516
1870
  for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
1517
1871
  args[_key] = arguments[_key];
@@ -1573,13 +1927,13 @@ function initJscadutils(_CSG, options = {}) {
1573
1927
  }[[ axis, rotateaxis ].sort().join("")];
1574
1928
  var centroid = object.centroid();
1575
1929
  var rotateDelta = getDelta(objectSize, bounds, rotateOffsetAxis, rotateoffset);
1576
- var rotationCenter = options.rotationCenter || new CSG.Vector3D(axisApply("xyz", function(i, a) {
1930
+ var rotationCenter = options.rotationCenter || new CSG$1.Vector3D(axisApply("xyz", function(i, a) {
1577
1931
  if (a == axis) return cutDelta[i];
1578
1932
  if (a == rotateOffsetAxis) return rotateDelta[i];
1579
1933
  return centroid[a];
1580
1934
  }));
1581
1935
  var theRotationAxis = rotationAxes[rotateaxis];
1582
- var cutplane = CSG.OrthoNormalBasis.GetCartesian(info.orthoNormalCartesian[0], info.orthoNormalCartesian[1]).translate(cutDelta).rotate(rotationCenter, theRotationAxis, angle);
1936
+ var cutplane = CSG$1.OrthoNormalBasis.GetCartesian(info.orthoNormalCartesian[0], info.orthoNormalCartesian[1]).translate(cutDelta).rotate(rotationCenter, theRotationAxis, angle);
1583
1937
  debug$2("bisect", debug$2.enabled && {
1584
1938
  axis,
1585
1939
  offset,
@@ -1592,7 +1946,26 @@ function initJscadutils(_CSG, options = {}) {
1592
1946
  cutplane,
1593
1947
  options
1594
1948
  });
1595
- var g = Group("negative,positive", [ object.cutByPlane(cutplane.plane).color(options.color && "red"), object.cutByPlane(cutplane.plane.flipped()).color(options.color && "blue") ]);
1949
+ var negative = object.cutByPlane(cutplane.plane);
1950
+ var positive = object.cutByPlane(cutplane.plane.flipped());
1951
+ var negSize = size(negative);
1952
+ var posSize = size(positive);
1953
+ if (negSize[axis] >= objectSize[axis] - EPS || posSize[axis] >= objectSize[axis] - EPS) {
1954
+ var halves = splitCSGByPlane(object, cutplane.plane);
1955
+ if (negSize[axis] >= objectSize[axis] - EPS) {
1956
+ negative = halves.back;
1957
+ try {
1958
+ negative = negative.cutByPlane(cutplane.plane);
1959
+ } catch (e) {}
1960
+ }
1961
+ if (posSize[axis] >= objectSize[axis] - EPS) {
1962
+ positive = halves.front;
1963
+ try {
1964
+ positive = positive.cutByPlane(cutplane.plane.flipped());
1965
+ } catch (e) {}
1966
+ }
1967
+ }
1968
+ var g = Group("negative,positive", [ negative.color(options.color && "red"), positive.color(options.color && "blue") ]);
1596
1969
  if (options.addRotationCenter) g.add(unitAxis(objectSize.length() + 10, .1, rotationCenter), "rotationCenter");
1597
1970
  return g;
1598
1971
  }
@@ -1605,9 +1978,9 @@ function initJscadutils(_CSG, options = {}) {
1605
1978
  addRotationCenter: true
1606
1979
  };
1607
1980
  var info = normalVector(axis);
1608
- var rotationCenter = options.rotationCenter || new CSG.Vector3D(0, 0, 0);
1981
+ var rotationCenter = options.rotationCenter || new CSG$1.Vector3D(0, 0, 0);
1609
1982
  var theRotationAxis = rotationAxes[rotateaxis];
1610
- var cutplane = CSG.OrthoNormalBasis.GetCartesian(info.orthoNormalCartesian[0], info.orthoNormalCartesian[1]).rotate(rotationCenter, theRotationAxis, angle);
1983
+ var cutplane = CSG$1.OrthoNormalBasis.GetCartesian(info.orthoNormalCartesian[0], info.orthoNormalCartesian[1]).rotate(rotationCenter, theRotationAxis, angle);
1611
1984
  var g = Group("negative,positive", [ object.cutByPlane(cutplane.plane).color(options.color && "red"), object.cutByPlane(cutplane.plane.flipped()).color(options.color && "blue") ]);
1612
1985
  if (options.addRotationCenter) {
1613
1986
  var objectSize = size(object);
@@ -1632,14 +2005,14 @@ function initJscadutils(_CSG, options = {}) {
1632
2005
  var bounds = object.getBounds();
1633
2006
  var objectSize = size(object);
1634
2007
  var cutDelta = getDelta(objectSize, bounds, axis, offset, true);
1635
- return object.stretchAtPlane(normal[axis], cutDelta, distance);
2008
+ return assertValidCSG$1(object.stretchAtPlane(normal[axis], cutDelta, distance), "stretch");
1636
2009
  }
1637
2010
  function poly2solid(top, bottom, height) {
1638
2011
  if (top.sides.length == 0) {
1639
- return new CSG;
2012
+ return new CSG$1;
1640
2013
  }
1641
- var offsetVector = CSG.Vector3D.Create(0, 0, height);
1642
- var normalVector = CSG.Vector3D.Create(0, 1, 0);
2014
+ var offsetVector = CSG$1.Vector3D.Create(0, 0, height);
2015
+ var normalVector = CSG$1.Vector3D.Create(0, 1, 0);
1643
2016
  var polygons = [];
1644
2017
  polygons = polygons.concat(bottom._toPlanePolygons({
1645
2018
  translation: [ 0, 0, 0 ],
@@ -1651,14 +2024,14 @@ function initJscadutils(_CSG, options = {}) {
1651
2024
  normalVector,
1652
2025
  flipped: offsetVector.z < 0
1653
2026
  }));
1654
- var c1 = new CSG.Connector(offsetVector.times(0), [ 0, 0, offsetVector.z ], normalVector);
1655
- var c2 = new CSG.Connector(offsetVector, [ 0, 0, offsetVector.z ], normalVector);
2027
+ var c1 = new CSG$1.Connector(offsetVector.times(0), [ 0, 0, offsetVector.z ], normalVector);
2028
+ var c2 = new CSG$1.Connector(offsetVector, [ 0, 0, offsetVector.z ], normalVector);
1656
2029
  polygons = polygons.concat(bottom._toWallPolygons({
1657
2030
  cag: top,
1658
2031
  toConnector1: c1,
1659
2032
  toConnector2: c2
1660
2033
  }));
1661
- return CSG.fromPolygons(polygons);
2034
+ return assertValidCSG$1(CSG$1.fromPolygons(polygons), "poly2solid");
1662
2035
  }
1663
2036
  function slices2poly(slices, options, axis) {
1664
2037
  debug$2("slices2poly", slices, options, axis);
@@ -1667,7 +2040,7 @@ function initJscadutils(_CSG, options = {}) {
1667
2040
  twiststeps: 0
1668
2041
  }, options);
1669
2042
  var twistangle = options && parseFloat(options.twistangle) || 0;
1670
- options && parseInt(options.twiststeps) || CSG.defaultResolution3D;
2043
+ options && parseInt(options.twiststeps) || CSG$1.defaultResolution3D;
1671
2044
  var normalVector = options.si.normalVector;
1672
2045
  var polygons = [];
1673
2046
  var first$1 = first(slices);
@@ -1696,8 +2069,8 @@ function initJscadutils(_CSG, options = {}) {
1696
2069
  var nextidx = idx + 1;
1697
2070
  var top = !up ? slices[nextidx] : slice;
1698
2071
  var bottom = up ? slices[nextidx] : slice;
1699
- var c1 = new CSG.Connector(bottom.offset, connectorAxis, rotate(normalVector, twistangle, idx / slices.length));
1700
- var c2 = new CSG.Connector(top.offset, connectorAxis, rotate(normalVector, twistangle, nextidx / slices.length));
2072
+ var c1 = new CSG$1.Connector(bottom.offset, connectorAxis, rotate(normalVector, twistangle, idx / slices.length));
2073
+ var c2 = new CSG$1.Connector(top.offset, connectorAxis, rotate(normalVector, twistangle, nextidx / slices.length));
1701
2074
  polygons = polygons.concat(bottom.poly._toWallPolygons({
1702
2075
  cag: top.poly,
1703
2076
  toConnector1: c1,
@@ -1705,21 +2078,21 @@ function initJscadutils(_CSG, options = {}) {
1705
2078
  }));
1706
2079
  }
1707
2080
  });
1708
- return CSG.fromPolygons(polygons);
2081
+ return assertValidCSG$1(CSG$1.fromPolygons(polygons), "slices2poly");
1709
2082
  }
1710
2083
  function normalVector(axis) {
1711
2084
  var axisInfo = {
1712
2085
  z: {
1713
2086
  orthoNormalCartesian: [ "X", "Y" ],
1714
- normalVector: CSG.Vector3D.Create(0, 1, 0)
2087
+ normalVector: CSG$1.Vector3D.Create(0, 1, 0)
1715
2088
  },
1716
2089
  x: {
1717
2090
  orthoNormalCartesian: [ "Y", "Z" ],
1718
- normalVector: CSG.Vector3D.Create(0, 0, 1)
2091
+ normalVector: CSG$1.Vector3D.Create(0, 0, 1)
1719
2092
  },
1720
2093
  y: {
1721
- orthoNormalCartesian: [ "X", "Z" ],
1722
- normalVector: CSG.Vector3D.Create(0, 0, 1)
2094
+ orthoNormalCartesian: [ "Z", "X" ],
2095
+ normalVector: CSG$1.Vector3D.Create(0, 0, 1)
1723
2096
  }
1724
2097
  };
1725
2098
  if (!axisInfo[axis]) error("normalVector: invalid axis " + axis);
@@ -1760,7 +2133,7 @@ function initJscadutils(_CSG, options = {}) {
1760
2133
  var si = sliceParams(orientation, radius, b);
1761
2134
  debug$2("reShape", absoluteRadius, si);
1762
2135
  if (si.axis !== "z") throw new Error('reShape error: CAG._toPlanePolygons only uses the "z" axis. You must use the "z" axis for now.');
1763
- var cutplane = CSG.OrthoNormalBasis.GetCartesian(si.orthoNormalCartesian[0], si.orthoNormalCartesian[1]).translate(si.cutDelta);
2136
+ var cutplane = CSG$1.OrthoNormalBasis.GetCartesian(si.orthoNormalCartesian[0], si.orthoNormalCartesian[1]).translate(si.cutDelta);
1764
2137
  var slice = object.sectionCut(cutplane);
1765
2138
  var first = axisApply(si.axis, function() {
1766
2139
  return si.positive ? 0 : absoluteRadius;
@@ -1775,25 +2148,25 @@ function initJscadutils(_CSG, options = {}) {
1775
2148
  si
1776
2149
  }), si.axis).color(options.color);
1777
2150
  var remainder = object.cutByPlane(plane);
1778
- return union([ options.unionOriginal ? object : remainder, delta.translate(si.moveDelta) ]);
2151
+ return assertValidCSG$1(union([ options.unionOriginal ? object : remainder, delta.translate(si.moveDelta) ]), "reShape");
1779
2152
  }
1780
2153
  function chamfer(object, radius, orientation, options) {
1781
- return reShape(object, radius, orientation, options, function(first, last, slice) {
2154
+ return assertValidCSG$1(reShape(object, radius, orientation, options, function(first, last, slice) {
1782
2155
  return [ {
1783
2156
  poly: slice,
1784
- offset: new CSG.Vector3D(first)
2157
+ offset: new CSG$1.Vector3D(first)
1785
2158
  }, {
1786
2159
  poly: enlarge(slice, [ -radius * 2, -radius * 2 ]),
1787
- offset: new CSG.Vector3D(last)
2160
+ offset: new CSG$1.Vector3D(last)
1788
2161
  } ];
1789
- });
2162
+ }), "chamfer");
1790
2163
  }
1791
2164
  function fillet(object, radius, orientation, options) {
1792
2165
  options = options || {};
1793
- return reShape(object, radius, orientation, options, function(first, last, slice) {
1794
- var v1 = new CSG.Vector3D(first);
1795
- var v2 = new CSG.Vector3D(last);
1796
- var res = options.resolution || CSG.defaultResolution3D;
2166
+ return assertValidCSG$1(reShape(object, radius, orientation, options, function(first, last, slice) {
2167
+ var v1 = new CSG$1.Vector3D(first);
2168
+ var v2 = new CSG$1.Vector3D(last);
2169
+ var res = options.resolution || CSG$1.defaultResolution3D;
1797
2170
  var slices = range(0, res).map(function(i) {
1798
2171
  var p = i > 0 ? i / (res - 1) : 0;
1799
2172
  var v = v1.lerp(v2, p);
@@ -1804,7 +2177,7 @@ function initJscadutils(_CSG, options = {}) {
1804
2177
  };
1805
2178
  });
1806
2179
  return slices;
1807
- });
2180
+ }), "fillet");
1808
2181
  }
1809
2182
  function calcRotate(part, solid, axis) {
1810
2183
  var axes = {
@@ -1821,7 +2194,7 @@ function initJscadutils(_CSG, options = {}) {
1821
2194
  }
1822
2195
  function rotateAround(part, solid, axis, angle) {
1823
2196
  var _calcRotate = calcRotate(part, solid, axis), rotationCenter = _calcRotate.rotationCenter, rotationAxis = _calcRotate.rotationAxis;
1824
- return part.rotate(rotationCenter, rotationAxis, angle);
2197
+ return assertValidCSG$1("rotateAround")(part.rotate(rotationCenter, rotationAxis, angle));
1825
2198
  }
1826
2199
  function cloneProperties(from, to) {
1827
2200
  return Object.entries(from).reduce(function(props, _ref) {
@@ -1831,19 +2204,20 @@ function initJscadutils(_CSG, options = {}) {
1831
2204
  }, to);
1832
2205
  }
1833
2206
  function clone(o) {
1834
- var c = CSG.fromPolygons(o.toPolygons());
2207
+ var c = CSG$1.fromPolygons(o.toPolygons());
1835
2208
  cloneProperties(o, c);
1836
- debug$2("clone", o, c, CSG);
1837
- return c;
2209
+ debug$2("clone", o, c, CSG$1);
2210
+ return assertValidCSG$1(c, "clone");
1838
2211
  }
1839
2212
  function addConnector(object, name) {
1840
2213
  var point = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : [ 0, 0, 0 ];
1841
2214
  var axis = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : [ 1, 0, 0 ];
1842
2215
  var normal = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : [ 0, 0, 1 ];
1843
- object.properties[name] = new CSG.Connector(point, axis, normal);
1844
- return object;
2216
+ object.properties[name] = new CSG$1.Connector(point, axis, normal);
2217
+ return assertValidCSG$1("addConnector")(object);
1845
2218
  }
1846
2219
  var debug$1 = Debug("jscadUtils:parts");
2220
+ var assertValidCSG = AssertValidCSG("parts");
1847
2221
  var parts = {
1848
2222
  BBox: BBox$1,
1849
2223
  Cube,
@@ -1853,7 +2227,7 @@ function initJscadutils(_CSG, options = {}) {
1853
2227
  };
1854
2228
  function BBox$1() {
1855
2229
  function box(object) {
1856
- return CSG.cube({
2230
+ return CSG$1.cube({
1857
2231
  center: object.centroid(),
1858
2232
  radius: object.size().dividedBy(2)
1859
2233
  });
@@ -1861,17 +2235,17 @@ function initJscadutils(_CSG, options = {}) {
1861
2235
  for (var _len = arguments.length, objects = new Array(_len), _key = 0; _key < _len; _key++) {
1862
2236
  objects[_key] = arguments[_key];
1863
2237
  }
1864
- return objects.reduce(function(bbox, part) {
2238
+ return assertValidCSG(objects.reduce(function(bbox, part) {
1865
2239
  var object = bbox ? union([ bbox, box(part) ]) : part;
1866
2240
  return box(object);
1867
- }, undefined);
2241
+ }, undefined), "BBox");
1868
2242
  }
1869
2243
  function Cube(width) {
1870
2244
  var r = div$1(fromxyz(width), 2);
1871
- return CSG.cube({
2245
+ return assertValidCSG(CSG$1.cube({
1872
2246
  center: r,
1873
2247
  radius: r
1874
- });
2248
+ }), "Cube");
1875
2249
  }
1876
2250
  function RoundedCube(x, y, thickness, corner_radius) {
1877
2251
  if (x.getBounds) {
@@ -1887,11 +2261,11 @@ function initJscadutils(_CSG, options = {}) {
1887
2261
  center: [ r[0], r[1], 0 ],
1888
2262
  radius: r,
1889
2263
  roundradius: corner_radius,
1890
- resolution: CSG.defaultResolution2D
2264
+ resolution: CSG$1.defaultResolution2D
1891
2265
  }).extrude({
1892
2266
  offset: [ 0, 0, thickness || 1.62 ]
1893
2267
  });
1894
- return roundedcube;
2268
+ return assertValidCSG(roundedcube, "RoundedCube");
1895
2269
  }
1896
2270
  function Cylinder(diameter, height) {
1897
2271
  var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
@@ -1900,39 +2274,39 @@ function initJscadutils(_CSG, options = {}) {
1900
2274
  start: [ 0, 0, 0 ],
1901
2275
  end: [ 0, 0, height ],
1902
2276
  radius: diameter / 2,
1903
- resolution: CSG.defaultResolution2D
2277
+ resolution: CSG$1.defaultResolution2D
1904
2278
  }, options);
1905
- return CSG.cylinder(options);
2279
+ return assertValidCSG(CSG$1.cylinder(options), "Cylinder");
1906
2280
  }
1907
2281
  function Cone(diameter1, diameter2, height) {
1908
2282
  var options = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {};
1909
2283
  debug$1("parts.Cone", diameter1, diameter2, height, options);
1910
- return CSG.cylinder(Object.assign({
2284
+ return assertValidCSG(CSG$1.cylinder(Object.assign({
1911
2285
  start: [ 0, 0, 0 ],
1912
2286
  end: [ 0, 0, height ],
1913
2287
  radiusStart: diameter1 / 2,
1914
2288
  radiusEnd: diameter2 / 2,
1915
- resolution: CSG.defaultResolution2D
1916
- }, options));
2289
+ resolution: CSG$1.defaultResolution2D
2290
+ }, options)), "Cone");
1917
2291
  }
1918
2292
  function Hexagon(diameter, height) {
1919
2293
  debug$1("hexagon", diameter, height);
1920
2294
  var radius = diameter / 2;
1921
2295
  var sqrt3 = Math.sqrt(3) / 2;
1922
2296
  var hex = CAG.fromPoints([ [ radius, 0 ], [ radius / 2, radius * sqrt3 ], [ -radius / 2, radius * sqrt3 ], [ -radius, 0 ], [ -radius / 2, -radius * sqrt3 ], [ radius / 2, -radius * sqrt3 ] ]);
1923
- return hex.extrude({
2297
+ return assertValidCSG(hex.extrude({
1924
2298
  offset: [ 0, 0, height ]
1925
- });
2299
+ }), "Hexagon");
1926
2300
  }
1927
2301
  function Triangle(base, height) {
1928
2302
  var radius = base / 2;
1929
2303
  var tri = CAG.fromPoints([ [ -radius, 0 ], [ radius, 0 ], [ 0, Math.sin(30) * radius ] ]);
1930
- return tri.extrude({
2304
+ return assertValidCSG(tri.extrude({
1931
2305
  offset: [ 0, 0, height ]
1932
- });
2306
+ }), "Triangle");
1933
2307
  }
1934
2308
  function Tube(outsideDiameter, insideDiameter, height, outsideOptions, insideOptions) {
1935
- return Cylinder(outsideDiameter, height, outsideOptions).subtract(Cylinder(insideDiameter, height, insideOptions || outsideOptions));
2309
+ return assertValidCSG(Cylinder(outsideDiameter, height, outsideOptions).subtract(Cylinder(insideDiameter, height, insideOptions || outsideOptions)), "Tube");
1936
2310
  }
1937
2311
  function Anchor() {
1938
2312
  var width = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 10;
@@ -1950,11 +2324,11 @@ function initJscadutils(_CSG, options = {}) {
1950
2324
  center: [ r[0], r[1], 0 ],
1951
2325
  radius: r,
1952
2326
  roundradius: corner_radius,
1953
- resolution: CSG.defaultResolution2D
2327
+ resolution: CSG$1.defaultResolution2D
1954
2328
  }).extrude({
1955
2329
  offset: [ 0, 0, thickness || 1.62 ]
1956
2330
  });
1957
- return board;
2331
+ return assertValidCSG(board, "Board");
1958
2332
  }
1959
2333
  var Hardware = {
1960
2334
  Orientation: {
@@ -2045,6 +2419,10 @@ function initJscadutils(_CSG, options = {}) {
2045
2419
  gap = gap || .25;
2046
2420
  var inside = thickness - gap;
2047
2421
  var outside = -thickness + gap;
2422
+ var boxHeight = box.size().z;
2423
+ if (Math.abs(height) >= boxHeight) {
2424
+ throw new Error("Rabett: height (".concat(height, ") must be less than the object height (").concat(boxHeight, ")"));
2425
+ }
2048
2426
  debug("inside", inside, "outside", outside);
2049
2427
  var group = Group();
2050
2428
  var _box$bisect$parts = box.bisect("z", height, options).parts, top = _box$bisect$parts.positive, lower2_3rd = _box$bisect$parts.negative;
@@ -2115,10 +2493,10 @@ function initJscadutils(_CSG, options = {}) {
2115
2493
  thickness = thickness || 2;
2116
2494
  var s = div$1(xyz2array(size), 2);
2117
2495
  var r = add(s, thickness);
2118
- var box = CSG.cube({
2496
+ var box = CSG$1.cube({
2119
2497
  center: r,
2120
2498
  radius: r
2121
- }).subtract(CSG.cube({
2499
+ }).subtract(CSG$1.cube({
2122
2500
  center: r,
2123
2501
  radius: s
2124
2502
  }));
@@ -2136,7 +2514,7 @@ function initJscadutils(_CSG, options = {}) {
2136
2514
  var BBox = function BBox(o) {
2137
2515
  depreciated("BBox", true, "Use 'parts.BBox' instead");
2138
2516
  var s = div$1(xyz2array(o.size()), 2);
2139
- return CSG.cube({
2517
+ return CSG$1.cube({
2140
2518
  center: s,
2141
2519
  radius: s
2142
2520
  }).align(o, "xyz");
@@ -2148,7 +2526,7 @@ function initJscadutils(_CSG, options = {}) {
2148
2526
  var gap = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : .25;
2149
2527
  var r = add(getRadius(box), -thickness / 2);
2150
2528
  r[2] = thickness / 2;
2151
- var cutter = CSG.cube({
2529
+ var cutter = CSG$1.cube({
2152
2530
  center: r,
2153
2531
  radius: r
2154
2532
  }).align(box, "xy").color("green");