@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.
@@ -99,6 +99,8 @@ function initJscadutils(_CSG, options = {}) {
99
99
  enabled: [],
100
100
  disabled: []
101
101
  });
102
+ var jscadUtilsAssertValidCSGWarnings = options.assertValidCSGWarnings || false;
103
+ var jscadUtilsAssertValidCSG = options.assertValidCSG || false;
102
104
  var jscadUtils = function(exports, jsCadCSG, scadApi) {
103
105
  "use strict";
104
106
  function _interopDefaultLegacy(e) {
@@ -332,6 +334,51 @@ function initJscadutils(_CSG, options = {}) {
332
334
  function _arrayWithHoles(r) {
333
335
  if (Array.isArray(r)) return r;
334
336
  }
337
+ function _createForOfIteratorHelper(r, e) {
338
+ var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"];
339
+ if (!t) {
340
+ if (Array.isArray(r) || (t = _unsupportedIterableToArray(r)) || e && r && "number" == typeof r.length) {
341
+ t && (r = t);
342
+ var n = 0, F = function() {};
343
+ return {
344
+ s: F,
345
+ n: function() {
346
+ return n >= r.length ? {
347
+ done: !0
348
+ } : {
349
+ done: !1,
350
+ value: r[n++]
351
+ };
352
+ },
353
+ e: function(r) {
354
+ throw r;
355
+ },
356
+ f: F
357
+ };
358
+ }
359
+ throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
360
+ }
361
+ var o, a = !0, u = !1;
362
+ return {
363
+ s: function() {
364
+ t = t.call(r);
365
+ },
366
+ n: function() {
367
+ var r = t.next();
368
+ return a = r.done, r;
369
+ },
370
+ e: function(r) {
371
+ u = !0, o = r;
372
+ },
373
+ f: function() {
374
+ try {
375
+ a || null == t.return || t.return();
376
+ } finally {
377
+ if (u) throw o;
378
+ }
379
+ }
380
+ };
381
+ }
335
382
  function _defineProperty(e, r, t) {
336
383
  return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, {
337
384
  value: t,
@@ -752,6 +799,219 @@ function initJscadutils(_CSG, options = {}) {
752
799
  c[3] = g || 1;
753
800
  return o.setColor(c);
754
801
  }
802
+ function validateCSG(csg, options) {
803
+ var errors = [];
804
+ var warnings = [];
805
+ if (!csg || !csg.polygons || csg.polygons.length === 0) {
806
+ errors.push("Empty mesh: no polygons");
807
+ return {
808
+ ok: false,
809
+ errors,
810
+ warnings
811
+ };
812
+ }
813
+ var opts = _objectSpread2({
814
+ fixTJunctions: true
815
+ }, options);
816
+ if (opts.fixTJunctions && typeof csg.canonicalized === "function") {
817
+ csg = csg.canonicalized();
818
+ if (typeof csg.reTesselated === "function") {
819
+ csg = csg.reTesselated();
820
+ }
821
+ if (typeof csg.fixTJunctions === "function") {
822
+ csg = csg.fixTJunctions();
823
+ }
824
+ }
825
+ var AREA_EPS = 1e-10;
826
+ var KEY_EPS = 1e-5;
827
+ var degenerateCount = 0;
828
+ var invalidVertexCount = 0;
829
+ var _iterator = _createForOfIteratorHelper(csg.polygons), _step;
830
+ try {
831
+ for (_iterator.s(); !(_step = _iterator.n()).done; ) {
832
+ var npoly = _step.value;
833
+ var _iterator4 = _createForOfIteratorHelper(npoly.vertices), _step4;
834
+ try {
835
+ for (_iterator4.s(); !(_step4 = _iterator4.n()).done; ) {
836
+ var nvert = _step4.value;
837
+ var np = nvert.pos;
838
+ 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)) {
839
+ invalidVertexCount++;
840
+ break;
841
+ }
842
+ }
843
+ } catch (err) {
844
+ _iterator4.e(err);
845
+ } finally {
846
+ _iterator4.f();
847
+ }
848
+ }
849
+ } catch (err) {
850
+ _iterator.e(err);
851
+ } finally {
852
+ _iterator.f();
853
+ }
854
+ if (invalidVertexCount > 0) {
855
+ errors.push(invalidVertexCount + " polygon(s) with invalid vertex coordinates (NaN or Infinity)");
856
+ }
857
+ function vtxKey(v) {
858
+ var p = v.pos;
859
+ return Math.round(p.x / KEY_EPS) + "," + Math.round(p.y / KEY_EPS) + "," + Math.round(p.z / KEY_EPS);
860
+ }
861
+ var validPolygons = [];
862
+ var _iterator2 = _createForOfIteratorHelper(csg.polygons), _step2;
863
+ try {
864
+ for (_iterator2.s(); !(_step2 = _iterator2.n()).done; ) {
865
+ var poly = _step2.value;
866
+ var verts = poly.vertices;
867
+ var nv = verts.length;
868
+ if (nv < 3) {
869
+ degenerateCount++;
870
+ continue;
871
+ }
872
+ var hasInvalid = false;
873
+ var _iterator5 = _createForOfIteratorHelper(verts), _step5;
874
+ try {
875
+ for (_iterator5.s(); !(_step5 = _iterator5.n()).done; ) {
876
+ var vert = _step5.value;
877
+ var ip = vert.pos;
878
+ if (!Number.isFinite(ip.x) || !Number.isFinite(ip.y) || !Number.isFinite(ip.z)) {
879
+ hasInvalid = true;
880
+ break;
881
+ }
882
+ }
883
+ } catch (err) {
884
+ _iterator5.e(err);
885
+ } finally {
886
+ _iterator5.f();
887
+ }
888
+ if (hasInvalid) continue;
889
+ var area = 0;
890
+ for (var ai = 0; ai < nv - 2; ai++) {
891
+ area += verts[ai + 1].pos.minus(verts[0].pos).cross(verts[ai + 2].pos.minus(verts[ai + 1].pos)).length();
892
+ }
893
+ area *= .5;
894
+ if (area < AREA_EPS) {
895
+ degenerateCount++;
896
+ continue;
897
+ }
898
+ validPolygons.push(poly);
899
+ }
900
+ } catch (err) {
901
+ _iterator2.e(err);
902
+ } finally {
903
+ _iterator2.f();
904
+ }
905
+ if (degenerateCount > 0) {
906
+ warnings.push(degenerateCount + " degenerate polygon(s) (fewer than 3 vertices or near-zero area)");
907
+ if (opts.fixTJunctions && typeof CSG !== "undefined") {
908
+ var cleaned = CSG.fromPolygons(validPolygons);
909
+ cleaned = cleaned.canonicalized();
910
+ if (typeof cleaned.reTesselated === "function") {
911
+ cleaned = cleaned.reTesselated();
912
+ }
913
+ if (typeof cleaned.fixTJunctions === "function") {
914
+ cleaned = cleaned.fixTJunctions();
915
+ }
916
+ validPolygons = [];
917
+ var _iterator3 = _createForOfIteratorHelper(cleaned.polygons), _step3;
918
+ try {
919
+ for (_iterator3.s(); !(_step3 = _iterator3.n()).done; ) {
920
+ var cpoly = _step3.value;
921
+ var cverts = cpoly.vertices;
922
+ var cnv = cverts.length;
923
+ if (cnv < 3) continue;
924
+ var carea = 0;
925
+ for (var cai = 0; cai < cnv - 2; cai++) {
926
+ carea += cverts[cai + 1].pos.minus(cverts[0].pos).cross(cverts[cai + 2].pos.minus(cverts[cai + 1].pos)).length();
927
+ }
928
+ carea *= .5;
929
+ if (carea < AREA_EPS) continue;
930
+ validPolygons.push(cpoly);
931
+ }
932
+ } catch (err) {
933
+ _iterator3.e(err);
934
+ } finally {
935
+ _iterator3.f();
936
+ }
937
+ }
938
+ }
939
+ var edgeCounts = {};
940
+ for (var _i = 0, _validPolygons = validPolygons; _i < _validPolygons.length; _i++) {
941
+ var vpoly = _validPolygons[_i];
942
+ var vverts = vpoly.vertices;
943
+ var vnv = vverts.length;
944
+ for (var ei = 0; ei < vnv; ei++) {
945
+ var v0 = vverts[ei];
946
+ var v1 = vverts[(ei + 1) % vnv];
947
+ var edgeKey = vtxKey(v0) + "/" + vtxKey(v1);
948
+ edgeCounts[edgeKey] = (edgeCounts[edgeKey] || 0) + 1;
949
+ }
950
+ }
951
+ var unmatchedEdges = 0;
952
+ var nonManifoldEdges = 0;
953
+ var checked = {};
954
+ for (var _i2 = 0, _Object$keys = Object.keys(edgeCounts); _i2 < _Object$keys.length; _i2++) {
955
+ var _edgeKey = _Object$keys[_i2];
956
+ if (checked[_edgeKey]) continue;
957
+ var parts = _edgeKey.split("/");
958
+ var reverseKey = parts[1] + "/" + parts[0];
959
+ var forwardCount = edgeCounts[_edgeKey] || 0;
960
+ var reverseCount = edgeCounts[reverseKey] || 0;
961
+ checked[_edgeKey] = true;
962
+ checked[reverseKey] = true;
963
+ if (forwardCount !== reverseCount) {
964
+ unmatchedEdges += Math.abs(forwardCount - reverseCount);
965
+ }
966
+ if (forwardCount > 1 || reverseCount > 1) {
967
+ nonManifoldEdges++;
968
+ }
969
+ }
970
+ if (unmatchedEdges > 0) {
971
+ errors.push(unmatchedEdges + " unmatched edge(s): mesh is not watertight");
972
+ }
973
+ if (nonManifoldEdges > 0) {
974
+ errors.push(nonManifoldEdges + " non-manifold edge(s): edge shared by more than 2 polygons");
975
+ }
976
+ return {
977
+ ok: errors.length === 0,
978
+ errors,
979
+ warnings
980
+ };
981
+ }
982
+ function _noOp(csg) {
983
+ return csg;
984
+ }
985
+ function _makeAssertFn(warnEnabled) {
986
+ return function _assert(csg) {
987
+ var functionName = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : "unknown";
988
+ var moduleName = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : "unknown";
989
+ if (!csg || csg.polygons === undefined) return csg;
990
+ var result = validateCSG(csg);
991
+ if (!result.ok) {
992
+ throw new Error(moduleName + ":" + functionName + ": " + "invalid CSG: " + result.errors.join(", "));
993
+ }
994
+ if (warnEnabled && result.warnings.length > 0) {
995
+ throw new Error(moduleName + ":" + functionName + ": " + "CSG warnings: " + result.warnings.join(", "));
996
+ }
997
+ return csg;
998
+ };
999
+ }
1000
+ var _assertFn = _noOp;
1001
+ function _resolveFromGlobals() {
1002
+ var enabled = typeof jscadUtilsAssertValidCSG !== "undefined" && !!jscadUtilsAssertValidCSG;
1003
+ var warnEnabled = typeof jscadUtilsAssertValidCSGWarnings !== "undefined" && !!jscadUtilsAssertValidCSGWarnings;
1004
+ return enabled ? _makeAssertFn(warnEnabled) : _noOp;
1005
+ }
1006
+ function AssertValidCSG() {
1007
+ var moduleName = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : "unknown";
1008
+ {
1009
+ _assertFn = _resolveFromGlobals();
1010
+ }
1011
+ return function(csg, name) {
1012
+ return _assertFn(csg, name, moduleName);
1013
+ };
1014
+ }
755
1015
  function init(proto) {
756
1016
  if (proto.prototype._jscadutilsinit) return;
757
1017
  proto.prototype.color = function(r, g, b, a) {
@@ -845,6 +1105,9 @@ function initJscadutils(_CSG, options = {}) {
845
1105
  proto.prototype.subtractIf = function subtractIf(object, condition) {
846
1106
  return condition ? this.subtract(result(this, object)) : this;
847
1107
  };
1108
+ proto.prototype.validate = function validate(options) {
1109
+ return validateCSG(this, options);
1110
+ };
848
1111
  proto.prototype._translate = proto.prototype.translate;
849
1112
  proto.prototype.translate = function translate() {
850
1113
  if (arguments.length === 1) {
@@ -877,12 +1140,13 @@ function initJscadutils(_CSG, options = {}) {
877
1140
  __proto__: null,
878
1141
  default: init
879
1142
  });
880
- var CSG = jsCadCSG__default["default"].CSG, CAG = jsCadCSG__default["default"].CAG;
1143
+ var CSG$1 = jsCadCSG__default["default"].CSG, CAG = jsCadCSG__default["default"].CAG;
881
1144
  var rectangular_extrude = scadApi__default["default"].extrusions.rectangular_extrude;
882
1145
  var _scadApi$text = scadApi__default["default"].text, vector_text = _scadApi$text.vector_text, vector_char = _scadApi$text.vector_char;
883
1146
  var union = scadApi__default["default"].booleanOps.union;
884
- init(CSG);
1147
+ init(CSG$1);
885
1148
  var debug$3 = Debug("jscadUtils:group");
1149
+ var assertValidCSG$2 = AssertValidCSG("group");
886
1150
  function JsCadUtilsGroup() {
887
1151
  var names = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];
888
1152
  var parts = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
@@ -933,7 +1197,7 @@ function initJscadutils(_CSG, options = {}) {
933
1197
  debug$3("combine mapPick", value, key, object);
934
1198
  return map ? map(value, key, index, object) : identity(value);
935
1199
  }, self.name));
936
- return g.subtractIf(self.holes && Array.isArray(self.holes) ? union(self.holes) : self.holes, self.holes && !options.noholes);
1200
+ return assertValidCSG$2(g.subtractIf(self.holes && Array.isArray(self.holes) ? union(self.holes) : self.holes, self.holes && !options.noholes), "combine");
937
1201
  } catch (err) {
938
1202
  debug$3("combine error", this, pieces, options, err);
939
1203
  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");
@@ -974,7 +1238,7 @@ function initJscadutils(_CSG, options = {}) {
974
1238
  });
975
1239
  if (self.holes) {
976
1240
  group.holes = toArray(self.holes).map(function(part) {
977
- return map(CSG.fromPolygons(part.toPolygons()), "holes");
1241
+ return assertValidCSG$2(map(CSG$1.fromPolygons(part.toPolygons()), "holes"), "clone");
978
1242
  });
979
1243
  }
980
1244
  return group;
@@ -993,7 +1257,7 @@ function initJscadutils(_CSG, options = {}) {
993
1257
  var rotationCenter = solid.centroid();
994
1258
  var rotationAxis = axes[axis];
995
1259
  self.map(function(part) {
996
- return part.rotate(rotationCenter, rotationAxis, angle);
1260
+ return assertValidCSG$2(part.rotate(rotationCenter, rotationAxis, angle), "rotate");
997
1261
  });
998
1262
  return self;
999
1263
  };
@@ -1006,7 +1270,7 @@ function initJscadutils(_CSG, options = {}) {
1006
1270
  var self = this;
1007
1271
  var t = calcSnap(self.combine(part), to, axis, orientation, delta);
1008
1272
  self.map(function(part) {
1009
- return part.translate(t);
1273
+ return assertValidCSG$2(part.translate(t), "snap");
1010
1274
  });
1011
1275
  return self;
1012
1276
  } catch (err) {
@@ -1021,7 +1285,7 @@ function initJscadutils(_CSG, options = {}) {
1021
1285
  noholes: true
1022
1286
  }), axis, to, delta);
1023
1287
  self.map(function(part) {
1024
- return part.translate(t);
1288
+ return assertValidCSG$2(part.translate(t), "align");
1025
1289
  });
1026
1290
  return self;
1027
1291
  } catch (err) {
@@ -1053,14 +1317,14 @@ function initJscadutils(_CSG, options = {}) {
1053
1317
  var myConnector = connectorName.split(".").reduce(function(a, v) {
1054
1318
  return a[v];
1055
1319
  }, self.parts[partName].properties);
1056
- debug$3("toConnector", to instanceof CSG.Connector);
1320
+ debug$3("toConnector", to instanceof CSG$1.Connector);
1057
1321
  var toConnector = toConnectorName.split(".").reduce(function(a, v) {
1058
1322
  return a[v];
1059
1323
  }, to.properties);
1060
1324
  var matrix = myConnector.getTransformationTo(toConnector, mirror, normalrotation);
1061
1325
  debug$3("connectTo", matrix);
1062
1326
  self.map(function(part) {
1063
- return part.transform(matrix);
1327
+ return assertValidCSG$2(part.transform(matrix), "connectTo");
1064
1328
  });
1065
1329
  return self;
1066
1330
  };
@@ -1071,7 +1335,7 @@ function initJscadutils(_CSG, options = {}) {
1071
1335
  return to - size[a] / 2;
1072
1336
  });
1073
1337
  self.map(function(part) {
1074
- return part.translate(t);
1338
+ return assertValidCSG$2(part.translate(t), "midlineTo");
1075
1339
  });
1076
1340
  return self;
1077
1341
  };
@@ -1080,7 +1344,7 @@ function initJscadutils(_CSG, options = {}) {
1080
1344
  var t = Array.isArray(x) ? x : [ x, y, z ];
1081
1345
  debug$3("translate", t);
1082
1346
  self.map(function(part) {
1083
- return part.translate(t);
1347
+ return assertValidCSG$2(part.translate(t), "translate");
1084
1348
  });
1085
1349
  return self;
1086
1350
  };
@@ -1090,7 +1354,7 @@ function initJscadutils(_CSG, options = {}) {
1090
1354
  if (!map) map = identity;
1091
1355
  var g = Group();
1092
1356
  p.forEach(function(name) {
1093
- g.add(map(CSG.fromPolygons(self.parts[name].toPolygons()), name), name);
1357
+ g.add(assertValidCSG$2(map(CSG$1.fromPolygons(self.parts[name].toPolygons()), name), "pick"), name);
1094
1358
  });
1095
1359
  return g;
1096
1360
  };
@@ -1105,7 +1369,7 @@ function initJscadutils(_CSG, options = {}) {
1105
1369
  debug$3("array error", _this, parts);
1106
1370
  throw error('group::array error "'.concat(name, '" not found.\nthis: ').concat(_this, '\nparts: "').concat(parts, '"\n'), "JSCAD_UTILS_GROUP_ERROR");
1107
1371
  }
1108
- a.push(map(CSG.fromPolygons(self.parts[name].toPolygons()), name));
1372
+ a.push(assertValidCSG$2(map(CSG$1.fromPolygons(self.parts[name].toPolygons()), name), "array"));
1109
1373
  });
