UNPKG

rabbit-ear

Version:
92 lines (88 loc) 3.58 kB
/* Rabbit Ear 0.9.4 alpha 2024-04-20 (c) Kraft, GNU GPLv3 License */ import { EPSILON } from '../../math/constant.js'; import { epsilonEqual } from '../../math/compare.js'; import { add2, scale2, resize2 } from '../../math/vector.js'; import { clusterSortedGeneric } from '../../general/cluster.js'; import { removeDuplicateVertices } from '../vertices/duplicate.js'; import { removeCircularEdges } from '../edges/circular.js'; import { invertArrayToFlatMap, mergeNextmaps, mergeFlatNextmaps } from '../maps.js'; import { edgeToLine2 } from '../edges/lines.js'; import { makeVerticesEdgesUnsorted } from '../make/verticesEdges.js'; import { intersectAllEdges } from './intersectAllEdges.js'; import '../../fold/spec.js'; const planarizeOverlaps = ( { vertices_coords, vertices_edges, edges_vertices, edges_assignment, edges_foldAngle }, epsilon = EPSILON, ) => { if (!vertices_edges) { vertices_edges = makeVerticesEdgesUnsorted({ edges_vertices }); } const edgesParams = edges_vertices.map(() => []); const intersections = intersectAllEdges({ vertices_coords, vertices_edges, edges_vertices, }, epsilon); intersections .filter(({ a }) => !epsilonEqual(a, 0) && !epsilonEqual(a, 1)) .forEach(({ i, a }) => edgesParams[i].push(a)); intersections .filter(({ b }) => !epsilonEqual(b, 0) && !epsilonEqual(b, 1)) .forEach(({ j, b }) => edgesParams[j].push(b)); edgesParams.forEach(points => points.sort((a, b) => a - b)); const edgesPointClusters = edgesParams .map(points => clusterSortedGeneric(points, epsilonEqual)); const average = (numbers) => (numbers.length ? numbers.reduce((a, b) => a + b, 0) / numbers.length : 0); const edgesSplitParams = edgesPointClusters .map((clusters, e) => clusters .map(cluster => cluster.map(i => edgesParams[e][i])) .map(average)); let newEdgeIndex = 0; const edgeNextmapPlanarized = edgesSplitParams .map(params => Array.from(Array(params.length + 1)).map(() => newEdgeIndex++)); const edgeBackmapPlanarized = invertArrayToFlatMap(edgeNextmapPlanarized); let newVertexIndex = vertices_coords.length; const edges_verticesNew = edgesSplitParams .map(params => params.map(() => newVertexIndex++)) .map((verts, e) => [ edges_vertices[e][0], ...verts, edges_vertices[e][1], ]) .flatMap(vertices => Array.from(Array(vertices.length - 1)) .map((_, i) => [vertices[i], vertices[i + 1]])) .map(([a, b]) => [a, b]); const additionalVertices_coords = edgesSplitParams.flatMap((params, edge) => { if (!params.length) { return []; } const line = edgeToLine2({ vertices_coords, edges_vertices }, edge); return params.map(t => add2(line.origin, scale2(line.vector, t))); }); const vertices_coordsNew = vertices_coords .concat(additionalVertices_coords) .map(resize2); const result = { vertices_coords: vertices_coordsNew, edges_vertices: edges_verticesNew, }; if (edges_assignment) { result.edges_assignment = edgeBackmapPlanarized .map(e => edges_assignment[e]); } if (edges_foldAngle) { result.edges_foldAngle = edgeBackmapPlanarized .map(e => edges_foldAngle[e]); } const startNextmap = vertices_coords.map((_, i) => i); const { map: verticesMapDuplicate } = removeDuplicateVertices(result, epsilon); const { map: edgeMapCircular } = removeCircularEdges(result); const edgesMap = mergeNextmaps(edgeNextmapPlanarized, edgeMapCircular); const verticesMap = mergeFlatNextmaps(startNextmap, verticesMapDuplicate); return { result, changes: { vertices: { map: verticesMap }, edges: { map: edgesMap }, } }; }; export { planarizeOverlaps };