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