jsketcher/web/app/cad/sketch/sketchReader.js
2020-07-18 22:18:03 -07:00

241 lines
No EOL
6.6 KiB
JavaScript

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;
}
}