@jscad/modeling 2.9.5 → 2.9.6
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/CHANGELOG.md +16 -0
- package/dist/jscad-modeling.min.js +4 -4
- package/package.json +2 -2
- package/src/geometries/path2/appendPoints.js +3 -12
- package/src/geometries/path2/appendPoints.test.js +16 -0
- package/src/geometries/path2/concat.js +9 -8
- package/src/geometries/path2/concat.test.js +13 -7
- package/src/operations/modifiers/insertTjunctions.js +34 -35
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,22 @@
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
5
5
|
|
|
6
|
+
## [2.9.6](https://github.com/jscad/OpenJSCAD.org/compare/@jscad/modeling@2.9.5...@jscad/modeling@2.9.6) (2022-07-17)
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
### Bug Fixes
|
|
10
|
+
|
|
11
|
+
* **modeling:** corrected concat to prevent modifying original paths ([#1118](https://github.com/jscad/OpenJSCAD.org/issues/1118)) ([ebeaa26](https://github.com/jscad/OpenJSCAD.org/commit/ebeaa26d087646cc6b0f9b927a9230db471a0469))
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
### Performance Improvements
|
|
15
|
+
|
|
16
|
+
* **modeling:** convert {} objects to Map in insertTjunctions ([#1109](https://github.com/jscad/OpenJSCAD.org/issues/1109)) ([03c7fd1](https://github.com/jscad/OpenJSCAD.org/commit/03c7fd12af53ca025e32d481989563717b8d2137))
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
|
|
6
22
|
## [2.9.5](https://github.com/jscad/OpenJSCAD.org/compare/@jscad/modeling@2.9.4...@jscad/modeling@2.9.5) (2022-06-12)
|
|
7
23
|
|
|
8
24
|
|
|
@@ -143,9 +143,9 @@ const vec2=require("../../maths/vec2"),fromPoints=require("./fromPoints"),toPoin
|
|
|
143
143
|
const vec2=require("../../maths/vec2"),vec3=require("../../maths/vec2"),appendPoints=require("./appendPoints"),toPoints=require("./toPoints"),appendBezier=(e,t)=>{let{controlPoints:o,segments:r}=Object.assign({},{segments:16},e);if(!Array.isArray(o))throw new Error("controlPoints must be an array of one or more points");if(o.length<1)throw new Error("controlPoints must be an array of one or more points");if(r<4)throw new Error("segments must be four or more");if(t.isClosed)throw new Error("the given geometry cannot be closed");const n=toPoints(t);if(n.length<1)throw new Error("the given path must contain one or more points (as the starting point for the bezier curve)");if(null===(o=o.slice())[0]){if(o.length<2)throw new Error("a null control point must be passed with one more control points");let e=n[n.length-2];if("lastBezierControlPoint"in t&&(e=t.lastBezierControlPoint),!Array.isArray(e))throw new Error("the given path must contain TWO or more points if given a null control point");const r=vec2.scale(vec2.create(),n[n.length-1],2);vec2.subtract(r,r,e),o[0]=r}o.unshift(n[n.length-1]);const s=o.length-1,i=[];let c=1;for(let e=0;e<=s;++e)e>0&&(c*=e),i.push(c);const a=[];for(let e=0;e<=s;++e){const t=i[s]/(i[e]*i[s-e]);a.push(t)}const l=vec2.create(),h=vec2.create(),p=vec3.create(),u=e=>{let t=1,r=Math.pow(1-e,s);const n=1!==e?1/(1-e):1,i=vec2.create();for(let c=0;c<=s;++c){c===s&&(r=1);const h=a[c]*t*r,p=vec2.scale(l,o[c],h);vec2.add(i,i,p),t*=e,r*=n}return i},v=[],f=[],m=s+1;for(let e=0;e<m;++e){const t=e/(m-1),o=u(t);v.push(o),f.push(t)}let g=1;const w=2*Math.PI/r,P=Math.sin(w);for(;g<v.length-1;){const e=vec2.subtract(l,v[g],v[g-1]);vec2.normalize(e,e);const t=vec2.subtract(h,v[g+1],v[g]);vec2.normalize(t,t);const o=vec2.cross(p,e,t);if(Math.abs(o[2])>P){const e=f[g-1],t=f[g+1],o=e+1*(t-e)/3,r=e+2*(t-e)/3,n=u(o),s=u(r);v.splice(g,1,n,s),f.splice(g,1,o,r),--g<1&&(g=1)}else++g}v.shift();const b=appendPoints(v,t);return b.lastBezierControlPoint=o[o.length-2],b};module.exports=appendBezier;
|
|
144
144
|
|
|
145
145
|
},{"../../maths/vec2":186,"./appendPoints":49,"./toPoints":62}],49:[function(require,module,exports){
|
|
146
|
-
const
|
|
146
|
+
const concat=require("./concat"),create=require("./create"),appendPoints=(e,c)=>concat(c,create(e));module.exports=appendPoints;
|
|
147
147
|
|
|
148
|
-
},{"./
|
|
148
|
+
},{"./concat":53,"./create":54}],50:[function(require,module,exports){
|
|
149
149
|
const mat4=require("../../maths/mat4"),vec2=require("../../maths/vec2"),applyTransforms=r=>mat4.isIdentity(r.transforms)?r:(r.points=r.points.map(s=>vec2.transform(vec2.create(),s,r.transforms)),r.transforms=mat4.create(),r);module.exports=applyTransforms;
|
|
150
150
|
|
|
151
151
|
},{"../../maths/mat4":139,"../../maths/vec2":186}],51:[function(require,module,exports){
|
|
@@ -155,7 +155,7 @@ const clone=e=>Object.assign({},e);module.exports=clone;
|
|
|
155
155
|
const{EPS:EPS}=require("../../maths/constants"),vec2=require("../../maths/vec2"),clone=require("./clone"),close=e=>{if(e.isClosed)return e;const t=clone(e);if(t.isClosed=!0,t.points.length>1){const e=t.points,n=e[0];let o=e[e.length-1];for(;vec2.distance(n,o)<EPS*EPS&&(e.pop(),1!==e.length);)o=e[e.length-1]}return t};module.exports=close;
|
|
156
156
|
|
|
157
157
|
},{"../../maths/constants":90,"../../maths/vec2":186,"./clone":51}],53:[function(require,module,exports){
|
|
158
|
-
const fromPoints=require("./fromPoints"),toPoints=require("./toPoints"),{equals:equals}=require("../../maths/vec2"),concat=(...
|
|
158
|
+
const fromPoints=require("./fromPoints"),toPoints=require("./toPoints"),{equals:equals}=require("../../maths/vec2"),concat=(...t)=>{let o=!1,e=[];return t.forEach((t,n)=>{const s=toPoints(t).slice();if(e.length>0&&s.length>0&&equals(s[0],e[e.length-1])&&s.shift(),s.length>0&&o)throw new Error(`Cannot concatenate to a closed path; check the ${n}th path`);o=t.isClosed,e=e.concat(s)}),fromPoints({closed:o},e)};module.exports=concat;
|
|
159
159
|
|
|
160
160
|
},{"../../maths/vec2":186,"./fromPoints":57,"./toPoints":62}],54:[function(require,module,exports){
|
|
161
161
|
const mat4=require("../../maths/mat4"),create=e=>(void 0===e&&(e=[]),{points:e,isClosed:!1,transforms:mat4.create()});module.exports=create;
|
|
@@ -1034,7 +1034,7 @@ const flatten=require("../../utils/flatten"),measureEpsilon=require("../../measu
|
|
|
1034
1034
|
module.exports={generalize:require("./generalize"),snap:require("./snap")};
|
|
1035
1035
|
|
|
1036
1036
|
},{"./generalize":344,"./snap":350}],346:[function(require,module,exports){
|
|
1037
|
-
const constants=require("../../maths/constants"),vec3=require("../../maths/vec3"),poly3=require("../../geometries/poly3"),assert=!1,getTag=e=>`${e}`,addSide=(e,t,n,
|
|
1037
|
+
const constants=require("../../maths/constants"),vec3=require("../../maths/vec3"),poly3=require("../../geometries/poly3"),assert=!1,getTag=e=>`${e}`,addSide=(e,t,s,n,r,c)=>{const o=getTag(n),g=getTag(r);const l=`${o}/${g}`,a=`${g}/${o}`;if(e.has(a))return deleteSide(e,t,s,r,n,null),null;const i={vertex0:n,vertex1:r,polygonindex:c};return e.has(l)?e.get(l).push(i):e.set(l,[i]),t.has(o)?t.get(o).push(l):t.set(o,[l]),s.has(g)?s.get(g).push(l):s.set(g,[l]),l},deleteSide=(e,t,s,n,r,c)=>{const o=getTag(n),g=getTag(r),l=`${o}/${g}`;let a=-1;const i=e.get(l);for(let e=0;e<i.length;e++){const t=i[e];let s=getTag(t.vertex0);if(s===o&&((s=getTag(t.vertex1))===g&&(null===c||t.polygonindex===c))){a=e;break}}i.splice(a,1),0===i.length&&e.delete(l),a=t.get(o).indexOf(l),t.get(o).splice(a,1),0===t.get(o).length&&t.delete(o),a=s.get(g).indexOf(l),s.get(g).splice(a,1),0===s.get(g).length&&s.delete(g)},insertTjunctions=e=>{const t=new Map;for(let s=0;s<e.length;s++){const n=e[s],r=n.vertices.length;if(r>=3){let e=n.vertices[0],c=getTag(e);for(let o=0;o<r;o++){let g=o+1;g===r&&(g=0);const l=n.vertices[g],a=getTag(l),i=`${c}/${a}`,v=`${a}/${c}`;if(t.has(v)){const e=t.get(v);e.splice(-1,1),0===e.length&&t.delete(v)}else{const n={vertex0:e,vertex1:l,polygonindex:s};t.has(i)?t.get(i).push(n):t.set(i,[n])}e=l,c=a}}else console.warn("warning: invalid polygon found during insertTjunctions")}if(t.size>0){const s=new Map,n=new Map,r=new Map;for(const[e,c]of t)r.set(e,!0),c.forEach(t=>{const r=getTag(t.vertex0),c=getTag(t.vertex1);s.has(r)?s.get(r).push(e):s.set(r,[e]),n.has(c)?n.get(c).push(e):n.set(c,[e])});const c=e.slice(0);for(;0!==t.size;){for(const e of t.keys())r.set(e,!0);let e=!1;for(;;){const o=Array.from(r.keys());if(0===o.length)break;const g=o[0];let l=!0;if(t.has(g)){const o=t.get(g);0;const a=o[0];for(let o=0;o<2;o++){const g=0===o?a.vertex0:a.vertex1,i=0===o?a.vertex1:a.vertex0,v=getTag(g),d=getTag(i);let h=[];0===o?n.has(v)&&(h=n.get(v)):s.has(v)&&(h=s.get(v));for(let a=0;a<h.length;a++){const v=h[a],f=t.get(v)[0],u=0===o?f.vertex0:f.vertex1,x=0===o?f.vertex1:f.vertex0,p=getTag(u);getTag(x);if(p===d){deleteSide(t,s,n,g,i,null),deleteSide(t,s,n,i,g,null),l=!1,o=2,e=!0;break}{const a=g,v=i,d=u,h=vec3.subtract(vec3.create(),d,a),x=vec3.dot(vec3.subtract(vec3.create(),v,a),h)/vec3.dot(h,h);if(x>0&&x<1){const g=vec3.scale(vec3.create(),h,x);if(vec3.add(g,g,a),vec3.squaredDistance(g,v)<constants.EPS*constants.EPS){const g=f.polygonindex,a=c[g],v=getTag(f.vertex1);let d=-1;for(let e=0;e<a.vertices.length;e++)if(getTag(a.vertices[e])===v){d=e;break}0;const h=a.vertices.slice(0);h.splice(d,0,i);const u=poly3.create(h);c[g]=u,deleteSide(t,s,n,f.vertex0,f.vertex1,g);const x=addSide(t,s,n,f.vertex0,i,g),p=addSide(t,s,n,i,f.vertex1,g);null!==x&&r.set(x,!0),null!==p&&r.set(p,!0),l=!1,o=2,e=!0;break}}}}}}l&&r.delete(g)}if(!e)break}e=c}return t.clear(),e};module.exports=insertTjunctions;
|
|
1038
1038
|
|
|
1039
1039
|
},{"../../geometries/poly3":75,"../../maths/constants":90,"../../maths/vec3":217}],347:[function(require,module,exports){
|
|
1040
1040
|
const aboutEqualNormals=require("../../maths/utils/aboutEqualNormals"),vec3=require("../../maths/vec3"),poly3=require("../../geometries/poly3"),createEdges=e=>{const n=poly3.toPoints(e),t=[];for(let e=0;e<n.length;e++){const l=(e+1)%n.length,r={v1:n[e],v2:n[l]};t.push(r)}for(let e=0;e<t.length;e++){const l=(e+1)%n.length;t[e].next=t[l],t[l].prev=t[e]}return t},insertEdge=(e,n)=>{const t=`${n.v1}:${n.v2}`;e.set(t,n)},deleteEdge=(e,n)=>{const t=`${n.v1}:${n.v2}`;e.delete(t)},findOppositeEdge=(e,n)=>{const t=`${n.v2}:${n.v1}`;return e.get(t)},calculateAnglesBetween=(e,n,t)=>{let l=e.prev.v1,r=e.prev.v2,o=n.next.v2;const v=calculateAngle(l,r,o,t);return l=n.prev.v1,r=n.prev.v2,o=e.next.v2,[v,calculateAngle(l,r,o,t)]},v1=vec3.create(),v2=vec3.create(),calculateAngle=(e,n,t,l)=>{const r=vec3.subtract(v1,n,e),o=vec3.subtract(v2,t,n);return vec3.cross(r,r,o),vec3.dot(r,l)},createPolygonAnd=e=>{let n;const t=[];for(;e.next;){const n=e.next;t.push(e.v1),e.v1=null,e.v2=null,e.next=null,e.prev=null,e=n}return t.length>0&&(n=poly3.create(t)),n},mergeCoplanarPolygons=e=>{if(e.length<2)return e;const n=e[0].plane,t=e.slice(),l=new Map;for(;t.length>0;){const e=t.shift(),r=createEdges(e);for(let e=0;e<r.length;e++){const t=r[e],o=findOppositeEdge(l,t);if(o){const e=calculateAnglesBetween(t,o,n);if(e[0]>=0&&e[1]>=0){const n=o.next,r=t.next;t.prev.next=o.next,t.next.prev=o.prev,o.prev.next=t.next,o.next.prev=t.prev,t.v1=null,t.v2=null,t.next=null,t.prev=null,deleteEdge(l,o),o.v1=null,o.v2=null,o.next=null,o.prev=null;const v=(e,n,t)=>{const l={v1:t.v1,v2:n.v2,next:n.next,prev:t.prev};t.prev.next=l,n.next.prev=l,deleteEdge(e,n),n.v1=null,n.v2=null,n.next=null,n.prev=null,deleteEdge(e,t),t.v1=null,t.v2=null,t.next=null,t.prev=null};0===e[0]&&v(l,n,n.prev),0===e[1]&&v(l,r,r.prev)}}else t.next&&insertEdge(l,t)}}const r=[];return l.forEach(e=>{const n=createPolygonAnd(e);n&&r.push(n)}),l.clear(),r},coplanar=(e,n)=>Math.abs(e[3]-n[3])<1.5e-7&&aboutEqualNormals(e,n),mergePolygons=(e,n)=>{const t=[];n.forEach(e=>{const n=t.find(n=>coplanar(n[0],poly3.plane(e)));if(n){n[1].push(e)}else t.push([poly3.plane(e),[e]])});let l=[];return t.forEach(e=>{const n=e[1],t=mergeCoplanarPolygons(n);l=l.concat(t)}),l};module.exports=mergePolygons;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jscad/modeling",
|
|
3
|
-
"version": "2.9.
|
|
3
|
+
"version": "2.9.6",
|
|
4
4
|
"description": "Constructive Solid Geometry (CSG) Library for JSCAD",
|
|
5
5
|
"homepage": "https://openjscad.xyz/",
|
|
6
6
|
"repository": "https://github.com/jscad/OpenJSCAD.org",
|
|
@@ -61,5 +61,5 @@
|
|
|
61
61
|
"nyc": "15.1.0",
|
|
62
62
|
"uglifyify": "5.0.2"
|
|
63
63
|
},
|
|
64
|
-
"gitHead": "
|
|
64
|
+
"gitHead": "9768af96e5da00cd113c00ddeb0f6046707819b1"
|
|
65
65
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
const
|
|
2
|
-
const
|
|
1
|
+
const concat = require('./concat')
|
|
2
|
+
const create = require('./create')
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* Append the given list of points to the end of the given geometry.
|
|
@@ -10,15 +10,6 @@ const toPoints = require('./toPoints')
|
|
|
10
10
|
* @example
|
|
11
11
|
* let newpath = appendPoints([[3, 4], [4, 5]], oldpath)
|
|
12
12
|
*/
|
|
13
|
-
const appendPoints = (points, geometry) =>
|
|
14
|
-
if (geometry.isClosed) {
|
|
15
|
-
throw new Error('cannot append points to a closed path')
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
let newpoints = toPoints(geometry)
|
|
19
|
-
newpoints = newpoints.concat(points)
|
|
20
|
-
|
|
21
|
-
return fromPoints({}, newpoints)
|
|
22
|
-
}
|
|
13
|
+
const appendPoints = (points, geometry) => concat(geometry, create(points))
|
|
23
14
|
|
|
24
15
|
module.exports = appendPoints
|
|
@@ -17,3 +17,19 @@ test('appendPoints: appending to a path produces a new path with expected points
|
|
|
17
17
|
t.not(p1, obs)
|
|
18
18
|
t.is(pts.length, 4)
|
|
19
19
|
})
|
|
20
|
+
|
|
21
|
+
test('appendPoints: appending empty points to a path produces a new path with expected points', (t) => {
|
|
22
|
+
const p1 = fromPoints({}, [[1, 1], [2, 2]])
|
|
23
|
+
const obs = appendPoints([], p1)
|
|
24
|
+
const pts = toPoints(obs)
|
|
25
|
+
t.not(p1, obs)
|
|
26
|
+
t.is(pts.length, 2)
|
|
27
|
+
})
|
|
28
|
+
|
|
29
|
+
test('appendPoints: appending same points to a path produces a new path with expected points', (t) => {
|
|
30
|
+
const p1 = fromPoints({}, [[1, 1], [2, 2]])
|
|
31
|
+
const obs = appendPoints([[2, 2], [3, 3]], p1)
|
|
32
|
+
const pts = toPoints(obs)
|
|
33
|
+
t.not(p1, obs)
|
|
34
|
+
t.is(pts.length, 3)
|
|
35
|
+
})
|
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
const fromPoints = require('./fromPoints')
|
|
2
2
|
const toPoints = require('./toPoints')
|
|
3
|
+
|
|
3
4
|
const { equals } = require('../../maths/vec2')
|
|
5
|
+
|
|
4
6
|
/**
|
|
5
7
|
* Concatenate the given paths.
|
|
8
|
+
*
|
|
6
9
|
* If both contain the same point at the junction, merge it into one.
|
|
7
10
|
* A concatenation of zero paths is an empty, open path.
|
|
8
11
|
* A concatenation of one closed path to a series of open paths produces a closed path.
|
|
@@ -17,16 +20,14 @@ const { equals } = require('../../maths/vec2')
|
|
|
17
20
|
const concat = (...paths) => {
|
|
18
21
|
// Only the last path can be closed, producing a closed path.
|
|
19
22
|
let isClosed = false
|
|
20
|
-
for (const path of paths) {
|
|
21
|
-
if (isClosed) {
|
|
22
|
-
throw new Error('Cannot concatenate to a closed path')
|
|
23
|
-
}
|
|
24
|
-
isClosed = path.isClosed
|
|
25
|
-
}
|
|
26
23
|
let newpoints = []
|
|
27
|
-
paths.forEach((path) => {
|
|
28
|
-
const tmp = toPoints(path)
|
|
24
|
+
paths.forEach((path, i) => {
|
|
25
|
+
const tmp = toPoints(path).slice()
|
|
29
26
|
if (newpoints.length > 0 && tmp.length > 0 && equals(tmp[0], newpoints[newpoints.length - 1])) tmp.shift()
|
|
27
|
+
if (tmp.length > 0 && isClosed) {
|
|
28
|
+
throw new Error(`Cannot concatenate to a closed path; check the ${i}th path`)
|
|
29
|
+
}
|
|
30
|
+
isClosed = path.isClosed
|
|
30
31
|
newpoints = newpoints.concat(tmp)
|
|
31
32
|
})
|
|
32
33
|
return fromPoints({ closed: isClosed }, newpoints)
|
|
@@ -10,10 +10,16 @@ test('concat: empty paths produces an empty open path', (t) => {
|
|
|
10
10
|
t.true(equals(concat(fromPoints({}, []), fromPoints({}, [])), fromPoints({ closed: false }, [])))
|
|
11
11
|
})
|
|
12
12
|
|
|
13
|
-
test('concat:
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
fromPoints({ closed: false }, [[
|
|
13
|
+
test('concat: many open paths produces a open path', (t) => {
|
|
14
|
+
const p1 = fromPoints({ closed: false }, [[0, 0]])
|
|
15
|
+
const p2 = fromPoints({ closed: false }, [[1, 1]])
|
|
16
|
+
const p3 = fromPoints({ closed: false }, [[1, 1], [3, 3]])
|
|
17
|
+
|
|
18
|
+
const result = concat(p1, p2, p3)
|
|
19
|
+
t.true(equals(result, fromPoints({}, [[0, 0], [1, 1], [3, 3]])))
|
|
20
|
+
t.is(p1.points.length, 1)
|
|
21
|
+
t.is(p2.points.length, 1)
|
|
22
|
+
t.is(p3.points.length, 2)
|
|
17
23
|
})
|
|
18
24
|
|
|
19
25
|
test('concat: An open path and a closed path produces a closed path', (t) => {
|
|
@@ -23,7 +29,7 @@ test('concat: An open path and a closed path produces a closed path', (t) => {
|
|
|
23
29
|
})
|
|
24
30
|
|
|
25
31
|
test('concat: A closed path and an open path throws an error', (t) => {
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
{ message: 'Cannot concatenate to a closed path' })
|
|
32
|
+
const p1 = fromPoints({ closed: true }, [[0, 0]])
|
|
33
|
+
const p2 = fromPoints({ closed: false }, [[1, 1]])
|
|
34
|
+
t.throws(() => concat(p1, p2), { message: 'Cannot concatenate to a closed path; check the 1th path' })
|
|
29
35
|
})
|
|
@@ -28,15 +28,15 @@ const addSide = (sidemap, vertextag2sidestart, vertextag2sideend, vertex0, verte
|
|
|
28
28
|
} else {
|
|
29
29
|
sidemap.get(newsidetag).push(newsideobj)
|
|
30
30
|
}
|
|
31
|
-
if (starttag
|
|
32
|
-
vertextag2sidestart
|
|
31
|
+
if (vertextag2sidestart.has(starttag)) {
|
|
32
|
+
vertextag2sidestart.get(starttag).push(newsidetag)
|
|
33
33
|
} else {
|
|
34
|
-
vertextag2sidestart
|
|
34
|
+
vertextag2sidestart.set(starttag, [newsidetag])
|
|
35
35
|
}
|
|
36
|
-
if (endtag
|
|
37
|
-
vertextag2sideend
|
|
36
|
+
if (vertextag2sideend.has(endtag)) {
|
|
37
|
+
vertextag2sideend.get(endtag).push(newsidetag)
|
|
38
38
|
} else {
|
|
39
|
-
vertextag2sideend
|
|
39
|
+
vertextag2sideend.set(endtag, [newsidetag])
|
|
40
40
|
}
|
|
41
41
|
return newsidetag
|
|
42
42
|
}
|
|
@@ -67,18 +67,18 @@ const deleteSide = (sidemap, vertextag2sidestart, vertextag2sideend, vertex0, ve
|
|
|
67
67
|
}
|
|
68
68
|
|
|
69
69
|
// adjust start and end lists
|
|
70
|
-
idx = vertextag2sidestart
|
|
70
|
+
idx = vertextag2sidestart.get(starttag).indexOf(sidetag)
|
|
71
71
|
if (assert && idx < 0) throw new Error('assert failed')
|
|
72
|
-
vertextag2sidestart
|
|
73
|
-
if (vertextag2sidestart
|
|
74
|
-
delete
|
|
72
|
+
vertextag2sidestart.get(starttag).splice(idx, 1)
|
|
73
|
+
if (vertextag2sidestart.get(starttag).length === 0) {
|
|
74
|
+
vertextag2sidestart.delete(starttag)
|
|
75
75
|
}
|
|
76
76
|
|
|
77
|
-
idx = vertextag2sideend
|
|
77
|
+
idx = vertextag2sideend.get(endtag).indexOf(sidetag)
|
|
78
78
|
if (assert && idx < 0) throw new Error('assert failed')
|
|
79
|
-
vertextag2sideend
|
|
80
|
-
if (vertextag2sideend
|
|
81
|
-
delete
|
|
79
|
+
vertextag2sideend.get(endtag).splice(idx, 1)
|
|
80
|
+
if (vertextag2sideend.get(endtag).length === 0) {
|
|
81
|
+
vertextag2sideend.delete(endtag)
|
|
82
82
|
}
|
|
83
83
|
}
|
|
84
84
|
|
|
@@ -158,25 +158,24 @@ const insertTjunctions = (polygons) => {
|
|
|
158
158
|
}
|
|
159
159
|
|
|
160
160
|
if (sidemap.size > 0) {
|
|
161
|
-
// console.log('insertTjunctions',sidemap.size)
|
|
162
161
|
// STEP 2 : create a list of starting sides and ending sides
|
|
163
|
-
const vertextag2sidestart =
|
|
164
|
-
const vertextag2sideend =
|
|
165
|
-
const
|
|
162
|
+
const vertextag2sidestart = new Map()
|
|
163
|
+
const vertextag2sideend = new Map()
|
|
164
|
+
const sidesToCheck = new Map()
|
|
166
165
|
for (const [sidetag, sideobjs] of sidemap) {
|
|
167
|
-
|
|
166
|
+
sidesToCheck.set(sidetag, true)
|
|
168
167
|
sideobjs.forEach((sideobj) => {
|
|
169
168
|
const starttag = getTag(sideobj.vertex0)
|
|
170
169
|
const endtag = getTag(sideobj.vertex1)
|
|
171
|
-
if (starttag
|
|
172
|
-
vertextag2sidestart
|
|
170
|
+
if (vertextag2sidestart.has(starttag)) {
|
|
171
|
+
vertextag2sidestart.get(starttag).push(sidetag)
|
|
173
172
|
} else {
|
|
174
|
-
vertextag2sidestart
|
|
173
|
+
vertextag2sidestart.set(starttag, [sidetag])
|
|
175
174
|
}
|
|
176
|
-
if (endtag
|
|
177
|
-
vertextag2sideend
|
|
175
|
+
if (vertextag2sideend.has(endtag)) {
|
|
176
|
+
vertextag2sideend.get(endtag).push(sidetag)
|
|
178
177
|
} else {
|
|
179
|
-
vertextag2sideend
|
|
178
|
+
vertextag2sideend.set(endtag, [sidetag])
|
|
180
179
|
}
|
|
181
180
|
})
|
|
182
181
|
}
|
|
@@ -187,13 +186,13 @@ const insertTjunctions = (polygons) => {
|
|
|
187
186
|
if (sidemap.size === 0) break
|
|
188
187
|
|
|
189
188
|
for (const sidetag of sidemap.keys()) {
|
|
190
|
-
|
|
189
|
+
sidesToCheck.set(sidetag, true)
|
|
191
190
|
}
|
|
192
191
|
|
|
193
192
|
let donesomething = false
|
|
194
193
|
while (true) {
|
|
195
|
-
const sidetags =
|
|
196
|
-
if (sidetags.length === 0) break //
|
|
194
|
+
const sidetags = Array.from(sidesToCheck.keys())
|
|
195
|
+
if (sidetags.length === 0) break // sidesToCheck is empty, we're done!
|
|
197
196
|
const sidetagtocheck = sidetags[0]
|
|
198
197
|
let donewithside = true
|
|
199
198
|
if (sidemap.has(sidetagtocheck)) {
|
|
@@ -207,12 +206,12 @@ const insertTjunctions = (polygons) => {
|
|
|
207
206
|
const endvertextag = getTag(endvertex)
|
|
208
207
|
let matchingsides = []
|
|
209
208
|
if (directionindex === 0) {
|
|
210
|
-
if (startvertextag
|
|
211
|
-
matchingsides = vertextag2sideend
|
|
209
|
+
if (vertextag2sideend.has(startvertextag)) {
|
|
210
|
+
matchingsides = vertextag2sideend.get(startvertextag)
|
|
212
211
|
}
|
|
213
212
|
} else {
|
|
214
|
-
if (startvertextag
|
|
215
|
-
matchingsides = vertextag2sidestart
|
|
213
|
+
if (vertextag2sidestart.has(startvertextag)) {
|
|
214
|
+
matchingsides = vertextag2sidestart.get(startvertextag)
|
|
216
215
|
}
|
|
217
216
|
}
|
|
218
217
|
for (let matchingsideindex = 0; matchingsideindex < matchingsides.length; matchingsideindex++) {
|
|
@@ -267,8 +266,8 @@ const insertTjunctions = (polygons) => {
|
|
|
267
266
|
deleteSide(sidemap, vertextag2sidestart, vertextag2sideend, matchingside.vertex0, matchingside.vertex1, polygonindex)
|
|
268
267
|
const newsidetag1 = addSide(sidemap, vertextag2sidestart, vertextag2sideend, matchingside.vertex0, endvertex, polygonindex)
|
|
269
268
|
const newsidetag2 = addSide(sidemap, vertextag2sidestart, vertextag2sideend, endvertex, matchingside.vertex1, polygonindex)
|
|
270
|
-
if (newsidetag1 !== null)
|
|
271
|
-
if (newsidetag2 !== null)
|
|
269
|
+
if (newsidetag1 !== null) sidesToCheck.set(newsidetag1, true)
|
|
270
|
+
if (newsidetag2 !== null) sidesToCheck.set(newsidetag2, true)
|
|
272
271
|
donewithside = false
|
|
273
272
|
directionindex = 2 // skip reverse direction check
|
|
274
273
|
donesomething = true
|
|
@@ -280,7 +279,7 @@ const insertTjunctions = (polygons) => {
|
|
|
280
279
|
} // for directionindex
|
|
281
280
|
} // if(sidetagtocheck in sidemap)
|
|
282
281
|
if (donewithside) {
|
|
283
|
-
delete
|
|
282
|
+
sidesToCheck.delete(sidetagtocheck)
|
|
284
283
|
}
|
|
285
284
|
}
|
|
286
285
|
if (!donesomething) break
|