UNPKG

@kylebarron/snap-to-tin

Version:

Snap vector features to the faces of a triangulated irregular network (TIN).

2 lines (1 loc) 6.57 kB
!function(t,n){"object"==typeof exports&&"undefined"!=typeof module?module.exports=n(require("lineclip"),require("flatbush"),require("lodash.orderby")):"function"==typeof define&&define.amd?define(["lineclip","flatbush","lodash.orderby"],n):(t=t||self)["snap-features-to-mesh"]=n(t.lineclip,t.Flatbush,t.orderBy)}(this,(function(t,n,e){"use strict";function o(t,n){for(const e of a(t)){const t=e[0],o=e[1];if(!s(t,o,n))continue;const i=r(t,n)/r(t,o),u=t[2]+i*(o[2]-t[2]);return[n[0],n[1],u]}return null}function s(t,n,e){return function(t,n,e=1e-10){return Math.abs(t-n)<e}(r(t,e)+r(n,e)-r(t,n),0)}function r(t,n){const e=n[0]-t[0],o=n[1]-t[1];return Math.sqrt(Math.pow(e,2)+Math.pow(o,2))}function i(t,n,e,o){const s=(n[0]-t[0])*(o[1]-e[1])-(o[0]-e[0])*(n[1]-t[1]);if(0===s)return null;const r=((o[1]-e[1])*(o[0]-t[0])+(e[0]-o[0])*(o[1]-t[1]))/s,i=((t[1]-n[1])*(o[0]-t[0])+(n[0]-t[0])*(o[1]-t[1]))/s;return 0<=r&&r<=1&&0<=i&&i<=1?[t[0]+r*(n[0]-t[0]),t[1]+r*(n[1]-t[1])]:null}function u(t,n){const e=[];for(const o of a(n)){const n=i(t[0],t[1],o[0],o[1]);n&&e.push(n)}return e}function*a(t){for(let n=0;n<3;n++){let e=[];0===n?(e.push(c(0,t)),e.push(c(1,t))):1===n?(e.push(c(1,t)),e.push(c(2,t))):2===n&&(e.push(c(2,t)),e.push(c(0,t))),yield e}}function c(t,n){return n.subarray(3*t,3*(t+1))}function h(t){if(9!==t.length)throw new Error(`Incorrect length of triangle: ${t.length}`);const n=Math.min(t[0],t[3],t[6]),e=Math.max(t[0],t[3],t[6]);return[n,Math.min(t[1],t[4],t[7]),e,Math.max(t[1],t[4],t[7])]}function l(t,n){const e=n.subarray(0,3),o=n.subarray(3,6),s=n.subarray(6,9),r=.5*(-o[1]*s[0]+e[1]*(-o[0]+s[0])+e[0]*(o[1]-s[1])+o[0]*s[1]),i=1/(2*r)*(e[1]*s[0]-e[0]*s[1]+(s[1]-e[1])*t[0]+(e[0]-s[0])*t[1]),u=1/(2*r)*(e[0]*o[1]-e[1]*o[0]+(e[1]-o[1])*t[0]+(o[0]-e[0])*t[1]);return[1-i-u,i,u]}function f(t,e){const o=function(t,n){const e=new Float32Array(3*t.length);for(let o=0;o<t.length;o+=3){const s=t[o],r=t[o+1],i=t[o+2],u=n.subarray(3*s,3*(s+1)),a=n.subarray(3*r,3*(r+1)),c=n.subarray(3*i,3*(i+1));e.set(u,3*o),e.set(a,3*(o+1)),e.set(c,3*(o+2))}return e}(t,e),s=new n(o.length/9,16,Float32Array);for(let t=0;t<o.length/9;t++){const n=o.subarray(9*t,9*(t+1)),[e,r,i,u]=h(n);s.add(e,r,i,u)}return s.finish(),{index:s,triangles:o}}function d(t,n,e=.01){const o=function(t,n){const[e,o]=t,s=[];for(let t=0;t<n;t++){const r=e[0]+t/n*(o[0]-e[0]),i=e[1]+t/n*(o[1]-e[1]),u=e[0]+(t+1)/n*(o[0]-e[0]),a=e[1]+(t+1)/n*(o[1]-e[1]);s.push([[r,i],[u,a]])}return s}(t,function(t,n,e=.01){if(!n)return 1;const[o,s]=t[0],[r,i]=t[1],u=(r-o)*(i-s)/n;return Math.max(1,Math.ceil(u/e))}(t,function(t){let n;t.minX!==1/0&&t.minY!==1/0&&t.maxX!==-1/0&&t.maxY!==-1/0&&(n=(t.maxX-t.minX)*(t.maxY-t.minY));return n}(n),e)),s=new Set;for(const t of o){const[e,o]=t[0],[r,i]=t[1];n.search(e,o,r,i).forEach(t=>s.add(t))}return Array.from(s)}function p(t,n,e){const[o,s]=t.slice(0,2),r=n.search(o,s,o,s).map(t=>e.subarray(9*t,9*(t+1))).filter(n=>{if(function(t,n){const[e,o,s]=l(t,n);return e>=0&&o>=0&&s>=0}(t,n))return n});if(0===r.length)return null;const i=r[0];return function(t,n){const e=n[2],o=n[5],s=n[8],r=l(t,n);if(r[0]<0||1<r[0]||r[1]<0||1<r[1]||r[2]<0||1<r[2])return null;const i=r[0]*e+r[1]*o+r[2]*s;return[t[0],t[1],i]}(t,i)}function y(t,n,e){const o=t.length,s=[];for(let r=0;r<o-1;r++){const o=t[r],i=t[r+1],u=p(o,n,e);u&&s.push(u);const a=g([o,i],n,e);if(a)for(const t of a)s.push(t)}const r=p(t[t.length-1],n,e);return r&&s.push(r),s}function g(t,n,s){const[r,i]=t;if(r[0]===i[0]&&r[1]===i[1])return null;const a=d(t,n);let c=new Float32Array(2*a.length*3),h=0;const l=new Set;for(const n of a){const e=s.subarray(9*n,9*(n+1)),r=u(t,e);if(r&&0!==r.length)for(const t of r){if(l.has(t[0]))continue;l.add(t[0]);const n=o(e,t);n&&(c.set(n,3*h),h++)}}c=c.subarray(0,3*h);const f=[];for(let t=0;t<c.length/3;t++)f.push(c.subarray(3*t,3*(t+1)));const p=i[0]-r[0],y=i[1]-r[1];let g;if(p>0)g=e(f,t=>t[0],"asc");else if(p<0)g=e(f,t=>t[0],"desc");else if(y>0)g=e(f,t=>t[1],"asc");else{if(!(y<0))throw new Error("start and end point same???");g=e(f,t=>t[1],"desc")}return g}t=t&&Object.prototype.hasOwnProperty.call(t,"default")?t.default:t,n=n&&Object.prototype.hasOwnProperty.call(n,"default")?n.default:n,e=e&&Object.prototype.hasOwnProperty.call(e,"default")?e.default:e;return class{constructor(n){this.snapFeatures=t=>{const{features:n}=t,e=[];for(const t of n){const n=t.geometry.type;if("Point"===n){const n=t.geometry.coordinates,o=this._handlePoint(n);if(!o)continue;t.geometry.coordinates=o,e.push(t)}else if("MultiPoint"===n){const n=[];for(const e of t.geometry.coordinates){const t=this._handlePoint(e);t&&n.push(t)}t.geometry.coordinates=n,e.push(t)}else if("LineString"===n){const n=this._handleLine(t.geometry.coordinates);if(!n)continue;1===n.length?t.geometry.coordinates=n[0]:(t.geometry.type="MultiLineString",t.geometry.coordinates=n),e.push(t)}else if("MultiLineString"===n){const n=[];for(const e of t.geometry.coordinates){const t=this._handleLine(e);t&&(1===t.length?n.push(t[0]):n.push.apply(t))}t.geometry.coordinates=n,e.push(t)}}return e},this._handlePoint=t=>{if(!this.bounds||4!==this.bounds.length||!(t[0]<this.bounds[0]||t[0]>this.bounds[2]||t[1]<this.bounds[1]||t[1]>this.bounds[3]))return p(t,this.index,this.triangles)},this._handleLine=n=>{let e=[n];if(this.bounds&&4===this.bounds.length&&(e=t(n,this.bounds),0===e.length))return;const o=[];for(const t of e)o.push(y(t,this.index,this.triangles));return o},this.snapPoints=t=>{const{positions:n,coordLength:e=2,featureIds:o}=t,s=new Float32Array(n.length/e*3),r=new Uint32Array(o&&o.length||0);let i=0;for(let t=0;t<n.length/e;t++){const u=n.subarray(t*e,(t+1)*e),a=this._handlePoint(u);a&&(s.set(a,3*i),o&&(r[i]=o[t]),i++)}return{positions:s.subarray(0,3*i),featureIds:o}},this.snapLines=t=>{const{positions:n,pathIndices:e,coordLength:o=2,featureIds:s}=t,r=[],i=[],u=e||[0,n.length];for(let t=0;t<u.length-1;t++){const e=u[t],a=u[t+1],c=[];for(let t=e;t<a;t++)c.push(n.subarray(t*o,(t+1)*o));const h=this._handleLine(c);if(!h)continue;const l=s&&s[t];for(const t of h)r.push(t),l&&i.push(l)}const a=[],c=[],h=[];let l=0;for(let t=0;t<r.length;t++){const n=r[t];if(a.push.apply(n),c.push(l),s)for(let e=0;e<n.length;e++)h.push(i[t]);l+=n.length}return c.push(a.length),{positions:Float32Array.from(a),pathIndices:Uint32Array.from(c),featureIds:Uint32Array.from(h)}};const{indices:e,positions:o,bounds:s=[-1/0,-1/0,1/0,1/0]}=n,{index:r,triangles:i}=f(e,o);this.index=r,this.triangles=i,this.bounds=[Math.max(s[0],r.minX),Math.max(s[1],r.minY),Math.min(s[2],r.maxX),Math.min(s[3],r.maxY)]}}}));