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