@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.
@@ -67,6 +67,8 @@ function initJscadutils(_CSG, options = {}) {
67
67
  enabled: [],
68
68
  disabled: []
69
69
  });
70
+ var jscadUtilsAssertValidCSGWarnings = options.assertValidCSGWarnings || false;
71
+ var jscadUtilsAssertValidCSG = options.assertValidCSG || false;
70
72
  var jscadUtils = function(exports, jsCadCSG, scadApi) {
71
73
  "use strict";
72
74
  function _interopDefaultLegacy(e) {
@@ -300,6 +302,51 @@ function initJscadutils(_CSG, options = {}) {
300
302
  function _arrayWithHoles(r) {
301
303
  if (Array.isArray(r)) return r;
302
304
  }
305
+ function _createForOfIteratorHelper(r, e) {
306
+ var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"];
307
+ if (!t) {
308
+ if (Array.isArray(r) || (t = _unsupportedIterableToArray(r)) || e && r && "number" == typeof r.length) {
309
+ t && (r = t);
310
+ var n = 0, F = function() {};
311
+ return {
312
+ s: F,
313
+ n: function() {
314
+ return n >= r.length ? {
315
+ done: !0
316
+ } : {
317
+ done: !1,
318
+ value: r[n++]
319
+ };
320
+ },
321
+ e: function(r) {
322
+ throw r;
323
+ },
324
+ f: F
325
+ };
326
+ }
327
+ throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
328
+ }
329
+ var o, a = !0, u = !1;
330
+ return {
331
+ s: function() {
332
+ t = t.call(r);
333
+ },
334
+ n: function() {
335
+ var r = t.next();
336
+ return a = r.done, r;
337
+ },
338
+ e: function(r) {
339
+ u = !0, o = r;
340
+ },
341
+ f: function() {
342
+ try {
343
+ a || null == t.return || t.return();
344
+ } finally {
345
+ if (u) throw o;
346
+ }
347
+ }
348
+ };
349
+ }
303
350
  function _defineProperty(e, r, t) {
304
351
  return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, {
305
352
  value: t,
@@ -720,6 +767,219 @@ function initJscadutils(_CSG, options = {}) {
720
767
  c[3] = g || 1;
721
768
  return o.setColor(c);
722
769
  }
770
+ function validateCSG(csg, options) {
771
+ var errors = [];
772
+ var warnings = [];
773
+ if (!csg || !csg.polygons || csg.polygons.length === 0) {
774
+ errors.push("Empty mesh: no polygons");
775
+ return {
776
+ ok: false,
777
+ errors,
778
+ warnings
779
+ };
780
+ }
781
+ var opts = _objectSpread2({
782
+ fixTJunctions: true
783
+ }, options);
784
+ if (opts.fixTJunctions && typeof csg.canonicalized === "function") {
785
+ csg = csg.canonicalized();
786
+ if (typeof csg.reTesselated === "function") {
787
+ csg = csg.reTesselated();
788
+ }
789
+ if (typeof csg.fixTJunctions === "function") {
790
+ csg = csg.fixTJunctions();
791
+ }
792
+ }
793
+ var AREA_EPS = 1e-10;
794
+ var KEY_EPS = 1e-5;
795
+ var degenerateCount = 0;
796
+ var invalidVertexCount = 0;
797
+ var _iterator = _createForOfIteratorHelper(csg.polygons), _step;
798
+ try {
799
+ for (_iterator.s(); !(_step = _iterator.n()).done; ) {
800
+ var npoly = _step.value;
801
+ var _iterator4 = _createForOfIteratorHelper(npoly.vertices), _step4;
802
+ try {
803
+ for (_iterator4.s(); !(_step4 = _iterator4.n()).done; ) {
804
+ var nvert = _step4.value;
805
+ var np = nvert.pos;
806
+ 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)) {
807
+ invalidVertexCount++;
808
+ break;
809
+ }
810
+ }
811
+ } catch (err) {
812
+ _iterator4.e(err);
813
+ } finally {
814
+ _iterator4.f();
815
+ }
816
+ }
817
+ } catch (err) {
818
+ _iterator.e(err);
819
+ } finally {
820
+ _iterator.f();
821
+ }
822
+ if (invalidVertexCount > 0) {
823
+ errors.push(invalidVertexCount + " polygon(s) with invalid vertex coordinates (NaN or Infinity)");
824
+ }
825
+ function vtxKey(v) {
826
+ var p = v.pos;
827
+ return Math.round(p.x / KEY_EPS) + "," + Math.round(p.y / KEY_EPS) + "," + Math.round(p.z / KEY_EPS);
828
+ }
829
+ var validPolygons = [];
830
+ var _iterator2 = _createForOfIteratorHelper(csg.polygons), _step2;
831
+ try {
832
+ for (_iterator2.s(); !(_step2 = _iterator2.n()).done; ) {
833
+ var poly = _step2.value;
834
+ var verts = poly.vertices;
835
+ var nv = verts.length;
836
+ if (nv < 3) {
837
+ degenerateCount++;
838
+ continue;
839
+ }
840
+ var hasInvalid = false;
841
+ var _iterator5 = _createForOfIteratorHelper(verts), _step5;
842
+ try {
843
+ for (_iterator5.s(); !(_step5 = _iterator5.n()).done; ) {
844
+ var vert = _step5.value;
845
+ var ip = vert.pos;
846
+ if (!Number.isFinite(ip.x) || !Number.isFinite(ip.y) || !Number.isFinite(ip.z)) {
847
+ hasInvalid = true;
848
+ break;
849
+ }
850
+ }
851
+ } catch (err) {
852
+ _iterator5.e(err);
853
+ } finally {
854
+ _iterator5.f();
855
+ }
856
+ if (hasInvalid) continue;
857
+ var area = 0;
858
+ for (var ai = 0; ai < nv - 2; ai++) {
859
+ area += verts[ai + 1].pos.minus(verts[0].pos).cross(verts[ai + 2].pos.minus(verts[ai + 1].pos)).length();
860
+ }
861
+ area *= .5;
862
+ if (area < AREA_EPS) {
863
+ degenerateCount++;
864
+ continue;
865
+ }
866
+ validPolygons.push(poly);
867
+ }
868
+ } catch (err) {
869
+ _iterator2.e(err);
870
+ } finally {
871
+ _iterator2.f();
872
+ }
873
+ if (degenerateCount > 0) {
874
+ warnings.push(degenerateCount + " degenerate polygon(s) (fewer than 3 vertices or near-zero area)");
875
+ if (opts.fixTJunctions && typeof CSG !== "undefined") {
876
+ var cleaned = CSG.fromPolygons(validPolygons);
877
+ cleaned = cleaned.canonicalized();
878
+ if (typeof cleaned.reTesselated === "function") {
879
+ cleaned = cleaned.reTesselated();
880
+ }
881
+ if (typeof cleaned.fixTJunctions === "function") {
882
+ cleaned = cleaned.fixTJunctions();
883
+ }
884
+ validPolygons = [];
885
+ var _iterator3 = _createForOfIteratorHelper(cleaned.polygons), _step3;
886
+ try {
887
+ for (_iterator3.s(); !(_step3 = _iterator3.n()).done; ) {
888
+ var cpoly = _step3.value;
889
+ var cverts = cpoly.vertices;
890
+ var cnv = cverts.length;
891
+ if (cnv < 3) continue;
892
+ var carea = 0;
893
+ for (var cai = 0; cai < cnv - 2; cai++) {
894
+ carea += cverts[cai + 1].pos.minus(cverts[0].pos).cross(cverts[cai + 2].pos.minus(cverts[cai + 1].pos)).length();
895
+ }
896
+ carea *= .5;
897
+ if (carea < AREA_EPS) continue;
898
+ validPolygons.push(cpoly);
899
+ }
900
+ } catch (err) {
901
+ _iterator3.e(err);
902
+ } finally {
903
+ _iterator3.f();
904
+ }
905
+ }
906
+ }
907
+ var edgeCounts = {};
908
+ for (var _i = 0, _validPolygons = validPolygons; _i < _validPolygons.length; _i++) {
909
+ var vpoly = _validPolygons[_i];
910
+ var vverts = vpoly.vertices;
911
+ var vnv = vverts.length;
912
+ for (var ei = 0; ei < vnv; ei++) {
913
+ var v0 = vverts[ei];
914
+ var v1 = vverts[(ei + 1) % vnv];
915
+ var edgeKey = vtxKey(v0) + "/" + vtxKey(v1);
916
+ edgeCounts[edgeKey] = (edgeCounts[edgeKey] || 0) + 1;
917
+ }
918
+ }
919
+ var unmatchedEdges = 0;
920
+ var nonManifoldEdges = 0;
921
+ var checked = {};
922
+ for (var _i2 = 0, _Object$keys = Object.keys(edgeCounts); _i2 < _Object$keys.length; _i2++) {
923
+ var _edgeKey = _Object$keys[_i2];
924
+ if (checked[_edgeKey]) continue;
925
+ var parts = _edgeKey.split("/");
926
+ var reverseKey = parts[1] + "/" + parts[0];
927
+ var forwardCount = edgeCounts[_edgeKey] || 0;
928
+ var reverseCount = edgeCounts[reverseKey] || 0;
929
+ checked[_edgeKey] = true;
930
+ checked[reverseKey] = true;
931
+ if (forwardCount !== reverseCount) {
932
+ unmatchedEdges += Math.abs(forwardCount - reverseCount);
933
+ }
934
+ if (forwardCount > 1 || reverseCount > 1) {
935
+ nonManifoldEdges++;
936
+ }
937
+ }
938
+ if (unmatchedEdges > 0) {
939
+ errors.push(unmatchedEdges + " unmatched edge(s): mesh is not watertight");
940
+ }
941
+ if (nonManifoldEdges > 0) {
942
+ errors.push(nonManifoldEdges + " non-manifold edge(s): edge shared by more than 2 polygons");
943
+ }
944
+ return {
945
+ ok: errors.length === 0,
946
+ errors,
947
+ warnings
948
+ };
949
+ }
950
+ function _noOp(csg) {
951
+ return csg;
952
+ }
953
+ function _makeAssertFn(warnEnabled) {
954
+ return function _assert(csg) {
955
+ var functionName = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : "unknown";
956
+ var moduleName = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : "unknown";
957
+ if (!csg || csg.polygons === undefined) return csg;
958
+ var result = validateCSG(csg);
959
+ if (!result.ok) {
960
+ throw new Error(moduleName + ":" + functionName + ": " + "invalid CSG: " + result.errors.join(", "));
961
+ }
962
+ if (warnEnabled && result.warnings.length > 0) {
963
+ throw new Error(moduleName + ":" + functionName + ": " + "CSG warnings: " + result.warnings.join(", "));
964
+ }
965
+ return csg;
966
+ };
967
+ }
968
+ var _assertFn = _noOp;
969
+ function _resolveFromGlobals() {
970
+ var enabled = typeof jscadUtilsAssertValidCSG !== "undefined" && !!jscadUtilsAssertValidCSG;
971
+ var warnEnabled = typeof jscadUtilsAssertValidCSGWarnings !== "undefined" && !!jscadUtilsAssertValidCSGWarnings;
972
+ return enabled ? _makeAssertFn(warnEnabled) : _noOp;
973
+ }
974
+ function AssertValidCSG() {
975
+ var moduleName = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : "unknown";
976
+ {
977
+ _assertFn = _resolveFromGlobals();
978
+ }
979
+ return function(csg, name) {
980
+ return _assertFn(csg, name, moduleName);
981
+ };
982
+ }
723
983
  function init(proto) {
724
984
  if (proto.prototype._jscadutilsinit) return;
725
985
  proto.prototype.color = function(r, g, b, a) {
@@ -813,6 +1073,9 @@ function initJscadutils(_CSG, options = {}) {
813
1073
  proto.prototype.subtractIf = function subtractIf(object, condition) {
814
1074
  return condition ? this.subtract(result(this, object)) : this;
815
1075
  };
1076
+ proto.prototype.validate = function validate(options) {
1077
+ return validateCSG(this, options);
1078
+ };
816
1079
  proto.prototype._translate = proto.prototype.translate;
817
1080
  proto.prototype.translate = function translate() {
818
1081
  if (arguments.length === 1) {
@@ -845,12 +1108,13 @@ function initJscadutils(_CSG, options = {}) {
845
1108
  __proto__: null,
846
1109
  default: init
847
1110
  });
848
- var CSG = jsCadCSG__default["default"].CSG, CAG = jsCadCSG__default["default"].CAG;
1111
+ var CSG$1 = jsCadCSG__default["default"].CSG, CAG = jsCadCSG__default["default"].CAG;
849
1112
  var rectangular_extrude = scadApi__default["default"].extrusions.rectangular_extrude;
850
1113
  var _scadApi$text = scadApi__default["default"].text, vector_text = _scadApi$text.vector_text, vector_char = _scadApi$text.vector_char;
851
1114
  var union = scadApi__default["default"].booleanOps.union;
852
- init(CSG);
1115
+ init(CSG$1);
853
1116
  var debug$3 = Debug("jscadUtils:group");
1117
+ var assertValidCSG$2 = AssertValidCSG("group");
854
1118
  function JsCadUtilsGroup() {
855
1119
  var names = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];
856
1120
  var parts = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
@@ -901,7 +1165,7 @@ function initJscadutils(_CSG, options = {}) {
901
1165
  debug$3("combine mapPick", value, key, object);
902
1166
  return map ? map(value, key, index, object) : identity(value);
903
1167
  }, self.name));
904
- return g.subtractIf(self.holes && Array.isArray(self.holes) ? union(self.holes) : self.holes, self.holes && !options.noholes);
1168
+ return assertValidCSG$2(g.subtractIf(self.holes && Array.isArray(self.holes) ? union(self.holes) : self.holes, self.holes && !options.noholes), "combine");
905
1169
  } catch (err) {
906
1170
  debug$3("combine error", this, pieces, options, err);
907
1171
  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");
@@ -942,7 +1206,7 @@ function initJscadutils(_CSG, options = {}) {
942
1206
  });
943
1207
  if (self.holes) {
944
1208
  group.holes = toArray(self.holes).map(function(part) {
945
- return map(CSG.fromPolygons(part.toPolygons()), "holes");
1209
+ return assertValidCSG$2(map(CSG$1.fromPolygons(part.toPolygons()), "holes"), "clone");
946
1210
  });
947
1211
  }
948
1212
  return group;
@@ -961,7 +1225,7 @@ function initJscadutils(_CSG, options = {}) {
961
1225
  var rotationCenter = solid.centroid();
962
1226
  var rotationAxis = axes[axis];
963
1227
  self.map(function(part) {
964
- return part.rotate(rotationCenter, rotationAxis, angle);
1228
+ return assertValidCSG$2(part.rotate(rotationCenter, rotationAxis, angle), "rotate");
965
1229
  });
966
1230
  return self;
967
1231
  };
@@ -974,7 +1238,7 @@ function initJscadutils(_CSG, options = {}) {
974
1238
  var self = this;
975
1239
  var t = calcSnap(self.combine(part), to, axis, orientation, delta);
976
1240
  self.map(function(part) {
977
- return part.translate(t);
1241
+ return assertValidCSG$2(part.translate(t), "snap");
978
1242
  });
979
1243
  return self;
980
1244
  } catch (err) {
@@ -989,7 +1253,7 @@ function initJscadutils(_CSG, options = {}) {
989
1253
  noholes: true
990
1254
  }), axis, to, delta);
991
1255
  self.map(function(part) {
992
- return part.translate(t);
1256
+ return assertValidCSG$2(part.translate(t), "align");
993
1257
  });
994
1258
  return self;
995
1259
  } catch (err) {
@@ -1021,14 +1285,14 @@ function initJscadutils(_CSG, options = {}) {
1021
1285
  var myConnector = connectorName.split(".").reduce(function(a, v) {
1022
1286
  return a[v];
1023
1287
  }, self.parts[partName].properties);
1024
- debug$3("toConnector", to instanceof CSG.Connector);
1288
+ debug$3("toConnector", to instanceof CSG$1.Connector);
1025
1289
  var toConnector = toConnectorName.split(".").reduce(function(a, v) {
1026
1290
  return a[v];
1027
1291
  }, to.properties);
1028
1292
  var matrix = myConnector.getTransformationTo(toConnector, mirror, normalrotation);
1029
1293
  debug$3("connectTo", matrix);
1030
1294
  self.map(function(part) {
1031
- return part.transform(matrix);
1295
+ return assertValidCSG$2(part.transform(matrix), "connectTo");
1032
1296
  });
1033
1297
  return self;
1034
1298
  };
@@ -1039,7 +1303,7 @@ function initJscadutils(_CSG, options = {}) {
1039
1303
  return to - size[a] / 2;
1040
1304
  });
1041
1305
  self.map(function(part) {
1042
- return part.translate(t);
1306
+ return assertValidCSG$2(part.translate(t), "midlineTo");
1043
1307
  });
1044
1308
  return self;
1045
1309
  };
@@ -1048,7 +1312,7 @@ function initJscadutils(_CSG, options = {}) {
1048
1312
  var t = Array.isArray(x) ? x : [ x, y, z ];
1049
1313
  debug$3("translate", t);
1050
1314
  self.map(function(part) {
1051
- return part.translate(t);
1315
+ return assertValidCSG$2(part.translate(t), "translate");
1052
1316
  });
1053
1317
  return self;
1054
1318
  };
@@ -1058,7 +1322,7 @@ function initJscadutils(_CSG, options = {}) {
1058
1322
  if (!map) map = identity;
1059
1323
  var g = Group();
1060
1324
  p.forEach(function(name) {
1061
- g.add(map(CSG.fromPolygons(self.parts[name].toPolygons()), name), name);
1325
+ g.add(assertValidCSG$2(map(CSG$1.fromPolygons(self.parts[name].toPolygons()), name), "pick"), name);
1062
1326
  });
1063
1327
  return g;
1064
1328
  };
@@ -1073,7 +1337,7 @@ function initJscadutils(_CSG, options = {}) {
1073
1337
  debug$3("array error", _this, parts);
1074
1338
  throw error('group::array error "'.concat(name, '" not found.\nthis: ').concat(_this, '\nparts: "').concat(parts, '"\n'), "JSCAD_UTILS_GROUP_ERROR");
1075
1339
  }
1076
- a.push(map(CSG.fromPolygons(self.parts[name].toPolygons()), name));
1340
+ a.push(assertValidCSG$2(map(CSG$1.fromPolygons(self.parts[name].toPolygons()), name), "array"));
1077
1341
  });
