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