@jwc/jscad-utils 5.1.0 → 5.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -72,6 +72,8 @@ function initJscadutils(_CSG, options = {}) {
72
72
  enabled: [],
73
73
  disabled: []
74
74
  });
75
+ var jscadUtilsAssertValidCSGWarnings = options.assertValidCSGWarnings || false;
76
+ var jscadUtilsAssertValidCSG = options.assertValidCSG || false;
75
77
  var jscadUtils = function(exports, jsCadCSG, scadApi) {
76
78
  "use strict";
77
79
  function _interopDefaultLegacy(e) {
@@ -305,6 +307,51 @@ function initJscadutils(_CSG, options = {}) {
305
307
  function _arrayWithHoles(r) {
306
308
  if (Array.isArray(r)) return r;
307
309
  }
310
+ function _createForOfIteratorHelper(r, e) {
311
+ var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"];
312
+ if (!t) {
313
+ if (Array.isArray(r) || (t = _unsupportedIterableToArray(r)) || e && r && "number" == typeof r.length) {
314
+ t && (r = t);
315
+ var n = 0, F = function() {};
316
+ return {
317
+ s: F,
318
+ n: function() {
319
+ return n >= r.length ? {
320
+ done: !0
321
+ } : {
322
+ done: !1,
323
+ value: r[n++]
324
+ };
325
+ },
326
+ e: function(r) {
327
+ throw r;
328
+ },
329
+ f: F
330
+ };
331
+ }
332
+ throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
333
+ }
334
+ var o, a = !0, u = !1;
335
+ return {
336
+ s: function() {
337
+ t = t.call(r);
338
+ },
339
+ n: function() {
340
+ var r = t.next();
341
+ return a = r.done, r;
342
+ },
343
+ e: function(r) {
344
+ u = !0, o = r;
345
+ },
346
+ f: function() {
347
+ try {
348
+ a || null == t.return || t.return();
349
+ } finally {
350
+ if (u) throw o;
351
+ }
352
+ }
353
+ };
354
+ }
308
355
  function _defineProperty(e, r, t) {
309
356
  return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, {
310
357
  value: t,
@@ -725,6 +772,219 @@ function initJscadutils(_CSG, options = {}) {
725
772
  c[3] = g || 1;
726
773
  return o.setColor(c);
727
774
  }
775
+ function validateCSG(csg, options) {
776
+ var errors = [];
777
+ var warnings = [];
778
+ if (!csg || !csg.polygons || csg.polygons.length === 0) {
779
+ errors.push("Empty mesh: no polygons");
780
+ return {
781
+ ok: false,
782
+ errors,
783
+ warnings
784
+ };
785
+ }
786
+ var opts = _objectSpread2({
787
+ fixTJunctions: true
788
+ }, options);
789
+ if (opts.fixTJunctions && typeof csg.canonicalized === "function") {
790
+ csg = csg.canonicalized();
791
+ if (typeof csg.reTesselated === "function") {
792
+ csg = csg.reTesselated();
793
+ }
794
+ if (typeof csg.fixTJunctions === "function") {
795
+ csg = csg.fixTJunctions();
796
+ }
797
+ }
798
+ var AREA_EPS = 1e-10;
799
+ var KEY_EPS = 1e-5;
800
+ var degenerateCount = 0;
801
+ var invalidVertexCount = 0;
802
+ var _iterator = _createForOfIteratorHelper(csg.polygons), _step;
803
+ try {
804
+ for (_iterator.s(); !(_step = _iterator.n()).done; ) {
805
+ var npoly = _step.value;
806
+ var _iterator4 = _createForOfIteratorHelper(npoly.vertices), _step4;
807
+ try {
808
+ for (_iterator4.s(); !(_step4 = _iterator4.n()).done; ) {
809
+ var nvert = _step4.value;
810
+ var np = nvert.pos;
811
+ 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)) {
812
+ invalidVertexCount++;
813
+ break;
814
+ }
815
+ }
816
+ } catch (err) {
817
+ _iterator4.e(err);
818
+ } finally {
819
+ _iterator4.f();
820
+ }
821
+ }
822
+ } catch (err) {
823
+ _iterator.e(err);
824
+ } finally {
825
+ _iterator.f();
826
+ }
827
+ if (invalidVertexCount > 0) {
828
+ errors.push(invalidVertexCount + " polygon(s) with invalid vertex coordinates (NaN or Infinity)");
829
+ }
830
+ function vtxKey(v) {
831
+ var p = v.pos;
832
+ return Math.round(p.x / KEY_EPS) + "," + Math.round(p.y / KEY_EPS) + "," + Math.round(p.z / KEY_EPS);
833
+ }
834
+ var validPolygons = [];
835
+ var _iterator2 = _createForOfIteratorHelper(csg.polygons), _step2;
836
+ try {
837
+ for (_iterator2.s(); !(_step2 = _iterator2.n()).done; ) {
838
+ var poly = _step2.value;
839
+ var verts = poly.vertices;
840
+ var nv = verts.length;
841
+ if (nv < 3) {
842
+ degenerateCount++;
843
+ continue;
844
+ }
845
+ var hasInvalid = false;
846
+ var _iterator5 = _createForOfIteratorHelper(verts), _step5;
847
+ try {
848
+ for (_iterator5.s(); !(_step5 = _iterator5.n()).done; ) {
849
+ var vert = _step5.value;
850
+ var ip = vert.pos;
851
+ if (!Number.isFinite(ip.x) || !Number.isFinite(ip.y) || !Number.isFinite(ip.z)) {
852
+ hasInvalid = true;
853
+ break;
854
+ }
855
+ }
856
+ } catch (err) {
857
+ _iterator5.e(err);
858
+ } finally {
859
+ _iterator5.f();
860
+ }
861
+ if (hasInvalid) continue;
862
+ var area = 0;
863
+ for (var ai = 0; ai < nv - 2; ai++) {
864
+ area += verts[ai + 1].pos.minus(verts[0].pos).cross(verts[ai + 2].pos.minus(verts[ai + 1].pos)).length();
865
+ }
866
+ area *= .5;
867
+ if (area < AREA_EPS) {
868
+ degenerateCount++;
869
+ continue;
870
+ }
871
+ validPolygons.push(poly);
872
+ }
873
+ } catch (err) {
874
+ _iterator2.e(err);
875
+ } finally {
876
+ _iterator2.f();
877
+ }
878
+ if (degenerateCount > 0) {
879
+ warnings.push(degenerateCount + " degenerate polygon(s) (fewer than 3 vertices or near-zero area)");
880
+ if (opts.fixTJunctions && typeof CSG !== "undefined") {
881
+ var cleaned = CSG.fromPolygons(validPolygons);
882
+ cleaned = cleaned.canonicalized();
883
+ if (typeof cleaned.reTesselated === "function") {
884
+ cleaned = cleaned.reTesselated();
885
+ }
886
+ if (typeof cleaned.fixTJunctions === "function") {
887
+ cleaned = cleaned.fixTJunctions();
888
+ }
889
+ validPolygons = [];
890
+ var _iterator3 = _createForOfIteratorHelper(cleaned.polygons), _step3;
891
+ try {
892
+ for (_iterator3.s(); !(_step3 = _iterator3.n()).done; ) {
893
+ var cpoly = _step3.value;
894
+ var cverts = cpoly.vertices;
895
+ var cnv = cverts.length;
896
+ if (cnv < 3) continue;
897
+ var carea = 0;
898
+ for (var cai = 0; cai < cnv - 2; cai++) {
899
+ carea += cverts[cai + 1].pos.minus(cverts[0].pos).cross(cverts[cai + 2].pos.minus(cverts[cai + 1].pos)).length();
900
+ }
901
+ carea *= .5;
902
+ if (carea < AREA_EPS) continue;
903
+ validPolygons.push(cpoly);
904
+ }
905
+ } catch (err) {
906
+ _iterator3.e(err);
907
+ } finally {
908
+ _iterator3.f();
909
+ }
910
+ }
911
+ }
912
+ var edgeCounts = {};
913
+ for (var _i = 0, _validPolygons = validPolygons; _i < _validPolygons.length; _i++) {
914
+ var vpoly = _validPolygons[_i];
915
+ var vverts = vpoly.vertices;
916
+ var vnv = vverts.length;
917
+ for (var ei = 0; ei < vnv; ei++) {
918
+ var v0 = vverts[ei];
919
+ var v1 = vverts[(ei + 1) % vnv];
920
+ var edgeKey = vtxKey(v0) + "/" + vtxKey(v1);
921
+ edgeCounts[edgeKey] = (edgeCounts[edgeKey] || 0) + 1;
922
+ }
923
+ }
924
+ var unmatchedEdges = 0;
925
+ var nonManifoldEdges = 0;
926
+ var checked = {};
927
+ for (var _i2 = 0, _Object$keys = Object.keys(edgeCounts); _i2 < _Object$keys.length; _i2++) {
928
+ var _edgeKey = _Object$keys[_i2];
929
+ if (checked[_edgeKey]) continue;
930
+ var parts = _edgeKey.split("/");
931
+ var reverseKey = parts[1] + "/" + parts[0];
932
+ var forwardCount = edgeCounts[_edgeKey] || 0;
933
+ var reverseCount = edgeCounts[reverseKey] || 0;
934
+ checked[_edgeKey] = true;
935
+ checked[reverseKey] = true;
936
+ if (forwardCount !== reverseCount) {
937
+ unmatchedEdges += Math.abs(forwardCount - reverseCount);
938
+ }
939
+ if (forwardCount > 1 || reverseCount > 1) {
940
+ nonManifoldEdges++;
941
+ }
942
+ }
943
+ if (unmatchedEdges > 0) {
944
+ errors.push(unmatchedEdges + " unmatched edge(s): mesh is not watertight");
945
+ }
946
+ if (nonManifoldEdges > 0) {
947
+ errors.push(nonManifoldEdges + " non-manifold edge(s): edge shared by more than 2 polygons");
948
+ }
949
+ return {
950
+ ok: errors.length === 0,
951
+ errors,
952
+ warnings
953
+ };
954
+ }
955
+ function _noOp(csg) {
956
+ return csg;
957
+ }
958
+ function _makeAssertFn(warnEnabled) {
959
+ return function _assert(csg) {
960
+ var functionName = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : "unknown";
961
+ var moduleName = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : "unknown";
962
+ if (!csg || csg.polygons === undefined) return csg;
963
+ var result = validateCSG(csg);
964
+ if (!result.ok) {
965
+ throw new Error(moduleName + ":" + functionName + ": " + "invalid CSG: " + result.errors.join(", "));
966
+ }
967
+ if (warnEnabled && result.warnings.length > 0) {
968
+ throw new Error(moduleName + ":" + functionName + ": " + "CSG warnings: " + result.warnings.join(", "));
969
+ }
970
+ return csg;
971
+ };
972
+ }
973
+ var _assertFn = _noOp;
974
+ function _resolveFromGlobals() {
975
+ var enabled = typeof jscadUtilsAssertValidCSG !== "undefined" && !!jscadUtilsAssertValidCSG;
976
+ var warnEnabled = typeof jscadUtilsAssertValidCSGWarnings !== "undefined" && !!jscadUtilsAssertValidCSGWarnings;
977
+ return enabled ? _makeAssertFn(warnEnabled) : _noOp;
978
+ }
979
+ function AssertValidCSG() {
980
+ var moduleName = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : "unknown";
981
+ {
982
+ _assertFn = _resolveFromGlobals();
983
+ }
984
+ return function(csg, name) {
985
+ return _assertFn(csg, name, moduleName);
986
+ };
987
+ }
728
988
  function init(proto) {
729
989
  if (proto.prototype._jscadutilsinit) return;
730
990
  proto.prototype.color = function(r, g, b, a) {
@@ -818,6 +1078,9 @@ function initJscadutils(_CSG, options = {}) {
818
1078
  proto.prototype.subtractIf = function subtractIf(object, condition) {
819
1079
  return condition ? this.subtract(result(this, object)) : this;
820
1080
  };
1081
+ proto.prototype.validate = function validate(options) {
1082
+ return validateCSG(this, options);
1083
+ };
821
1084
  proto.prototype._translate = proto.prototype.translate;
822
1085
  proto.prototype.translate = function translate() {
823
1086
  if (arguments.length === 1) {
@@ -850,12 +1113,13 @@ function initJscadutils(_CSG, options = {}) {
850
1113
  __proto__: null,
851
1114
  default: init
852
1115
  });
853
- var CSG = jsCadCSG__default["default"].CSG, CAG = jsCadCSG__default["default"].CAG;
1116
+ var CSG$1 = jsCadCSG__default["default"].CSG, CAG = jsCadCSG__default["default"].CAG;
854
1117
  var rectangular_extrude = scadApi__default["default"].extrusions.rectangular_extrude;
855
1118
  var _scadApi$text = scadApi__default["default"].text, vector_text = _scadApi$text.vector_text, vector_char = _scadApi$text.vector_char;
856
1119
  var union = scadApi__default["default"].booleanOps.union;
857
- init(CSG);
1120
+ init(CSG$1);
858
1121
  var debug$3 = Debug("jscadUtils:group");
1122
+ var assertValidCSG$2 = AssertValidCSG("group");
859
1123
  function JsCadUtilsGroup() {
860
1124
  var names = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];
861
1125
  var parts = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
@@ -906,7 +1170,7 @@ function initJscadutils(_CSG, options = {}) {
906
1170
  debug$3("combine mapPick", value, key, object);
907
1171
  return map ? map(value, key, index, object) : identity(value);
908
1172
  }, self.name));
909
- return g.subtractIf(self.holes && Array.isArray(self.holes) ? union(self.holes) : self.holes, self.holes && !options.noholes);
1173
+ return assertValidCSG$2(g.subtractIf(self.holes && Array.isArray(self.holes) ? union(self.holes) : self.holes, self.holes && !options.noholes), "combine");
910
1174
  } catch (err) {
911
1175
  debug$3("combine error", this, pieces, options, err);
912
1176
  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");
@@ -947,7 +1211,7 @@ function initJscadutils(_CSG, options = {}) {
947
1211
  });
948
1212
  if (self.holes) {
949
1213
  group.holes = toArray(self.holes).map(function(part) {
950
- return map(CSG.fromPolygons(part.toPolygons()), "holes");
1214
+ return assertValidCSG$2(map(CSG$1.fromPolygons(part.toPolygons()), "holes"), "clone");
951
1215
  });
952
1216
  }
953
1217
  return group;
@@ -966,7 +1230,7 @@ function initJscadutils(_CSG, options = {}) {
966
1230
  var rotationCenter = solid.centroid();
967
1231
  var rotationAxis = axes[axis];
968
1232
  self.map(function(part) {
969
- return part.rotate(rotationCenter, rotationAxis, angle);
1233
+ return assertValidCSG$2(part.rotate(rotationCenter, rotationAxis, angle), "rotate");
970
1234
  });
971
1235
  return self;
972
1236
  };
@@ -979,7 +1243,7 @@ function initJscadutils(_CSG, options = {}) {
979
1243
  var self = this;
980
1244
  var t = calcSnap(self.combine(part), to, axis, orientation, delta);
981
1245
  self.map(function(part) {
982
- return part.translate(t);
1246
+ return assertValidCSG$2(part.translate(t), "snap");
983
1247
  });
984
1248
  return self;
985
1249
  } catch (err) {
@@ -994,7 +1258,7 @@ function initJscadutils(_CSG, options = {}) {
994
1258
  noholes: true
995
1259
  }), axis, to, delta);
996
1260
  self.map(function(part) {
997
- return part.translate(t);
1261
+ return assertValidCSG$2(part.translate(t), "align");
998
1262
  });
999
1263
  return self;
1000
1264
  } catch (err) {
@@ -1026,14 +1290,14 @@ function initJscadutils(_CSG, options = {}) {
1026
1290
  var myConnector = connectorName.split(".").reduce(function(a, v) {
1027
1291
  return a[v];
1028
1292
  }, self.parts[partName].properties);
1029
- debug$3("toConnector", to instanceof CSG.Connector);
1293
+ debug$3("toConnector", to instanceof CSG$1.Connector);
1030
1294
  var toConnector = toConnectorName.split(".").reduce(function(a, v) {
1031
1295
  return a[v];
1032
1296
  }, to.properties);
1033
1297
  var matrix = myConnector.getTransformationTo(toConnector, mirror, normalrotation);
1034
1298
  debug$3("connectTo", matrix);
1035
1299
  self.map(function(part) {
1036
- return part.transform(matrix);
1300
+ return assertValidCSG$2(part.transform(matrix), "connectTo");
1037
1301
  });
1038
1302
  return self;
1039
1303
  };
@@ -1044,7 +1308,7 @@ function initJscadutils(_CSG, options = {}) {
1044
1308
  return to - size[a] / 2;
1045
1309
  });
1046
1310
  self.map(function(part) {
1047
- return part.translate(t);
1311
+ return assertValidCSG$2(part.translate(t), "midlineTo");
1048
1312
  });
1049
1313
  return self;
1050
1314
  };
@@ -1053,7 +1317,7 @@ function initJscadutils(_CSG, options = {}) {
1053
1317
  var t = Array.isArray(x) ? x : [ x, y, z ];
1054
1318
  debug$3("translate", t);
1055
1319
  self.map(function(part) {
1056
- return part.translate(t);
1320
+ return assertValidCSG$2(part.translate(t), "translate");
1057
1321
  });
1058
1322
  return self;
1059
1323
  };
@@ -1063,7 +1327,7 @@ function initJscadutils(_CSG, options = {}) {
1063
1327
  if (!map) map = identity;
1064
1328
  var g = Group();
1065
1329
  p.forEach(function(name) {
1066
- g.add(map(CSG.fromPolygons(self.parts[name].toPolygons()), name), name);
1330
+ g.add(assertValidCSG$2(map(CSG$1.fromPolygons(self.parts[name].toPolygons()), name), "pick"), name);
1067
1331
  });
1068
1332
  return g;
1069
1333
  };
@@ -1078,7 +1342,7 @@ function initJscadutils(_CSG, options = {}) {
1078
1342
  debug$3("array error", _this, parts);
1079
1343
  throw error('group::array error "'.concat(name, '" not found.\nthis: ').concat(_this, '\nparts: "').concat(parts, '"\n'), "JSCAD_UTILS_GROUP_ERROR");
1080
1344
  }
1081
- a.push(map(CSG.fromPolygons(self.parts[name].toPolygons()), name));
1345
+ a.push(assertValidCSG$2(map(CSG$1.fromPolygons(self.parts[name].toPolygons()), name), "array"));
1082
1346
  });
