@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.
- package/README.md +1 -5
- package/dist/compat.js +641 -100
- package/dist/examples/bisect.jscad +471 -93
- package/dist/examples/bisect2.jscad +2614 -0
- package/dist/examples/boxes.jscad +481 -102
- package/dist/examples/chamfer.jscad +471 -93
- package/dist/examples/fillet.jscad +471 -93
- package/dist/examples/fit.jscad +471 -93
- package/dist/examples/groups.jscad +471 -93
- package/dist/examples/midlineTo.jscad +471 -93
- package/dist/examples/parts-hexagon.jscad +471 -93
- package/dist/examples/rabett-tb.jscad +471 -93
- package/dist/examples/rabett.jscad +471 -93
- package/dist/examples/rabett2.jscad +471 -93
- package/dist/examples/rabett3.jscad +2614 -0
- package/dist/examples/retraction-test.jscad +471 -93
- package/dist/examples/size.jscad +471 -93
- package/dist/examples/snap.jscad +471 -93
- package/dist/examples/text.jscad +471 -93
- package/dist/examples/wedge.jscad +471 -93
- package/dist/index.js +638 -100
- package/package.json +8 -4
- package/src/add-prototype.js +5 -1
- package/src/boxes.js +11 -3
- package/src/compat.js +3 -0
- package/src/group.js +13 -11
- package/src/parts.js +25 -23
- package/src/util.js +239 -72
- package/src/validate.js +335 -0
package/dist/index.js
CHANGED
|
@@ -89,6 +89,54 @@ var jscadUtils = (function (exports, jsCadCSG, scadApi) {
|
|
|
89
89
|
function _arrayWithHoles(r) {
|
|
90
90
|
if (Array.isArray(r)) return r;
|
|
91
91
|
}
|
|
92
|
+
function _createForOfIteratorHelper(r, e) {
|
|
93
|
+
var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"];
|
|
94
|
+
if (!t) {
|
|
95
|
+
if (Array.isArray(r) || (t = _unsupportedIterableToArray(r)) || e && r && "number" == typeof r.length) {
|
|
96
|
+
t && (r = t);
|
|
97
|
+
var n = 0,
|
|
98
|
+
F = function () {};
|
|
99
|
+
return {
|
|
100
|
+
s: F,
|
|
101
|
+
n: function () {
|
|
102
|
+
return n >= r.length ? {
|
|
103
|
+
done: !0
|
|
104
|
+
} : {
|
|
105
|
+
done: !1,
|
|
106
|
+
value: r[n++]
|
|
107
|
+
};
|
|
108
|
+
},
|
|
109
|
+
e: function (r) {
|
|
110
|
+
throw r;
|
|
111
|
+
},
|
|
112
|
+
f: F
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
|
|
116
|
+
}
|
|
117
|
+
var o,
|
|
118
|
+
a = !0,
|
|
119
|
+
u = !1;
|
|
120
|
+
return {
|
|
121
|
+
s: function () {
|
|
122
|
+
t = t.call(r);
|
|
123
|
+
},
|
|
124
|
+
n: function () {
|
|
125
|
+
var r = t.next();
|
|
126
|
+
return a = r.done, r;
|
|
127
|
+
},
|
|
128
|
+
e: function (r) {
|
|
129
|
+
u = !0, o = r;
|
|
130
|
+
},
|
|
131
|
+
f: function () {
|
|
132
|
+
try {
|
|
133
|
+
a || null == t.return || t.return();
|
|
134
|
+
} finally {
|
|
135
|
+
if (u) throw o;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
};
|
|
139
|
+
}
|
|
92
140
|
function _defineProperty(e, r, t) {
|
|
93
141
|
return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, {
|
|
94
142
|
value: t,
|
|
@@ -761,6 +809,344 @@ var jscadUtils = (function (exports, jsCadCSG, scadApi) {
|
|
|
761
809
|
return o.setColor(c);
|
|
762
810
|
}
|
|
763
811
|
|
|
812
|
+
/* globals jscadUtilsAssertValidCSG jscadUtilsAssertValidCSGWarnings */
|
|
813
|
+
/**
|
|
814
|
+
* @typedef {Object} CSG
|
|
815
|
+
* @property {Array<{vertices: Array<{pos: any}>}>} polygons
|
|
816
|
+
* @property {function(): CSG} [canonicalized]
|
|
817
|
+
* @property {function(): CSG} [reTesselated]
|
|
818
|
+
* @property {function(): CSG} [fixTJunctions]
|
|
819
|
+
* @property {function(): Array} [getBounds]
|
|
820
|
+
* @property {Object} [properties]
|
|
821
|
+
*/
|
|
822
|
+
/**
|
|
823
|
+
* Validate that a CSG object represents a solid, watertight mesh
|
|
824
|
+
* without degenerate faces. Returns an object with an `ok` boolean
|
|
825
|
+
* and an `errors` array describing any problems found.
|
|
826
|
+
*
|
|
827
|
+
* Checks performed:
|
|
828
|
+
* - **No empty mesh** – the object must contain at least one polygon.
|
|
829
|
+
* - **No degenerate polygons** – every polygon must have ≥ 3 vertices
|
|
830
|
+
* and a computable area greater than `EPS²`.
|
|
831
|
+
* - **Watertight / manifold edges** – every directed edge A→B in the
|
|
832
|
+
* mesh must be matched by exactly one reverse edge B→A in another
|
|
833
|
+
* polygon. Unmatched edges indicate holes; edges shared more than
|
|
834
|
+
* twice indicate non-manifold geometry.
|
|
835
|
+
*
|
|
836
|
+
* By default, the mesh is canonicalized and T-junctions are repaired
|
|
837
|
+
* before validation so that results from boolean operations (union,
|
|
838
|
+
* subtract, intersect) can be validated successfully. Pass
|
|
839
|
+
* `{ fixTJunctions: false }` to skip this step and validate the raw
|
|
840
|
+
* mesh.
|
|
841
|
+
*
|
|
842
|
+
* @param {CSG} csg The CSG object to validate.
|
|
843
|
+
* @param {object} [options] Validation options.
|
|
844
|
+
* @param {boolean} [options.fixTJunctions=true] Whether to canonicalize and fix T-junctions before validation.
|
|
845
|
+
* @return {{ ok: boolean, errors: string[], warnings: string[] }} Validation result.
|
|
846
|
+
* @function validateCSG
|
|
847
|
+
*/
|
|
848
|
+
function validateCSG(csg, options) {
|
|
849
|
+
/** @type {string[]} */
|
|
850
|
+
var errors = [];
|
|
851
|
+
/** @type {string[]} */
|
|
852
|
+
var warnings = [];
|
|
853
|
+
if (!csg || !csg.polygons || csg.polygons.length === 0) {
|
|
854
|
+
errors.push('Empty mesh: no polygons');
|
|
855
|
+
return {
|
|
856
|
+
ok: false,
|
|
857
|
+
errors: errors,
|
|
858
|
+
warnings: warnings
|
|
859
|
+
};
|
|
860
|
+
}
|
|
861
|
+
var opts = _objectSpread2({
|
|
862
|
+
fixTJunctions: true
|
|
863
|
+
}, options);
|
|
864
|
+
|
|
865
|
+
// Optionally canonicalize and fix T-junctions so that boolean-op
|
|
866
|
+
// output can pass the watertight check.
|
|
867
|
+
if (opts.fixTJunctions && typeof csg.canonicalized === 'function') {
|
|
868
|
+
csg = csg.canonicalized();
|
|
869
|
+
if (typeof csg.reTesselated === 'function') {
|
|
870
|
+
csg = csg.reTesselated();
|
|
871
|
+
}
|
|
872
|
+
if (typeof csg.fixTJunctions === 'function') {
|
|
873
|
+
csg = csg.fixTJunctions();
|
|
874
|
+
}
|
|
875
|
+
}
|
|
876
|
+
var AREA_EPS = 1e-10;
|
|
877
|
+
var KEY_EPS = 1e-5;
|
|
878
|
+
var degenerateCount = 0;
|
|
879
|
+
var invalidVertexCount = 0;
|
|
880
|
+
|
|
881
|
+
// Check for NaN/Infinity vertex coordinates which cause WebGL errors
|
|
882
|
+
// (GL_INVALID_VALUE: glVertexAttribPointer: Vertex attribute size must be 1, 2, 3, or 4)
|
|
883
|
+
var _iterator = _createForOfIteratorHelper(csg.polygons),
|
|
884
|
+
_step;
|
|
885
|
+
try {
|
|
886
|
+
for (_iterator.s(); !(_step = _iterator.n()).done;) {
|
|
887
|
+
var npoly = _step.value;
|
|
888
|
+
var _iterator4 = _createForOfIteratorHelper(npoly.vertices),
|
|
889
|
+
_step4;
|
|
890
|
+
try {
|
|
891
|
+
for (_iterator4.s(); !(_step4 = _iterator4.n()).done;) {
|
|
892
|
+
var nvert = _step4.value;
|
|
893
|
+
var np = nvert.pos;
|
|
894
|
+
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)) {
|
|
895
|
+
invalidVertexCount++;
|
|
896
|
+
break;
|
|
897
|
+
}
|
|
898
|
+
}
|
|
899
|
+
} catch (err) {
|
|
900
|
+
_iterator4.e(err);
|
|
901
|
+
} finally {
|
|
902
|
+
_iterator4.f();
|
|
903
|
+
}
|
|
904
|
+
}
|
|
905
|
+
} catch (err) {
|
|
906
|
+
_iterator.e(err);
|
|
907
|
+
} finally {
|
|
908
|
+
_iterator.f();
|
|
909
|
+
}
|
|
910
|
+
if (invalidVertexCount > 0) {
|
|
911
|
+
errors.push(invalidVertexCount + ' polygon(s) with invalid vertex coordinates (NaN or Infinity)');
|
|
912
|
+
}
|
|
913
|
+
|
|
914
|
+
// Position-based vertex key (shared vertices across polygons have different
|
|
915
|
+
// object tags but the same position, so we round coordinates to match them).
|
|
916
|
+
/** @param {{ pos: { x: number, y: number, z: number } }} v */
|
|
917
|
+
function vtxKey(v) {
|
|
918
|
+
var p = v.pos;
|
|
919
|
+
return Math.round(p.x / KEY_EPS) + ',' + Math.round(p.y / KEY_EPS) + ',' + Math.round(p.z / KEY_EPS);
|
|
920
|
+
}
|
|
921
|
+
|
|
922
|
+
// First pass: identify degenerate polygons
|
|
923
|
+
var validPolygons = [];
|
|
924
|
+
var _iterator2 = _createForOfIteratorHelper(csg.polygons),
|
|
925
|
+
_step2;
|
|
926
|
+
try {
|
|
927
|
+
for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
|
|
928
|
+
var poly = _step2.value;
|
|
929
|
+
var verts = poly.vertices;
|
|
930
|
+
var nv = verts.length;
|
|
931
|
+
if (nv < 3) {
|
|
932
|
+
degenerateCount++;
|
|
933
|
+
continue;
|
|
934
|
+
}
|
|
935
|
+
|
|
936
|
+
// Skip polygons with invalid vertex coordinates
|
|
937
|
+
var hasInvalid = false;
|
|
938
|
+
var _iterator5 = _createForOfIteratorHelper(verts),
|
|
939
|
+
_step5;
|
|
940
|
+
try {
|
|
941
|
+
for (_iterator5.s(); !(_step5 = _iterator5.n()).done;) {
|
|
942
|
+
var vert = _step5.value;
|
|
943
|
+
var ip = vert.pos;
|
|
944
|
+
if (!Number.isFinite(ip.x) || !Number.isFinite(ip.y) || !Number.isFinite(ip.z)) {
|
|
945
|
+
hasInvalid = true;
|
|
946
|
+
break;
|
|
947
|
+
}
|
|
948
|
+
}
|
|
949
|
+
} catch (err) {
|
|
950
|
+
_iterator5.e(err);
|
|
951
|
+
} finally {
|
|
952
|
+
_iterator5.f();
|
|
953
|
+
}
|
|
954
|
+
if (hasInvalid) continue;
|
|
955
|
+
|
|
956
|
+
// Check degenerate area using cross-product summation
|
|
957
|
+
var area = 0;
|
|
958
|
+
for (var ai = 0; ai < nv - 2; ai++) {
|
|
959
|
+
area += verts[ai + 1].pos.minus(verts[0].pos).cross(verts[ai + 2].pos.minus(verts[ai + 1].pos)).length();
|
|
960
|
+
}
|
|
961
|
+
area *= 0.5;
|
|
962
|
+
if (area < AREA_EPS) {
|
|
963
|
+
degenerateCount++;
|
|
964
|
+
continue;
|
|
965
|
+
}
|
|
966
|
+
validPolygons.push(poly);
|
|
967
|
+
}
|
|
968
|
+
} catch (err) {
|
|
969
|
+
_iterator2.e(err);
|
|
970
|
+
} finally {
|
|
971
|
+
_iterator2.f();
|
|
972
|
+
}
|
|
973
|
+
if (degenerateCount > 0) {
|
|
974
|
+
warnings.push(degenerateCount + ' degenerate polygon(s) (fewer than 3 vertices or near-zero area)');
|
|
975
|
+
|
|
976
|
+
// Rebuild the CSG from valid polygons only and re-run the repair
|
|
977
|
+
// pipeline so that fixTJunctions can close gaps left by the removed
|
|
978
|
+
// degenerate faces.
|
|
979
|
+
/* eslint-disable no-undef */
|
|
980
|
+
// @ts-ignore — CSG is a runtime global injected by the JSCAD compat layer
|
|
981
|
+
if (opts.fixTJunctions && typeof CSG !== 'undefined') {
|
|
982
|
+
// @ts-ignore
|
|
983
|
+
var cleaned = CSG.fromPolygons(validPolygons);
|
|
984
|
+
/* eslint-enable no-undef */
|
|
985
|
+
cleaned = cleaned.canonicalized();
|
|
986
|
+
if (typeof cleaned.reTesselated === 'function') {
|
|
987
|
+
cleaned = cleaned.reTesselated();
|
|
988
|
+
}
|
|
989
|
+
if (typeof cleaned.fixTJunctions === 'function') {
|
|
990
|
+
cleaned = cleaned.fixTJunctions();
|
|
991
|
+
}
|
|
992
|
+
// Re-scan for valid polygons after second repair pass
|
|
993
|
+
validPolygons = [];
|
|
994
|
+
var _iterator3 = _createForOfIteratorHelper(cleaned.polygons),
|
|
995
|
+
_step3;
|
|
996
|
+
try {
|
|
997
|
+
for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) {
|
|
998
|
+
var cpoly = _step3.value;
|
|
999
|
+
var cverts = cpoly.vertices;
|
|
1000
|
+
var cnv = cverts.length;
|
|
1001
|
+
if (cnv < 3) continue;
|
|
1002
|
+
var carea = 0;
|
|
1003
|
+
for (var cai = 0; cai < cnv - 2; cai++) {
|
|
1004
|
+
carea += cverts[cai + 1].pos.minus(cverts[0].pos).cross(cverts[cai + 2].pos.minus(cverts[cai + 1].pos)).length();
|
|
1005
|
+
}
|
|
1006
|
+
carea *= 0.5;
|
|
1007
|
+
if (carea < AREA_EPS) continue;
|
|
1008
|
+
validPolygons.push(cpoly);
|
|
1009
|
+
}
|
|
1010
|
+
} catch (err) {
|
|
1011
|
+
_iterator3.e(err);
|
|
1012
|
+
} finally {
|
|
1013
|
+
_iterator3.f();
|
|
1014
|
+
}
|
|
1015
|
+
}
|
|
1016
|
+
}
|
|
1017
|
+
|
|
1018
|
+
// Edge map: key = "vtxKeyA/vtxKeyB", value = count
|
|
1019
|
+
/** @type {Record<string, number>} */
|
|
1020
|
+
var edgeCounts = {};
|
|
1021
|
+
|
|
1022
|
+
// Accumulate directed edges from valid polygons only
|
|
1023
|
+
for (var _i = 0, _validPolygons = validPolygons; _i < _validPolygons.length; _i++) {
|
|
1024
|
+
var vpoly = _validPolygons[_i];
|
|
1025
|
+
var vverts = vpoly.vertices;
|
|
1026
|
+
var vnv = vverts.length;
|
|
1027
|
+
for (var ei = 0; ei < vnv; ei++) {
|
|
1028
|
+
var v0 = vverts[ei];
|
|
1029
|
+
var v1 = vverts[(ei + 1) % vnv];
|
|
1030
|
+
var edgeKey = vtxKey(v0) + '/' + vtxKey(v1);
|
|
1031
|
+
edgeCounts[edgeKey] = (edgeCounts[edgeKey] || 0) + 1;
|
|
1032
|
+
}
|
|
1033
|
+
}
|
|
1034
|
+
|
|
1035
|
+
// Check edge manifoldness: every edge A→B should be cancelled by B→A
|
|
1036
|
+
var unmatchedEdges = 0;
|
|
1037
|
+
var nonManifoldEdges = 0;
|
|
1038
|
+
/** @type {Record<string, boolean>} */
|
|
1039
|
+
var checked = {};
|
|
1040
|
+
for (var _i2 = 0, _Object$keys = Object.keys(edgeCounts); _i2 < _Object$keys.length; _i2++) {
|
|
1041
|
+
var _edgeKey = _Object$keys[_i2];
|
|
1042
|
+
if (checked[_edgeKey]) continue;
|
|
1043
|
+
var parts = _edgeKey.split('/');
|
|
1044
|
+
var reverseKey = parts[1] + '/' + parts[0];
|
|
1045
|
+
var forwardCount = edgeCounts[_edgeKey] || 0;
|
|
1046
|
+
var reverseCount = edgeCounts[reverseKey] || 0;
|
|
1047
|
+
checked[_edgeKey] = true;
|
|
1048
|
+
checked[reverseKey] = true;
|
|
1049
|
+
if (forwardCount !== reverseCount) {
|
|
1050
|
+
unmatchedEdges += Math.abs(forwardCount - reverseCount);
|
|
1051
|
+
}
|
|
1052
|
+
if (forwardCount > 1 || reverseCount > 1) {
|
|
1053
|
+
nonManifoldEdges++;
|
|
1054
|
+
}
|
|
1055
|
+
}
|
|
1056
|
+
if (unmatchedEdges > 0) {
|
|
1057
|
+
errors.push(unmatchedEdges + ' unmatched edge(s): mesh is not watertight');
|
|
1058
|
+
}
|
|
1059
|
+
if (nonManifoldEdges > 0) {
|
|
1060
|
+
errors.push(nonManifoldEdges + ' non-manifold edge(s): edge shared by more than 2 polygons');
|
|
1061
|
+
}
|
|
1062
|
+
return {
|
|
1063
|
+
ok: errors.length === 0,
|
|
1064
|
+
errors: errors,
|
|
1065
|
+
warnings: warnings
|
|
1066
|
+
};
|
|
1067
|
+
}
|
|
1068
|
+
|
|
1069
|
+
/** @param {any} csg @returns {any} */
|
|
1070
|
+
function _noOp(csg) {
|
|
1071
|
+
return csg;
|
|
1072
|
+
}
|
|
1073
|
+
|
|
1074
|
+
/**
|
|
1075
|
+
* @param {boolean} warnEnabled
|
|
1076
|
+
* @returns {function(*, string=, string=): *}
|
|
1077
|
+
*/
|
|
1078
|
+
function _makeAssertFn(warnEnabled) {
|
|
1079
|
+
return function _assert(csg) {
|
|
1080
|
+
var functionName = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'unknown';
|
|
1081
|
+
var moduleName = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 'unknown';
|
|
1082
|
+
// Only validate CSG-like objects (they have a polygons array).
|
|
1083
|
+
// CAG objects (2D cross-sections) have `sides` instead and are passed through.
|
|
1084
|
+
if (!csg || csg.polygons === undefined) return csg;
|
|
1085
|
+
var result = validateCSG(csg);
|
|
1086
|
+
if (!result.ok) {
|
|
1087
|
+
throw new Error(moduleName + ':' + functionName + ': ' + 'invalid CSG: ' + result.errors.join(', '));
|
|
1088
|
+
}
|
|
1089
|
+
if (warnEnabled && result.warnings.length > 0) {
|
|
1090
|
+
throw new Error(moduleName + ':' + functionName + ': ' + 'CSG warnings: ' + result.warnings.join(', '));
|
|
1091
|
+
}
|
|
1092
|
+
return csg;
|
|
1093
|
+
};
|
|
1094
|
+
}
|
|
1095
|
+
|
|
1096
|
+
// Live pointer that all returned closures call through — swap this and all
|
|
1097
|
+
// existing closures immediately pick up the change.
|
|
1098
|
+
/** @type {function(*, string=, string=): *} */
|
|
1099
|
+
var _assertFn = _noOp;
|
|
1100
|
+
|
|
1101
|
+
// Read compat globals set by initJscadutils — mirrors the Debug() pattern
|
|
1102
|
+
// in debug.js. Returns _noOp when globals are absent (ESM / test context).
|
|
1103
|
+
function _resolveFromGlobals() {
|
|
1104
|
+
/* eslint-disable no-undef */
|
|
1105
|
+
// @ts-ignore — globals set by the JSCAD compat layer before bundle injection
|
|
1106
|
+
var enabled = typeof jscadUtilsAssertValidCSG !== 'undefined' && !!jscadUtilsAssertValidCSG;
|
|
1107
|
+
// @ts-ignore
|
|
1108
|
+
var warnEnabled = typeof jscadUtilsAssertValidCSGWarnings !== 'undefined' && !!jscadUtilsAssertValidCSGWarnings;
|
|
1109
|
+
/* eslint-enable no-undef */
|
|
1110
|
+
return enabled ? _makeAssertFn(warnEnabled) : _noOp;
|
|
1111
|
+
}
|
|
1112
|
+
|
|
1113
|
+
/**
|
|
1114
|
+
* Returns an asserter function bound to `moduleName`. Call the returned
|
|
1115
|
+
* function with a CSG object and the calling function's name to validate it
|
|
1116
|
+
* (when enabled) or pass it through unchanged (when disabled).
|
|
1117
|
+
*
|
|
1118
|
+
* Best practice is to call `AssertValidCSG` once per module at load time and
|
|
1119
|
+
* capture the result as a module-level constant so that `moduleName` appears
|
|
1120
|
+
* consistently in every error message thrown from that module.
|
|
1121
|
+
*
|
|
1122
|
+
* On creation, reads compat globals (jscadUtilsAssertValidCSG /
|
|
1123
|
+
* jscadUtilsAssertValidCSGWarnings) if setValidationEnabled() has not been
|
|
1124
|
+
* called explicitly — identical to how Debug('name') reads jscadUtilsDebug.
|
|
1125
|
+
*
|
|
1126
|
+
* Error message format: `moduleName:functionName: invalid CSG: <errors>`
|
|
1127
|
+
*
|
|
1128
|
+
* @example
|
|
1129
|
+
* // Once at the top of your module:
|
|
1130
|
+
* const assertValidCSG = AssertValidCSG('myModule');
|
|
1131
|
+
*
|
|
1132
|
+
* export function enlarge(object, ...) {
|
|
1133
|
+
* // ...
|
|
1134
|
+
* return assertValidCSG(new_object.translate(delta), 'enlarge');
|
|
1135
|
+
* }
|
|
1136
|
+
*
|
|
1137
|
+
* @param {string} [moduleName='unknown'] Module name, included in error messages.
|
|
1138
|
+
* @return {function(CSG, string=): CSG}
|
|
1139
|
+
*/
|
|
1140
|
+
function AssertValidCSG() {
|
|
1141
|
+
var moduleName = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 'unknown';
|
|
1142
|
+
{
|
|
1143
|
+
_assertFn = _resolveFromGlobals();
|
|
1144
|
+
}
|
|
1145
|
+
return function (csg, name) {
|
|
1146
|
+
return _assertFn(csg, name, moduleName);
|
|
1147
|
+
};
|
|
1148
|
+
}
|
|
1149
|
+
|
|
764
1150
|
/** @typedef {object} ExtendedCSG
|
|
765
1151
|
* @property {object} prototype
|
|
766
1152
|
* @property {function} prototype.color
|
|
@@ -833,7 +1219,6 @@ var jscadUtils = (function (exports, jsCadCSG, scadApi) {
|
|
|
833
1219
|
* @property {function} stackTrace
|
|
834
1220
|
* @property {function} getConnector
|
|
835
1221
|
*/
|
|
836
|
-
|
|
837
1222
|
/**
|
|
838
1223
|
* Initialize `jscad-utils` and add utilities to the `proto` object.
|
|
839
1224
|
* @param {CSG} proto The global `proto` object
|
|
@@ -943,6 +1328,9 @@ var jscadUtils = (function (exports, jsCadCSG, scadApi) {
|
|
|
943
1328
|
proto.prototype.subtractIf = function subtractIf(object, condition) {
|
|
944
1329
|
return condition ? this.subtract(result(this, object)) : this;
|
|
945
1330
|
};
|
|
1331
|
+
proto.prototype.validate = function validate(options) {
|
|
1332
|
+
return validateCSG(this, options);
|
|
1333
|
+
};
|
|
946
1334
|
proto.prototype._translate = proto.prototype.translate;
|
|
947
1335
|
|
|
948
1336
|
/**
|
|
@@ -994,16 +1382,17 @@ var jscadUtils = (function (exports, jsCadCSG, scadApi) {
|
|
|
994
1382
|
'default': init
|
|
995
1383
|
});
|
|
996
1384
|
|
|
997
|
-
var CSG = jsCadCSG__default["default"].CSG,
|
|
1385
|
+
var CSG$1 = jsCadCSG__default["default"].CSG,
|
|
998
1386
|
CAG = jsCadCSG__default["default"].CAG;
|
|
999
1387
|
var rectangular_extrude = scadApi__default["default"].extrusions.rectangular_extrude;
|
|
1000
1388
|
var _scadApi$text = scadApi__default["default"].text,
|
|
1001
1389
|
vector_text = _scadApi$text.vector_text,
|
|
1002
1390
|
vector_char = _scadApi$text.vector_char;
|
|
1003
1391
|
var union = scadApi__default["default"].booleanOps.union;
|
|
1004
|
-
init(CSG);
|
|
1392
|
+
init(CSG$1);
|
|
1005
1393
|
|
|
1006
1394
|
var debug$3 = Debug('jscadUtils:group');
|
|
1395
|
+
var assertValidCSG$2 = AssertValidCSG('group');
|
|
1007
1396
|
|
|
1008
1397
|
/**
|
|
1009
1398
|
* @function JsCadUtilsGroup
|
|
@@ -1082,7 +1471,7 @@ var jscadUtils = (function (exports, jsCadCSG, scadApi) {
|
|
|
1082
1471
|
debug$3('combine mapPick', value, key, object);
|
|
1083
1472
|
return map ? map(value, key, index, object) : identity(value);
|
|
1084
1473
|
}, self.name));
|
|
1085
|
-
return g.subtractIf(self.holes && Array.isArray(self.holes) ? union(self.holes) : self.holes, self.holes && !options.noholes);
|
|
1474
|
+
return assertValidCSG$2(g.subtractIf(self.holes && Array.isArray(self.holes) ? union(self.holes) : self.holes, self.holes && !options.noholes), 'combine');
|
|
1086
1475
|
} catch (err) {
|
|
1087
1476
|
debug$3('combine error', this, pieces, options, err);
|
|
1088
1477
|
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');
|
|
@@ -1144,7 +1533,7 @@ var jscadUtils = (function (exports, jsCadCSG, scadApi) {
|
|
|
1144
1533
|
});
|
|
1145
1534
|
if (self.holes) {
|
|
1146
1535
|
group.holes = toArray(self.holes).map(function (part) {
|
|
1147
|
-
return map(CSG.fromPolygons(part.toPolygons()), 'holes');
|
|
1536
|
+
return assertValidCSG$2(map(CSG$1.fromPolygons(part.toPolygons()), 'holes'), 'clone');
|
|
1148
1537
|
});
|
|
1149
1538
|
}
|
|
1150
1539
|
return group;
|
|
@@ -1172,7 +1561,7 @@ var jscadUtils = (function (exports, jsCadCSG, scadApi) {
|
|
|
1172
1561
|
var rotationCenter = solid.centroid();
|
|
1173
1562
|
var rotationAxis = axes[axis];
|
|
1174
1563
|
self.map(function (part) {
|
|
1175
|
-
return part.rotate(rotationCenter, rotationAxis, angle);
|
|
1564
|
+
return assertValidCSG$2(part.rotate(rotationCenter, rotationAxis, angle), 'rotate');
|
|
1176
1565
|
});
|
|
1177
1566
|
return self;
|
|
1178
1567
|
};
|
|
@@ -1206,7 +1595,7 @@ var jscadUtils = (function (exports, jsCadCSG, scadApi) {
|
|
|
1206
1595
|
// debug(', self);
|
|
1207
1596
|
var t = calcSnap(self.combine(part), to, axis, orientation, delta);
|
|
1208
1597
|
self.map(function (part) {
|
|
1209
|
-
return part.translate(t);
|
|
1598
|
+
return assertValidCSG$2(part.translate(t), 'snap');
|
|
1210
1599
|
});
|
|
1211
1600
|
return self;
|
|
1212
1601
|
} catch (err) {
|
|
@@ -1232,7 +1621,7 @@ var jscadUtils = (function (exports, jsCadCSG, scadApi) {
|
|
|
1232
1621
|
noholes: true
|
|
1233
1622
|
}), axis, to, delta);
|
|
1234
1623
|
self.map(function (part /*, name */) {
|
|
1235
|
-
return part.translate(t);
|
|
1624
|
+
return assertValidCSG$2(part.translate(t), 'align');
|
|
1236
1625
|
});
|
|
1237
1626
|
|
|
1238
1627
|
// if (self.holes)
|
|
@@ -1270,14 +1659,14 @@ var jscadUtils = (function (exports, jsCadCSG, scadApi) {
|
|
|
1270
1659
|
var myConnector = connectorName.split('.').reduce(function (a, v) {
|
|
1271
1660
|
return a[v];
|
|
1272
1661
|
}, self.parts[partName].properties);
|
|
1273
|
-
debug$3('toConnector', to instanceof CSG.Connector);
|
|
1662
|
+
debug$3('toConnector', to instanceof CSG$1.Connector);
|
|
1274
1663
|
var toConnector = toConnectorName.split('.').reduce(function (a, v) {
|
|
1275
1664
|
return a[v];
|
|
1276
1665
|
}, to.properties);
|
|
1277
1666
|
var matrix = myConnector.getTransformationTo(toConnector, mirror, normalrotation);
|
|
1278
1667
|
debug$3('connectTo', matrix);
|
|
1279
1668
|
self.map(function (part) {
|
|
1280
|
-
return part.transform(matrix);
|
|
1669
|
+
return assertValidCSG$2(part.transform(matrix), 'connectTo');
|
|
1281
1670
|
});
|
|
1282
1671
|
return self;
|
|
1283
1672
|
};
|
|
@@ -1298,7 +1687,7 @@ var jscadUtils = (function (exports, jsCadCSG, scadApi) {
|
|
|
1298
1687
|
// debug(' part, t);
|
|
1299
1688
|
// var t = util.calcCenterWith(self.combine(part), axis, to, delta);
|
|
1300
1689
|
self.map(function (part) {
|
|
1301
|
-
return part.translate(t);
|
|
1690
|
+
return assertValidCSG$2(part.translate(t), 'midlineTo');
|
|
1302
1691
|
});
|
|
1303
1692
|
|
|
1304
1693
|
// if (self.holes)
|
|
@@ -1322,7 +1711,7 @@ var jscadUtils = (function (exports, jsCadCSG, scadApi) {
|
|
|
1322
1711
|
var t = Array.isArray(x) ? x : [x, y, z];
|
|
1323
1712
|
debug$3('translate', t);
|
|
1324
1713
|
self.map(function (part) {
|
|
1325
|
-
return part.translate(t);
|
|
1714
|
+
return assertValidCSG$2(part.translate(t), 'translate');
|
|
1326
1715
|
});
|
|
1327
1716
|
|
|
1328
1717
|
// if (self.holes)
|
|
@@ -1346,7 +1735,7 @@ var jscadUtils = (function (exports, jsCadCSG, scadApi) {
|
|
|
1346
1735
|
if (!map) map = identity;
|
|
1347
1736
|
var g = Group();
|
|
1348
1737
|
p.forEach(function (name) {
|
|
1349
|
-
g.add(map(CSG.fromPolygons(self.parts[name].toPolygons()), name), name);
|
|
1738
|
+
g.add(assertValidCSG$2(map(CSG$1.fromPolygons(self.parts[name].toPolygons()), name), 'pick'), name);
|
|
1350
1739
|
});
|
|
1351
1740
|
return g;
|
|
1352
1741
|
};
|
|
@@ -1370,7 +1759,7 @@ var jscadUtils = (function (exports, jsCadCSG, scadApi) {
|
|
|
1370
1759
|
debug$3('array error', _this, parts);
|
|
1371
1760
|
throw error("group::array error \"".concat(name, "\" not found.\nthis: ").concat(_this, "\nparts: \"").concat(parts, "\"\n"), 'JSCAD_UTILS_GROUP_ERROR');
|
|
1372
1761
|
}
|
|
1373
|
-
a.push(map(CSG.fromPolygons(self.parts[name].toPolygons()), name));
|
|
1762
|
+
a.push(assertValidCSG$2(map(CSG$1.fromPolygons(self.parts[name].toPolygons()), name), 'array'));
|
|
1374
1763
|
});
|
|
1375
1764
|
return a;
|
|
1376
1765
|
// } catch (err) {
|
|
@@ -1439,7 +1828,7 @@ var jscadUtils = (function (exports, jsCadCSG, scadApi) {
|
|
|
1439
1828
|
self.names = names && names.length > 0 && names.split(',') || [];
|
|
1440
1829
|
if (Array.isArray(objects)) {
|
|
1441
1830
|
self.parts = zipObject(self.names, objects);
|
|
1442
|
-
} else if (objects instanceof CSG) {
|
|
1831
|
+
} else if (objects instanceof CSG$1) {
|
|
1443
1832
|
self.parts = zipObject(self.names, [objects]);
|
|
1444
1833
|
} else {
|
|
1445
1834
|
self.parts = objects || {};
|
|
@@ -1464,6 +1853,8 @@ var jscadUtils = (function (exports, jsCadCSG, scadApi) {
|
|
|
1464
1853
|
}
|
|
1465
1854
|
|
|
1466
1855
|
var debug$2 = Debug('jscadUtils:util');
|
|
1856
|
+
var assertValidCSG$1 = AssertValidCSG('util');
|
|
1857
|
+
|
|
1467
1858
|
// import utilInit from '../src/add-prototype';
|
|
1468
1859
|
// utilInit(CSG);
|
|
1469
1860
|
// console.trace('CSG', CSG.prototype);
|
|
@@ -1627,12 +2018,12 @@ var jscadUtils = (function (exports, jsCadCSG, scadApi) {
|
|
|
1627
2018
|
// console.trace('label', Object.getPrototypeOf(union(o)));
|
|
1628
2019
|
// var foo = union(o);
|
|
1629
2020
|
// console.trace('typeof', typeof foo);
|
|
1630
|
-
return center(union(o));
|
|
2021
|
+
return assertValidCSG$1(center(union(o)), 'label');
|
|
1631
2022
|
}
|
|
1632
2023
|
function text(text) {
|
|
1633
2024
|
var l = vector_char(0, 0, text); // l contains a list of polylines to draw
|
|
1634
2025
|
var _char = l.segments.reduce(function (result, segment) {
|
|
1635
|
-
var path = new CSG.Path2D(segment);
|
|
2026
|
+
var path = new CSG$1.Path2D(segment);
|
|
1636
2027
|
var cag = path.expandToCAG(2);
|
|
1637
2028
|
// debug('reduce', result, segment, path, cag);
|
|
1638
2029
|
return result ? result.union(cag) : cag;
|
|
@@ -1641,17 +2032,17 @@ var jscadUtils = (function (exports, jsCadCSG, scadApi) {
|
|
|
1641
2032
|
}
|
|
1642
2033
|
function unitCube(length, radius) {
|
|
1643
2034
|
radius = radius || 0.5;
|
|
1644
|
-
return CSG.cube({
|
|
2035
|
+
return assertValidCSG$1(CSG$1.cube({
|
|
1645
2036
|
center: [0, 0, 0],
|
|
1646
2037
|
radius: [radius, radius, length || 0.5]
|
|
1647
|
-
});
|
|
2038
|
+
}), 'unitCube');
|
|
1648
2039
|
}
|
|
1649
2040
|
function unitAxis(length, radius, centroid) {
|
|
1650
2041
|
debug$2('unitAxis', length, radius, centroid);
|
|
1651
2042
|
centroid = centroid || [0, 0, 0];
|
|
1652
2043
|
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)]);
|
|
1653
|
-
unitaxis.properties.origin = new CSG.Connector([0, 0, 0], [1, 0, 0], [0, 1, 0]);
|
|
1654
|
-
return unitaxis.translate(centroid);
|
|
2044
|
+
unitaxis.properties.origin = new CSG$1.Connector([0, 0, 0], [1, 0, 0], [0, 1, 0]);
|
|
2045
|
+
return assertValidCSG$1(unitaxis.translate(centroid), 'unitAxis');
|
|
1655
2046
|
}
|
|
1656
2047
|
function toArray(a) {
|
|
1657
2048
|
return Array.isArray(a) ? a : [a];
|
|
@@ -1775,15 +2166,15 @@ var jscadUtils = (function (exports, jsCadCSG, scadApi) {
|
|
|
1775
2166
|
}
|
|
1776
2167
|
function center(object, objectSize) {
|
|
1777
2168
|
objectSize = objectSize || size(object.getBounds());
|
|
1778
|
-
return centerY(centerX(object, objectSize), objectSize);
|
|
2169
|
+
return assertValidCSG$1(centerY(centerX(object, objectSize), objectSize), 'center');
|
|
1779
2170
|
}
|
|
1780
2171
|
function centerY(object, objectSize) {
|
|
1781
2172
|
objectSize = objectSize || size(object.getBounds());
|
|
1782
|
-
return object.translate([0, -objectSize.y / 2, 0]);
|
|
2173
|
+
return assertValidCSG$1(object.translate([0, -objectSize.y / 2, 0]), 'centerY');
|
|
1783
2174
|
}
|
|
1784
2175
|
function centerX(object, objectSize) {
|
|
1785
2176
|
objectSize = objectSize || size(object.getBounds());
|
|
1786
|
-
return object.translate([-objectSize.x / 2, 0, 0]);
|
|
2177
|
+
return assertValidCSG$1(object.translate([-objectSize.x / 2, 0, 0]), 'centerX');
|
|
1787
2178
|
}
|
|
1788
2179
|
|
|
1789
2180
|
/**
|
|
@@ -1815,7 +2206,7 @@ var jscadUtils = (function (exports, jsCadCSG, scadApi) {
|
|
|
1815
2206
|
|
|
1816
2207
|
/// Calculate the difference between the original centroid and the new
|
|
1817
2208
|
var delta = new_centroid.minus(objectCentroid).times(-1);
|
|
1818
|
-
return new_object.translate(delta);
|
|
2209
|
+
return assertValidCSG$1(new_object.translate(delta), 'enlarge');
|
|
1819
2210
|
}
|
|
1820
2211
|
|
|
1821
2212
|
/**
|
|
@@ -1847,10 +2238,10 @@ var jscadUtils = (function (exports, jsCadCSG, scadApi) {
|
|
|
1847
2238
|
}
|
|
1848
2239
|
var s = [scale(objectSize.x, x), scale(objectSize.y, y), scale(objectSize.z, z)];
|
|
1849
2240
|
var min$1 = min(s);
|
|
1850
|
-
return centerWith(object.scale(s.map(function (d, i) {
|
|
2241
|
+
return assertValidCSG$1(centerWith(object.scale(s.map(function (d, i) {
|
|
1851
2242
|
if (a[i] === 0) return 1; // don't scale when value is zero
|
|
1852
2243
|
return keep_aspect_ratio ? min$1 : d;
|
|
1853
|
-
})), 'xyz', object);
|
|
2244
|
+
})), 'xyz', object), 'fit');
|
|
1854
2245
|
}
|
|
1855
2246
|
function shift(object, x, y, z) {
|
|
1856
2247
|
var hsize = this.div(this.size(object.getBounds()), 2);
|
|
@@ -1858,10 +2249,10 @@ var jscadUtils = (function (exports, jsCadCSG, scadApi) {
|
|
|
1858
2249
|
}
|
|
1859
2250
|
function zero(object) {
|
|
1860
2251
|
var bounds = object.getBounds();
|
|
1861
|
-
return object.translate([0, 0, -bounds[0].z]);
|
|
2252
|
+
return assertValidCSG$1(object.translate([0, 0, -bounds[0].z]), 'zero');
|
|
1862
2253
|
}
|
|
1863
2254
|
function mirrored4(x) {
|
|
1864
|
-
return x.union([x.mirroredY(90), x.mirroredX(90), x.mirroredY(90).mirroredX(90)]);
|
|
2255
|
+
return assertValidCSG$1(x.union([x.mirroredY(90), x.mirroredX(90), x.mirroredY(90).mirroredX(90)]), 'mirrored4');
|
|
1865
2256
|
}
|
|
1866
2257
|
var flushSide = {
|
|
1867
2258
|
'above-outside': [1, 0],
|
|
@@ -1927,7 +2318,7 @@ var jscadUtils = (function (exports, jsCadCSG, scadApi) {
|
|
|
1927
2318
|
function snap(moveobj, withobj, axis, orientation, delta) {
|
|
1928
2319
|
debug$2('snap', moveobj, withobj, axis, orientation, delta);
|
|
1929
2320
|
var t = calcSnap(moveobj, withobj, axis, orientation, delta);
|
|
1930
|
-
return moveobj.translate(t);
|
|
2321
|
+
return assertValidCSG$1(moveobj.translate(t), 'snap');
|
|
1931
2322
|
}
|
|
1932
2323
|
|
|
1933
2324
|
/**
|
|
@@ -1940,23 +2331,35 @@ var jscadUtils = (function (exports, jsCadCSG, scadApi) {
|
|
|
1940
2331
|
* @return {CSG} [description]
|
|
1941
2332
|
*/
|
|
1942
2333
|
function flush(moveobj, withobj, axis, mside, wside) {
|
|
1943
|
-
return moveobj.translate(calcFlush(moveobj, withobj, axis, mside, wside));
|
|
2334
|
+
return assertValidCSG$1(moveobj.translate(calcFlush(moveobj, withobj, axis, mside, wside)), 'flush');
|
|
1944
2335
|
}
|
|
2336
|
+
|
|
2337
|
+
/**
|
|
2338
|
+
*
|
|
2339
|
+
* @param {AxisStrings} axes
|
|
2340
|
+
* @param {function(number, string): number} valfun
|
|
2341
|
+
* @param {Array<number>} [a] In initial array to apply the values to, if not provided a new array will be created.
|
|
2342
|
+
* @returns {Array<number>} The resulting array after applying the function to the specified axes.
|
|
2343
|
+
*/
|
|
1945
2344
|
function axisApply(axes, valfun, a) {
|
|
1946
2345
|
debug$2('axisApply', axes, valfun, a);
|
|
2346
|
+
|
|
2347
|
+
/** @type {Array<number>} */
|
|
1947
2348
|
var retval = a || [0, 0, 0];
|
|
2349
|
+
|
|
2350
|
+
/** @type {Record<AxisString, number>} */
|
|
1948
2351
|
var lookup = {
|
|
1949
2352
|
x: 0,
|
|
1950
2353
|
y: 1,
|
|
1951
2354
|
z: 2
|
|
1952
2355
|
};
|
|
1953
2356
|
axes.split('').forEach(function (axis) {
|
|
1954
|
-
retval[lookup[axis]] = valfun(lookup[axis], axis);
|
|
2357
|
+
retval[lookup[(/** @type {AxisString} */axis)]] = valfun(lookup[(/** @type {AxisString} */axis)], axis);
|
|
1955
2358
|
});
|
|
1956
2359
|
return retval;
|
|
1957
2360
|
}
|
|
1958
2361
|
function axis2array(axes, valfun) {
|
|
1959
|
-
depreciated('axis2array');
|
|
2362
|
+
depreciated('axis2array', false, 'Use axisApply instead.');
|
|
1960
2363
|
var a = [0, 0, 0];
|
|
1961
2364
|
var lookup = {
|
|
1962
2365
|
x: 0,
|
|
@@ -1997,7 +2400,7 @@ var jscadUtils = (function (exports, jsCadCSG, scadApi) {
|
|
|
1997
2400
|
});
|
|
1998
2401
|
}
|
|
1999
2402
|
function midlineTo(o, axis, to) {
|
|
2000
|
-
return o.translate(calcmidlineTo(o, axis, to));
|
|
2403
|
+
return assertValidCSG$1(o.translate(calcmidlineTo(o, axis, to)), 'midlineTo');
|
|
2001
2404
|
}
|
|
2002
2405
|
function translator(o, axis, withObj) {
|
|
2003
2406
|
var objectCentroid = centroid(o);
|
|
@@ -2018,7 +2421,7 @@ var jscadUtils = (function (exports, jsCadCSG, scadApi) {
|
|
|
2018
2421
|
return delta ? add(t, delta) : t;
|
|
2019
2422
|
}
|
|
2020
2423
|
function centerWith(o, axis, withObj) {
|
|
2021
|
-
return o.translate(calcCenterWith(o, axis, withObj));
|
|
2424
|
+
return assertValidCSG$1(o.translate(calcCenterWith(o, axis, withObj)), 'centerWith');
|
|
2022
2425
|
}
|
|
2023
2426
|
|
|
2024
2427
|
/**
|
|
@@ -2048,6 +2451,109 @@ var jscadUtils = (function (exports, jsCadCSG, scadApi) {
|
|
|
2048
2451
|
return bounds[0][a] + (isEmpty(dist) ? size[axis] / 2 : dist);
|
|
2049
2452
|
});
|
|
2050
2453
|
}
|
|
2454
|
+
var EPS = 1e-5;
|
|
2455
|
+
|
|
2456
|
+
/**
|
|
2457
|
+
* Split a CSG object into two halves along a plane by directly
|
|
2458
|
+
* splitting polygons. This avoids BSP-tree-based boolean operations
|
|
2459
|
+
* which can fail on geometry produced by stretchAtPlane.
|
|
2460
|
+
* @param {CSG} csg The object to split
|
|
2461
|
+
* @param {CSG.Plane} plane The splitting plane
|
|
2462
|
+
* @return {{ front: CSG, back: CSG }} front (positive normal side) and back (negative normal side)
|
|
2463
|
+
*/
|
|
2464
|
+
function splitCSGByPlane(csg, plane) {
|
|
2465
|
+
var frontPolys = [];
|
|
2466
|
+
var backPolys = [];
|
|
2467
|
+
csg.polygons.forEach(function (poly) {
|
|
2468
|
+
var vertices = poly.vertices;
|
|
2469
|
+
var numVerts = vertices.length;
|
|
2470
|
+
var hasfront = false;
|
|
2471
|
+
var hasback = false;
|
|
2472
|
+
var vertexIsBack = [];
|
|
2473
|
+
for (var i = 0; i < numVerts; i++) {
|
|
2474
|
+
var t = plane.normal.dot(vertices[i].pos) - plane.w;
|
|
2475
|
+
vertexIsBack.push(t < 0);
|
|
2476
|
+
if (t > EPS) hasfront = true;
|
|
2477
|
+
if (t < -EPS) hasback = true;
|
|
2478
|
+
}
|
|
2479
|
+
if (!hasfront && !hasback) {
|
|
2480
|
+
// coplanar — assign based on normal alignment
|
|
2481
|
+
var d = plane.normal.dot(poly.plane.normal);
|
|
2482
|
+
if (d >= 0) {
|
|
2483
|
+
frontPolys.push(poly);
|
|
2484
|
+
} else {
|
|
2485
|
+
backPolys.push(poly);
|
|
2486
|
+
}
|
|
2487
|
+
} else if (!hasback) {
|
|
2488
|
+
frontPolys.push(poly);
|
|
2489
|
+
} else if (!hasfront) {
|
|
2490
|
+
backPolys.push(poly);
|
|
2491
|
+
} else {
|
|
2492
|
+
// spanning — split the polygon
|
|
2493
|
+
var fv = [];
|
|
2494
|
+
var bv = [];
|
|
2495
|
+
for (var vi = 0; vi < numVerts; vi++) {
|
|
2496
|
+
var vertex = vertices[vi];
|
|
2497
|
+
var nextVi = (vi + 1) % numVerts;
|
|
2498
|
+
var isback = vertexIsBack[vi];
|
|
2499
|
+
var nextisback = vertexIsBack[nextVi];
|
|
2500
|
+
if (isback === nextisback) {
|
|
2501
|
+
if (isback) {
|
|
2502
|
+
bv.push(vertex);
|
|
2503
|
+
} else {
|
|
2504
|
+
fv.push(vertex);
|
|
2505
|
+
}
|
|
2506
|
+
} else {
|
|
2507
|
+
var point = vertex.pos;
|
|
2508
|
+
var nextpoint = vertices[nextVi].pos;
|
|
2509
|
+
var ip = plane.splitLineBetweenPoints(point, nextpoint);
|
|
2510
|
+
var iv = new CSG$1.Vertex(ip);
|
|
2511
|
+
if (isback) {
|
|
2512
|
+
bv.push(vertex);
|
|
2513
|
+
bv.push(iv);
|
|
2514
|
+
fv.push(iv);
|
|
2515
|
+
} else {
|
|
2516
|
+
fv.push(vertex);
|
|
2517
|
+
fv.push(iv);
|
|
2518
|
+
bv.push(iv);
|
|
2519
|
+
}
|
|
2520
|
+
}
|
|
2521
|
+
}
|
|
2522
|
+
// Remove degenerate (near-duplicate) adjacent vertices that arise
|
|
2523
|
+
// when the cut plane passes very close to existing vertices.
|
|
2524
|
+
// This matches the cleanup done by the BSP-tree splitter.
|
|
2525
|
+
var EPSEPS = EPS * EPS;
|
|
2526
|
+
if (fv.length >= 3) {
|
|
2527
|
+
var prev = fv[fv.length - 1];
|
|
2528
|
+
for (var fi = 0; fi < fv.length; fi++) {
|
|
2529
|
+
var curr = fv[fi];
|
|
2530
|
+
if (curr.pos.distanceToSquared(prev.pos) < EPSEPS) {
|
|
2531
|
+
fv.splice(fi, 1);
|
|
2532
|
+
fi--;
|
|
2533
|
+
}
|
|
2534
|
+
prev = curr;
|
|
2535
|
+
}
|
|
2536
|
+
}
|
|
2537
|
+
if (bv.length >= 3) {
|
|
2538
|
+
var prev = bv[bv.length - 1];
|
|
2539
|
+
for (var bi = 0; bi < bv.length; bi++) {
|
|
2540
|
+
var curr = bv[bi];
|
|
2541
|
+
if (curr.pos.distanceToSquared(prev.pos) < EPSEPS) {
|
|
2542
|
+
bv.splice(bi, 1);
|
|
2543
|
+
bi--;
|
|
2544
|
+
}
|
|
2545
|
+
prev = curr;
|
|
2546
|
+
}
|
|
2547
|
+
}
|
|
2548
|
+
if (fv.length >= 3) frontPolys.push(new CSG$1.Polygon(fv, poly.shared, poly.plane));
|
|
2549
|
+
if (bv.length >= 3) backPolys.push(new CSG$1.Polygon(bv, poly.shared, poly.plane));
|
|
2550
|
+
}
|
|
2551
|
+
});
|
|
2552
|
+
return {
|
|
2553
|
+
front: CSG$1.fromPolygons(frontPolys),
|
|
2554
|
+
back: CSG$1.fromPolygons(backPolys)
|
|
2555
|
+
};
|
|
2556
|
+
}
|
|
2051
2557
|
|
|
2052
2558
|
/**
|
|
2053
2559
|
* Cut an object into two pieces, along a given axis. The offset
|
|
@@ -2058,7 +2564,7 @@ var jscadUtils = (function (exports, jsCadCSG, scadApi) {
|
|
|
2058
2564
|
*
|
|
2059
2565
|
* You can angle the cut plane and position the rotation point.
|
|
2060
2566
|
*
|
|
2061
|
-
* 
|
|
2062
2568
|
* @param {CSG} object object to bisect
|
|
2063
2569
|
* @param {string} axis axis to cut along
|
|
2064
2570
|
* @param {number} [offset] offset to cut at
|
|
@@ -2136,13 +2642,13 @@ var jscadUtils = (function (exports, jsCadCSG, scadApi) {
|
|
|
2136
2642
|
}[[axis, rotateaxis].sort().join('')];
|
|
2137
2643
|
var centroid = object.centroid();
|
|
2138
2644
|
var rotateDelta = getDelta(objectSize, bounds, rotateOffsetAxis, rotateoffset);
|
|
2139
|
-
var rotationCenter = options.rotationCenter || new CSG.Vector3D(axisApply('xyz', function (i, a) {
|
|
2645
|
+
var rotationCenter = options.rotationCenter || new CSG$1.Vector3D(axisApply('xyz', function (i, a) {
|
|
2140
2646
|
if (a == axis) return cutDelta[i];
|
|
2141
2647
|
if (a == rotateOffsetAxis) return rotateDelta[i];
|
|
2142
2648
|
return centroid[a];
|
|
2143
2649
|
}));
|
|
2144
2650
|
var theRotationAxis = rotationAxes[rotateaxis];
|
|
2145
|
-
var cutplane = CSG.OrthoNormalBasis.GetCartesian(info.orthoNormalCartesian[0], info.orthoNormalCartesian[1]).translate(cutDelta).rotate(rotationCenter, theRotationAxis, angle);
|
|
2651
|
+
var cutplane = CSG$1.OrthoNormalBasis.GetCartesian(info.orthoNormalCartesian[0], info.orthoNormalCartesian[1]).translate(cutDelta).rotate(rotationCenter, theRotationAxis, angle);
|
|
2146
2652
|
debug$2('bisect', debug$2.enabled && {
|
|
2147
2653
|
axis: axis,
|
|
2148
2654
|
offset: offset,
|
|
@@ -2155,7 +2661,33 @@ var jscadUtils = (function (exports, jsCadCSG, scadApi) {
|
|
|
2155
2661
|
cutplane: cutplane,
|
|
2156
2662
|
options: options
|
|
2157
2663
|
});
|
|
2158
|
-
var
|
|
2664
|
+
var negative = object.cutByPlane(cutplane.plane);
|
|
2665
|
+
var positive = object.cutByPlane(cutplane.plane.flipped());
|
|
2666
|
+
|
|
2667
|
+
// Detect cutByPlane failure: if a half's bounding box in the cut axis
|
|
2668
|
+
// is not smaller than the original, the BSP-tree-based cut failed.
|
|
2669
|
+
// Fall back to direct polygon splitting which is more robust, then
|
|
2670
|
+
// apply cutByPlane to the simpler half to add cap faces.
|
|
2671
|
+
var negSize = size(negative);
|
|
2672
|
+
var posSize = size(positive);
|
|
2673
|
+
if (negSize[axis] >= objectSize[axis] - EPS || posSize[axis] >= objectSize[axis] - EPS) {
|
|
2674
|
+
var halves = splitCSGByPlane(object, cutplane.plane);
|
|
2675
|
+
if (negSize[axis] >= objectSize[axis] - EPS) {
|
|
2676
|
+
negative = halves.back;
|
|
2677
|
+
// Cap the open cut face
|
|
2678
|
+
try {
|
|
2679
|
+
negative = negative.cutByPlane(cutplane.plane);
|
|
2680
|
+
} catch (e) {/* keep uncapped */}
|
|
2681
|
+
}
|
|
2682
|
+
if (posSize[axis] >= objectSize[axis] - EPS) {
|
|
2683
|
+
positive = halves.front;
|
|
2684
|
+
// Cap the open cut face
|
|
2685
|
+
try {
|
|
2686
|
+
positive = positive.cutByPlane(cutplane.plane.flipped());
|
|
2687
|
+
} catch (e) {/* keep uncapped */}
|
|
2688
|
+
}
|
|
2689
|
+
}
|
|
2690
|
+
var g = Group('negative,positive', [negative.color(options.color && 'red'), positive.color(options.color && 'blue')]);
|
|
2159
2691
|
if (options.addRotationCenter) g.add(unitAxis(objectSize.length() + 10, 0.1, rotationCenter), 'rotationCenter');
|
|
2160
2692
|
return g;
|
|
2161
2693
|
}
|
|
@@ -2180,9 +2712,9 @@ var jscadUtils = (function (exports, jsCadCSG, scadApi) {
|
|
|
2180
2712
|
addRotationCenter: true
|
|
2181
2713
|
};
|
|
2182
2714
|
var info = normalVector(axis);
|
|
2183
|
-
var rotationCenter = options.rotationCenter || new CSG.Vector3D(0, 0, 0);
|
|
2715
|
+
var rotationCenter = options.rotationCenter || new CSG$1.Vector3D(0, 0, 0);
|
|
2184
2716
|
var theRotationAxis = rotationAxes[rotateaxis];
|
|
2185
|
-
var cutplane = CSG.OrthoNormalBasis.GetCartesian(info.orthoNormalCartesian[0], info.orthoNormalCartesian[1])
|
|
2717
|
+
var cutplane = CSG$1.OrthoNormalBasis.GetCartesian(info.orthoNormalCartesian[0], info.orthoNormalCartesian[1])
|
|
2186
2718
|
// .translate(cutDelta)
|
|
2187
2719
|
.rotate(rotationCenter, theRotationAxis, angle);
|
|
2188
2720
|
var g = Group('negative,positive', [object.cutByPlane(cutplane.plane).color(options.color && 'red'), object.cutByPlane(cutplane.plane.flipped()).color(options.color && 'blue')]);
|
|
@@ -2197,7 +2729,7 @@ var jscadUtils = (function (exports, jsCadCSG, scadApi) {
|
|
|
2197
2729
|
* Creates a `JsCadUtilsGroup` object that has `body` and `wedge` objects. The `wedge` object
|
|
2198
2730
|
* is created by radially cutting the object from the `start` to the `end` angle.
|
|
2199
2731
|
*
|
|
2200
|
-
* 
|
|
2201
2733
|
*
|
|
2202
2734
|
*
|
|
2203
2735
|
* @example
|
|
@@ -2253,7 +2785,7 @@ var jscadUtils = (function (exports, jsCadCSG, scadApi) {
|
|
|
2253
2785
|
var objectSize = size(object);
|
|
2254
2786
|
var cutDelta = getDelta(objectSize, bounds, axis, offset, true);
|
|
2255
2787
|
// debug('stretch.cutDelta', cutDelta, normal[axis]);
|
|
2256
|
-
return object.stretchAtPlane(normal[axis], cutDelta, distance);
|
|
2788
|
+
return assertValidCSG$1(object.stretchAtPlane(normal[axis], cutDelta, distance), 'stretch');
|
|
2257
2789
|
}
|
|
2258
2790
|
|
|
2259
2791
|
/**
|
|
@@ -2268,11 +2800,11 @@ var jscadUtils = (function (exports, jsCadCSG, scadApi) {
|
|
|
2268
2800
|
function poly2solid(top, bottom, height) {
|
|
2269
2801
|
if (top.sides.length == 0) {
|
|
2270
2802
|
// empty!
|
|
2271
|
-
return new CSG();
|
|
2803
|
+
return new CSG$1();
|
|
2272
2804
|
}
|
|
2273
2805
|
// var offsetVector = CSG.parseOptionAs3DVector(options, "offset", [0, 0, 10]);
|
|
2274
|
-
var offsetVector = CSG.Vector3D.Create(0, 0, height);
|
|
2275
|
-
var normalVector = CSG.Vector3D.Create(0, 1, 0);
|
|
2806
|
+
var offsetVector = CSG$1.Vector3D.Create(0, 0, height);
|
|
2807
|
+
var normalVector = CSG$1.Vector3D.Create(0, 1, 0);
|
|
2276
2808
|
var polygons = [];
|
|
2277
2809
|
// bottom and top
|
|
2278
2810
|
polygons = polygons.concat(bottom._toPlanePolygons({
|
|
@@ -2286,8 +2818,8 @@ var jscadUtils = (function (exports, jsCadCSG, scadApi) {
|
|
|
2286
2818
|
flipped: offsetVector.z < 0
|
|
2287
2819
|
}));
|
|
2288
2820
|
// walls
|
|
2289
|
-
var c1 = new CSG.Connector(offsetVector.times(0), [0, 0, offsetVector.z], normalVector);
|
|
2290
|
-
var c2 = new CSG.Connector(offsetVector, [0, 0, offsetVector.z], normalVector);
|
|
2821
|
+
var c1 = new CSG$1.Connector(offsetVector.times(0), [0, 0, offsetVector.z], normalVector);
|
|
2822
|
+
var c2 = new CSG$1.Connector(offsetVector, [0, 0, offsetVector.z], normalVector);
|
|
2291
2823
|
polygons = polygons.concat(bottom._toWallPolygons({
|
|
2292
2824
|
cag: top,
|
|
2293
2825
|
toConnector1: c1,
|
|
@@ -2295,7 +2827,7 @@ var jscadUtils = (function (exports, jsCadCSG, scadApi) {
|
|
|
2295
2827
|
}));
|
|
2296
2828
|
// }
|
|
2297
2829
|
|
|
2298
|
-
return CSG.fromPolygons(polygons);
|
|
2830
|
+
return assertValidCSG$1(CSG$1.fromPolygons(polygons), 'poly2solid');
|
|
2299
2831
|
}
|
|
2300
2832
|
function slices2poly(slices, options, axis) {
|
|
2301
2833
|
debug$2('slices2poly', slices, options, axis);
|
|
@@ -2304,7 +2836,7 @@ var jscadUtils = (function (exports, jsCadCSG, scadApi) {
|
|
|
2304
2836
|
twiststeps: 0
|
|
2305
2837
|
}, options);
|
|
2306
2838
|
var twistangle = options && parseFloat(options.twistangle) || 0;
|
|
2307
|
-
options && parseInt(options.twiststeps) || CSG.defaultResolution3D;
|
|
2839
|
+
options && parseInt(options.twiststeps) || CSG$1.defaultResolution3D;
|
|
2308
2840
|
var normalVector = options.si.normalVector;
|
|
2309
2841
|
var polygons = [];
|
|
2310
2842
|
|
|
@@ -2343,8 +2875,8 @@ var jscadUtils = (function (exports, jsCadCSG, scadApi) {
|
|
|
2343
2875
|
var nextidx = idx + 1;
|
|
2344
2876
|
var top = !up ? slices[nextidx] : slice;
|
|
2345
2877
|
var bottom = up ? slices[nextidx] : slice;
|
|
2346
|
-
var c1 = new CSG.Connector(bottom.offset, connectorAxis, rotate(normalVector, twistangle, idx / slices.length));
|
|
2347
|
-
var c2 = new CSG.Connector(top.offset, connectorAxis, rotate(normalVector, twistangle, nextidx / slices.length));
|
|
2878
|
+
var c1 = new CSG$1.Connector(bottom.offset, connectorAxis, rotate(normalVector, twistangle, idx / slices.length));
|
|
2879
|
+
var c2 = new CSG$1.Connector(top.offset, connectorAxis, rotate(normalVector, twistangle, nextidx / slices.length));
|
|
2348
2880
|
|
|
2349
2881
|
// debug('slices2poly.slices', c1.point, c2.point);
|
|
2350
2882
|
polygons = polygons.concat(bottom.poly._toWallPolygons({
|
|
@@ -2354,21 +2886,21 @@ var jscadUtils = (function (exports, jsCadCSG, scadApi) {
|
|
|
2354
2886
|
}));
|
|
2355
2887
|
}
|
|
2356
2888
|
});
|
|
2357
|
-
return CSG.fromPolygons(polygons);
|
|
2889
|
+
return assertValidCSG$1(CSG$1.fromPolygons(polygons), 'slices2poly');
|
|
2358
2890
|
}
|
|
2359
2891
|
function normalVector(axis) {
|
|
2360
2892
|
var axisInfo = {
|
|
2361
2893
|
z: {
|
|
2362
2894
|
orthoNormalCartesian: ['X', 'Y'],
|
|
2363
|
-
normalVector: CSG.Vector3D.Create(0, 1, 0)
|
|
2895
|
+
normalVector: CSG$1.Vector3D.Create(0, 1, 0)
|
|
2364
2896
|
},
|
|
2365
2897
|
x: {
|
|
2366
2898
|
orthoNormalCartesian: ['Y', 'Z'],
|
|
2367
|
-
normalVector: CSG.Vector3D.Create(0, 0, 1)
|
|
2899
|
+
normalVector: CSG$1.Vector3D.Create(0, 0, 1)
|
|
2368
2900
|
},
|
|
2369
2901
|
y: {
|
|
2370
|
-
orthoNormalCartesian: ['
|
|
2371
|
-
normalVector: CSG.Vector3D.Create(0, 0, 1)
|
|
2902
|
+
orthoNormalCartesian: ['Z', 'X'],
|
|
2903
|
+
normalVector: CSG$1.Vector3D.Create(0, 0, 1)
|
|
2372
2904
|
}
|
|
2373
2905
|
};
|
|
2374
2906
|
if (!axisInfo[axis]) error('normalVector: invalid axis ' + axis);
|
|
@@ -2420,7 +2952,7 @@ var jscadUtils = (function (exports, jsCadCSG, scadApi) {
|
|
|
2420
2952
|
var si = sliceParams(orientation, radius, b);
|
|
2421
2953
|
debug$2('reShape', absoluteRadius, si);
|
|
2422
2954
|
if (si.axis !== 'z') throw new Error('reShape error: CAG._toPlanePolygons only uses the "z" axis. You must use the "z" axis for now.');
|
|
2423
|
-
var cutplane = CSG.OrthoNormalBasis.GetCartesian(si.orthoNormalCartesian[0], si.orthoNormalCartesian[1]).translate(si.cutDelta);
|
|
2955
|
+
var cutplane = CSG$1.OrthoNormalBasis.GetCartesian(si.orthoNormalCartesian[0], si.orthoNormalCartesian[1]).translate(si.cutDelta);
|
|
2424
2956
|
var slice = object.sectionCut(cutplane);
|
|
2425
2957
|
var first = axisApply(si.axis, function () {
|
|
2426
2958
|
return si.positive ? 0 : absoluteRadius;
|
|
@@ -2435,25 +2967,25 @@ var jscadUtils = (function (exports, jsCadCSG, scadApi) {
|
|
|
2435
2967
|
si: si
|
|
2436
2968
|
}), si.axis).color(options.color);
|
|
2437
2969
|
var remainder = object.cutByPlane(plane);
|
|
2438
|
-
return union([options.unionOriginal ? object : remainder, delta.translate(si.moveDelta)]);
|
|
2970
|
+
return assertValidCSG$1(union([options.unionOriginal ? object : remainder, delta.translate(si.moveDelta)]), 'reShape');
|
|
2439
2971
|
}
|
|
2440
2972
|
function chamfer(object, radius, orientation, options) {
|
|
2441
|
-
return reShape(object, radius, orientation, options, function (first, last, slice) {
|
|
2973
|
+
return assertValidCSG$1(reShape(object, radius, orientation, options, function (first, last, slice) {
|
|
2442
2974
|
return [{
|
|
2443
2975
|
poly: slice,
|
|
2444
|
-
offset: new CSG.Vector3D(first)
|
|
2976
|
+
offset: new CSG$1.Vector3D(first)
|
|
2445
2977
|
}, {
|
|
2446
2978
|
poly: enlarge(slice, [-radius * 2, -radius * 2]),
|
|
2447
|
-
offset: new CSG.Vector3D(last)
|
|
2979
|
+
offset: new CSG$1.Vector3D(last)
|
|
2448
2980
|
}];
|
|
2449
|
-
});
|
|
2981
|
+
}), 'chamfer');
|
|
2450
2982
|
}
|
|
2451
2983
|
function fillet(object, radius, orientation, options) {
|
|
2452
2984
|
options = options || {};
|
|
2453
|
-
return reShape(object, radius, orientation, options, function (first, last, slice) {
|
|
2454
|
-
var v1 = new CSG.Vector3D(first);
|
|
2455
|
-
var v2 = new CSG.Vector3D(last);
|
|
2456
|
-
var res = options.resolution || CSG.defaultResolution3D;
|
|
2985
|
+
return assertValidCSG$1(reShape(object, radius, orientation, options, function (first, last, slice) {
|
|
2986
|
+
var v1 = new CSG$1.Vector3D(first);
|
|
2987
|
+
var v2 = new CSG$1.Vector3D(last);
|
|
2988
|
+
var res = options.resolution || CSG$1.defaultResolution3D;
|
|
2457
2989
|
var slices = range(0, res).map(function (i) {
|
|
2458
2990
|
var p = i > 0 ? i / (res - 1) : 0;
|
|
2459
2991
|
var v = v1.lerp(v2, p);
|
|
@@ -2464,7 +2996,7 @@ var jscadUtils = (function (exports, jsCadCSG, scadApi) {
|
|
|
2464
2996
|
};
|
|
2465
2997
|
});
|
|
2466
2998
|
return slices;
|
|
2467
|
-
});
|
|
2999
|
+
}), 'fillet');
|
|
2468
3000
|
}
|
|
2469
3001
|
function calcRotate(part, solid, axis /* , angle */) {
|
|
2470
3002
|
var axes = {
|
|
@@ -2483,7 +3015,7 @@ var jscadUtils = (function (exports, jsCadCSG, scadApi) {
|
|
|
2483
3015
|
var _calcRotate = calcRotate(part, solid, axis),
|
|
2484
3016
|
rotationCenter = _calcRotate.rotationCenter,
|
|
2485
3017
|
rotationAxis = _calcRotate.rotationAxis;
|
|
2486
|
-
return part.rotate(rotationCenter, rotationAxis, angle);
|
|
3018
|
+
return assertValidCSG$1('rotateAround')(part.rotate(rotationCenter, rotationAxis, angle));
|
|
2487
3019
|
}
|
|
2488
3020
|
function cloneProperties(from, to) {
|
|
2489
3021
|
return Object.entries(from).reduce(function (props, _ref) {
|
|
@@ -2495,10 +3027,10 @@ var jscadUtils = (function (exports, jsCadCSG, scadApi) {
|
|
|
2495
3027
|
}, to);
|
|
2496
3028
|
}
|
|
2497
3029
|
function clone(o) {
|
|
2498
|
-
var c = CSG.fromPolygons(o.toPolygons());
|
|
3030
|
+
var c = CSG$1.fromPolygons(o.toPolygons());
|
|
2499
3031
|
cloneProperties(o, c);
|
|
2500
|
-
debug$2('clone', o, c, CSG);
|
|
2501
|
-
return c;
|
|
3032
|
+
debug$2('clone', o, c, CSG$1);
|
|
3033
|
+
return assertValidCSG$1(c, 'clone');
|
|
2502
3034
|
}
|
|
2503
3035
|
|
|
2504
3036
|
/**
|
|
@@ -2514,11 +3046,12 @@ var jscadUtils = (function (exports, jsCadCSG, scadApi) {
|
|
|
2514
3046
|
var point = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : [0, 0, 0];
|
|
2515
3047
|
var axis = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : [1, 0, 0];
|
|
2516
3048
|
var normal = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : [0, 0, 1];
|
|
2517
|
-
object.properties[name] = new CSG.Connector(point, axis, normal);
|
|
2518
|
-
return object;
|
|
3049
|
+
object.properties[name] = new CSG$1.Connector(point, axis, normal);
|
|
3050
|
+
return assertValidCSG$1('addConnector')(object);
|
|
2519
3051
|
}
|
|
2520
3052
|
|
|
2521
3053
|
var debug$1 = Debug('jscadUtils:parts');
|
|
3054
|
+
var assertValidCSG = AssertValidCSG('parts');
|
|
2522
3055
|
var parts = {
|
|
2523
3056
|
BBox: BBox$1,
|
|
2524
3057
|
Cube: Cube,
|
|
@@ -2536,7 +3069,7 @@ var jscadUtils = (function (exports, jsCadCSG, scadApi) {
|
|
|
2536
3069
|
*/
|
|
2537
3070
|
function BBox$1() {
|
|
2538
3071
|
function box(object) {
|
|
2539
|
-
return CSG.cube({
|
|
3072
|
+
return CSG$1.cube({
|
|
2540
3073
|
center: object.centroid(),
|
|
2541
3074
|
radius: object.size().dividedBy(2)
|
|
2542
3075
|
});
|
|
@@ -2544,17 +3077,17 @@ var jscadUtils = (function (exports, jsCadCSG, scadApi) {
|
|
|
2544
3077
|
for (var _len = arguments.length, objects = new Array(_len), _key = 0; _key < _len; _key++) {
|
|
2545
3078
|
objects[_key] = arguments[_key];
|
|
2546
3079
|
}
|
|
2547
|
-
return objects.reduce(function (bbox, part) {
|
|
3080
|
+
return assertValidCSG(objects.reduce(function (bbox, part) {
|
|
2548
3081
|
var object = bbox ? union([bbox, box(part)]) : part;
|
|
2549
3082
|
return box(object);
|
|
2550
|
-
}, undefined);
|
|
3083
|
+
}, undefined), 'BBox');
|
|
2551
3084
|
}
|
|
2552
3085
|
function Cube(width) {
|
|
2553
3086
|
var r = div$1(fromxyz(width), 2);
|
|
2554
|
-
return CSG.cube({
|
|
3087
|
+
return assertValidCSG(CSG$1.cube({
|
|
2555
3088
|
center: r,
|
|
2556
3089
|
radius: r
|
|
2557
|
-
});
|
|
3090
|
+
}), 'Cube');
|
|
2558
3091
|
}
|
|
2559
3092
|
|
|
2560
3093
|
// export function Sphere(diameter) {
|
|
@@ -2588,11 +3121,11 @@ var jscadUtils = (function (exports, jsCadCSG, scadApi) {
|
|
|
2588
3121
|
center: [r[0], r[1], 0],
|
|
2589
3122
|
radius: r,
|
|
2590
3123
|
roundradius: corner_radius,
|
|
2591
|
-
resolution: CSG.defaultResolution2D
|
|
3124
|
+
resolution: CSG$1.defaultResolution2D
|
|
2592
3125
|
}).extrude({
|
|
2593
3126
|
offset: [0, 0, thickness || 1.62]
|
|
2594
3127
|
});
|
|
2595
|
-
return roundedcube;
|
|
3128
|
+
return assertValidCSG(roundedcube, 'RoundedCube');
|
|
2596
3129
|
}
|
|
2597
3130
|
|
|
2598
3131
|
/**
|
|
@@ -2610,9 +3143,9 @@ var jscadUtils = (function (exports, jsCadCSG, scadApi) {
|
|
|
2610
3143
|
start: [0, 0, 0],
|
|
2611
3144
|
end: [0, 0, height],
|
|
2612
3145
|
radius: diameter / 2,
|
|
2613
|
-
resolution: CSG.defaultResolution2D
|
|
3146
|
+
resolution: CSG$1.defaultResolution2D
|
|
2614
3147
|
}, options);
|
|
2615
|
-
return CSG.cylinder(options);
|
|
3148
|
+
return assertValidCSG(CSG$1.cylinder(options), 'Cylinder');
|
|
2616
3149
|
}
|
|
2617
3150
|
|
|
2618
3151
|
/**
|
|
@@ -2627,13 +3160,13 @@ var jscadUtils = (function (exports, jsCadCSG, scadApi) {
|
|
|
2627
3160
|
function Cone(diameter1, diameter2, height) {
|
|
2628
3161
|
var options = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {};
|
|
2629
3162
|
debug$1('parts.Cone', diameter1, diameter2, height, options);
|
|
2630
|
-
return CSG.cylinder(Object.assign({
|
|
3163
|
+
return assertValidCSG(CSG$1.cylinder(Object.assign({
|
|
2631
3164
|
start: [0, 0, 0],
|
|
2632
3165
|
end: [0, 0, height],
|
|
2633
3166
|
radiusStart: diameter1 / 2,
|
|
2634
3167
|
radiusEnd: diameter2 / 2,
|
|
2635
|
-
resolution: CSG.defaultResolution2D
|
|
2636
|
-
}, options));
|
|
3168
|
+
resolution: CSG$1.defaultResolution2D
|
|
3169
|
+
}, options)), 'Cone');
|
|
2637
3170
|
}
|
|
2638
3171
|
|
|
2639
3172
|
/**
|
|
@@ -2646,9 +3179,9 @@ var jscadUtils = (function (exports, jsCadCSG, scadApi) {
|
|
|
2646
3179
|
var radius = diameter / 2;
|
|
2647
3180
|
var sqrt3 = Math.sqrt(3) / 2;
|
|
2648
3181
|
var hex = CAG.fromPoints([[radius, 0], [radius / 2, radius * sqrt3], [-radius / 2, radius * sqrt3], [-radius, 0], [-radius / 2, -radius * sqrt3], [radius / 2, -radius * sqrt3]]);
|
|
2649
|
-
return hex.extrude({
|
|
3182
|
+
return assertValidCSG(hex.extrude({
|
|
2650
3183
|
offset: [0, 0, height]
|
|
2651
|
-
});
|
|
3184
|
+
}), 'Hexagon');
|
|
2652
3185
|
}
|
|
2653
3186
|
|
|
2654
3187
|
/**
|
|
@@ -2661,9 +3194,9 @@ var jscadUtils = (function (exports, jsCadCSG, scadApi) {
|
|
|
2661
3194
|
function Triangle(base, height) {
|
|
2662
3195
|
var radius = base / 2;
|
|
2663
3196
|
var tri = CAG.fromPoints([[-radius, 0], [radius, 0], [0, Math.sin(30) * radius]]);
|
|
2664
|
-
return tri.extrude({
|
|
3197
|
+
return assertValidCSG(tri.extrude({
|
|
2665
3198
|
offset: [0, 0, height]
|
|
2666
|
-
});
|
|
3199
|
+
}), 'Triangle');
|
|
2667
3200
|
}
|
|
2668
3201
|
|
|
2669
3202
|
/**
|
|
@@ -2678,7 +3211,7 @@ var jscadUtils = (function (exports, jsCadCSG, scadApi) {
|
|
|
2678
3211
|
* @returns {CSG} A CSG Tube
|
|
2679
3212
|
*/
|
|
2680
3213
|
function Tube(outsideDiameter, insideDiameter, height, outsideOptions, insideOptions) {
|
|
2681
|
-
return Cylinder(outsideDiameter, height, outsideOptions).subtract(Cylinder(insideDiameter, height, insideOptions || outsideOptions));
|
|
3214
|
+
return assertValidCSG(Cylinder(outsideDiameter, height, outsideOptions).subtract(Cylinder(insideDiameter, height, insideOptions || outsideOptions)), 'Tube');
|
|
2682
3215
|
}
|
|
2683
3216
|
|
|
2684
3217
|
/**
|
|
@@ -2702,11 +3235,11 @@ var jscadUtils = (function (exports, jsCadCSG, scadApi) {
|
|
|
2702
3235
|
center: [r[0], r[1], 0],
|
|
2703
3236
|
radius: r,
|
|
2704
3237
|
roundradius: corner_radius,
|
|
2705
|
-
resolution: CSG.defaultResolution2D
|
|
3238
|
+
resolution: CSG$1.defaultResolution2D
|
|
2706
3239
|
}).extrude({
|
|
2707
3240
|
offset: [0, 0, thickness || 1.62]
|
|
2708
3241
|
});
|
|
2709
|
-
return board;
|
|
3242
|
+
return assertValidCSG(board, 'Board');
|
|
2710
3243
|
}
|
|
2711
3244
|
var Hardware = {
|
|
2712
3245
|
Orientation: {
|
|
@@ -2856,7 +3389,7 @@ var jscadUtils = (function (exports, jsCadCSG, scadApi) {
|
|
|
2856
3389
|
* This will bisect an object using a rabett join. Returns a
|
|
2857
3390
|
* `group` object with `positive` and `negative` parts.
|
|
2858
3391
|
*
|
|
2859
|
-
*
|
|
3392
|
+
* 
|
|
2860
3393
|
* @example
|
|
2861
3394
|
*include('dist/jscad-utils.jscad');
|
|
2862
3395
|
*
|
|
@@ -2886,6 +3419,11 @@ var jscadUtils = (function (exports, jsCadCSG, scadApi) {
|
|
|
2886
3419
|
gap = gap || 0.25;
|
|
2887
3420
|
var inside = thickness - gap;
|
|
2888
3421
|
var outside = -thickness + gap;
|
|
3422
|
+
var boxHeight = box.size().z;
|
|
3423
|
+
if (Math.abs(height) >= boxHeight) {
|
|
3424
|
+
throw new Error("Rabett: height (".concat(height, ") must be less than the object height (").concat(boxHeight, ")"));
|
|
3425
|
+
}
|
|
3426
|
+
|
|
2889
3427
|
// options.color = true;
|
|
2890
3428
|
debug('inside', inside, 'outside', outside);
|
|
2891
3429
|
var group = Group();
|
|
@@ -2915,7 +3453,7 @@ var jscadUtils = (function (exports, jsCadCSG, scadApi) {
|
|
|
2915
3453
|
* Used on a hollow object, this will rabett out the top and/or
|
|
2916
3454
|
* bottom of the object.
|
|
2917
3455
|
*
|
|
2918
|
-
* 
|
|
2919
3457
|
*
|
|
2920
3458
|
* @example
|
|
2921
3459
|
*include('dist/jscad-utils.jscad');
|
|
@@ -3002,10 +3540,10 @@ var jscadUtils = (function (exports, jsCadCSG, scadApi) {
|
|
|
3002
3540
|
thickness = thickness || 2;
|
|
3003
3541
|
var s = div$1(xyz2array(size), 2);
|
|
3004
3542
|
var r = add(s, thickness);
|
|
3005
|
-
var box = CSG.cube({
|
|
3543
|
+
var box = CSG$1.cube({
|
|
3006
3544
|
center: r,
|
|
3007
3545
|
radius: r
|
|
3008
|
-
}).subtract(CSG.cube({
|
|
3546
|
+
}).subtract(CSG$1.cube({
|
|
3009
3547
|
center: r,
|
|
3010
3548
|
radius: s
|
|
3011
3549
|
}));
|
|
@@ -3020,7 +3558,7 @@ var jscadUtils = (function (exports, jsCadCSG, scadApi) {
|
|
|
3020
3558
|
* wall thickness. This is done by reducing the object by half the
|
|
3021
3559
|
* thickness and subtracting the reduced version from the original object.
|
|
3022
3560
|
*
|
|
3023
|
-
* 
|
|
3024
3562
|
*
|
|
3025
3563
|
* @param {CSG} object A CSG object
|
|
3026
3564
|
* @param {Number} [thickness=2] The thickness of the walls.
|
|
@@ -3048,7 +3586,7 @@ var jscadUtils = (function (exports, jsCadCSG, scadApi) {
|
|
|
3048
3586
|
var BBox = function BBox(o) {
|
|
3049
3587
|
depreciated('BBox', true, "Use 'parts.BBox' instead");
|
|
3050
3588
|
var s = div$1(xyz2array(o.size()), 2);
|
|
3051
|
-
return CSG.cube({
|
|
3589
|
+
return CSG$1.cube({
|
|
3052
3590
|
center: s,
|
|
3053
3591
|
radius: s
|
|
3054
3592
|
}).align(o, 'xyz');
|
|
@@ -3060,7 +3598,7 @@ var jscadUtils = (function (exports, jsCadCSG, scadApi) {
|
|
|
3060
3598
|
var gap = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 0.25;
|
|
3061
3599
|
var r = add(getRadius(box), -thickness / 2);
|
|
3062
3600
|
r[2] = thickness / 2;
|
|
3063
|
-
var cutter = CSG.cube({
|
|
3601
|
+
var cutter = CSG$1.cube({
|
|
3064
3602
|
center: r,
|
|
3065
3603
|
radius: r
|
|
3066
3604
|
}).align(box, 'xy').color('green');
|