1078
1342
  return a;
1079
1343
  };
@@ -1106,7 +1370,7 @@ function initJscadutils(_CSG, options = {}) {
1106
1370
  self.names = names && names.length > 0 && names.split(",") || [];
1107
1371
  if (Array.isArray(objects)) {
1108
1372
  self.parts = zipObject(self.names, objects);
1109
- } else if (objects instanceof CSG) {
1373
+ } else if (objects instanceof CSG$1) {
1110
1374
  self.parts = zipObject(self.names, [ objects ]);
1111
1375
  } else {
1112
1376
  self.parts = objects || {};
@@ -1127,6 +1391,7 @@ function initJscadutils(_CSG, options = {}) {
1127
1391
  return new JsCadUtilsGroup(self.names, self.parts, self.holes);
1128
1392
  }
1129
1393
  var debug$2 = Debug("jscadUtils:util");
1394
+ var assertValidCSG$1 = AssertValidCSG("util");
1130
1395
  var NOZZEL_SIZE = .4;
1131
1396
  var nearest = {
1132
1397
  under: function under(desired) {
@@ -1203,12 +1468,12 @@ function initJscadutils(_CSG, options = {}) {
1203
1468
  h: height || 2
1204
1469
  }));
1205
1470
  });
1206
- return center(union(o));
1471
+ return assertValidCSG$1(center(union(o)), "label");
1207
1472
  }