1083
1347
  return a;
1084
1348
  };
@@ -1111,7 +1375,7 @@ function initJscadutils(_CSG, options = {}) {
1111
1375
  self.names = names && names.length > 0 && names.split(",") || [];
1112
1376
  if (Array.isArray(objects)) {
1113
1377
  self.parts = zipObject(self.names, objects);
1114
- } else if (objects instanceof CSG) {
1378
+ } else if (objects instanceof CSG$1) {
1115
1379
  self.parts = zipObject(self.names, [ objects ]);
1116
1380
  } else {
1117
1381
  self.parts = objects || {};
@@ -1132,6 +1396,7 @@ function initJscadutils(_CSG, options = {}) {
1132
1396
  return new JsCadUtilsGroup(self.names, self.parts, self.holes);
1133
1397
  }
1134
1398
  var debug$2 = Debug("jscadUtils:util");
1399
+ var assertValidCSG$1 = AssertValidCSG("util");
1135
1400
  var NOZZEL_SIZE = .4;
1136
1401
  var nearest = {
1137
1402
  under: function under(desired) {
@@ -1208,12 +1473,12 @@ function initJscadutils(_CSG, options = {}) {
1208
1473
  h: height || 2
1209
1474
  }));
1210
1475
  });
1211
- return center(union(o));
1476
+ return assertValidCSG$1(center(union(o)), "label");
1212
1477
  }
