import * as sm from './sketchModel' import {Graph} from '../../math/graph' import * as math from '../../../../modules/math/commons' import {HashTable} from '../../utils/hashmap' import Joints from '../../../../modules/gems/joints'; import sketchObjectGlobalId from './sketchObjectGlobalId'; import VectorFactory from '../../../../modules/math/vectorFactory'; class SketchGeom { constructor() { this.connections = []; this.loops = []; this.constructionSegments = []; this._contours = null; } fetchContours() { if (this._contours === null) { this._contours = FetchContours(this); } return this._contours; } findById(id) { function _find() { for (let arr of arguments) { for (let segment of arr) { if (segment.id === id) { return segment; } } } return null; } return _find(this.connections, this.loops, this.constructionSegments); } getAllObjects() { return [...this.connections, ...this.loops, ...this.constructionSegments]; } } export function ReadSketch(sketch, sketchId, readConstructionSegments) { const getID = obj => sketchObjectGlobalId(sketchId, obj.id); const out = new SketchGeom(); let coiJoints = new Joints(); if (sketch.constraints !== undefined) { for (let i = 0; i < sketch.constraints.length; ++i) { let c = sketch.constraints[i]; let name = c[0]; let ps = c[1]; if (name === 'coi') { coiJoints.connect(ps[0], ps[1]); } } } let vectorFactory = new VectorFactory(); let pointsById = new Map(); function ReadSketchPoint(pt) { return vectorFactory.create(pt.x, pt.y, 0); } if (sketch.version !== 3) { return out; } for (let obj of sketch.objects) { let isConstructionObject = obj.role === 'construction'; if (isConstructionObject && !readConstructionSegments) continue; // if (isConstructionObject && obj._class !== 'TCAD.TWO.Segment') continue; const data = obj.data; if (obj.type === 'Segment') { const segA = ReadSketchPoint(data.a); const segB = ReadSketchPoint(data.b); const pushOn = isConstructionObject ? out.constructionSegments : out.connections; pushOn.push(new sm.Segment(getID(obj), segA, segB)); } else if (obj.type === 'Arc') { const arcA = ReadSketchPoint(data.a); const arcB = ReadSketchPoint(data.b); const arcCenter = ReadSketchPoint(data.c); out.connections.push(new sm.Arc(getID(obj), arcA, arcB, arcCenter)); } else if (obj.type === 'EllipticalArc') { if (data.ep1) { continue; } const c = ReadSketchPoint(data.c); const rx = readSketchFloat(data.rx); const ry = readSketchFloat(data.ry); const rot = readSketchFloat(data.rot); const a = ReadSketchPoint(data.a); const b = ReadSketchPoint(data.b); out.loops.push(new sm.EllipticalArc(getID(obj), c, rx, ry, rot, a, b)); } else if (obj.type === 'BezierCurve') { const a = ReadSketchPoint(data.cp1); const b = ReadSketchPoint(data.cp4); const cp1 = ReadSketchPoint(data.cp2); const cp2 = ReadSketchPoint(data.cp3); out.connections.push(new sm.BezierCurve(getID(obj), a, b, cp1, cp2)); } else if (obj.type === 'Circle') { const circleCenter = ReadSketchPoint(data.c); out.loops.push(new sm.Circle(getID(obj), circleCenter, readSketchFloat(data.r))); } else if (obj.type === 'Ellipse') { if (data.ep1) { continue; } const c = ReadSketchPoint(data.c); const rx = readSketchFloat(data.rx); const ry = readSketchFloat(data.ry); const rot = readSketchFloat(data.rot); out.loops.push(new sm.Ellipse(getID(obj), c, rx, ry, rot)); } } return out; } export function FetchContours(geom) { const contours = findClosedContours(geom.connections); for (let loop of geom.loops) { const contour = new sm.Contour(); contour.add(loop); contours.push(contour); } for (let contour of contours) { if (!contour.isCCW()) { contour.reverse(); } } return contours; } function findClosedContours(segments) { const result = []; findClosedContoursFromPairedCurves(segments, result); findClosedContoursFromGraph(segments, result); return result; } function findClosedContoursFromPairedCurves(segments, result) { for (let i = 0; i < segments.length; i++) { const s1 = segments[i]; for (let j = i; j < segments.length; j++) { if (i === j) continue; const s2 = segments[j]; if (s1.isCurve || s2.isCurve) { let paired = false; if (math.strictEqual2D(s1.a, s2.a) && math.strictEqual2D(s1.b, s2.b)) { paired = true; s2.invert(); } else if (math.strictEqual2D(s1.a, s2.b) && math.strictEqual2D(s1.b, s2.a)) { paired = true; } if (paired) { const contour = new sm.Contour(); contour.add(s1); contour.add(s2); result.push(contour); } } } } } function findClosedContoursFromGraph(segments, result) { const dict = HashTable.forVector2d(); const edges = HashTable.forDoubleArray(); function edgeKey(a, b) { return [a.x, a.y, b.x, b.y]; } const points = []; function memDir(a, b) { let dirs = dict.get(a); if (dirs === null) { dirs = []; dict.put(a, dirs); points.push(a); } dirs.push(b); } for (let seg of segments) { const a = seg.a; const b = seg.b; memDir(a, b); memDir(b, a); edges.put(edgeKey(a, b), seg); } const graph = { connections : function(e) { const dirs = dict.get(e); return dirs === null ? [] : dirs; }, at : function(index) { return points[index]; }, size : function() { return points.length; } }; const loops = Graph.findAllLoops(graph, dict.hashCodeF, dict.equalsF); for (let loop of loops) { const contour = new sm.Contour(); for (let pi = 0; pi < loop.length; ++pi) { const point = loop[pi]; const next = loop[(pi + 1) % loop.length]; let edge = edges.get(edgeKey(point, next)); if (edge === null) { edge = edges.get(edgeKey(next, point)); edge.invert(); } contour.add(edge); } result.push(contour); } } const READ_AS_IS = v => v; const READ_AS_INT = v => Math.round(v); export let readSketchFloat = READ_AS_IS; export function setSketchPrecision(precision) { if (precision === undefined) { readSketchFloat = READ_AS_IS; } else if (precision === 0) { readSketchFloat = READ_AS_INT; } else { const factor = Math.pow(10, precision); readSketchFloat = v => Math.round(v * factor) / factor; } }