@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.
@@ -52,6 +52,8 @@ function initJscadutils(_CSG, options = {}) {
52
52
  enabled: [],
53
53
  disabled: []
54
54
  });
55
+ var jscadUtilsAssertValidCSGWarnings = options.assertValidCSGWarnings || false;
56
+ var jscadUtilsAssertValidCSG = options.assertValidCSG || false;
55
57
  var jscadUtils = function(exports, jsCadCSG, scadApi) {
56
58
  "use strict";
57
59
  function _interopDefaultLegacy(e) {
@@ -285,6 +287,51 @@ function initJscadutils(_CSG, options = {}) {
285
287
  function _arrayWithHoles(r) {
286
288
  if (Array.isArray(r)) return r;
287
289
  }
290
+ function _createForOfIteratorHelper(r, e) {
291
+ var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"];
292
+ if (!t) {
293
+ if (Array.isArray(r) || (t = _unsupportedIterableToArray(r)) || e && r && "number" == typeof r.length) {
294
+ t && (r = t);
295
+ var n = 0, F = function() {};
296
+ return {
297
+ s: F,
298
+ n: function() {
299
+ return n >= r.length ? {
300
+ done: !0
301
+ } : {
302
+ done: !1,
303
+ value: r[n++]
304
+ };
305
+ },
306
+ e: function(r) {
307
+ throw r;
308
+ },
309
+ f: F
310
+ };
311
+ }
312
+ throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
313
+ }
314
+ var o, a = !0, u = !1;
315
+ return {
316
+ s: function() {
317
+ t = t.call(r);
318
+ },
319
+ n: function() {
320
+ var r = t.next();
321
+ return a = r.done, r;
322
+ },
323
+ e: function(r) {
324
+ u = !0, o = r;
325
+ },
326
+ f: function() {
327
+ try {
328
+ a || null == t.return || t.return();
329
+ } finally {
330
+ if (u) throw o;
331
+ }
332
+ }
333
+ };
334
+ }
288
335
  function _defineProperty(e, r, t) {
289
336
  return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, {
290
337
  value: t,
@@ -705,6 +752,219 @@ function initJscadutils(_CSG, options = {}) {
705
752
  c[3] = g || 1;
706
753
  return o.setColor(c);
707
754
  }
755
+ function validateCSG(csg, options) {
756
+ var errors = [];
757
+ var warnings = [];
758
+ if (!csg || !csg.polygons || csg.polygons.length === 0) {
759
+ errors.push("Empty mesh: no polygons");
760
+ return {
761
+ ok: false,
762
+ errors,
763
+ warnings
764
+ };
765
+ }
766
+ var opts = _objectSpread2({
767
+ fixTJunctions: true
768
+ }, options);
769
+ if (opts.fixTJunctions && typeof csg.canonicalized === "function") {
770
+ csg = csg.canonicalized();
771
+ if (typeof csg.reTesselated === "function") {
772
+ csg = csg.reTesselated();
773
+ }
774
+ if (typeof csg.fixTJunctions === "function") {
775
+ csg = csg.fixTJunctions();
776
+ }
777
+ }
778
+ var AREA_EPS = 1e-10;
779
+ var KEY_EPS = 1e-5;
780
+ var degenerateCount = 0;
781
+ var invalidVertexCount = 0;
782
+ var _iterator = _createForOfIteratorHelper(csg.polygons), _step;
783
+ try {
784
+ for (_iterator.s(); !(_step = _iterator.n()).done; ) {
785
+ var npoly = _step.value;
786
+ var _iterator4 = _createForOfIteratorHelper(npoly.vertices), _step4;
787
+ try {
788
+ for (_iterator4.s(); !(_step4 = _iterator4.n()).done; ) {
789
+ var nvert = _step4.value;
790
+ var np = nvert.pos;
791
+ 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)) {
792
+ invalidVertexCount++;
793
+ break;
794
+ }
795
+ }
796
+ } catch (err) {
797
+ _iterator4.e(err);
798
+ } finally {
799
+ _iterator4.f();
800
+ }
801
+ }
802
+ } catch (err) {
803
+ _iterator.e(err);
804
+ } finally {
805
+ _iterator.f();
806
+ }
807
+ if (invalidVertexCount > 0) {
808
+ errors.push(invalidVertexCount + " polygon(s) with invalid vertex coordinates (NaN or Infinity)");
809
+ }
810
+ function vtxKey(v) {
811
+ var p = v.pos;
812
+ return Math.round(p.x / KEY_EPS) + "," + Math.round(p.y / KEY_EPS) + "," + Math.round(p.z / KEY_EPS);
813
+ }
814
+ var validPolygons = [];
815
+ var _iterator2 = _createForOfIteratorHelper(csg.polygons), _step2;
816
+ try {
817
+ for (_iterator2.s(); !(_step2 = _iterator2.n()).done; ) {
818
+ var poly = _step2.value;
819
+ var verts = poly.vertices;
820
+ var nv = verts.length;
821
+ if (nv < 3) {
822
+ degenerateCount++;
823
+ continue;
824
+ }
825
+ var hasInvalid = false;
826
+ var _iterator5 = _createForOfIteratorHelper(verts), _step5;
827
+ try {
828
+ for (_iterator5.s(); !(_step5 = _iterator5.n()).done; ) {
829
+ var vert = _step5.value;
830
+ var ip = vert.pos;
831
+ if (!Number.isFinite(ip.x) || !Number.isFinite(ip.y) || !Number.isFinite(ip.z)) {
832
+ hasInvalid = true;
833
+ break;
834
+ }
835
+ }
836
+ } catch (err) {
837
+ _iterator5.e(err);
838
+ } finally {
839
+ _iterator5.f();
840
+ }
841
+ if (hasInvalid) continue;
842
+ var area = 0;
843
+ for (var ai = 0; ai < nv - 2; ai++) {
844
+ area += verts[ai + 1].pos.minus(verts[0].pos).cross(verts[ai + 2].pos.minus(verts[ai + 1].pos)).length();
845
+ }
846
+ area *= .5;
847
+ if (area < AREA_EPS) {
848
+ degenerateCount++;
849
+ continue;
850
+ }
851
+ validPolygons.push(poly);
852
+ }
853
+ } catch (err) {
854
+ _iterator2.e(err);
855
+ } finally {
856
+ _iterator2.f();
857
+ }
858
+ if (degenerateCount > 0) {
859
+ warnings.push(degenerateCount + " degenerate polygon(s) (fewer than 3 vertices or near-zero area)");
860
+ if (opts.fixTJunctions && typeof CSG !== "undefined") {
861
+ var cleaned = CSG.fromPolygons(validPolygons);
862
+ cleaned = cleaned.canonicalized();
863
+ if (typeof cleaned.reTesselated === "function") {
864
+ cleaned = cleaned.reTesselated();
865
+ }
866
+ if (typeof cleaned.fixTJunctions === "function") {
867
+ cleaned = cleaned.fixTJunctions();
868
+ }
869
+ validPolygons = [];
870
+ var _iterator3 = _createForOfIteratorHelper(cleaned.polygons), _step3;
871
+ try {
872
+ for (_iterator3.s(); !(_step3 = _iterator3.n()).done; ) {
873
+ var cpoly = _step3.value;
874
+ var cverts = cpoly.vertices;
875
+ var cnv = cverts.length;
876
+ if (cnv < 3) continue;
877
+ var carea = 0;
878
+ for (var cai = 0; cai < cnv - 2; cai++) {
879
+ carea += cverts[cai + 1].pos.minus(cverts[0].pos).cross(cverts[cai + 2].pos.minus(cverts[cai + 1].pos)).length();
880
+ }
881
+ carea *= .5;
882
+ if (carea < AREA_EPS) continue;
883
+ validPolygons.push(cpoly);
884
+ }
885
+ } catch (err) {
886
+ _iterator3.e(err);
887
+ } finally {
888
+ _iterator3.f();
889
+ }
890
+ }
891
+ }
892
+ var edgeCounts = {};
893
+ for (var _i = 0, _validPolygons = validPolygons; _i < _validPolygons.length; _i++) {
894
+ var vpoly = _validPolygons[_i];
895
+ var vverts = vpoly.vertices;
896
+ var vnv = vverts.length;
897
+ for (var ei = 0; ei < vnv; ei++) {
898
+ var v0 = vverts[ei];
899
+ var v1 = vverts[(ei + 1) % vnv];
900
+ var edgeKey = vtxKey(v0) + "/" + vtxKey(v1);
901
+ edgeCounts[edgeKey] = (edgeCounts[edgeKey] || 0) + 1;
902
+ }
903
+ }
904
+ var unmatchedEdges = 0;
905
+ var nonManifoldEdges = 0;
906
+ var checked = {};
907
+ for (var _i2 = 0, _Object$keys = Object.keys(edgeCounts); _i2 < _Object$keys.length; _i2++) {
908
+ var _edgeKey = _Object$keys[_i2];
909
+ if (checked[_edgeKey]) continue;
910
+ var parts = _edgeKey.split("/");
911
+ var reverseKey = parts[1] + "/" + parts[0];
912
+ var forwardCount = edgeCounts[_edgeKey] || 0;
913
+ var reverseCount = edgeCounts[reverseKey] || 0;
914
+ checked[_edgeKey] = true;
915
+ checked[reverseKey] = true;
916
+ if (forwardCount !== reverseCount) {
917
+ unmatchedEdges += Math.abs(forwardCount - reverseCount);
918
+ }
919
+ if (forwardCount > 1 || reverseCount > 1) {
920
+ nonManifoldEdges++;
921
+ }
922
+ }
923
+ if (unmatchedEdges > 0) {
924
+ errors.push(unmatchedEdges + " unmatched edge(s): mesh is not watertight");
925
+ }
926
+ if (nonManifoldEdges > 0) {
927
+ errors.push(nonManifoldEdges + " non-manifold edge(s): edge shared by more than 2 polygons");
928
+ }
929
+ return {
930
+ ok: errors.length === 0,
931
+ errors,
932
+ warnings
933
+ };
934
+ }
935
+ function _noOp(csg) {
936
+ return csg;
937
+ }
938
+ function _makeAssertFn(warnEnabled) {
939
+ return function _assert(csg) {
940
+ var functionName = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : "unknown";
941
+ var moduleName = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : "unknown";
942
+ if (!csg || csg.polygons === undefined) return csg;
943
+ var result = validateCSG(csg);
944
+ if (!result.ok) {
945
+ throw new Error(moduleName + ":" + functionName + ": " + "invalid CSG: " + result.errors.join(", "));
946
+ }
947
+ if (warnEnabled && result.warnings.length > 0) {
948
+ throw new Error(moduleName + ":" + functionName + ": " + "CSG warnings: " + result.warnings.join(", "));
949
+ }
950
+ return csg;
951
+ };
952
+ }
953
+ var _assertFn = _noOp;
954
+ function _resolveFromGlobals() {
955
+ var enabled = typeof jscadUtilsAssertValidCSG !== "undefined" && !!jscadUtilsAssertValidCSG;
956
+ var warnEnabled = typeof jscadUtilsAssertValidCSGWarnings !== "undefined" && !!jscadUtilsAssertValidCSGWarnings;
957
+ return enabled ? _makeAssertFn(warnEnabled) : _noOp;
958
+ }
959
+ function AssertValidCSG() {
960
+ var moduleName = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : "unknown";
961
+ {
962
+ _assertFn = _resolveFromGlobals();
963
+ }
964
+ return function(csg, name) {
965
+ return _assertFn(csg, name, moduleName);
966
+ };
967
+ }
708
968
  function init(proto) {
709
969
  if (proto.prototype._jscadutilsinit) return;
710
970
  proto.prototype.color = function(r, g, b, a) {
@@ -798,6 +1058,9 @@ function initJscadutils(_CSG, options = {}) {
798
1058
  proto.prototype.subtractIf = function subtractIf(object, condition) {
799
1059
  return condition ? this.subtract(result(this, object)) : this;
800
1060
  };
1061
+ proto.prototype.validate = function validate(options) {
1062
+ return validateCSG(this, options);
1063
+ };
801
1064
  proto.prototype._translate = proto.prototype.translate;
802
1065
  proto.prototype.translate = function translate() {
803
1066
  if (arguments.length === 1) {
@@ -830,12 +1093,13 @@ function initJscadutils(_CSG, options = {}) {
830
1093
  __proto__: null,
831
1094
  default: init
832
1095
  });
833
- var CSG = jsCadCSG__default["default"].CSG, CAG = jsCadCSG__default["default"].CAG;
1096
+ var CSG$1 = jsCadCSG__default["default"].CSG, CAG = jsCadCSG__default["default"].CAG;
834
1097
  var rectangular_extrude = scadApi__default["default"].extrusions.rectangular_extrude;
835
1098
  var _scadApi$text = scadApi__default["default"].text, vector_text = _scadApi$text.vector_text, vector_char = _scadApi$text.vector_char;
836
1099
  var union = scadApi__default["default"].booleanOps.union;
837
- init(CSG);
1100
+ init(CSG$1);
838
1101
  var debug$3 = Debug("jscadUtils:group");
1102
+ var assertValidCSG$2 = AssertValidCSG("group");
839
1103
  function JsCadUtilsGroup() {
840
1104
  var names = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];
841
1105
  var parts = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
@@ -886,7 +1150,7 @@ function initJscadutils(_CSG, options = {}) {
886
1150
  debug$3("combine mapPick", value, key, object);
887
1151
  return map ? map(value, key, index, object) : identity(value);
888
1152
  }, self.name));
889
- return g.subtractIf(self.holes && Array.isArray(self.holes) ? union(self.holes) : self.holes, self.holes && !options.noholes);
1153
+ return assertValidCSG$2(g.subtractIf(self.holes && Array.isArray(self.holes) ? union(self.holes) : self.holes, self.holes && !options.noholes), "combine");
890
1154
  } catch (err) {
891
1155
  debug$3("combine error", this, pieces, options, err);
892
1156
  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");
@@ -927,7 +1191,7 @@ function initJscadutils(_CSG, options = {}) {
927
1191
  });
928
1192
  if (self.holes) {
929
1193
  group.holes = toArray(self.holes).map(function(part) {
930
- return map(CSG.fromPolygons(part.toPolygons()), "holes");
1194
+ return assertValidCSG$2(map(CSG$1.fromPolygons(part.toPolygons()), "holes"), "clone");
931
1195
  });
932
1196
  }
933
1197
  return group;
@@ -946,7 +1210,7 @@ function initJscadutils(_CSG, options = {}) {
946
1210
  var rotationCenter = solid.centroid();
947
1211
  var rotationAxis = axes[axis];
948
1212
  self.map(function(part) {
949
- return part.rotate(rotationCenter, rotationAxis, angle);
1213
+ return assertValidCSG$2(part.rotate(rotationCenter, rotationAxis, angle), "rotate");
950
1214
  });
951
1215
  return self;
952
1216
  };
@@ -959,7 +1223,7 @@ function initJscadutils(_CSG, options = {}) {
959
1223
  var self = this;
960
1224
  var t = calcSnap(self.combine(part), to, axis, orientation, delta);
961
1225
  self.map(function(part) {
962
- return part.translate(t);
1226
+ return assertValidCSG$2(part.translate(t), "snap");
963
1227
  });
964
1228
  return self;
965
1229
  } catch (err) {
@@ -974,7 +1238,7 @@ function initJscadutils(_CSG, options = {}) {
974
1238
  noholes: true
975
1239
  }), axis, to, delta);
976
1240
  self.map(function(part) {
977
- return part.translate(t);
1241
+ return assertValidCSG$2(part.translate(t), "align");
978
1242
  });
979
1243
  return self;
980
1244
  } catch (err) {
@@ -1006,14 +1270,14 @@ function initJscadutils(_CSG, options = {}) {
1006
1270
  var myConnector = connectorName.split(".").reduce(function(a, v) {
1007
1271
  return a[v];
1008
1272
  }, self.parts[partName].properties);
1009
- debug$3("toConnector", to instanceof CSG.Connector);
1273
+ debug$3("toConnector", to instanceof CSG$1.Connector);
1010
1274
  var toConnector = toConnectorName.split(".").reduce(function(a, v) {
1011
1275
  return a[v];
1012
1276
  }, to.properties);
1013
1277
  var matrix = myConnector.getTransformationTo(toConnector, mirror, normalrotation);
1014
1278
  debug$3("connectTo", matrix);
1015
1279
  self.map(function(part) {
1016
- return part.transform(matrix);
1280
+ return assertValidCSG$2(part.transform(matrix), "connectTo");
1017
1281
  });
1018
1282
  return self;
1019
1283
  };
@@ -1024,7 +1288,7 @@ function initJscadutils(_CSG, options = {}) {
1024
1288
  return to - size[a] / 2;
1025
1289
  });
1026
1290
  self.map(function(part) {
1027
- return part.translate(t);
1291
+ return assertValidCSG$2(part.translate(t), "midlineTo");
1028
1292
  });
1029
1293
  return self;
1030
1294
  };
@@ -1033,7 +1297,7 @@ function initJscadutils(_CSG, options = {}) {
1033
1297
  var t = Array.isArray(x) ? x : [ x, y, z ];
1034
1298
  debug$3("translate", t);
1035
1299
  self.map(function(part) {
1036
- return part.translate(t);
1300
+ return assertValidCSG$2(part.translate(t), "translate");
1037
1301
  });
1038
1302
  return self;
1039
1303
  };
@@ -1043,7 +1307,7 @@ function initJscadutils(_CSG, options = {}) {
1043
1307
  if (!map) map = identity;
1044
1308
  var g = Group();
1045
1309
  p.forEach(function(name) {
1046
- g.add(map(CSG.fromPolygons(self.parts[name].toPolygons()), name), name);
1310
+ g.add(assertValidCSG$2(map(CSG$1.fromPolygons(self.parts[name].toPolygons()), name), "pick"), name);
1047
1311
  });
1048
1312
  return g;
1049
1313
  };
@@ -1058,7 +1322,7 @@ function initJscadutils(_CSG, options = {}) {
1058
1322
  debug$3("array error", _this, parts);
1059
1323
  throw error('group::array error "'.concat(name, '" not found.\nthis: ').concat(_this, '\nparts: "').concat(parts, '"\n'), "JSCAD_UTILS_GROUP_ERROR");
1060
1324
  }
1061
- a.push(map(CSG.fromPolygons(self.parts[name].toPolygons()), name));
1325
+ a.push(assertValidCSG$2(map(CSG$1.fromPolygons(self.parts[name].toPolygons()), name), "array"));
1062
1326
  });