1213
1478
  function text(text) {
1214
1479
  var l = vector_char(0, 0, text);
1215
1480
  var _char = l.segments.reduce(function(result, segment) {
1216
- var path = new CSG.Path2D(segment);
1481
+ var path = new CSG$1.Path2D(segment);
1217
1482
  var cag = path.expandToCAG(2);
1218
1483
  return result ? result.union(cag) : cag;
1219
1484
  }, undefined);
@@ -1221,17 +1486,17 @@ function initJscadutils(_CSG, options = {}) {
1221
1486
  }
1222
1487
  function unitCube(length, radius) {
1223
1488
  radius = radius || .5;
1224
- return CSG.cube({
1489
+ return assertValidCSG$1(CSG$1.cube({
1225
1490
  center: [ 0, 0, 0 ],
1226
1491
  radius: [ radius, radius, length || .5 ]
1227
- });
1492
+ }), "unitCube");
1228
1493
  }
1229
1494
  function unitAxis(length, radius, centroid) {
1230
1495
  debug$2("unitAxis", length, radius, centroid);
1231
1496
  centroid = centroid || [ 0, 0, 0 ];
1232
1497
  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) ]);
1233
- unitaxis.properties.origin = new CSG.Connector([ 0, 0, 0 ], [ 1, 0, 0 ], [ 0, 1, 0 ]);
1234
- return unitaxis.translate(centroid);
1498
+ unitaxis.properties.origin = new CSG$1.Connector([ 0, 0, 0 ], [ 1, 0, 0 ], [ 0, 1, 0 ]);
1499
+ return assertValidCSG$1(unitaxis.translate(centroid), "unitAxis");
1235
1500
  }