1110
1374
  return a;
1111
1375
  };
@@ -1138,7 +1402,7 @@ function initJscadutils(_CSG, options = {}) {
1138
1402
  self.names = names && names.length > 0 && names.split(",") || [];
1139
1403
  if (Array.isArray(objects)) {
1140
1404
  self.parts = zipObject(self.names, objects);
1141
- } else if (objects instanceof CSG) {
1405
+ } else if (objects instanceof CSG$1) {
1142
1406
  self.parts = zipObject(self.names, [ objects ]);
1143
1407
  } else {
1144
1408
  self.parts = objects || {};
@@ -1159,6 +1423,7 @@ function initJscadutils(_CSG, options = {}) {
1159
1423
  return new JsCadUtilsGroup(self.names, self.parts, self.holes);
1160
1424
  }
1161
1425
  var debug$2 = Debug("jscadUtils:util");
1426
+ var assertValidCSG$1 = AssertValidCSG("util");
1162
1427
  var NOZZEL_SIZE = .4;
1163
1428
  var nearest = {
1164
1429
  under: function under(desired) {
@@ -1235,12 +1500,12 @@ function initJscadutils(_CSG, options = {}) {
1235
1500
  h: height || 2
1236
1501
  }));
1237
1502
  });
1238
- return center(union(o));
1503
+ return assertValidCSG$1(center(union(o)), "label");
1239
1504
  }