1208
1473
  function text(text) {
1209
1474
  var l = vector_char(0, 0, text);
1210
1475
  var _char = l.segments.reduce(function(result, segment) {
1211
- var path = new CSG.Path2D(segment);
1476
+ var path = new CSG$1.Path2D(segment);
1212
1477
  var cag = path.expandToCAG(2);
1213
1478
  return result ? result.union(cag) : cag;
1214
1479
  }, undefined);
@@ -1216,17 +1481,17 @@ function initJscadutils(_CSG, options = {}) {
1216
1481
  }
1217
1482
  function unitCube(length, radius) {
1218
1483
  radius = radius || .5;
1219
- return CSG.cube({
1484
+ return assertValidCSG$1(CSG$1.cube({
1220
1485
  center: [ 0, 0, 0 ],
1221
1486
  radius: [ radius, radius, length || .5 ]
1222
- });
1487
+ }), "unitCube");
1223
1488
  }
1224
1489
  function unitAxis(length, radius, centroid) {
1225
1490
  debug$2("unitAxis", length, radius, centroid);
1226
1491
  centroid = centroid || [ 0, 0, 0 ];
1227
1492
  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) ]);
1228
- unitaxis.properties.origin = new CSG.Connector([ 0, 0, 0 ], [ 1, 0, 0 ], [ 0, 1, 0 ]);
1229
- return unitaxis.translate(centroid);
1493
+ unitaxis.properties.origin = new CSG$1.Connector([ 0, 0, 0 ], [ 1, 0, 0 ], [ 0, 1, 0 ]);
1494
+ return assertValidCSG$1(unitaxis.translate(centroid), "unitAxis");
1230
1495
  }