1063
1327
  return a;
1064
1328
  };
@@ -1091,7 +1355,7 @@ function initJscadutils(_CSG, options = {}) {
1091
1355
  self.names = names && names.length > 0 && names.split(",") || [];
1092
1356
  if (Array.isArray(objects)) {
1093
1357
  self.parts = zipObject(self.names, objects);
1094
- } else if (objects instanceof CSG) {
1358
+ } else if (objects instanceof CSG$1) {
1095
1359
  self.parts = zipObject(self.names, [ objects ]);
1096
1360
  } else {
1097
1361
  self.parts = objects || {};
@@ -1112,6 +1376,7 @@ function initJscadutils(_CSG, options = {}) {
1112
1376
  return new JsCadUtilsGroup(self.names, self.parts, self.holes);
1113
1377
  }
1114
1378
  var debug$2 = Debug("jscadUtils:util");
1379
+ var assertValidCSG$1 = AssertValidCSG("util");
1115
1380
  var NOZZEL_SIZE = .4;
1116
1381
  var nearest = {
1117
1382
  under: function under(desired) {
@@ -1188,12 +1453,12 @@ function initJscadutils(_CSG, options = {}) {
1188
1453
  h: height || 2
1189
1454
  }));
1190
1455
  });
1191
- return center(union(o));
1456
+ return assertValidCSG$1(center(union(o)), "label");
1192
1457
  }