1240
1505
  function text(text) {
1241
1506
  var l = vector_char(0, 0, text);
1242
1507
  var _char = l.segments.reduce(function(result, segment) {
1243
- var path = new CSG.Path2D(segment);
1508
+ var path = new CSG$1.Path2D(segment);
1244
1509
  var cag = path.expandToCAG(2);
1245
1510
  return result ? result.union(cag) : cag;
1246
1511
  }, undefined);
@@ -1248,17 +1513,17 @@ function initJscadutils(_CSG, options = {}) {
1248
1513
  }
1249
1514
  function unitCube(length, radius) {
1250
1515
  radius = radius || .5;
1251
- return CSG.cube({
1516
+ return assertValidCSG$1(CSG$1.cube({
1252
1517
  center: [ 0, 0, 0 ],
1253
1518
  radius: [ radius, radius, length || .5 ]
1254
- });
1519
+ }), "unitCube");
1255
1520
  }
1256
1521
  function unitAxis(length, radius, centroid) {
1257
1522
  debug$2("unitAxis", length, radius, centroid);
1258
1523
  centroid = centroid || [ 0, 0, 0 ];
1259
1524
  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) ]);
1260
- unitaxis.properties.origin = new CSG.Connector([ 0, 0, 0 ], [ 1, 0, 0 ], [ 0, 1, 0 ]);
1261
- return unitaxis.translate(centroid);
1525
+ unitaxis.properties.origin = new CSG$1.Connector([ 0, 0, 0 ], [ 1, 0, 0 ], [ 0, 1, 0 ]);
1526
+ return assertValidCSG$1(unitaxis.translate(centroid), "unitAxis");
1262
1527
  }
