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