1193
1458
  function text(text) {
1194
1459
  var l = vector_char(0, 0, text);
1195
1460
  var _char = l.segments.reduce(function(result, segment) {
1196
- var path = new CSG.Path2D(segment);
1461
+ var path = new CSG$1.Path2D(segment);
1197
1462
  var cag = path.expandToCAG(2);
1198
1463
  return result ? result.union(cag) : cag;
1199
1464
  }, undefined);
@@ -1201,17 +1466,17 @@ function initJscadutils(_CSG, options = {}) {
1201
1466
  }
1202
1467
  function unitCube(length, radius) {
1203
1468
  radius = radius || .5;
1204
- return CSG.cube({
1469
+ return assertValidCSG$1(CSG$1.cube({
1205
1470
  center: [ 0, 0, 0 ],
1206
1471
  radius: [ radius, radius, length || .5 ]
1207
- });
1472
+ }), "unitCube");
1208
1473
  }
1209
1474
  function unitAxis(length, radius, centroid) {
1210
1475
  debug$2("unitAxis", length, radius, centroid);
1211
1476
  centroid = centroid || [ 0, 0, 0 ];
1212
1477
  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) ]);
1213
- unitaxis.properties.origin = new CSG.Connector([ 0, 0, 0 ], [ 1, 0, 0 ], [ 0, 1, 0 ]);
1214
- return unitaxis.translate(centroid);
1478
+ unitaxis.properties.origin = new CSG$1.Connector([ 0, 0, 0 ], [ 1, 0, 0 ], [ 0, 1, 0 ]);
1479
+ return assertValidCSG$1(unitaxis.translate(centroid), "unitAxis");
1215
1480
  }