1236
1501
  function toArray(a) {
1237
1502
  return Array.isArray(a) ? a : [ a ];
@@ -1321,15 +1586,15 @@ function initJscadutils(_CSG, options = {}) {
1321
1586
  }
1322
1587
  function center(object, objectSize) {
1323
1588
  objectSize = objectSize || size(object.getBounds());
1324
- return centerY(centerX(object, objectSize), objectSize);
1589
+ return assertValidCSG$1(centerY(centerX(object, objectSize), objectSize), "center");
1325
1590
  }
1326
1591
  function centerY(object, objectSize) {
1327
1592
  objectSize = objectSize || size(object.getBounds());
1328
- return object.translate([ 0, -objectSize.y / 2, 0 ]);
1593
+ return assertValidCSG$1(object.translate([ 0, -objectSize.y / 2, 0 ]), "centerY");
1329
1594
  }
1330
1595
  function centerX(object, objectSize) {
1331
1596
  objectSize = objectSize || size(object.getBounds());
1332
- return object.translate([ -objectSize.x / 2, 0, 0 ]);
1597
+ return assertValidCSG$1(object.translate([ -objectSize.x / 2, 0, 0 ]), "centerX");
1333
1598
  }
1334
1599
  function enlarge(object, x, y, z) {
1335
1600
  var a;
@@ -1347,7 +1612,7 @@ function initJscadutils(_CSG, options = {}) {
1347
1612
  var new_object = object.scale(t);
1348
1613
  var new_centroid = centroid(new_object);
1349
1614
  var delta = new_centroid.minus(objectCentroid).times(-1);
1350
- return new_object.translate(delta);
1615
+ return assertValidCSG$1(new_object.translate(delta), "enlarge");
1351
1616
  }
1352
1617
  function fit(object, x, y, z, keep_aspect_ratio) {
1353
1618
  var a;
@@ -1367,10 +1632,10 @@ function initJscadutils(_CSG, options = {}) {
1367
1632
  }
1368
1633
  var s = [ scale(objectSize.x, x), scale(objectSize.y, y), scale(objectSize.z, z) ];
1369
1634
  var min$1 = min(s);
1370
- return centerWith(object.scale(s.map(function(d, i) {
1635
+ return assertValidCSG$1(centerWith(object.scale(s.map(function(d, i) {
1371
1636
  if (a[i] === 0) return 1;
1372
1637
  return keep_aspect_ratio ? min$1 : d;
1373
- })), "xyz", object);
1638
+ })), "xyz", object), "fit");
1374
1639
  }
1375
1640
  function shift(object, x, y, z) {
1376
1641
  var hsize = this.div(this.size(object.getBounds()), 2);
@@ -1378,10 +1643,10 @@ function initJscadutils(_CSG, options = {}) {
1378
1643
  }
1379
1644
  function zero(object) {
1380
1645
  var bounds = object.getBounds();
1381
- return object.translate([ 0, 0, -bounds[0].z ]);
1646
+ return assertValidCSG$1(object.translate([ 0, 0, -bounds[0].z ]), "zero");
1382
1647
  }
1383
1648
  function mirrored4(x) {
1384
- return x.union([ x.mirroredY(90), x.mirroredX(90), x.mirroredY(90).mirroredX(90) ]);
1649
+ return assertValidCSG$1(x.union([ x.mirroredY(90), x.mirroredX(90), x.mirroredY(90).mirroredX(90) ]), "mirrored4");
1385
1650
  }
1386
1651
  var flushSide = {
1387
1652
  "above-outside": [ 1, 0 ],
@@ -1442,10 +1707,10 @@ function initJscadutils(_CSG, options = {}) {
1442
1707
  function snap(moveobj, withobj, axis, orientation, delta) {
1443
1708
  debug$2("snap", moveobj, withobj, axis, orientation, delta);
1444
1709
  var t = calcSnap(moveobj, withobj, axis, orientation, delta);
1445
- return moveobj.translate(t);
1710
+ return assertValidCSG$1(moveobj.translate(t), "snap");
1446
1711
  }
1447
1712
  function flush(moveobj, withobj, axis, mside, wside) {
1448
- return moveobj.translate(calcFlush(moveobj, withobj, axis, mside, wside));
1713
+ return assertValidCSG$1(moveobj.translate(calcFlush(moveobj, withobj, axis, mside, wside)), "flush");
1449
1714
  }
1450
1715
  function axisApply(axes, valfun, a) {
1451
1716
  debug$2("axisApply", axes, valfun, a);
@@ -1461,7 +1726,7 @@ function initJscadutils(_CSG, options = {}) {
1461
1726
  return retval;
1462
1727
  }
1463
1728
  function axis2array(axes, valfun) {
1464
- depreciated("axis2array");
1729
+ depreciated("axis2array", false, "Use axisApply instead.");
1465
1730
  var a = [ 0, 0, 0 ];
1466
1731
  var lookup = {
1467
1732
  x: 0,
@@ -1491,7 +1756,7 @@ function initJscadutils(_CSG, options = {}) {
1491
1756
  });
1492
1757
  }
1493
1758
  function midlineTo(o, axis, to) {
1494
- return o.translate(calcmidlineTo(o, axis, to));
1759
+ return assertValidCSG$1(o.translate(calcmidlineTo(o, axis, to)), "midlineTo");
1495
1760
  }
1496
1761
  function translator(o, axis, withObj) {
1497
1762
  var objectCentroid = centroid(o);
@@ -1511,7 +1776,7 @@ function initJscadutils(_CSG, options = {}) {
1511
1776
  return delta ? add(t, delta) : t;
1512
1777
  }
1513
1778
  function centerWith(o, axis, withObj) {
1514
- return o.translate(calcCenterWith(o, axis, withObj));
1779
+ return assertValidCSG$1(o.translate(calcCenterWith(o, axis, withObj)), "centerWith");
1515
1780
  }
1516
1781
  function getDelta(size, bounds, axis, offset, nonzero) {
1517
1782
  if (!isEmpty(offset) && nonzero) {
@@ -1524,6 +1789,95 @@ function initJscadutils(_CSG, options = {}) {
1524
1789
  return bounds[0][a] + (isEmpty(dist) ? size[axis] / 2 : dist);
1525
1790
  });
1526
1791
  }
1792
+ var EPS = 1e-5;
1793
+ function splitCSGByPlane(csg, plane) {
1794
+ var frontPolys = [];
1795
+ var backPolys = [];
1796
+ csg.polygons.forEach(function(poly) {
1797
+ var vertices = poly.vertices;
1798
+ var numVerts = vertices.length;
1799
+ var hasfront = false;
1800
+ var hasback = false;
1801
+ var vertexIsBack = [];
1802
+ for (var i = 0; i < numVerts; i++) {
1803
+ var t = plane.normal.dot(vertices[i].pos) - plane.w;
1804
+ vertexIsBack.push(t < 0);
1805
+ if (t > EPS) hasfront = true;
1806
+ if (t < -EPS) hasback = true;
1807
+ }
1808
+ if (!hasfront && !hasback) {
1809
+ var d = plane.normal.dot(poly.plane.normal);
1810
+ if (d >= 0) {
1811
+ frontPolys.push(poly);
1812
+ } else {
1813
+ backPolys.push(poly);
1814
+ }
1815
+ } else if (!hasback) {
1816
+ frontPolys.push(poly);
1817
+ } else if (!hasfront) {
1818
+ backPolys.push(poly);
1819
+ } else {
1820
+ var fv = [];
1821
+ var bv = [];
1822
+ for (var vi = 0; vi < numVerts; vi++) {
1823
+ var vertex = vertices[vi];
1824
+ var nextVi = (vi + 1) % numVerts;
1825
+ var isback = vertexIsBack[vi];
1826
+ var nextisback = vertexIsBack[nextVi];
1827
+ if (isback === nextisback) {
1828
+ if (isback) {
1829
+ bv.push(vertex);
1830
+ } else {
1831
+ fv.push(vertex);
1832
+ }
1833
+ } else {
1834
+ var point = vertex.pos;
1835
+ var nextpoint = vertices[nextVi].pos;
1836
+ var ip = plane.splitLineBetweenPoints(point, nextpoint);
1837
+ var iv = new CSG$1.Vertex(ip);
1838
+ if (isback) {
1839
+ bv.push(vertex);
1840
+ bv.push(iv);
1841
+ fv.push(iv);
1842
+ } else {
1843
+ fv.push(vertex);
1844
+ fv.push(iv);
1845
+ bv.push(iv);
1846
+ }
1847
+ }
1848
+ }
1849
+ var EPSEPS = EPS * EPS;
1850
+ if (fv.length >= 3) {
1851
+ var prev = fv[fv.length - 1];
1852
+ for (var fi = 0; fi < fv.length; fi++) {
1853
+ var curr = fv[fi];
1854
+ if (curr.pos.distanceToSquared(prev.pos) < EPSEPS) {
1855
+ fv.splice(fi, 1);
1856
+ fi--;
1857
+ }
1858
+ prev = curr;
1859
+ }
1860
+ }
1861
+ if (bv.length >= 3) {
1862
+ var prev = bv[bv.length - 1];
1863
+ for (var bi = 0; bi < bv.length; bi++) {
1864
+ var curr = bv[bi];
1865
+ if (curr.pos.distanceToSquared(prev.pos) < EPSEPS) {
1866
+ bv.splice(bi, 1);
1867
+ bi--;
1868
+ }
1869
+ prev = curr;
1870
+ }
1871
+ }
1872
+ if (fv.length >= 3) frontPolys.push(new CSG$1.Polygon(fv, poly.shared, poly.plane));
1873
+ if (bv.length >= 3) backPolys.push(new CSG$1.Polygon(bv, poly.shared, poly.plane));
1874
+ }
1875
+ });
1876
+ return {
1877
+ front: CSG$1.fromPolygons(frontPolys),
1878
+ back: CSG$1.fromPolygons(backPolys)
1879
+ };
1880
+ }
1527
1881
  function bisect() {
1528
1882
  for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
1529
1883
  args[_key] = arguments[_key];
@@ -1585,13 +1939,13 @@ function initJscadutils(_CSG, options = {}) {
1585
1939
  }[[ axis, rotateaxis ].sort().join("")];
1586
1940
  var centroid = object.centroid();
1587
1941
  var rotateDelta = getDelta(objectSize, bounds, rotateOffsetAxis, rotateoffset);
1588
- var rotationCenter = options.rotationCenter || new CSG.Vector3D(axisApply("xyz", function(i, a) {
1942
+ var rotationCenter = options.rotationCenter || new CSG$1.Vector3D(axisApply("xyz", function(i, a) {
1589
1943
  if (a == axis) return cutDelta[i];
1590
1944
  if (a == rotateOffsetAxis) return rotateDelta[i];
1591
1945
  return centroid[a];
1592
1946
  }));
1593
1947
  var theRotationAxis = rotationAxes[rotateaxis];
1594
- var cutplane = CSG.OrthoNormalBasis.GetCartesian(info.orthoNormalCartesian[0], info.orthoNormalCartesian[1]).translate(cutDelta).rotate(rotationCenter, theRotationAxis, angle);
1948
+ var cutplane = CSG$1.OrthoNormalBasis.GetCartesian(info.orthoNormalCartesian[0], info.orthoNormalCartesian[1]).translate(cutDelta).rotate(rotationCenter, theRotationAxis, angle);
1595
1949
  debug$2("bisect", debug$2.enabled && {
1596
1950
  axis,
1597
1951
  offset,
@@ -1604,7 +1958,26 @@ function initJscadutils(_CSG, options = {}) {
1604
1958
  cutplane,
1605
1959
  options
1606
1960
  });
1607
- var g = Group("negative,positive", [ object.cutByPlane(cutplane.plane).color(options.color && "red"), object.cutByPlane(cutplane.plane.flipped()).color(options.color && "blue") ]);
1961
+ var negative = object.cutByPlane(cutplane.plane);
1962
+ var positive = object.cutByPlane(cutplane.plane.flipped());
1963
+ var negSize = size(negative);
1964
+ var posSize = size(positive);
1965
+ if (negSize[axis] >= objectSize[axis] - EPS || posSize[axis] >= objectSize[axis] - EPS) {
1966
+ var halves = splitCSGByPlane(object, cutplane.plane);
1967
+ if (negSize[axis] >= objectSize[axis] - EPS) {
1968
+ negative = halves.back;
1969
+ try {
1970
+ negative = negative.cutByPlane(cutplane.plane);
1971
+ } catch (e) {}
1972
+ }
1973
+ if (posSize[axis] >= objectSize[axis] - EPS) {
1974
+ positive = halves.front;
1975
+ try {
1976
+ positive = positive.cutByPlane(cutplane.plane.flipped());
1977
+ } catch (e) {}
1978
+ }
1979
+ }
1980
+ var g = Group("negative,positive", [ negative.color(options.color && "red"), positive.color(options.color && "blue") ]);
1608
1981
  if (options.addRotationCenter) g.add(unitAxis(objectSize.length() + 10, .1, rotationCenter), "rotationCenter");
1609
1982
  return g;
1610
1983
  }
@@ -1617,9 +1990,9 @@ function initJscadutils(_CSG, options = {}) {
1617
1990
  addRotationCenter: true
1618
1991
  };
1619
1992
  var info = normalVector(axis);
1620
- var rotationCenter = options.rotationCenter || new CSG.Vector3D(0, 0, 0);
1993
+ var rotationCenter = options.rotationCenter || new CSG$1.Vector3D(0, 0, 0);
1621
1994
  var theRotationAxis = rotationAxes[rotateaxis];
1622
- var cutplane = CSG.OrthoNormalBasis.GetCartesian(info.orthoNormalCartesian[0], info.orthoNormalCartesian[1]).rotate(rotationCenter, theRotationAxis, angle);
1995
+ var cutplane = CSG$1.OrthoNormalBasis.GetCartesian(info.orthoNormalCartesian[0], info.orthoNormalCartesian[1]).rotate(rotationCenter, theRotationAxis, angle);
1623
1996
  var g = Group("negative,positive", [ object.cutByPlane(cutplane.plane).color(options.color && "red"), object.cutByPlane(cutplane.plane.flipped()).color(options.color && "blue") ]);
1624
1997
  if (options.addRotationCenter) {
1625
1998
  var objectSize = size(object);
@@ -1644,14 +2017,14 @@ function initJscadutils(_CSG, options = {}) {
1644
2017
  var bounds = object.getBounds();
1645
2018
  var objectSize = size(object);
1646
2019
  var cutDelta = getDelta(objectSize, bounds, axis, offset, true);
1647
- return object.stretchAtPlane(normal[axis], cutDelta, distance);
2020
+ return assertValidCSG$1(object.stretchAtPlane(normal[axis], cutDelta, distance), "stretch");
1648
2021
  }
1649
2022
  function poly2solid(top, bottom, height) {
1650
2023
  if (top.sides.length == 0) {
1651
- return new CSG;
2024
+ return new CSG$1;
1652
2025
  }
1653
- var offsetVector = CSG.Vector3D.Create(0, 0, height);
1654
- var normalVector = CSG.Vector3D.Create(0, 1, 0);
2026
+ var offsetVector = CSG$1.Vector3D.Create(0, 0, height);
2027
+ var normalVector = CSG$1.Vector3D.Create(0, 1, 0);
1655
2028
  var polygons = [];
1656
2029
  polygons = polygons.concat(bottom._toPlanePolygons({
1657
2030
  translation: [ 0, 0, 0 ],
@@ -1663,14 +2036,14 @@ function initJscadutils(_CSG, options = {}) {
1663
2036
  normalVector,
1664
2037
  flipped: offsetVector.z < 0
1665
2038
  }));
1666
- var c1 = new CSG.Connector(offsetVector.times(0), [ 0, 0, offsetVector.z ], normalVector);
1667
- var c2 = new CSG.Connector(offsetVector, [ 0, 0, offsetVector.z ], normalVector);
2039
+ var c1 = new CSG$1.Connector(offsetVector.times(0), [ 0, 0, offsetVector.z ], normalVector);
2040
+ var c2 = new CSG$1.Connector(offsetVector, [ 0, 0, offsetVector.z ], normalVector);
1668
2041
  polygons = polygons.concat(bottom._toWallPolygons({
1669
2042
  cag: top,
1670
2043
  toConnector1: c1,
1671
2044
  toConnector2: c2
1672
2045
  }));
1673
- return CSG.fromPolygons(polygons);
2046
+ return assertValidCSG$1(CSG$1.fromPolygons(polygons), "poly2solid");
1674
2047
  }
1675
2048
  function slices2poly(slices, options, axis) {
1676
2049
  debug$2("slices2poly", slices, options, axis);
@@ -1679,7 +2052,7 @@ function initJscadutils(_CSG, options = {}) {
1679
2052
  twiststeps: 0
1680
2053
  }, options);
1681
2054
  var twistangle = options && parseFloat(options.twistangle) || 0;
1682
- options && parseInt(options.twiststeps) || CSG.defaultResolution3D;
2055
+ options && parseInt(options.twiststeps) || CSG$1.defaultResolution3D;
1683
2056
  var normalVector = options.si.normalVector;
1684
2057
  var polygons = [];
1685
2058
  var first$1 = first(slices);
@@ -1708,8 +2081,8 @@ function initJscadutils(_CSG, options = {}) {
1708
2081
  var nextidx = idx + 1;
1709
2082
  var top = !up ? slices[nextidx] : slice;
1710
2083
  var bottom = up ? slices[nextidx] : slice;
1711
- var c1 = new CSG.Connector(bottom.offset, connectorAxis, rotate(normalVector, twistangle, idx / slices.length));
1712
- var c2 = new CSG.Connector(top.offset, connectorAxis, rotate(normalVector, twistangle, nextidx / slices.length));
2084
+ var c1 = new CSG$1.Connector(bottom.offset, connectorAxis, rotate(normalVector, twistangle, idx / slices.length));
2085
+ var c2 = new CSG$1.Connector(top.offset, connectorAxis, rotate(normalVector, twistangle, nextidx / slices.length));
1713
2086
  polygons = polygons.concat(bottom.poly._toWallPolygons({
1714
2087
  cag: top.poly,
1715
2088
  toConnector1: c1,
@@ -1717,21 +2090,21 @@ function initJscadutils(_CSG, options = {}) {
1717
2090
  }));
1718
2091
  }
1719
2092
  });
1720
- return CSG.fromPolygons(polygons);
2093
+ return assertValidCSG$1(CSG$1.fromPolygons(polygons), "slices2poly");
1721
2094
  }
1722
2095
  function normalVector(axis) {
1723
2096
  var axisInfo = {
1724
2097
  z: {
1725
2098
  orthoNormalCartesian: [ "X", "Y" ],
1726
- normalVector: CSG.Vector3D.Create(0, 1, 0)
2099
+ normalVector: CSG$1.Vector3D.Create(0, 1, 0)
1727
2100
  },
1728
2101
  x: {
1729
2102
  orthoNormalCartesian: [ "Y", "Z" ],
1730
- normalVector: CSG.Vector3D.Create(0, 0, 1)
2103
+ normalVector: CSG$1.Vector3D.Create(0, 0, 1)
1731
2104
  },
1732
2105
  y: {
1733
- orthoNormalCartesian: [ "X", "Z" ],
1734
- normalVector: CSG.Vector3D.Create(0, 0, 1)
2106
+ orthoNormalCartesian: [ "Z", "X" ],
2107
+ normalVector: CSG$1.Vector3D.Create(0, 0, 1)
1735
2108
  }
1736
2109
  };
1737
2110
  if (!axisInfo[axis]) error("normalVector: invalid axis " + axis);
@@ -1772,7 +2145,7 @@ function initJscadutils(_CSG, options = {}) {
1772
2145
  var si = sliceParams(orientation, radius, b);
1773
2146
  debug$2("reShape", absoluteRadius, si);
1774
2147
  if (si.axis !== "z") throw new Error('reShape error: CAG._toPlanePolygons only uses the "z" axis. You must use the "z" axis for now.');
1775
- var cutplane = CSG.OrthoNormalBasis.GetCartesian(si.orthoNormalCartesian[0], si.orthoNormalCartesian[1]).translate(si.cutDelta);
2148
+ var cutplane = CSG$1.OrthoNormalBasis.GetCartesian(si.orthoNormalCartesian[0], si.orthoNormalCartesian[1]).translate(si.cutDelta);
1776
2149
  var slice = object.sectionCut(cutplane);
1777
2150
  var first = axisApply(si.axis, function() {
1778
2151
  return si.positive ? 0 : absoluteRadius;
@@ -1787,25 +2160,25 @@ function initJscadutils(_CSG, options = {}) {
1787
2160
  si
1788
2161
  }), si.axis).color(options.color);
1789
2162
  var remainder = object.cutByPlane(plane);
1790
- return union([ options.unionOriginal ? object : remainder, delta.translate(si.moveDelta) ]);
2163
+ return assertValidCSG$1(union([ options.unionOriginal ? object : remainder, delta.translate(si.moveDelta) ]), "reShape");
1791
2164
  }
1792
2165
  function chamfer(object, radius, orientation, options) {
1793
- return reShape(object, radius, orientation, options, function(first, last, slice) {
2166
+ return assertValidCSG$1(reShape(object, radius, orientation, options, function(first, last, slice) {
1794
2167
  return [ {
1795
2168
  poly: slice,
1796
- offset: new CSG.Vector3D(first)
2169
+ offset: new CSG$1.Vector3D(first)
1797
2170
  }, {
1798
2171
  poly: enlarge(slice, [ -radius * 2, -radius * 2 ]),
1799
- offset: new CSG.Vector3D(last)
2172
+ offset: new CSG$1.Vector3D(last)
1800
2173
  } ];
1801
- });
2174
+ }), "chamfer");
1802
2175
  }
1803
2176
  function fillet(object, radius, orientation, options) {
1804
2177
  options = options || {};
1805
- return reShape(object, radius, orientation, options, function(first, last, slice) {
1806
- var v1 = new CSG.Vector3D(first);
1807
- var v2 = new CSG.Vector3D(last);
1808
- var res = options.resolution || CSG.defaultResolution3D;
2178
+ return assertValidCSG$1(reShape(object, radius, orientation, options, function(first, last, slice) {
2179
+ var v1 = new CSG$1.Vector3D(first);
2180
+ var v2 = new CSG$1.Vector3D(last);
2181
+ var res = options.resolution || CSG$1.defaultResolution3D;
1809
2182
  var slices = range(0, res).map(function(i) {
1810
2183
  var p = i > 0 ? i / (res - 1) : 0;
1811
2184
  var v = v1.lerp(v2, p);
@@ -1816,7 +2189,7 @@ function initJscadutils(_CSG, options = {}) {
1816
2189
  };
1817
2190
  });
1818
2191
  return slices;
1819
- });
2192
+ }), "fillet");
1820
2193
  }
1821
2194
  function calcRotate(part, solid, axis) {
1822
2195
  var axes = {
@@ -1833,7 +2206,7 @@ function initJscadutils(_CSG, options = {}) {
1833
2206
  }
1834
2207
  function rotateAround(part, solid, axis, angle) {
1835
2208
  var _calcRotate = calcRotate(part, solid, axis), rotationCenter = _calcRotate.rotationCenter, rotationAxis = _calcRotate.rotationAxis;
1836
- return part.rotate(rotationCenter, rotationAxis, angle);
2209
+ return assertValidCSG$1("rotateAround")(part.rotate(rotationCenter, rotationAxis, angle));
1837
2210
  }
1838
2211
  function cloneProperties(from, to) {
1839
2212
  return Object.entries(from).reduce(function(props, _ref) {
@@ -1843,19 +2216,20 @@ function initJscadutils(_CSG, options = {}) {
1843
2216
  }, to);
1844
2217
  }
1845
2218
  function clone(o) {
1846
- var c = CSG.fromPolygons(o.toPolygons());
2219
+ var c = CSG$1.fromPolygons(o.toPolygons());
1847
2220
  cloneProperties(o, c);
1848
- debug$2("clone", o, c, CSG);
1849
- return c;
2221
+ debug$2("clone", o, c, CSG$1);
2222
+ return assertValidCSG$1(c, "clone");
1850
2223
  }
1851
2224
  function addConnector(object, name) {
1852
2225
  var point = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : [ 0, 0, 0 ];
1853
2226
  var axis = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : [ 1, 0, 0 ];
1854
2227
  var normal = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : [ 0, 0, 1 ];
1855
- object.properties[name] = new CSG.Connector(point, axis, normal);
1856
- return object;
2228
+ object.properties[name] = new CSG$1.Connector(point, axis, normal);
2229
+ return assertValidCSG$1("addConnector")(object);
1857
2230
  }
1858
2231
  var debug$1 = Debug("jscadUtils:parts");
2232
+ var assertValidCSG = AssertValidCSG("parts");
1859
2233
  var parts = {
1860
2234
  BBox: BBox$1,
1861
2235
  Cube,
@@ -1865,7 +2239,7 @@ function initJscadutils(_CSG, options = {}) {
1865
2239
  };
1866
2240
  function BBox$1() {
1867
2241
  function box(object) {
1868
- return CSG.cube({
2242
+ return CSG$1.cube({
1869
2243
  center: object.centroid(),
1870
2244
  radius: object.size().dividedBy(2)
1871
2245
  });
@@ -1873,17 +2247,17 @@ function initJscadutils(_CSG, options = {}) {
1873
2247
  for (var _len = arguments.length, objects = new Array(_len), _key = 0; _key < _len; _key++) {
1874
2248
  objects[_key] = arguments[_key];
1875
2249
  }
1876
- return objects.reduce(function(bbox, part) {
2250
+ return assertValidCSG(objects.reduce(function(bbox, part) {
1877
2251
  var object = bbox ? union([ bbox, box(part) ]) : part;
1878
2252
  return box(object);
1879
- }, undefined);
2253
+ }, undefined), "BBox");
1880
2254
  }
1881
2255
  function Cube(width) {
1882
2256
  var r = div$1(fromxyz(width), 2);
1883
- return CSG.cube({
2257
+ return assertValidCSG(CSG$1.cube({
1884
2258
  center: r,
1885
2259
  radius: r
1886
- });
2260
+ }), "Cube");
1887
2261
  }
1888
2262
  function RoundedCube(x, y, thickness, corner_radius) {
1889
2263
  if (x.getBounds) {
@@ -1899,11 +2273,11 @@ function initJscadutils(_CSG, options = {}) {
1899
2273
  center: [ r[0], r[1], 0 ],
1900
2274
  radius: r,
1901
2275
  roundradius: corner_radius,
1902
- resolution: CSG.defaultResolution2D
2276
+ resolution: CSG$1.defaultResolution2D
1903
2277
  }).extrude({
1904
2278
  offset: [ 0, 0, thickness || 1.62 ]
1905
2279
  });
1906
- return roundedcube;
2280
+ return assertValidCSG(roundedcube, "RoundedCube");
1907
2281
  }
1908
2282
  function Cylinder(diameter, height) {
1909
2283
  var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
@@ -1912,39 +2286,39 @@ function initJscadutils(_CSG, options = {}) {
1912
2286
  start: [ 0, 0, 0 ],
1913
2287
  end: [ 0, 0, height ],
1914
2288
  radius: diameter / 2,
1915
- resolution: CSG.defaultResolution2D
2289
+ resolution: CSG$1.defaultResolution2D
1916
2290
  }, options);
1917
- return CSG.cylinder(options);
2291
+ return assertValidCSG(CSG$1.cylinder(options), "Cylinder");
1918
2292
  }
1919
2293
  function Cone(diameter1, diameter2, height) {
1920
2294
  var options = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {};
1921
2295
  debug$1("parts.Cone", diameter1, diameter2, height, options);
1922
- return CSG.cylinder(Object.assign({
2296
+ return assertValidCSG(CSG$1.cylinder(Object.assign({
1923
2297
  start: [ 0, 0, 0 ],
1924
2298
  end: [ 0, 0, height ],
1925
2299
  radiusStart: diameter1 / 2,
1926
2300
  radiusEnd: diameter2 / 2,
1927
- resolution: CSG.defaultResolution2D
1928
- }, options));
2301
+ resolution: CSG$1.defaultResolution2D
2302
+ }, options)), "Cone");
1929
2303
  }
1930
2304
  function Hexagon(diameter, height) {
1931
2305
  debug$1("hexagon", diameter, height);
1932
2306
  var radius = diameter / 2;
1933
2307
  var sqrt3 = Math.sqrt(3) / 2;
1934
2308
  var hex = CAG.fromPoints([ [ radius, 0 ], [ radius / 2, radius * sqrt3 ], [ -radius / 2, radius * sqrt3 ], [ -radius, 0 ], [ -radius / 2, -radius * sqrt3 ], [ radius / 2, -radius * sqrt3 ] ]);
1935
- return hex.extrude({
2309
+ return assertValidCSG(hex.extrude({
1936
2310
  offset: [ 0, 0, height ]
1937
- });
2311
+ }), "Hexagon");
1938
2312
  }
1939
2313
  function Triangle(base, height) {
1940
2314
  var radius = base / 2;
1941
2315
  var tri = CAG.fromPoints([ [ -radius, 0 ], [ radius, 0 ], [ 0, Math.sin(30) * radius ] ]);
1942
- return tri.extrude({
2316
+ return assertValidCSG(tri.extrude({
1943
2317
  offset: [ 0, 0, height ]
1944
- });
2318
+ }), "Triangle");
1945
2319
  }
1946
2320
  function Tube(outsideDiameter, insideDiameter, height, outsideOptions, insideOptions) {
1947
- return Cylinder(outsideDiameter, height, outsideOptions).subtract(Cylinder(insideDiameter, height, insideOptions || outsideOptions));
2321
+ return assertValidCSG(Cylinder(outsideDiameter, height, outsideOptions).subtract(Cylinder(insideDiameter, height, insideOptions || outsideOptions)), "Tube");
1948
2322
  }
1949
2323
  function Anchor() {
1950
2324
  var width = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 10;
@@ -1962,11 +2336,11 @@ function initJscadutils(_CSG, options = {}) {
1962
2336
  center: [ r[0], r[1], 0 ],
1963
2337
  radius: r,
1964
2338
  roundradius: corner_radius,
1965
- resolution: CSG.defaultResolution2D
2339
+ resolution: CSG$1.defaultResolution2D
1966
2340
  }).extrude({
1967
2341
  offset: [ 0, 0, thickness || 1.62 ]
1968
2342
  });
1969
- return board;
2343
+ return assertValidCSG(board, "Board");
1970
2344
  }
1971
2345
  var Hardware = {
1972
2346
  Orientation: {
@@ -2057,6 +2431,10 @@ function initJscadutils(_CSG, options = {}) {
2057
2431
  gap = gap || .25;
2058
2432
  var inside = thickness - gap;
2059
2433
  var outside = -thickness + gap;
2434
+ var boxHeight = box.size().z;
2435
+ if (Math.abs(height) >= boxHeight) {
2436
+ throw new Error("Rabett: height (".concat(height, ") must be less than the object height (").concat(boxHeight, ")"));
2437
+ }
2060
2438
  debug("inside", inside, "outside", outside);
2061
2439
  var group = Group();
2062
2440
  var _box$bisect$parts = box.bisect("z", height, options).parts, top = _box$bisect$parts.positive, lower2_3rd = _box$bisect$parts.negative;
@@ -2127,10 +2505,10 @@ function initJscadutils(_CSG, options = {}) {
2127
2505
  thickness = thickness || 2;
2128
2506
  var s = div$1(xyz2array(size), 2);
2129
2507
  var r = add(s, thickness);
2130
- var box = CSG.cube({
2508
+ var box = CSG$1.cube({
2131
2509
  center: r,
2132
2510
  radius: r
2133
- }).subtract(CSG.cube({
2511
+ }).subtract(CSG$1.cube({
2134
2512
  center: r,
2135
2513
  radius: s
2136
2514
  }));
@@ -2148,7 +2526,7 @@ function initJscadutils(_CSG, options = {}) {
2148
2526
  var BBox = function BBox(o) {
2149
2527
  depreciated("BBox", true, "Use 'parts.BBox' instead");
2150
2528
  var s = div$1(xyz2array(o.size()), 2);
2151
- return CSG.cube({
2529
+ return CSG$1.cube({
2152
2530
  center: s,
2153
2531
  radius: s
2154
2532
  }).align(o, "xyz");
@@ -2160,7 +2538,7 @@ function initJscadutils(_CSG, options = {}) {
2160
2538
  var gap = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : .25;
2161
2539
  var r = add(getRadius(box), -thickness / 2);
2162
2540
  r[2] = thickness / 2;
2163
- var cutter = CSG.cube({
2541
+ var cutter = CSG$1.cube({
2164
2542
  center: r,
2165
2543
  radius: r
2166
2544
  }).align(box, "xy").color("green");