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