1216
1481
  function toArray(a) {
1217
1482
  return Array.isArray(a) ? a : [ a ];
@@ -1301,15 +1566,15 @@ function initJscadutils(_CSG, options = {}) {
1301
1566
  }
1302
1567
  function center(object, objectSize) {
1303
1568
  objectSize = objectSize || size(object.getBounds());
1304
- return centerY(centerX(object, objectSize), objectSize);
1569
+ return assertValidCSG$1(centerY(centerX(object, objectSize), objectSize), "center");
1305
1570
  }
1306
1571
  function centerY(object, objectSize) {
1307
1572
  objectSize = objectSize || size(object.getBounds());
1308
- return object.translate([ 0, -objectSize.y / 2, 0 ]);
1573
+ return assertValidCSG$1(object.translate([ 0, -objectSize.y / 2, 0 ]), "centerY");
1309
1574
  }
1310
1575
  function centerX(object, objectSize) {
1311
1576
  objectSize = objectSize || size(object.getBounds());
1312
- return object.translate([ -objectSize.x / 2, 0, 0 ]);
1577
+ return assertValidCSG$1(object.translate([ -objectSize.x / 2, 0, 0 ]), "centerX");
1313
1578
  }
1314
1579
  function enlarge(object, x, y, z) {
1315
1580
  var a;
@@ -1327,7 +1592,7 @@ function initJscadutils(_CSG, options = {}) {
1327
1592
  var new_object = object.scale(t);
1328
1593
  var new_centroid = centroid(new_object);
1329
1594
  var delta = new_centroid.minus(objectCentroid).times(-1);
1330
- return new_object.translate(delta);
1595
+ return assertValidCSG$1(new_object.translate(delta), "enlarge");
1331
1596
  }
1332
1597
  function fit(object, x, y, z, keep_aspect_ratio) {
1333
1598
  var a;
@@ -1347,10 +1612,10 @@ function initJscadutils(_CSG, options = {}) {
1347
1612
  }
1348
1613
  var s = [ scale(objectSize.x, x), scale(objectSize.y, y), scale(objectSize.z, z) ];
1349
1614
  var min$1 = min(s);
1350
- return centerWith(object.scale(s.map(function(d, i) {
1615
+ return assertValidCSG$1(centerWith(object.scale(s.map(function(d, i) {
1351
1616
  if (a[i] === 0) return 1;
1352
1617
  return keep_aspect_ratio ? min$1 : d;
1353
- })), "xyz", object);
1618
+ })), "xyz", object), "fit");
1354
1619
  }
1355
1620
  function shift(object, x, y, z) {
1356
1621
  var hsize = this.div(this.size(object.getBounds()), 2);
@@ -1358,10 +1623,10 @@ function initJscadutils(_CSG, options = {}) {
1358
1623
  }
1359
1624
  function zero(object) {
1360
1625
  var bounds = object.getBounds();
1361
- return object.translate([ 0, 0, -bounds[0].z ]);
1626
+ return assertValidCSG$1(object.translate([ 0, 0, -bounds[0].z ]), "zero");
1362
1627
  }
1363
1628
  function mirrored4(x) {
1364
- return x.union([ x.mirroredY(90), x.mirroredX(90), x.mirroredY(90).mirroredX(90) ]);
1629
+ return assertValidCSG$1(x.union([ x.mirroredY(90), x.mirroredX(90), x.mirroredY(90).mirroredX(90) ]), "mirrored4");
1365
1630
  }
1366
1631
  var flushSide = {
1367
1632
  "above-outside": [ 1, 0 ],
@@ -1422,10 +1687,10 @@ function initJscadutils(_CSG, options = {}) {
1422
1687
  function snap(moveobj, withobj, axis, orientation, delta) {
1423
1688
  debug$2("snap", moveobj, withobj, axis, orientation, delta);
1424
1689
  var t = calcSnap(moveobj, withobj, axis, orientation, delta);
1425
- return moveobj.translate(t);
1690
+ return assertValidCSG$1(moveobj.translate(t), "snap");
1426
1691
  }
1427
1692
  function flush(moveobj, withobj, axis, mside, wside) {
1428
- return moveobj.translate(calcFlush(moveobj, withobj, axis, mside, wside));
1693
+ return assertValidCSG$1(moveobj.translate(calcFlush(moveobj, withobj, axis, mside, wside)), "flush");
1429
1694
  }
1430
1695
  function axisApply(axes, valfun, a) {
1431
1696
  debug$2("axisApply", axes, valfun, a);
@@ -1441,7 +1706,7 @@ function initJscadutils(_CSG, options = {}) {
1441
1706
  return retval;
1442
1707
  }
1443
1708
  function axis2array(axes, valfun) {
1444
- depreciated("axis2array");
1709
+ depreciated("axis2array", false, "Use axisApply instead.");
1445
1710
  var a = [ 0, 0, 0 ];
1446
1711
  var lookup = {
1447
1712
  x: 0,
@@ -1471,7 +1736,7 @@ function initJscadutils(_CSG, options = {}) {
1471
1736
  });
1472
1737
  }
1473
1738
  function midlineTo(o, axis, to) {
1474
- return o.translate(calcmidlineTo(o, axis, to));
1739
+ return assertValidCSG$1(o.translate(calcmidlineTo(o, axis, to)), "midlineTo");
1475
1740
  }
1476
1741
  function translator(o, axis, withObj) {
1477
1742
  var objectCentroid = centroid(o);
@@ -1491,7 +1756,7 @@ function initJscadutils(_CSG, options = {}) {
1491
1756
  return delta ? add(t, delta) : t;
1492
1757
  }
1493
1758
  function centerWith(o, axis, withObj) {
1494
- return o.translate(calcCenterWith(o, axis, withObj));
1759
+ return assertValidCSG$1(o.translate(calcCenterWith(o, axis, withObj)), "centerWith");
1495
1760
  }
1496
1761
  function getDelta(size, bounds, axis, offset, nonzero) {
1497
1762
  if (!isEmpty(offset) && nonzero) {
@@ -1504,6 +1769,95 @@ function initJscadutils(_CSG, options = {}) {
1504
1769
  return bounds[0][a] + (isEmpty(dist) ? size[axis] / 2 : dist);
1505
1770
  });
1506
1771
  }
1772
+ var EPS = 1e-5;
1773
+ function splitCSGByPlane(csg, plane) {
1774
+ var frontPolys = [];
1775
+ var backPolys = [];
1776
+ csg.polygons.forEach(function(poly) {
1777
+ var vertices = poly.vertices;
1778
+ var numVerts = vertices.length;
1779
+ var hasfront = false;
1780
+ var hasback = false;
1781
+ var vertexIsBack = [];
1782
+ for (var i = 0; i < numVerts; i++) {
1783
+ var t = plane.normal.dot(vertices[i].pos) - plane.w;
1784
+ vertexIsBack.push(t < 0);
1785
+ if (t > EPS) hasfront = true;
1786
+ if (t < -EPS) hasback = true;
1787
+ }
1788
+ if (!hasfront && !hasback) {
1789
+ var d = plane.normal.dot(poly.plane.normal);
1790
+ if (d >= 0) {
1791
+ frontPolys.push(poly);
1792
+ } else {
1793
+ backPolys.push(poly);
1794
+ }
1795
+ } else if (!hasback) {
1796
+ frontPolys.push(poly);
1797
+ } else if (!hasfront) {
1798
+ backPolys.push(poly);
1799
+ } else {
1800
+ var fv = [];
1801
+ var bv = [];
1802
+ for (var vi = 0; vi < numVerts; vi++) {
1803
+ var vertex = vertices[vi];
1804
+ var nextVi = (vi + 1) % numVerts;
1805
+ var isback = vertexIsBack[vi];
1806
+ var nextisback = vertexIsBack[nextVi];
1807
+ if (isback === nextisback) {
1808
+ if (isback) {
1809
+ bv.push(vertex);
1810
+ } else {
1811
+ fv.push(vertex);
1812
+ }
1813
+ } else {
1814
+ var point = vertex.pos;
1815
+ var nextpoint = vertices[nextVi].pos;
1816
+ var ip = plane.splitLineBetweenPoints(point, nextpoint);
1817
+ var iv = new CSG$1.Vertex(ip);
1818
+ if (isback) {
1819
+ bv.push(vertex);
1820
+ bv.push(iv);
1821
+ fv.push(iv);
1822
+ } else {
1823
+ fv.push(vertex);
1824
+ fv.push(iv);
1825
+ bv.push(iv);
1826
+ }
1827
+ }
1828
+ }
1829
+ var EPSEPS = EPS * EPS;
1830
+ if (fv.length >= 3) {
1831
+ var prev = fv[fv.length - 1];
1832
+ for (var fi = 0; fi < fv.length; fi++) {
1833
+ var curr = fv[fi];
1834
+ if (curr.pos.distanceToSquared(prev.pos) < EPSEPS) {
1835
+ fv.splice(fi, 1);
1836
+ fi--;
1837
+ }
1838
+ prev = curr;
1839
+ }
1840
+ }
1841
+ if (bv.length >= 3) {
1842
+ var prev = bv[bv.length - 1];
1843
+ for (var bi = 0; bi < bv.length; bi++) {
1844
+ var curr = bv[bi];
1845
+ if (curr.pos.distanceToSquared(prev.pos) < EPSEPS) {
1846
+ bv.splice(bi, 1);
1847
+ bi--;
1848
+ }
1849
+ prev = curr;
1850
+ }
1851
+ }
1852
+ if (fv.length >= 3) frontPolys.push(new CSG$1.Polygon(fv, poly.shared, poly.plane));
1853
+ if (bv.length >= 3) backPolys.push(new CSG$1.Polygon(bv, poly.shared, poly.plane));
1854
+ }
1855
+ });
1856
+ return {
1857
+ front: CSG$1.fromPolygons(frontPolys),
1858
+ back: CSG$1.fromPolygons(backPolys)
1859
+ };
1860
+ }
1507
1861
  function bisect() {
1508
1862
  for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
1509
1863
  args[_key] = arguments[_key];
@@ -1565,13 +1919,13 @@ function initJscadutils(_CSG, options = {}) {
1565
1919
  }[[ axis, rotateaxis ].sort().join("")];
1566
1920
  var centroid = object.centroid();
1567
1921
  var rotateDelta = getDelta(objectSize, bounds, rotateOffsetAxis, rotateoffset);
1568
- var rotationCenter = options.rotationCenter || new CSG.Vector3D(axisApply("xyz", function(i, a) {
1922
+ var rotationCenter = options.rotationCenter || new CSG$1.Vector3D(axisApply("xyz", function(i, a) {
1569
1923
  if (a == axis) return cutDelta[i];
1570
1924
  if (a == rotateOffsetAxis) return rotateDelta[i];
1571
1925
  return centroid[a];
1572
1926
  }));
1573
1927
  var theRotationAxis = rotationAxes[rotateaxis];
1574
- var cutplane = CSG.OrthoNormalBasis.GetCartesian(info.orthoNormalCartesian[0], info.orthoNormalCartesian[1]).translate(cutDelta).rotate(rotationCenter, theRotationAxis, angle);
1928
+ var cutplane = CSG$1.OrthoNormalBasis.GetCartesian(info.orthoNormalCartesian[0], info.orthoNormalCartesian[1]).translate(cutDelta).rotate(rotationCenter, theRotationAxis, angle);
1575
1929
  debug$2("bisect", debug$2.enabled && {
1576
1930
  axis,
1577
1931
  offset,
@@ -1584,7 +1938,26 @@ function initJscadutils(_CSG, options = {}) {
1584
1938
  cutplane,
1585
1939
  options
1586
1940
  });
1587
- var g = Group("negative,positive", [ object.cutByPlane(cutplane.plane).color(options.color && "red"), object.cutByPlane(cutplane.plane.flipped()).color(options.color && "blue") ]);
1941
+ var negative = object.cutByPlane(cutplane.plane);
1942
+ var positive = object.cutByPlane(cutplane.plane.flipped());
1943
+ var negSize = size(negative);
1944
+ var posSize = size(positive);
1945
+ if (negSize[axis] >= objectSize[axis] - EPS || posSize[axis] >= objectSize[axis] - EPS) {
1946
+ var halves = splitCSGByPlane(object, cutplane.plane);
1947
+ if (negSize[axis] >= objectSize[axis] - EPS) {
1948
+ negative = halves.back;
1949
+ try {
1950
+ negative = negative.cutByPlane(cutplane.plane);
1951
+ } catch (e) {}
1952
+ }
1953
+ if (posSize[axis] >= objectSize[axis] - EPS) {
1954
+ positive = halves.front;
1955
+ try {
1956
+ positive = positive.cutByPlane(cutplane.plane.flipped());
1957
+ } catch (e) {}
1958
+ }
1959
+ }
1960
+ var g = Group("negative,positive", [ negative.color(options.color && "red"), positive.color(options.color && "blue") ]);
1588
1961
  if (options.addRotationCenter) g.add(unitAxis(objectSize.length() + 10, .1, rotationCenter), "rotationCenter");
1589
1962
  return g;
1590
1963
  }
@@ -1597,9 +1970,9 @@ function initJscadutils(_CSG, options = {}) {
1597
1970
  addRotationCenter: true
1598
1971
  };
1599
1972
  var info = normalVector(axis);
1600
- var rotationCenter = options.rotationCenter || new CSG.Vector3D(0, 0, 0);
1973
+ var rotationCenter = options.rotationCenter || new CSG$1.Vector3D(0, 0, 0);
1601
1974
  var theRotationAxis = rotationAxes[rotateaxis];
1602
- var cutplane = CSG.OrthoNormalBasis.GetCartesian(info.orthoNormalCartesian[0], info.orthoNormalCartesian[1]).rotate(rotationCenter, theRotationAxis, angle);
1975
+ var cutplane = CSG$1.OrthoNormalBasis.GetCartesian(info.orthoNormalCartesian[0], info.orthoNormalCartesian[1]).rotate(rotationCenter, theRotationAxis, angle);
1603
1976
  var g = Group("negative,positive", [ object.cutByPlane(cutplane.plane).color(options.color && "red"), object.cutByPlane(cutplane.plane.flipped()).color(options.color && "blue") ]);
1604
1977
  if (options.addRotationCenter) {
1605
1978
  var objectSize = size(object);
@@ -1624,14 +1997,14 @@ function initJscadutils(_CSG, options = {}) {
1624
1997
  var bounds = object.getBounds();
1625
1998
  var objectSize = size(object);
1626
1999
  var cutDelta = getDelta(objectSize, bounds, axis, offset, true);
1627
- return object.stretchAtPlane(normal[axis], cutDelta, distance);
2000
+ return assertValidCSG$1(object.stretchAtPlane(normal[axis], cutDelta, distance), "stretch");
1628
2001
  }
1629
2002
  function poly2solid(top, bottom, height) {
1630
2003
  if (top.sides.length == 0) {
1631
- return new CSG;
2004
+ return new CSG$1;
1632
2005
  }
1633
- var offsetVector = CSG.Vector3D.Create(0, 0, height);
1634
- var normalVector = CSG.Vector3D.Create(0, 1, 0);
2006
+ var offsetVector = CSG$1.Vector3D.Create(0, 0, height);
2007
+ var normalVector = CSG$1.Vector3D.Create(0, 1, 0);
1635
2008
  var polygons = [];
1636
2009
  polygons = polygons.concat(bottom._toPlanePolygons({
1637
2010
  translation: [ 0, 0, 0 ],
@@ -1643,14 +2016,14 @@ function initJscadutils(_CSG, options = {}) {
1643
2016
  normalVector,
1644
2017
  flipped: offsetVector.z < 0
1645
2018
  }));
1646
- var c1 = new CSG.Connector(offsetVector.times(0), [ 0, 0, offsetVector.z ], normalVector);
1647
- var c2 = new CSG.Connector(offsetVector, [ 0, 0, offsetVector.z ], normalVector);
2019
+ var c1 = new CSG$1.Connector(offsetVector.times(0), [ 0, 0, offsetVector.z ], normalVector);
2020
+ var c2 = new CSG$1.Connector(offsetVector, [ 0, 0, offsetVector.z ], normalVector);
1648
2021
  polygons = polygons.concat(bottom._toWallPolygons({
1649
2022
  cag: top,
1650
2023
  toConnector1: c1,
1651
2024
  toConnector2: c2
1652
2025
  }));
1653
- return CSG.fromPolygons(polygons);
2026
+ return assertValidCSG$1(CSG$1.fromPolygons(polygons), "poly2solid");
1654
2027
  }
1655
2028
  function slices2poly(slices, options, axis) {
1656
2029
  debug$2("slices2poly", slices, options, axis);
@@ -1659,7 +2032,7 @@ function initJscadutils(_CSG, options = {}) {
1659
2032
  twiststeps: 0
1660
2033
  }, options);
1661
2034
  var twistangle = options && parseFloat(options.twistangle) || 0;
1662
- options && parseInt(options.twiststeps) || CSG.defaultResolution3D;
2035
+ options && parseInt(options.twiststeps) || CSG$1.defaultResolution3D;
1663
2036
  var normalVector = options.si.normalVector;
1664
2037
  var polygons = [];
1665
2038
  var first$1 = first(slices);
@@ -1688,8 +2061,8 @@ function initJscadutils(_CSG, options = {}) {
1688
2061
  var nextidx = idx + 1;
1689
2062
  var top = !up ? slices[nextidx] : slice;
1690
2063
  var bottom = up ? slices[nextidx] : slice;
1691
- var c1 = new CSG.Connector(bottom.offset, connectorAxis, rotate(normalVector, twistangle, idx / slices.length));
1692
- var c2 = new CSG.Connector(top.offset, connectorAxis, rotate(normalVector, twistangle, nextidx / slices.length));
2064
+ var c1 = new CSG$1.Connector(bottom.offset, connectorAxis, rotate(normalVector, twistangle, idx / slices.length));
2065
+ var c2 = new CSG$1.Connector(top.offset, connectorAxis, rotate(normalVector, twistangle, nextidx / slices.length));
1693
2066
  polygons = polygons.concat(bottom.poly._toWallPolygons({
1694
2067
  cag: top.poly,
1695
2068
  toConnector1: c1,
@@ -1697,21 +2070,21 @@ function initJscadutils(_CSG, options = {}) {
1697
2070
  }));
1698
2071
  }
1699
2072
  });
1700
- return CSG.fromPolygons(polygons);
2073
+ return assertValidCSG$1(CSG$1.fromPolygons(polygons), "slices2poly");
1701
2074
  }
1702
2075
  function normalVector(axis) {
1703
2076
  var axisInfo = {
1704
2077
  z: {
1705
2078
  orthoNormalCartesian: [ "X", "Y" ],
1706
- normalVector: CSG.Vector3D.Create(0, 1, 0)
2079
+ normalVector: CSG$1.Vector3D.Create(0, 1, 0)
1707
2080
  },
1708
2081
  x: {
1709
2082
  orthoNormalCartesian: [ "Y", "Z" ],
1710
- normalVector: CSG.Vector3D.Create(0, 0, 1)
2083
+ normalVector: CSG$1.Vector3D.Create(0, 0, 1)
1711
2084
  },
1712
2085
  y: {
1713
- orthoNormalCartesian: [ "X", "Z" ],
1714
- normalVector: CSG.Vector3D.Create(0, 0, 1)
2086
+ orthoNormalCartesian: [ "Z", "X" ],
2087
+ normalVector: CSG$1.Vector3D.Create(0, 0, 1)
1715
2088
  }
1716
2089
  };
1717
2090
  if (!axisInfo[axis]) error("normalVector: invalid axis " + axis);
@@ -1752,7 +2125,7 @@ function initJscadutils(_CSG, options = {}) {
1752
2125
  var si = sliceParams(orientation, radius, b);
1753
2126
  debug$2("reShape", absoluteRadius, si);
1754
2127
  if (si.axis !== "z") throw new Error('reShape error: CAG._toPlanePolygons only uses the "z" axis. You must use the "z" axis for now.');
1755
- var cutplane = CSG.OrthoNormalBasis.GetCartesian(si.orthoNormalCartesian[0], si.orthoNormalCartesian[1]).translate(si.cutDelta);
2128
+ var cutplane = CSG$1.OrthoNormalBasis.GetCartesian(si.orthoNormalCartesian[0], si.orthoNormalCartesian[1]).translate(si.cutDelta);
1756
2129
  var slice = object.sectionCut(cutplane);
1757
2130
  var first = axisApply(si.axis, function() {
1758
2131
  return si.positive ? 0 : absoluteRadius;
@@ -1767,25 +2140,25 @@ function initJscadutils(_CSG, options = {}) {
1767
2140
  si
1768
2141
  }), si.axis).color(options.color);
1769
2142
  var remainder = object.cutByPlane(plane);
1770
- return union([ options.unionOriginal ? object : remainder, delta.translate(si.moveDelta) ]);
2143
+ return assertValidCSG$1(union([ options.unionOriginal ? object : remainder, delta.translate(si.moveDelta) ]), "reShape");
1771
2144
  }
1772
2145
  function chamfer(object, radius, orientation, options) {
1773
- return reShape(object, radius, orientation, options, function(first, last, slice) {
2146
+ return assertValidCSG$1(reShape(object, radius, orientation, options, function(first, last, slice) {
1774
2147
  return [ {
1775
2148
  poly: slice,
1776
- offset: new CSG.Vector3D(first)
2149
+ offset: new CSG$1.Vector3D(first)
1777
2150
  }, {
1778
2151
  poly: enlarge(slice, [ -radius * 2, -radius * 2 ]),
1779
- offset: new CSG.Vector3D(last)
2152
+ offset: new CSG$1.Vector3D(last)
1780
2153
  } ];
1781
- });
2154
+ }), "chamfer");
1782
2155
  }
1783
2156
  function fillet(object, radius, orientation, options) {
1784
2157
  options = options || {};
1785
- return reShape(object, radius, orientation, options, function(first, last, slice) {
1786
- var v1 = new CSG.Vector3D(first);
1787
- var v2 = new CSG.Vector3D(last);
1788
- var res = options.resolution || CSG.defaultResolution3D;
2158
+ return assertValidCSG$1(reShape(object, radius, orientation, options, function(first, last, slice) {
2159
+ var v1 = new CSG$1.Vector3D(first);
2160
+ var v2 = new CSG$1.Vector3D(last);
2161
+ var res = options.resolution || CSG$1.defaultResolution3D;
1789
2162
  var slices = range(0, res).map(function(i) {
1790
2163
  var p = i > 0 ? i / (res - 1) : 0;
1791
2164
  var v = v1.lerp(v2, p);
@@ -1796,7 +2169,7 @@ function initJscadutils(_CSG, options = {}) {
1796
2169
  };
1797
2170
  });
1798
2171
  return slices;
1799
- });
2172
+ }), "fillet");
1800
2173
  }
1801
2174
  function calcRotate(part, solid, axis) {
1802
2175
  var axes = {
@@ -1813,7 +2186,7 @@ function initJscadutils(_CSG, options = {}) {
1813
2186
  }
1814
2187
  function rotateAround(part, solid, axis, angle) {
1815
2188
  var _calcRotate = calcRotate(part, solid, axis), rotationCenter = _calcRotate.rotationCenter, rotationAxis = _calcRotate.rotationAxis;
1816
- return part.rotate(rotationCenter, rotationAxis, angle);
2189
+ return assertValidCSG$1("rotateAround")(part.rotate(rotationCenter, rotationAxis, angle));
1817
2190
  }
1818
2191
  function cloneProperties(from, to) {
1819
2192
  return Object.entries(from).reduce(function(props, _ref) {
@@ -1823,19 +2196,20 @@ function initJscadutils(_CSG, options = {}) {
1823
2196
  }, to);
1824
2197
  }
1825
2198
  function clone(o) {
1826
- var c = CSG.fromPolygons(o.toPolygons());
2199
+ var c = CSG$1.fromPolygons(o.toPolygons());
1827
2200
  cloneProperties(o, c);
1828
- debug$2("clone", o, c, CSG);
1829
- return c;
2201
+ debug$2("clone", o, c, CSG$1);
2202
+ return assertValidCSG$1(c, "clone");
1830
2203
  }
1831
2204
  function addConnector(object, name) {
1832
2205
  var point = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : [ 0, 0, 0 ];
1833
2206
  var axis = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : [ 1, 0, 0 ];
1834
2207
  var normal = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : [ 0, 0, 1 ];
1835
- object.properties[name] = new CSG.Connector(point, axis, normal);
1836
- return object;
2208
+ object.properties[name] = new CSG$1.Connector(point, axis, normal);
2209
+ return assertValidCSG$1("addConnector")(object);
1837
2210
  }
1838
2211
  var debug$1 = Debug("jscadUtils:parts");
2212
+ var assertValidCSG = AssertValidCSG("parts");
1839
2213
  var parts = {
1840
2214
  BBox: BBox$1,
1841
2215
  Cube,
@@ -1845,7 +2219,7 @@ function initJscadutils(_CSG, options = {}) {
1845
2219
  };
1846
2220
  function BBox$1() {
1847
2221
  function box(object) {
1848
- return CSG.cube({
2222
+ return CSG$1.cube({
1849
2223
  center: object.centroid(),
1850
2224
  radius: object.size().dividedBy(2)
1851
2225
  });
@@ -1853,17 +2227,17 @@ function initJscadutils(_CSG, options = {}) {
1853
2227
  for (var _len = arguments.length, objects = new Array(_len), _key = 0; _key < _len; _key++) {
1854
2228
  objects[_key] = arguments[_key];
1855
2229
  }
1856
- return objects.reduce(function(bbox, part) {
2230
+ return assertValidCSG(objects.reduce(function(bbox, part) {
1857
2231
  var object = bbox ? union([ bbox, box(part) ]) : part;
1858
2232
  return box(object);
1859
- }, undefined);
2233
+ }, undefined), "BBox");
1860
2234
  }
1861
2235
  function Cube(width) {
1862
2236
  var r = div$1(fromxyz(width), 2);
1863
- return CSG.cube({
2237
+ return assertValidCSG(CSG$1.cube({
1864
2238
  center: r,
1865
2239
  radius: r
1866
- });
2240
+ }), "Cube");
1867
2241
  }
1868
2242
  function RoundedCube(x, y, thickness, corner_radius) {
1869
2243
  if (x.getBounds) {
@@ -1879,11 +2253,11 @@ function initJscadutils(_CSG, options = {}) {
1879
2253
  center: [ r[0], r[1], 0 ],
1880
2254
  radius: r,
1881
2255
  roundradius: corner_radius,
1882
- resolution: CSG.defaultResolution2D
2256
+ resolution: CSG$1.defaultResolution2D
1883
2257
  }).extrude({
1884
2258
  offset: [ 0, 0, thickness || 1.62 ]
1885
2259
  });
1886
- return roundedcube;
2260
+ return assertValidCSG(roundedcube, "RoundedCube");
1887
2261
  }
1888
2262
  function Cylinder(diameter, height) {
1889
2263
  var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
@@ -1892,39 +2266,39 @@ function initJscadutils(_CSG, options = {}) {
1892
2266
  start: [ 0, 0, 0 ],
1893
2267
  end: [ 0, 0, height ],
1894
2268
  radius: diameter / 2,
1895
- resolution: CSG.defaultResolution2D
2269
+ resolution: CSG$1.defaultResolution2D
1896
2270
  }, options);
1897
- return CSG.cylinder(options);
2271
+ return assertValidCSG(CSG$1.cylinder(options), "Cylinder");
1898
2272
  }
1899
2273
  function Cone(diameter1, diameter2, height) {
1900
2274
  var options = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {};
1901
2275
  debug$1("parts.Cone", diameter1, diameter2, height, options);
1902
- return CSG.cylinder(Object.assign({
2276
+ return assertValidCSG(CSG$1.cylinder(Object.assign({
1903
2277
  start: [ 0, 0, 0 ],
1904
2278
  end: [ 0, 0, height ],
1905
2279
  radiusStart: diameter1 / 2,
1906
2280
  radiusEnd: diameter2 / 2,
1907
- resolution: CSG.defaultResolution2D
1908
- }, options));
2281
+ resolution: CSG$1.defaultResolution2D
2282
+ }, options)), "Cone");
1909
2283
  }
1910
2284
  function Hexagon(diameter, height) {
1911
2285
  debug$1("hexagon", diameter, height);
1912
2286
  var radius = diameter / 2;
1913
2287
  var sqrt3 = Math.sqrt(3) / 2;
1914
2288
  var hex = CAG.fromPoints([ [ radius, 0 ], [ radius / 2, radius * sqrt3 ], [ -radius / 2, radius * sqrt3 ], [ -radius, 0 ], [ -radius / 2, -radius * sqrt3 ], [ radius / 2, -radius * sqrt3 ] ]);
1915
- return hex.extrude({
2289
+ return assertValidCSG(hex.extrude({
1916
2290
  offset: [ 0, 0, height ]
1917
- });
2291
+ }), "Hexagon");
1918
2292
  }
1919
2293
  function Triangle(base, height) {
1920
2294
  var radius = base / 2;
1921
2295
  var tri = CAG.fromPoints([ [ -radius, 0 ], [ radius, 0 ], [ 0, Math.sin(30) * radius ] ]);
1922
- return tri.extrude({
2296
+ return assertValidCSG(tri.extrude({
1923
2297
  offset: [ 0, 0, height ]
1924
- });
2298
+ }), "Triangle");
1925
2299
  }
1926
2300
  function Tube(outsideDiameter, insideDiameter, height, outsideOptions, insideOptions) {
1927
- return Cylinder(outsideDiameter, height, outsideOptions).subtract(Cylinder(insideDiameter, height, insideOptions || outsideOptions));
2301
+ return assertValidCSG(Cylinder(outsideDiameter, height, outsideOptions).subtract(Cylinder(insideDiameter, height, insideOptions || outsideOptions)), "Tube");
1928
2302
  }
1929
2303
  function Anchor() {
1930
2304
  var width = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 10;
@@ -1942,11 +2316,11 @@ function initJscadutils(_CSG, options = {}) {
1942
2316
  center: [ r[0], r[1], 0 ],
1943
2317
  radius: r,
1944
2318
  roundradius: corner_radius,
1945
- resolution: CSG.defaultResolution2D
2319
+ resolution: CSG$1.defaultResolution2D
1946
2320
  }).extrude({
1947
2321
  offset: [ 0, 0, thickness || 1.62 ]
1948
2322
  });
1949
- return board;
2323
+ return assertValidCSG(board, "Board");
1950
2324
  }
1951
2325
  var Hardware = {
1952
2326
  Orientation: {
@@ -2037,6 +2411,10 @@ function initJscadutils(_CSG, options = {}) {
2037
2411
  gap = gap || .25;
2038
2412
  var inside = thickness - gap;
2039
2413
  var outside = -thickness + gap;
2414
+ var boxHeight = box.size().z;
2415
+ if (Math.abs(height) >= boxHeight) {
2416
+ throw new Error("Rabett: height (".concat(height, ") must be less than the object height (").concat(boxHeight, ")"));
2417
+ }
2040
2418
  debug("inside", inside, "outside", outside);
2041
2419
  var group = Group();
2042
2420
  var _box$bisect$parts = box.bisect("z", height, options).parts, top = _box$bisect$parts.positive, lower2_3rd = _box$bisect$parts.negative;
@@ -2107,10 +2485,10 @@ function initJscadutils(_CSG, options = {}) {
2107
2485
  thickness = thickness || 2;
2108
2486
  var s = div$1(xyz2array(size), 2);
2109
2487
  var r = add(s, thickness);
2110
- var box = CSG.cube({
2488
+ var box = CSG$1.cube({
2111
2489
  center: r,
2112
2490
  radius: r
2113
- }).subtract(CSG.cube({
2491
+ }).subtract(CSG$1.cube({
2114
2492
  center: r,
2115
2493
  radius: s
2116
2494
  }));
@@ -2128,7 +2506,7 @@ function initJscadutils(_CSG, options = {}) {
2128
2506
  var BBox = function BBox(o) {
2129
2507
  depreciated("BBox", true, "Use 'parts.BBox' instead");
2130
2508
  var s = div$1(xyz2array(o.size()), 2);
2131
- return CSG.cube({
2509
+ return CSG$1.cube({
2132
2510
  center: s,
2133
2511
  radius: s
2134
2512
  }).align(o, "xyz");
@@ -2140,7 +2518,7 @@ function initJscadutils(_CSG, options = {}) {
2140
2518
  var gap = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : .25;
2141
2519
  var r = add(getRadius(box), -thickness / 2);
2142
2520
  r[2] = thickness / 2;
2143
- var cutter = CSG.cube({
2521
+ var cutter = CSG$1.cube({
2144
2522
  center: r,
2145
2523
  radius: r
2146
2524
  }).align(box, "xy").color("green");