1263
1528
  function toArray(a) {
1264
1529
  return Array.isArray(a) ? a : [ a ];
@@ -1348,15 +1613,15 @@ function initJscadutils(_CSG, options = {}) {
1348
1613
  }
1349
1614
  function center(object, objectSize) {
1350
1615
  objectSize = objectSize || size(object.getBounds());
1351
- return centerY(centerX(object, objectSize), objectSize);
1616
+ return assertValidCSG$1(centerY(centerX(object, objectSize), objectSize), "center");
1352
1617
  }
1353
1618
  function centerY(object, objectSize) {
1354
1619
  objectSize = objectSize || size(object.getBounds());
1355
- return object.translate([ 0, -objectSize.y / 2, 0 ]);
1620
+ return assertValidCSG$1(object.translate([ 0, -objectSize.y / 2, 0 ]), "centerY");
1356
1621
  }
1357
1622
  function centerX(object, objectSize) {
1358
1623
  objectSize = objectSize || size(object.getBounds());
1359
- return object.translate([ -objectSize.x / 2, 0, 0 ]);
1624
+ return assertValidCSG$1(object.translate([ -objectSize.x / 2, 0, 0 ]), "centerX");
1360
1625
  }
1361
1626
  function enlarge(object, x, y, z) {
1362
1627
  var a;
@@ -1374,7 +1639,7 @@ function initJscadutils(_CSG, options = {}) {
1374
1639
  var new_object = object.scale(t);
1375
1640
  var new_centroid = centroid(new_object);
1376
1641
  var delta = new_centroid.minus(objectCentroid).times(-1);
1377
- return new_object.translate(delta);
1642
+ return assertValidCSG$1(new_object.translate(delta), "enlarge");
1378
1643
  }
1379
1644
  function fit(object, x, y, z, keep_aspect_ratio) {
1380
1645
  var a;
@@ -1394,10 +1659,10 @@ function initJscadutils(_CSG, options = {}) {
1394
1659
  }
1395
1660
  var s = [ scale(objectSize.x, x), scale(objectSize.y, y), scale(objectSize.z, z) ];
1396
1661
  var min$1 = min(s);
1397
- return centerWith(object.scale(s.map(function(d, i) {
1662
+ return assertValidCSG$1(centerWith(object.scale(s.map(function(d, i) {
1398
1663
  if (a[i] === 0) return 1;
1399
1664
  return keep_aspect_ratio ? min$1 : d;
1400
- })), "xyz", object);
1665
+ })), "xyz", object), "fit");
1401
1666
  }
1402
1667
  function shift(object, x, y, z) {
1403
1668
  var hsize = this.div(this.size(object.getBounds()), 2);
@@ -1405,10 +1670,10 @@ function initJscadutils(_CSG, options = {}) {
1405
1670
  }
1406
1671
  function zero(object) {
1407
1672
  var bounds = object.getBounds();
1408
- return object.translate([ 0, 0, -bounds[0].z ]);
1673
+ return assertValidCSG$1(object.translate([ 0, 0, -bounds[0].z ]), "zero");
1409
1674
  }
1410
1675
  function mirrored4(x) {
1411
- return x.union([ x.mirroredY(90), x.mirroredX(90), x.mirroredY(90).mirroredX(90) ]);
1676
+ return assertValidCSG$1(x.union([ x.mirroredY(90), x.mirroredX(90), x.mirroredY(90).mirroredX(90) ]), "mirrored4");
1412
1677
  }
1413
1678
  var flushSide = {
1414
1679
  "above-outside": [ 1, 0 ],
@@ -1469,10 +1734,10 @@ function initJscadutils(_CSG, options = {}) {
1469
1734
  function snap(moveobj, withobj, axis, orientation, delta) {
1470
1735
  debug$2("snap", moveobj, withobj, axis, orientation, delta);
1471
1736
  var t = calcSnap(moveobj, withobj, axis, orientation, delta);
1472
- return moveobj.translate(t);
1737
+ return assertValidCSG$1(moveobj.translate(t), "snap");
1473
1738
  }
1474
1739
  function flush(moveobj, withobj, axis, mside, wside) {
1475
- return moveobj.translate(calcFlush(moveobj, withobj, axis, mside, wside));
1740
+ return assertValidCSG$1(moveobj.translate(calcFlush(moveobj, withobj, axis, mside, wside)), "flush");
1476
1741
  }
1477
1742
  function axisApply(axes, valfun, a) {
1478
1743
  debug$2("axisApply", axes, valfun, a);
@@ -1488,7 +1753,7 @@ function initJscadutils(_CSG, options = {}) {
1488
1753
  return retval;
1489
1754
  }
1490
1755
  function axis2array(axes, valfun) {
1491
- depreciated("axis2array");
1756
+ depreciated("axis2array", false, "Use axisApply instead.");
1492
1757
  var a = [ 0, 0, 0 ];
1493
1758
  var lookup = {
1494
1759
  x: 0,
@@ -1518,7 +1783,7 @@ function initJscadutils(_CSG, options = {}) {
1518
1783
  });
1519
1784
  }
1520
1785
  function midlineTo(o, axis, to) {
1521
- return o.translate(calcmidlineTo(o, axis, to));
1786
+ return assertValidCSG$1(o.translate(calcmidlineTo(o, axis, to)), "midlineTo");
1522
1787
  }
1523
1788
  function translator(o, axis, withObj) {
1524
1789
  var objectCentroid = centroid(o);
@@ -1538,7 +1803,7 @@ function initJscadutils(_CSG, options = {}) {
1538
1803
  return delta ? add(t, delta) : t;
1539
1804
  }
1540
1805
  function centerWith(o, axis, withObj) {
1541
- return o.translate(calcCenterWith(o, axis, withObj));
1806
+ return assertValidCSG$1(o.translate(calcCenterWith(o, axis, withObj)), "centerWith");
1542
1807
  }
1543
1808
  function getDelta(size, bounds, axis, offset, nonzero) {
1544
1809
  if (!isEmpty(offset) && nonzero) {
@@ -1551,6 +1816,95 @@ function initJscadutils(_CSG, options = {}) {
1551
1816
  return bounds[0][a] + (isEmpty(dist) ? size[axis] / 2 : dist);
1552
1817
  });
1553
1818
  }
1819
+ var EPS = 1e-5;
1820
+ function splitCSGByPlane(csg, plane) {
1821
+ var frontPolys = [];
1822
+ var backPolys = [];
1823
+ csg.polygons.forEach(function(poly) {
1824
+ var vertices = poly.vertices;
1825
+ var numVerts = vertices.length;
1826
+ var hasfront = false;
1827
+ var hasback = false;
1828
+ var vertexIsBack = [];
1829
+ for (var i = 0; i < numVerts; i++) {
1830
+ var t = plane.normal.dot(vertices[i].pos) - plane.w;
1831
+ vertexIsBack.push(t < 0);
1832
+ if (t > EPS) hasfront = true;
1833
+ if (t < -EPS) hasback = true;
1834
+ }
1835
+ if (!hasfront && !hasback) {
1836
+ var d = plane.normal.dot(poly.plane.normal);
1837
+ if (d >= 0) {
1838
+ frontPolys.push(poly);
1839
+ } else {
1840
+ backPolys.push(poly);
1841
+ }
1842
+ } else if (!hasback) {
1843
+ frontPolys.push(poly);
1844
+ } else if (!hasfront) {
1845
+ backPolys.push(poly);
1846
+ } else {
1847
+ var fv = [];
1848
+ var bv = [];
1849
+ for (var vi = 0; vi < numVerts; vi++) {
1850
+ var vertex = vertices[vi];
1851
+ var nextVi = (vi + 1) % numVerts;
1852
+ var isback = vertexIsBack[vi];
1853
+ var nextisback = vertexIsBack[nextVi];
1854
+ if (isback === nextisback) {
1855
+ if (isback) {
1856
+ bv.push(vertex);
1857
+ } else {
1858
+ fv.push(vertex);
1859
+ }
1860
+ } else {
1861
+ var point = vertex.pos;
1862
+ var nextpoint = vertices[nextVi].pos;
1863
+ var ip = plane.splitLineBetweenPoints(point, nextpoint);
1864
+ var iv = new CSG$1.Vertex(ip);
1865
+ if (isback) {
1866
+ bv.push(vertex);
1867
+ bv.push(iv);
1868
+ fv.push(iv);
1869
+ } else {
1870
+ fv.push(vertex);
1871
+ fv.push(iv);
1872
+ bv.push(iv);
1873
+ }
1874
+ }
1875
+ }
1876
+ var EPSEPS = EPS * EPS;
1877
+ if (fv.length >= 3) {
1878
+ var prev = fv[fv.length - 1];
1879
+ for (var fi = 0; fi < fv.length; fi++) {
1880
+ var curr = fv[fi];
1881
+ if (curr.pos.distanceToSquared(prev.pos) < EPSEPS) {
1882
+ fv.splice(fi, 1);
1883
+ fi--;
1884
+ }
1885
+ prev = curr;
1886
+ }
1887
+ }
1888
+ if (bv.length >= 3) {
1889
+ var prev = bv[bv.length - 1];
1890
+ for (var bi = 0; bi < bv.length; bi++) {
1891
+ var curr = bv[bi];
1892
+ if (curr.pos.distanceToSquared(prev.pos) < EPSEPS) {
1893
+ bv.splice(bi, 1);
1894
+ bi--;
1895
+ }
1896
+ prev = curr;
1897
+ }
1898
+ }
1899
+ if (fv.length >= 3) frontPolys.push(new CSG$1.Polygon(fv, poly.shared, poly.plane));
1900
+ if (bv.length >= 3) backPolys.push(new CSG$1.Polygon(bv, poly.shared, poly.plane));
1901
+ }
1902
+ });
1903
+ return {
1904
+ front: CSG$1.fromPolygons(frontPolys),
1905
+ back: CSG$1.fromPolygons(backPolys)
1906
+ };
1907
+ }
1554
1908
  function bisect() {
1555
1909
  for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
1556
1910
  args[_key] = arguments[_key];
@@ -1612,13 +1966,13 @@ function initJscadutils(_CSG, options = {}) {
1612
1966
  }[[ axis, rotateaxis ].sort().join("")];
1613
1967
  var centroid = object.centroid();
1614
1968
  var rotateDelta = getDelta(objectSize, bounds, rotateOffsetAxis, rotateoffset);
1615
- var rotationCenter = options.rotationCenter || new CSG.Vector3D(axisApply("xyz", function(i, a) {
1969
+ var rotationCenter = options.rotationCenter || new CSG$1.Vector3D(axisApply("xyz", function(i, a) {
1616
1970
  if (a == axis) return cutDelta[i];
1617
1971
  if (a == rotateOffsetAxis) return rotateDelta[i];
1618
1972
  return centroid[a];
1619
1973
  }));
1620
1974
  var theRotationAxis = rotationAxes[rotateaxis];
1621
- var cutplane = CSG.OrthoNormalBasis.GetCartesian(info.orthoNormalCartesian[0], info.orthoNormalCartesian[1]).translate(cutDelta).rotate(rotationCenter, theRotationAxis, angle);
1975
+ var cutplane = CSG$1.OrthoNormalBasis.GetCartesian(info.orthoNormalCartesian[0], info.orthoNormalCartesian[1]).translate(cutDelta).rotate(rotationCenter, theRotationAxis, angle);
1622
1976
  debug$2("bisect", debug$2.enabled && {
1623
1977
  axis,
1624
1978
  offset,
@@ -1631,7 +1985,26 @@ function initJscadutils(_CSG, options = {}) {
1631
1985
  cutplane,
1632
1986
  options
1633
1987
  });
1634
- var g = Group("negative,positive", [ object.cutByPlane(cutplane.plane).color(options.color && "red"), object.cutByPlane(cutplane.plane.flipped()).color(options.color && "blue") ]);
1988
+ var negative = object.cutByPlane(cutplane.plane);
1989
+ var positive = object.cutByPlane(cutplane.plane.flipped());
1990
+ var negSize = size(negative);
1991
+ var posSize = size(positive);
1992
+ if (negSize[axis] >= objectSize[axis] - EPS || posSize[axis] >= objectSize[axis] - EPS) {
1993
+ var halves = splitCSGByPlane(object, cutplane.plane);
1994
+ if (negSize[axis] >= objectSize[axis] - EPS) {
1995
+ negative = halves.back;
1996
+ try {
1997
+ negative = negative.cutByPlane(cutplane.plane);
1998
+ } catch (e) {}
1999
+ }
2000
+ if (posSize[axis] >= objectSize[axis] - EPS) {
2001
+ positive = halves.front;
2002
+ try {
2003
+ positive = positive.cutByPlane(cutplane.plane.flipped());
2004
+ } catch (e) {}
2005
+ }
2006
+ }
2007
+ var g = Group("negative,positive", [ negative.color(options.color && "red"), positive.color(options.color && "blue") ]);
1635
2008
  if (options.addRotationCenter) g.add(unitAxis(objectSize.length() + 10, .1, rotationCenter), "rotationCenter");
1636
2009
  return g;
1637
2010
  }
@@ -1644,9 +2017,9 @@ function initJscadutils(_CSG, options = {}) {
1644
2017
  addRotationCenter: true
1645
2018
  };
1646
2019
  var info = normalVector(axis);
1647
- var rotationCenter = options.rotationCenter || new CSG.Vector3D(0, 0, 0);
2020
+ var rotationCenter = options.rotationCenter || new CSG$1.Vector3D(0, 0, 0);
1648
2021
  var theRotationAxis = rotationAxes[rotateaxis];
1649
- var cutplane = CSG.OrthoNormalBasis.GetCartesian(info.orthoNormalCartesian[0], info.orthoNormalCartesian[1]).rotate(rotationCenter, theRotationAxis, angle);
2022
+ var cutplane = CSG$1.OrthoNormalBasis.GetCartesian(info.orthoNormalCartesian[0], info.orthoNormalCartesian[1]).rotate(rotationCenter, theRotationAxis, angle);
1650
2023
  var g = Group("negative,positive", [ object.cutByPlane(cutplane.plane).color(options.color && "red"), object.cutByPlane(cutplane.plane.flipped()).color(options.color && "blue") ]);
1651
2024
  if (options.addRotationCenter) {
1652
2025
  var objectSize = size(object);
@@ -1671,14 +2044,14 @@ function initJscadutils(_CSG, options = {}) {
1671
2044
  var bounds = object.getBounds();
1672
2045
  var objectSize = size(object);
1673
2046
  var cutDelta = getDelta(objectSize, bounds, axis, offset, true);
1674
- return object.stretchAtPlane(normal[axis], cutDelta, distance);
2047
+ return assertValidCSG$1(object.stretchAtPlane(normal[axis], cutDelta, distance), "stretch");
1675
2048
  }
1676
2049
  function poly2solid(top, bottom, height) {
1677
2050
  if (top.sides.length == 0) {
1678
- return new CSG;
2051
+ return new CSG$1;
1679
2052
  }
1680
- var offsetVector = CSG.Vector3D.Create(0, 0, height);
1681
- var normalVector = CSG.Vector3D.Create(0, 1, 0);
2053
+ var offsetVector = CSG$1.Vector3D.Create(0, 0, height);
2054
+ var normalVector = CSG$1.Vector3D.Create(0, 1, 0);
1682
2055
  var polygons = [];
1683
2056
  polygons = polygons.concat(bottom._toPlanePolygons({
1684
2057
  translation: [ 0, 0, 0 ],
@@ -1690,14 +2063,14 @@ function initJscadutils(_CSG, options = {}) {
1690
2063
  normalVector,
1691
2064
  flipped: offsetVector.z < 0
1692
2065
  }));
1693
- var c1 = new CSG.Connector(offsetVector.times(0), [ 0, 0, offsetVector.z ], normalVector);
1694
- var c2 = new CSG.Connector(offsetVector, [ 0, 0, offsetVector.z ], normalVector);
2066
+ var c1 = new CSG$1.Connector(offsetVector.times(0), [ 0, 0, offsetVector.z ], normalVector);
2067
+ var c2 = new CSG$1.Connector(offsetVector, [ 0, 0, offsetVector.z ], normalVector);
1695
2068
  polygons = polygons.concat(bottom._toWallPolygons({
1696
2069
  cag: top,
1697
2070
  toConnector1: c1,
1698
2071
  toConnector2: c2
1699
2072
  }));
1700
- return CSG.fromPolygons(polygons);
2073
+ return assertValidCSG$1(CSG$1.fromPolygons(polygons), "poly2solid");
1701
2074
  }
1702
2075
  function slices2poly(slices, options, axis) {
1703
2076
  debug$2("slices2poly", slices, options, axis);
@@ -1706,7 +2079,7 @@ function initJscadutils(_CSG, options = {}) {
1706
2079
  twiststeps: 0
1707
2080
  }, options);
1708
2081
  var twistangle = options && parseFloat(options.twistangle) || 0;
1709
- options && parseInt(options.twiststeps) || CSG.defaultResolution3D;
2082
+ options && parseInt(options.twiststeps) || CSG$1.defaultResolution3D;
1710
2083
  var normalVector = options.si.normalVector;
1711
2084
  var polygons = [];
1712
2085
  var first$1 = first(slices);
@@ -1735,8 +2108,8 @@ function initJscadutils(_CSG, options = {}) {
1735
2108
  var nextidx = idx + 1;
1736
2109
  var top = !up ? slices[nextidx] : slice;
1737
2110
  var bottom = up ? slices[nextidx] : slice;
1738
- var c1 = new CSG.Connector(bottom.offset, connectorAxis, rotate(normalVector, twistangle, idx / slices.length));
1739
- var c2 = new CSG.Connector(top.offset, connectorAxis, rotate(normalVector, twistangle, nextidx / slices.length));
2111
+ var c1 = new CSG$1.Connector(bottom.offset, connectorAxis, rotate(normalVector, twistangle, idx / slices.length));
2112
+ var c2 = new CSG$1.Connector(top.offset, connectorAxis, rotate(normalVector, twistangle, nextidx / slices.length));
1740
2113
  polygons = polygons.concat(bottom.poly._toWallPolygons({
1741
2114
  cag: top.poly,
1742
2115
  toConnector1: c1,
@@ -1744,21 +2117,21 @@ function initJscadutils(_CSG, options = {}) {
1744
2117
  }));
1745
2118
  }
1746
2119
  });
1747
- return CSG.fromPolygons(polygons);
2120
+ return assertValidCSG$1(CSG$1.fromPolygons(polygons), "slices2poly");
1748
2121
  }
1749
2122
  function normalVector(axis) {
1750
2123
  var axisInfo = {
1751
2124
  z: {
1752
2125
  orthoNormalCartesian: [ "X", "Y" ],
1753
- normalVector: CSG.Vector3D.Create(0, 1, 0)
2126
+ normalVector: CSG$1.Vector3D.Create(0, 1, 0)
1754
2127
  },
1755
2128
  x: {
1756
2129
  orthoNormalCartesian: [ "Y", "Z" ],
1757
- normalVector: CSG.Vector3D.Create(0, 0, 1)
2130
+ normalVector: CSG$1.Vector3D.Create(0, 0, 1)
1758
2131
  },
1759
2132
  y: {
1760
- orthoNormalCartesian: [ "X", "Z" ],
1761
- normalVector: CSG.Vector3D.Create(0, 0, 1)
2133
+ orthoNormalCartesian: [ "Z", "X" ],
2134
+ normalVector: CSG$1.Vector3D.Create(0, 0, 1)
1762
2135
  }
1763
2136
  };
1764
2137
  if (!axisInfo[axis]) error("normalVector: invalid axis " + axis);
@@ -1799,7 +2172,7 @@ function initJscadutils(_CSG, options = {}) {
1799
2172
  var si = sliceParams(orientation, radius, b);
1800
2173
  debug$2("reShape", absoluteRadius, si);
1801
2174
  if (si.axis !== "z") throw new Error('reShape error: CAG._toPlanePolygons only uses the "z" axis. You must use the "z" axis for now.');
1802
- var cutplane = CSG.OrthoNormalBasis.GetCartesian(si.orthoNormalCartesian[0], si.orthoNormalCartesian[1]).translate(si.cutDelta);
2175
+ var cutplane = CSG$1.OrthoNormalBasis.GetCartesian(si.orthoNormalCartesian[0], si.orthoNormalCartesian[1]).translate(si.cutDelta);
1803
2176
  var slice = object.sectionCut(cutplane);
1804
2177
  var first = axisApply(si.axis, function() {
1805
2178
  return si.positive ? 0 : absoluteRadius;
@@ -1814,25 +2187,25 @@ function initJscadutils(_CSG, options = {}) {
1814
2187
  si
1815
2188
  }), si.axis).color(options.color);
1816
2189
  var remainder = object.cutByPlane(plane);
1817
- return union([ options.unionOriginal ? object : remainder, delta.translate(si.moveDelta) ]);
2190
+ return assertValidCSG$1(union([ options.unionOriginal ? object : remainder, delta.translate(si.moveDelta) ]), "reShape");
1818
2191
  }
1819
2192
  function chamfer(object, radius, orientation, options) {
1820
- return reShape(object, radius, orientation, options, function(first, last, slice) {
2193
+ return assertValidCSG$1(reShape(object, radius, orientation, options, function(first, last, slice) {
1821
2194
  return [ {
1822
2195
  poly: slice,
1823
- offset: new CSG.Vector3D(first)
2196
+ offset: new CSG$1.Vector3D(first)
1824
2197
  }, {
1825
2198
  poly: enlarge(slice, [ -radius * 2, -radius * 2 ]),
1826
- offset: new CSG.Vector3D(last)
2199
+ offset: new CSG$1.Vector3D(last)
1827
2200
  } ];
1828
- });
2201
+ }), "chamfer");
1829
2202
  }
1830
2203
  function fillet(object, radius, orientation, options) {
1831
2204
  options = options || {};
1832
- return reShape(object, radius, orientation, options, function(first, last, slice) {
1833
- var v1 = new CSG.Vector3D(first);
1834
- var v2 = new CSG.Vector3D(last);
1835
- var res = options.resolution || CSG.defaultResolution3D;
2205
+ return assertValidCSG$1(reShape(object, radius, orientation, options, function(first, last, slice) {
2206
+ var v1 = new CSG$1.Vector3D(first);
2207
+ var v2 = new CSG$1.Vector3D(last);
2208
+ var res = options.resolution || CSG$1.defaultResolution3D;
1836
2209
  var slices = range(0, res).map(function(i) {
1837
2210
  var p = i > 0 ? i / (res - 1) : 0;
1838
2211
  var v = v1.lerp(v2, p);
@@ -1843,7 +2216,7 @@ function initJscadutils(_CSG, options = {}) {
1843
2216
  };
1844
2217
  });
1845
2218
  return slices;
1846
- });
2219
+ }), "fillet");
1847
2220
  }
1848
2221
  function calcRotate(part, solid, axis) {
1849
2222
  var axes = {
@@ -1860,7 +2233,7 @@ function initJscadutils(_CSG, options = {}) {
1860
2233
  }
1861
2234
  function rotateAround(part, solid, axis, angle) {
1862
2235
  var _calcRotate = calcRotate(part, solid, axis), rotationCenter = _calcRotate.rotationCenter, rotationAxis = _calcRotate.rotationAxis;
1863
- return part.rotate(rotationCenter, rotationAxis, angle);
2236
+ return assertValidCSG$1("rotateAround")(part.rotate(rotationCenter, rotationAxis, angle));
1864
2237
  }
1865
2238
  function cloneProperties(from, to) {
1866
2239
  return Object.entries(from).reduce(function(props, _ref) {
@@ -1870,19 +2243,20 @@ function initJscadutils(_CSG, options = {}) {
1870
2243
  }, to);
1871
2244
  }
1872
2245
  function clone(o) {
1873
- var c = CSG.fromPolygons(o.toPolygons());
2246
+ var c = CSG$1.fromPolygons(o.toPolygons());
1874
2247
  cloneProperties(o, c);
1875
- debug$2("clone", o, c, CSG);
1876
- return c;
2248
+ debug$2("clone", o, c, CSG$1);
2249
+ return assertValidCSG$1(c, "clone");
1877
2250
  }
1878
2251
  function addConnector(object, name) {
1879
2252
  var point = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : [ 0, 0, 0 ];
1880
2253
  var axis = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : [ 1, 0, 0 ];
1881
2254
  var normal = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : [ 0, 0, 1 ];
1882
- object.properties[name] = new CSG.Connector(point, axis, normal);
1883
- return object;
2255
+ object.properties[name] = new CSG$1.Connector(point, axis, normal);
2256
+ return assertValidCSG$1("addConnector")(object);
1884
2257
  }
1885
2258
  var debug$1 = Debug("jscadUtils:parts");
2259
+ var assertValidCSG = AssertValidCSG("parts");
1886
2260
  var parts = {
1887
2261
  BBox: BBox$1,
1888
2262
  Cube,
@@ -1892,7 +2266,7 @@ function initJscadutils(_CSG, options = {}) {
1892
2266
  };
1893
2267
  function BBox$1() {
1894
2268
  function box(object) {
1895
- return CSG.cube({
2269
+ return CSG$1.cube({
1896
2270
  center: object.centroid(),
1897
2271
  radius: object.size().dividedBy(2)
1898
2272
  });
@@ -1900,17 +2274,17 @@ function initJscadutils(_CSG, options = {}) {
1900
2274
  for (var _len = arguments.length, objects = new Array(_len), _key = 0; _key < _len; _key++) {
1901
2275
  objects[_key] = arguments[_key];
1902
2276
  }
1903
- return objects.reduce(function(bbox, part) {
2277
+ return assertValidCSG(objects.reduce(function(bbox, part) {
1904
2278
  var object = bbox ? union([ bbox, box(part) ]) : part;
1905
2279
  return box(object);
1906
- }, undefined);
2280
+ }, undefined), "BBox");
1907
2281
  }
1908
2282
  function Cube(width) {
1909
2283
  var r = div$1(fromxyz(width), 2);
1910
- return CSG.cube({
2284
+ return assertValidCSG(CSG$1.cube({
1911
2285
  center: r,
1912
2286
  radius: r
1913
- });
2287
+ }), "Cube");
1914
2288
  }
1915
2289
  function RoundedCube(x, y, thickness, corner_radius) {
1916
2290
  if (x.getBounds) {
@@ -1926,11 +2300,11 @@ function initJscadutils(_CSG, options = {}) {
1926
2300
  center: [ r[0], r[1], 0 ],
1927
2301
  radius: r,
1928
2302
  roundradius: corner_radius,
1929
- resolution: CSG.defaultResolution2D
2303
+ resolution: CSG$1.defaultResolution2D
1930
2304
  }).extrude({
1931
2305
  offset: [ 0, 0, thickness || 1.62 ]
1932
2306
  });
1933
- return roundedcube;
2307
+ return assertValidCSG(roundedcube, "RoundedCube");
1934
2308
  }
1935
2309
  function Cylinder(diameter, height) {
1936
2310
  var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
@@ -1939,39 +2313,39 @@ function initJscadutils(_CSG, options = {}) {
1939
2313
  start: [ 0, 0, 0 ],
1940
2314
  end: [ 0, 0, height ],
1941
2315
  radius: diameter / 2,
1942
- resolution: CSG.defaultResolution2D
2316
+ resolution: CSG$1.defaultResolution2D
1943
2317
  }, options);
1944
- return CSG.cylinder(options);
2318
+ return assertValidCSG(CSG$1.cylinder(options), "Cylinder");
1945
2319
  }
1946
2320
  function Cone(diameter1, diameter2, height) {
1947
2321
  var options = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {};
1948
2322
  debug$1("parts.Cone", diameter1, diameter2, height, options);
1949
- return CSG.cylinder(Object.assign({
2323
+ return assertValidCSG(CSG$1.cylinder(Object.assign({
1950
2324
  start: [ 0, 0, 0 ],
1951
2325
  end: [ 0, 0, height ],
1952
2326
  radiusStart: diameter1 / 2,
1953
2327
  radiusEnd: diameter2 / 2,
1954
- resolution: CSG.defaultResolution2D
1955
- }, options));
2328
+ resolution: CSG$1.defaultResolution2D
2329
+ }, options)), "Cone");
1956
2330
  }
1957
2331
  function Hexagon(diameter, height) {
1958
2332
  debug$1("hexagon", diameter, height);
1959
2333
  var radius = diameter / 2;
1960
2334
  var sqrt3 = Math.sqrt(3) / 2;
1961
2335
  var hex = CAG.fromPoints([ [ radius, 0 ], [ radius / 2, radius * sqrt3 ], [ -radius / 2, radius * sqrt3 ], [ -radius, 0 ], [ -radius / 2, -radius * sqrt3 ], [ radius / 2, -radius * sqrt3 ] ]);
1962
- return hex.extrude({
2336
+ return assertValidCSG(hex.extrude({
1963
2337
  offset: [ 0, 0, height ]
1964
- });
2338
+ }), "Hexagon");
1965
2339
  }
1966
2340
  function Triangle(base, height) {
1967
2341
  var radius = base / 2;
1968
2342
  var tri = CAG.fromPoints([ [ -radius, 0 ], [ radius, 0 ], [ 0, Math.sin(30) * radius ] ]);
1969
- return tri.extrude({
2343
+ return assertValidCSG(tri.extrude({
1970
2344
  offset: [ 0, 0, height ]
1971
- });
2345
+ }), "Triangle");
1972
2346
  }
1973
2347
  function Tube(outsideDiameter, insideDiameter, height, outsideOptions, insideOptions) {
1974
- return Cylinder(outsideDiameter, height, outsideOptions).subtract(Cylinder(insideDiameter, height, insideOptions || outsideOptions));
2348
+ return assertValidCSG(Cylinder(outsideDiameter, height, outsideOptions).subtract(Cylinder(insideDiameter, height, insideOptions || outsideOptions)), "Tube");
1975
2349
  }
1976
2350
  function Anchor() {
1977
2351
  var width = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 10;
@@ -1989,11 +2363,11 @@ function initJscadutils(_CSG, options = {}) {
1989
2363
  center: [ r[0], r[1], 0 ],
1990
2364
  radius: r,
1991
2365
  roundradius: corner_radius,
1992
- resolution: CSG.defaultResolution2D
2366
+ resolution: CSG$1.defaultResolution2D
1993
2367
  }).extrude({
1994
2368
  offset: [ 0, 0, thickness || 1.62 ]
1995
2369
  });
1996
- return board;
2370
+ return assertValidCSG(board, "Board");
1997
2371
  }
1998
2372
  var Hardware = {
1999
2373
  Orientation: {
@@ -2084,6 +2458,10 @@ function initJscadutils(_CSG, options = {}) {
2084
2458
  gap = gap || .25;
2085
2459
  var inside = thickness - gap;
2086
2460
  var outside = -thickness + gap;
2461
+ var boxHeight = box.size().z;
2462
+ if (Math.abs(height) >= boxHeight) {
2463
+ throw new Error("Rabett: height (".concat(height, ") must be less than the object height (").concat(boxHeight, ")"));
2464
+ }
2087
2465
  debug("inside", inside, "outside", outside);
2088
2466
  var group = Group();
2089
2467
  var _box$bisect$parts = box.bisect("z", height, options).parts, top = _box$bisect$parts.positive, lower2_3rd = _box$bisect$parts.negative;
@@ -2154,10 +2532,10 @@ function initJscadutils(_CSG, options = {}) {
2154
2532
  thickness = thickness || 2;
2155
2533
  var s = div$1(xyz2array(size), 2);
2156
2534
  var r = add(s, thickness);
2157
- var box = CSG.cube({
2535
+ var box = CSG$1.cube({
2158
2536
  center: r,
2159
2537
  radius: r
2160
- }).subtract(CSG.cube({
2538
+ }).subtract(CSG$1.cube({
2161
2539
  center: r,
2162
2540
  radius: s
2163
2541
  }));
@@ -2175,7 +2553,7 @@ function initJscadutils(_CSG, options = {}) {
2175
2553
  var BBox = function BBox(o) {
2176
2554
  depreciated("BBox", true, "Use 'parts.BBox' instead");
2177
2555
  var s = div$1(xyz2array(o.size()), 2);
2178
- return CSG.cube({
2556
+ return CSG$1.cube({
2179
2557
  center: s,
2180
2558
  radius: s
2181
2559
  }).align(o, "xyz");
@@ -2187,7 +2565,7 @@ function initJscadutils(_CSG, options = {}) {
2187
2565
  var gap = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : .25;
2188
2566
  var r = add(getRadius(box), -thickness / 2);
2189
2567
  r[2] = thickness / 2;
2190
- var cutter = CSG.cube({
2568
+ var cutter = CSG$1.cube({
2191
2569
  center: r,
2192
2570
  radius: r
2193
2571
  }).align(box, "xy").color("green");