1231
1496
  function toArray(a) {
1232
1497
  return Array.isArray(a) ? a : [ a ];
@@ -1316,15 +1581,15 @@ function initJscadutils(_CSG, options = {}) {
1316
1581
  }
1317
1582
  function center(object, objectSize) {
1318
1583
  objectSize = objectSize || size(object.getBounds());
1319
- return centerY(centerX(object, objectSize), objectSize);
1584
+ return assertValidCSG$1(centerY(centerX(object, objectSize), objectSize), "center");
1320
1585
  }
1321
1586
  function centerY(object, objectSize) {
1322
1587
  objectSize = objectSize || size(object.getBounds());
1323
- return object.translate([ 0, -objectSize.y / 2, 0 ]);
1588
+ return assertValidCSG$1(object.translate([ 0, -objectSize.y / 2, 0 ]), "centerY");
1324
1589
  }
1325
1590
  function centerX(object, objectSize) {
1326
1591
  objectSize = objectSize || size(object.getBounds());
1327
- return object.translate([ -objectSize.x / 2, 0, 0 ]);
1592
+ return assertValidCSG$1(object.translate([ -objectSize.x / 2, 0, 0 ]), "centerX");
1328
1593
  }
1329
1594
  function enlarge(object, x, y, z) {
1330
1595
  var a;
@@ -1342,7 +1607,7 @@ function initJscadutils(_CSG, options = {}) {
1342
1607
  var new_object = object.scale(t);
1343
1608
  var new_centroid = centroid(new_object);
1344
1609
  var delta = new_centroid.minus(objectCentroid).times(-1);
1345
- return new_object.translate(delta);
1610
+ return assertValidCSG$1(new_object.translate(delta), "enlarge");
1346
1611
  }
1347
1612
  function fit(object, x, y, z, keep_aspect_ratio) {
1348
1613
  var a;
@@ -1362,10 +1627,10 @@ function initJscadutils(_CSG, options = {}) {
1362
1627
  }
1363
1628
  var s = [ scale(objectSize.x, x), scale(objectSize.y, y), scale(objectSize.z, z) ];
1364
1629
  var min$1 = min(s);
1365
- return centerWith(object.scale(s.map(function(d, i) {
1630
+ return assertValidCSG$1(centerWith(object.scale(s.map(function(d, i) {
1366
1631
  if (a[i] === 0) return 1;
1367
1632
  return keep_aspect_ratio ? min$1 : d;
1368
- })), "xyz", object);
1633
+ })), "xyz", object), "fit");
1369
1634
  }
1370
1635
  function shift(object, x, y, z) {
1371
1636
  var hsize = this.div(this.size(object.getBounds()), 2);
@@ -1373,10 +1638,10 @@ function initJscadutils(_CSG, options = {}) {
1373
1638
  }
1374
1639
  function zero(object) {
1375
1640
  var bounds = object.getBounds();
1376
- return object.translate([ 0, 0, -bounds[0].z ]);
1641
+ return assertValidCSG$1(object.translate([ 0, 0, -bounds[0].z ]), "zero");
1377
1642
  }
1378
1643
  function mirrored4(x) {
1379
- return x.union([ x.mirroredY(90), x.mirroredX(90), x.mirroredY(90).mirroredX(90) ]);
1644
+ return assertValidCSG$1(x.union([ x.mirroredY(90), x.mirroredX(90), x.mirroredY(90).mirroredX(90) ]), "mirrored4");
1380
1645
  }
1381
1646
  var flushSide = {
1382
1647
  "above-outside": [ 1, 0 ],
@@ -1437,10 +1702,10 @@ function initJscadutils(_CSG, options = {}) {
1437
1702
  function snap(moveobj, withobj, axis, orientation, delta) {
1438
1703
  debug$2("snap", moveobj, withobj, axis, orientation, delta);
1439
1704
  var t = calcSnap(moveobj, withobj, axis, orientation, delta);
1440
- return moveobj.translate(t);
1705
+ return assertValidCSG$1(moveobj.translate(t), "snap");
1441
1706
  }
1442
1707
  function flush(moveobj, withobj, axis, mside, wside) {
1443
- return moveobj.translate(calcFlush(moveobj, withobj, axis, mside, wside));
1708
+ return assertValidCSG$1(moveobj.translate(calcFlush(moveobj, withobj, axis, mside, wside)), "flush");
1444
1709
  }
1445
1710
  function axisApply(axes, valfun, a) {
1446
1711
  debug$2("axisApply", axes, valfun, a);
@@ -1456,7 +1721,7 @@ function initJscadutils(_CSG, options = {}) {
1456
1721
  return retval;
1457
1722
  }
1458
1723
  function axis2array(axes, valfun) {
1459
- depreciated("axis2array");
1724
+ depreciated("axis2array", false, "Use axisApply instead.");
1460
1725
  var a = [ 0, 0, 0 ];
1461
1726
  var lookup = {
1462
1727
  x: 0,
@@ -1486,7 +1751,7 @@ function initJscadutils(_CSG, options = {}) {
1486
1751
  });
1487
1752
  }
1488
1753
  function midlineTo(o, axis, to) {
1489
- return o.translate(calcmidlineTo(o, axis, to));
1754
+ return assertValidCSG$1(o.translate(calcmidlineTo(o, axis, to)), "midlineTo");
1490
1755
  }
1491
1756
  function translator(o, axis, withObj) {
1492
1757
  var objectCentroid = centroid(o);
@@ -1506,7 +1771,7 @@ function initJscadutils(_CSG, options = {}) {
1506
1771
  return delta ? add(t, delta) : t;
1507
1772
  }
1508
1773
  function centerWith(o, axis, withObj) {
1509
- return o.translate(calcCenterWith(o, axis, withObj));
1774
+ return assertValidCSG$1(o.translate(calcCenterWith(o, axis, withObj)), "centerWith");
1510
1775
  }
1511
1776
  function getDelta(size, bounds, axis, offset, nonzero) {
1512
1777
  if (!isEmpty(offset) && nonzero) {
@@ -1519,6 +1784,95 @@ function initJscadutils(_CSG, options = {}) {
1519
1784
  return bounds[0][a] + (isEmpty(dist) ? size[axis] / 2 : dist);
1520
1785
  });
1521
1786
  }
1787
+ var EPS = 1e-5;
1788
+ function splitCSGByPlane(csg, plane) {
1789
+ var frontPolys = [];
1790
+ var backPolys = [];
1791
+ csg.polygons.forEach(function(poly) {
1792
+ var vertices = poly.vertices;
1793
+ var numVerts = vertices.length;
1794
+ var hasfront = false;
1795
+ var hasback = false;
1796
+ var vertexIsBack = [];
1797
+ for (var i = 0; i < numVerts; i++) {
1798
+ var t = plane.normal.dot(vertices[i].pos) - plane.w;
1799
+ vertexIsBack.push(t < 0);
1800
+ if (t > EPS) hasfront = true;
1801
+ if (t < -EPS) hasback = true;
1802
+ }
1803
+ if (!hasfront && !hasback) {
1804
+ var d = plane.normal.dot(poly.plane.normal);
1805
+ if (d >= 0) {
1806
+ frontPolys.push(poly);
1807
+ } else {
1808
+ backPolys.push(poly);
1809
+ }
1810
+ } else if (!hasback) {
1811
+ frontPolys.push(poly);
1812
+ } else if (!hasfront) {
1813
+ backPolys.push(poly);
1814
+ } else {
1815
+ var fv = [];
1816
+ var bv = [];
1817
+ for (var vi = 0; vi < numVerts; vi++) {
1818
+ var vertex = vertices[vi];
1819
+ var nextVi = (vi + 1) % numVerts;
1820
+ var isback = vertexIsBack[vi];
1821
+ var nextisback = vertexIsBack[nextVi];
1822
+ if (isback === nextisback) {
1823
+ if (isback) {
1824
+ bv.push(vertex);
1825
+ } else {
1826
+ fv.push(vertex);
1827
+ }
1828
+ } else {
1829
+ var point = vertex.pos;
1830
+ var nextpoint = vertices[nextVi].pos;
1831
+ var ip = plane.splitLineBetweenPoints(point, nextpoint);
1832
+ var iv = new CSG$1.Vertex(ip);
1833
+ if (isback) {
1834
+ bv.push(vertex);
1835
+ bv.push(iv);
1836
+ fv.push(iv);
1837
+ } else {
1838
+ fv.push(vertex);
1839
+ fv.push(iv);
1840
+ bv.push(iv);
1841
+ }
1842
+ }
1843
+ }
1844
+ var EPSEPS = EPS * EPS;
1845
+ if (fv.length >= 3) {
1846
+ var prev = fv[fv.length - 1];
1847
+ for (var fi = 0; fi < fv.length; fi++) {
1848
+ var curr = fv[fi];
1849
+ if (curr.pos.distanceToSquared(prev.pos) < EPSEPS) {
1850
+ fv.splice(fi, 1);
1851
+ fi--;
1852
+ }
1853
+ prev = curr;
1854
+ }
1855
+ }
1856
+ if (bv.length >= 3) {
1857
+ var prev = bv[bv.length - 1];
1858
+ for (var bi = 0; bi < bv.length; bi++) {
1859
+ var curr = bv[bi];
1860
+ if (curr.pos.distanceToSquared(prev.pos) < EPSEPS) {
1861
+ bv.splice(bi, 1);
1862
+ bi--;
1863
+ }
1864
+ prev = curr;
1865
+ }
1866
+ }
1867
+ if (fv.length >= 3) frontPolys.push(new CSG$1.Polygon(fv, poly.shared, poly.plane));
1868
+ if (bv.length >= 3) backPolys.push(new CSG$1.Polygon(bv, poly.shared, poly.plane));
1869
+ }
1870
+ });
1871
+ return {
1872
+ front: CSG$1.fromPolygons(frontPolys),
1873
+ back: CSG$1.fromPolygons(backPolys)
1874
+ };
1875
+ }
1522
1876
  function bisect() {
1523
1877
  for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
1524
1878
  args[_key] = arguments[_key];
@@ -1580,13 +1934,13 @@ function initJscadutils(_CSG, options = {}) {
1580
1934
  }[[ axis, rotateaxis ].sort().join("")];
1581
1935
  var centroid = object.centroid();
1582
1936
  var rotateDelta = getDelta(objectSize, bounds, rotateOffsetAxis, rotateoffset);
1583
- var rotationCenter = options.rotationCenter || new CSG.Vector3D(axisApply("xyz", function(i, a) {
1937
+ var rotationCenter = options.rotationCenter || new CSG$1.Vector3D(axisApply("xyz", function(i, a) {
1584
1938
  if (a == axis) return cutDelta[i];
1585
1939
  if (a == rotateOffsetAxis) return rotateDelta[i];
1586
1940
  return centroid[a];
1587
1941
  }));
1588
1942
  var theRotationAxis = rotationAxes[rotateaxis];
1589
- var cutplane = CSG.OrthoNormalBasis.GetCartesian(info.orthoNormalCartesian[0], info.orthoNormalCartesian[1]).translate(cutDelta).rotate(rotationCenter, theRotationAxis, angle);
1943
+ var cutplane = CSG$1.OrthoNormalBasis.GetCartesian(info.orthoNormalCartesian[0], info.orthoNormalCartesian[1]).translate(cutDelta).rotate(rotationCenter, theRotationAxis, angle);
1590
1944
  debug$2("bisect", debug$2.enabled && {
1591
1945
  axis,
1592
1946
  offset,
@@ -1599,7 +1953,26 @@ function initJscadutils(_CSG, options = {}) {
1599
1953
  cutplane,
1600
1954
  options
1601
1955
  });
1602
- var g = Group("negative,positive", [ object.cutByPlane(cutplane.plane).color(options.color && "red"), object.cutByPlane(cutplane.plane.flipped()).color(options.color && "blue") ]);
1956
+ var negative = object.cutByPlane(cutplane.plane);
1957
+ var positive = object.cutByPlane(cutplane.plane.flipped());
1958
+ var negSize = size(negative);
1959
+ var posSize = size(positive);
1960
+ if (negSize[axis] >= objectSize[axis] - EPS || posSize[axis] >= objectSize[axis] - EPS) {
1961
+ var halves = splitCSGByPlane(object, cutplane.plane);
1962
+ if (negSize[axis] >= objectSize[axis] - EPS) {
1963
+ negative = halves.back;
1964
+ try {
1965
+ negative = negative.cutByPlane(cutplane.plane);
1966
+ } catch (e) {}
1967
+ }
1968
+ if (posSize[axis] >= objectSize[axis] - EPS) {
1969
+ positive = halves.front;
1970
+ try {
1971
+ positive = positive.cutByPlane(cutplane.plane.flipped());
1972
+ } catch (e) {}
1973
+ }
1974
+ }
1975
+ var g = Group("negative,positive", [ negative.color(options.color && "red"), positive.color(options.color && "blue") ]);
1603
1976
  if (options.addRotationCenter) g.add(unitAxis(objectSize.length() + 10, .1, rotationCenter), "rotationCenter");
1604
1977
  return g;
1605
1978
  }
@@ -1612,9 +1985,9 @@ function initJscadutils(_CSG, options = {}) {
1612
1985
  addRotationCenter: true
1613
1986
  };
1614
1987
  var info = normalVector(axis);
1615
- var rotationCenter = options.rotationCenter || new CSG.Vector3D(0, 0, 0);
1988
+ var rotationCenter = options.rotationCenter || new CSG$1.Vector3D(0, 0, 0);
1616
1989
  var theRotationAxis = rotationAxes[rotateaxis];
1617
- var cutplane = CSG.OrthoNormalBasis.GetCartesian(info.orthoNormalCartesian[0], info.orthoNormalCartesian[1]).rotate(rotationCenter, theRotationAxis, angle);
1990
+ var cutplane = CSG$1.OrthoNormalBasis.GetCartesian(info.orthoNormalCartesian[0], info.orthoNormalCartesian[1]).rotate(rotationCenter, theRotationAxis, angle);
1618
1991
  var g = Group("negative,positive", [ object.cutByPlane(cutplane.plane).color(options.color && "red"), object.cutByPlane(cutplane.plane.flipped()).color(options.color && "blue") ]);
1619
1992
  if (options.addRotationCenter) {
1620
1993
  var objectSize = size(object);
@@ -1639,14 +2012,14 @@ function initJscadutils(_CSG, options = {}) {
1639
2012
  var bounds = object.getBounds();
1640
2013
  var objectSize = size(object);
1641
2014
  var cutDelta = getDelta(objectSize, bounds, axis, offset, true);
1642
- return object.stretchAtPlane(normal[axis], cutDelta, distance);
2015
+ return assertValidCSG$1(object.stretchAtPlane(normal[axis], cutDelta, distance), "stretch");
1643
2016
  }
1644
2017
  function poly2solid(top, bottom, height) {
1645
2018
  if (top.sides.length == 0) {
1646
- return new CSG;
2019
+ return new CSG$1;
1647
2020
  }
1648
- var offsetVector = CSG.Vector3D.Create(0, 0, height);
1649
- var normalVector = CSG.Vector3D.Create(0, 1, 0);
2021
+ var offsetVector = CSG$1.Vector3D.Create(0, 0, height);
2022
+ var normalVector = CSG$1.Vector3D.Create(0, 1, 0);
1650
2023
  var polygons = [];
1651
2024
  polygons = polygons.concat(bottom._toPlanePolygons({
1652
2025
  translation: [ 0, 0, 0 ],
@@ -1658,14 +2031,14 @@ function initJscadutils(_CSG, options = {}) {
1658
2031
  normalVector,
1659
2032
  flipped: offsetVector.z < 0
1660
2033
  }));
1661
- var c1 = new CSG.Connector(offsetVector.times(0), [ 0, 0, offsetVector.z ], normalVector);
1662
- var c2 = new CSG.Connector(offsetVector, [ 0, 0, offsetVector.z ], normalVector);
2034
+ var c1 = new CSG$1.Connector(offsetVector.times(0), [ 0, 0, offsetVector.z ], normalVector);
2035
+ var c2 = new CSG$1.Connector(offsetVector, [ 0, 0, offsetVector.z ], normalVector);
1663
2036
  polygons = polygons.concat(bottom._toWallPolygons({
1664
2037
  cag: top,
1665
2038
  toConnector1: c1,
1666
2039
  toConnector2: c2
1667
2040
  }));
1668
- return CSG.fromPolygons(polygons);
2041
+ return assertValidCSG$1(CSG$1.fromPolygons(polygons), "poly2solid");
1669
2042
  }
1670
2043
  function slices2poly(slices, options, axis) {
1671
2044
  debug$2("slices2poly", slices, options, axis);
@@ -1674,7 +2047,7 @@ function initJscadutils(_CSG, options = {}) {
1674
2047
  twiststeps: 0
1675
2048
  }, options);
1676
2049
  var twistangle = options && parseFloat(options.twistangle) || 0;
1677
- options && parseInt(options.twiststeps) || CSG.defaultResolution3D;
2050
+ options && parseInt(options.twiststeps) || CSG$1.defaultResolution3D;
1678
2051
  var normalVector = options.si.normalVector;
1679
2052
  var polygons = [];
1680
2053
  var first$1 = first(slices);
@@ -1703,8 +2076,8 @@ function initJscadutils(_CSG, options = {}) {
1703
2076
  var nextidx = idx + 1;
1704
2077
  var top = !up ? slices[nextidx] : slice;
1705
2078
  var bottom = up ? slices[nextidx] : slice;
1706
- var c1 = new CSG.Connector(bottom.offset, connectorAxis, rotate(normalVector, twistangle, idx / slices.length));
1707
- var c2 = new CSG.Connector(top.offset, connectorAxis, rotate(normalVector, twistangle, nextidx / slices.length));
2079
+ var c1 = new CSG$1.Connector(bottom.offset, connectorAxis, rotate(normalVector, twistangle, idx / slices.length));
2080
+ var c2 = new CSG$1.Connector(top.offset, connectorAxis, rotate(normalVector, twistangle, nextidx / slices.length));
1708
2081
  polygons = polygons.concat(bottom.poly._toWallPolygons({
1709
2082
  cag: top.poly,
1710
2083
  toConnector1: c1,
@@ -1712,21 +2085,21 @@ function initJscadutils(_CSG, options = {}) {
1712
2085
  }));
1713
2086
  }
1714
2087
  });
1715
- return CSG.fromPolygons(polygons);
2088
+ return assertValidCSG$1(CSG$1.fromPolygons(polygons), "slices2poly");
1716
2089
  }
1717
2090
  function normalVector(axis) {
1718
2091
  var axisInfo = {
1719
2092
  z: {
1720
2093
  orthoNormalCartesian: [ "X", "Y" ],
1721
- normalVector: CSG.Vector3D.Create(0, 1, 0)
2094
+ normalVector: CSG$1.Vector3D.Create(0, 1, 0)
1722
2095
  },
1723
2096
  x: {
1724
2097
  orthoNormalCartesian: [ "Y", "Z" ],
1725
- normalVector: CSG.Vector3D.Create(0, 0, 1)
2098
+ normalVector: CSG$1.Vector3D.Create(0, 0, 1)
1726
2099
  },
1727
2100
  y: {
1728
- orthoNormalCartesian: [ "X", "Z" ],
1729
- normalVector: CSG.Vector3D.Create(0, 0, 1)
2101
+ orthoNormalCartesian: [ "Z", "X" ],
2102
+ normalVector: CSG$1.Vector3D.Create(0, 0, 1)
1730
2103
  }
1731
2104
  };
1732
2105
  if (!axisInfo[axis]) error("normalVector: invalid axis " + axis);
@@ -1767,7 +2140,7 @@ function initJscadutils(_CSG, options = {}) {
1767
2140
  var si = sliceParams(orientation, radius, b);
1768
2141
  debug$2("reShape", absoluteRadius, si);
1769
2142
  if (si.axis !== "z") throw new Error('reShape error: CAG._toPlanePolygons only uses the "z" axis. You must use the "z" axis for now.');
1770
- var cutplane = CSG.OrthoNormalBasis.GetCartesian(si.orthoNormalCartesian[0], si.orthoNormalCartesian[1]).translate(si.cutDelta);
2143
+ var cutplane = CSG$1.OrthoNormalBasis.GetCartesian(si.orthoNormalCartesian[0], si.orthoNormalCartesian[1]).translate(si.cutDelta);
1771
2144
  var slice = object.sectionCut(cutplane);
1772
2145
  var first = axisApply(si.axis, function() {
1773
2146
  return si.positive ? 0 : absoluteRadius;
@@ -1782,25 +2155,25 @@ function initJscadutils(_CSG, options = {}) {
1782
2155
  si
1783
2156
  }), si.axis).color(options.color);
1784
2157
  var remainder = object.cutByPlane(plane);
1785
- return union([ options.unionOriginal ? object : remainder, delta.translate(si.moveDelta) ]);
2158
+ return assertValidCSG$1(union([ options.unionOriginal ? object : remainder, delta.translate(si.moveDelta) ]), "reShape");
1786
2159
  }
1787
2160
  function chamfer(object, radius, orientation, options) {
1788
- return reShape(object, radius, orientation, options, function(first, last, slice) {
2161
+ return assertValidCSG$1(reShape(object, radius, orientation, options, function(first, last, slice) {
1789
2162
  return [ {
1790
2163
  poly: slice,
1791
- offset: new CSG.Vector3D(first)
2164
+ offset: new CSG$1.Vector3D(first)
1792
2165
  }, {
1793
2166
  poly: enlarge(slice, [ -radius * 2, -radius * 2 ]),
1794
- offset: new CSG.Vector3D(last)
2167
+ offset: new CSG$1.Vector3D(last)
1795
2168
  } ];
1796
- });
2169
+ }), "chamfer");
1797
2170
  }
1798
2171
  function fillet(object, radius, orientation, options) {
1799
2172
  options = options || {};
1800
- return reShape(object, radius, orientation, options, function(first, last, slice) {
1801
- var v1 = new CSG.Vector3D(first);
1802
- var v2 = new CSG.Vector3D(last);
1803
- var res = options.resolution || CSG.defaultResolution3D;
2173
+ return assertValidCSG$1(reShape(object, radius, orientation, options, function(first, last, slice) {
2174
+ var v1 = new CSG$1.Vector3D(first);
2175
+ var v2 = new CSG$1.Vector3D(last);
2176
+ var res = options.resolution || CSG$1.defaultResolution3D;
1804
2177
  var slices = range(0, res).map(function(i) {
1805
2178
  var p = i > 0 ? i / (res - 1) : 0;
1806
2179
  var v = v1.lerp(v2, p);
@@ -1811,7 +2184,7 @@ function initJscadutils(_CSG, options = {}) {
1811
2184
  };
1812
2185
  });
1813
2186
  return slices;
1814
- });
2187
+ }), "fillet");
1815
2188
  }
1816
2189
  function calcRotate(part, solid, axis) {
1817
2190
  var axes = {
@@ -1828,7 +2201,7 @@ function initJscadutils(_CSG, options = {}) {
1828
2201
  }
1829
2202
  function rotateAround(part, solid, axis, angle) {
1830
2203
  var _calcRotate = calcRotate(part, solid, axis), rotationCenter = _calcRotate.rotationCenter, rotationAxis = _calcRotate.rotationAxis;
1831
- return part.rotate(rotationCenter, rotationAxis, angle);
2204
+ return assertValidCSG$1("rotateAround")(part.rotate(rotationCenter, rotationAxis, angle));
1832
2205
  }
1833
2206
  function cloneProperties(from, to) {
1834
2207
  return Object.entries(from).reduce(function(props, _ref) {
@@ -1838,19 +2211,20 @@ function initJscadutils(_CSG, options = {}) {
1838
2211
  }, to);
1839
2212
  }
1840
2213
  function clone(o) {
1841
- var c = CSG.fromPolygons(o.toPolygons());
2214
+ var c = CSG$1.fromPolygons(o.toPolygons());
1842
2215
  cloneProperties(o, c);
1843
- debug$2("clone", o, c, CSG);
1844
- return c;
2216
+ debug$2("clone", o, c, CSG$1);
2217
+ return assertValidCSG$1(c, "clone");
1845
2218
  }
1846
2219
  function addConnector(object, name) {
1847
2220
  var point = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : [ 0, 0, 0 ];
1848
2221
  var axis = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : [ 1, 0, 0 ];
1849
2222
  var normal = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : [ 0, 0, 1 ];
1850
- object.properties[name] = new CSG.Connector(point, axis, normal);
1851
- return object;
2223
+ object.properties[name] = new CSG$1.Connector(point, axis, normal);
2224
+ return assertValidCSG$1("addConnector")(object);
1852
2225
  }
1853
2226
  var debug$1 = Debug("jscadUtils:parts");
2227
+ var assertValidCSG = AssertValidCSG("parts");
1854
2228
  var parts = {
1855
2229
  BBox: BBox$1,
1856
2230
  Cube,
@@ -1860,7 +2234,7 @@ function initJscadutils(_CSG, options = {}) {
1860
2234
  };
1861
2235
  function BBox$1() {
1862
2236
  function box(object) {
1863
- return CSG.cube({
2237
+ return CSG$1.cube({
1864
2238
  center: object.centroid(),
1865
2239
  radius: object.size().dividedBy(2)
1866
2240
  });
@@ -1868,17 +2242,17 @@ function initJscadutils(_CSG, options = {}) {
1868
2242
  for (var _len = arguments.length, objects = new Array(_len), _key = 0; _key < _len; _key++) {
1869
2243
  objects[_key] = arguments[_key];
1870
2244
  }
1871
- return objects.reduce(function(bbox, part) {
2245
+ return assertValidCSG(objects.reduce(function(bbox, part) {
1872
2246
  var object = bbox ? union([ bbox, box(part) ]) : part;
1873
2247
  return box(object);
1874
- }, undefined);
2248
+ }, undefined), "BBox");
1875
2249
  }
1876
2250
  function Cube(width) {
1877
2251
  var r = div$1(fromxyz(width), 2);
1878
- return CSG.cube({
2252
+ return assertValidCSG(CSG$1.cube({
1879
2253
  center: r,
1880
2254
  radius: r
1881
- });
2255
+ }), "Cube");
1882
2256
  }
1883
2257
  function RoundedCube(x, y, thickness, corner_radius) {
1884
2258
  if (x.getBounds) {
@@ -1894,11 +2268,11 @@ function initJscadutils(_CSG, options = {}) {
1894
2268
  center: [ r[0], r[1], 0 ],
1895
2269
  radius: r,
1896
2270
  roundradius: corner_radius,
1897
- resolution: CSG.defaultResolution2D
2271
+ resolution: CSG$1.defaultResolution2D
1898
2272
  }).extrude({
1899
2273
  offset: [ 0, 0, thickness || 1.62 ]
1900
2274
  });
1901
- return roundedcube;
2275
+ return assertValidCSG(roundedcube, "RoundedCube");
1902
2276
  }
1903
2277
  function Cylinder(diameter, height) {
1904
2278
  var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
@@ -1907,39 +2281,39 @@ function initJscadutils(_CSG, options = {}) {
1907
2281
  start: [ 0, 0, 0 ],
1908
2282
  end: [ 0, 0, height ],
1909
2283
  radius: diameter / 2,
1910
- resolution: CSG.defaultResolution2D
2284
+ resolution: CSG$1.defaultResolution2D
1911
2285
  }, options);
1912
- return CSG.cylinder(options);
2286
+ return assertValidCSG(CSG$1.cylinder(options), "Cylinder");
1913
2287
  }
1914
2288
  function Cone(diameter1, diameter2, height) {
1915
2289
  var options = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {};
1916
2290
  debug$1("parts.Cone", diameter1, diameter2, height, options);
1917
- return CSG.cylinder(Object.assign({
2291
+ return assertValidCSG(CSG$1.cylinder(Object.assign({
1918
2292
  start: [ 0, 0, 0 ],
1919
2293
  end: [ 0, 0, height ],
1920
2294
  radiusStart: diameter1 / 2,
1921
2295
  radiusEnd: diameter2 / 2,
1922
- resolution: CSG.defaultResolution2D
1923
- }, options));
2296
+ resolution: CSG$1.defaultResolution2D
2297
+ }, options)), "Cone");
1924
2298
  }
1925
2299
  function Hexagon(diameter, height) {
1926
2300
  debug$1("hexagon", diameter, height);
1927
2301
  var radius = diameter / 2;
1928
2302
  var sqrt3 = Math.sqrt(3) / 2;
1929
2303
  var hex = CAG.fromPoints([ [ radius, 0 ], [ radius / 2, radius * sqrt3 ], [ -radius / 2, radius * sqrt3 ], [ -radius, 0 ], [ -radius / 2, -radius * sqrt3 ], [ radius / 2, -radius * sqrt3 ] ]);
1930
- return hex.extrude({
2304
+ return assertValidCSG(hex.extrude({
1931
2305
  offset: [ 0, 0, height ]
1932
- });
2306
+ }), "Hexagon");
1933
2307
  }
1934
2308
  function Triangle(base, height) {
1935
2309
  var radius = base / 2;
1936
2310
  var tri = CAG.fromPoints([ [ -radius, 0 ], [ radius, 0 ], [ 0, Math.sin(30) * radius ] ]);
1937
- return tri.extrude({
2311
+ return assertValidCSG(tri.extrude({
1938
2312
  offset: [ 0, 0, height ]
1939
- });
2313
+ }), "Triangle");
1940
2314
  }
1941
2315
  function Tube(outsideDiameter, insideDiameter, height, outsideOptions, insideOptions) {
1942
- return Cylinder(outsideDiameter, height, outsideOptions).subtract(Cylinder(insideDiameter, height, insideOptions || outsideOptions));
2316
+ return assertValidCSG(Cylinder(outsideDiameter, height, outsideOptions).subtract(Cylinder(insideDiameter, height, insideOptions || outsideOptions)), "Tube");
1943
2317
  }
1944
2318
  function Anchor() {
1945
2319
  var width = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 10;
@@ -1957,11 +2331,11 @@ function initJscadutils(_CSG, options = {}) {
1957
2331
  center: [ r[0], r[1], 0 ],
1958
2332
  radius: r,
1959
2333
  roundradius: corner_radius,
1960
- resolution: CSG.defaultResolution2D
2334
+ resolution: CSG$1.defaultResolution2D
1961
2335
  }).extrude({
1962
2336
  offset: [ 0, 0, thickness || 1.62 ]
1963
2337
  });
1964
- return board;
2338
+ return assertValidCSG(board, "Board");
1965
2339
  }
1966
2340
  var Hardware = {
1967
2341
  Orientation: {
@@ -2052,6 +2426,10 @@ function initJscadutils(_CSG, options = {}) {
2052
2426
  gap = gap || .25;
2053
2427
  var inside = thickness - gap;
2054
2428
  var outside = -thickness + gap;
2429
+ var boxHeight = box.size().z;
2430
+ if (Math.abs(height) >= boxHeight) {
2431
+ throw new Error("Rabett: height (".concat(height, ") must be less than the object height (").concat(boxHeight, ")"));
2432
+ }
2055
2433
  debug("inside", inside, "outside", outside);
2056
2434
  var group = Group();
2057
2435
  var _box$bisect$parts = box.bisect("z", height, options).parts, top = _box$bisect$parts.positive, lower2_3rd = _box$bisect$parts.negative;
@@ -2122,10 +2500,10 @@ function initJscadutils(_CSG, options = {}) {
2122
2500
  thickness = thickness || 2;
2123
2501
  var s = div$1(xyz2array(size), 2);
2124
2502
  var r = add(s, thickness);
2125
- var box = CSG.cube({
2503
+ var box = CSG$1.cube({
2126
2504
  center: r,
2127
2505
  radius: r
2128
- }).subtract(CSG.cube({
2506
+ }).subtract(CSG$1.cube({
2129
2507
  center: r,
2130
2508
  radius: s
2131
2509
  }));
@@ -2143,7 +2521,7 @@ function initJscadutils(_CSG, options = {}) {
2143
2521
  var BBox = function BBox(o) {
2144
2522
  depreciated("BBox", true, "Use 'parts.BBox' instead");
2145
2523
  var s = div$1(xyz2array(o.size()), 2);
2146
- return CSG.cube({
2524
+ return CSG$1.cube({
2147
2525
  center: s,
2148
2526
  radius: s
2149
2527
  }).align(o, "xyz");
@@ -2155,7 +2533,7 @@ function initJscadutils(_CSG, options = {}) {
2155
2533
  var gap = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : .25;
2156
2534
  var r = add(getRadius(box), -thickness / 2);
2157
2535
  r[2] = thickness / 2;
2158
- var cutter = CSG.cube({
2536
+ var cutter = CSG$1.cube({
2159
2537
  center: r,
2160
2538
  radius: r
2161
2539
  }).align(box, "xy").color("green");