jsketcher/web/app/cad/sketch/sketchReader.ts
2022-11-26 22:31:43 -08:00

263 lines
No EOL
7.1 KiB
TypeScript

import * as sm from './sketchModel'
import {Graph} from '../../utils/graph'
import {HashTable} from '../../utils/hashmap'
import Joints from 'gems/joints';
import sketchObjectGlobalId from './sketchObjectGlobalId';
import VectorFactory from 'math/vectorFactory';
import {strictEqual2D} from "math/equality";
import {Contour, Segment, SketchPrimitive} from "./sketchModel";
import Vector from "math/vector";
export class SketchGeom {
connections: SketchPrimitive[];
loops: SketchPrimitive[];
_contours: Contour[];
points: any[];
constructor() {
this.connections = [];
this.loops = [];
this._contours = null;
this.points = [];
}
fetchContours() {
if (this._contours === null) {
this._contours = FetchContours(this);
}
return this._contours;
}
get contours(): Contour[] {
return this.fetchContours();
}
getAllObjects() {
return [...this.connections, ...this.loops];
}
}
export function ReadSketch(sketch, sketchId) {
const getID = obj => sketchObjectGlobalId(sketchId, obj.id);
const out = new SketchGeom();
const coiJoints = new Joints();
if (sketch.constraints !== undefined) {
for (let i = 0; i < sketch.constraints.length; ++i) {
const c = sketch.constraints[i];
const name = c[0];
const ps = c[1];
if (name === 'coi') {
coiJoints.connect(ps[0], ps[1]);
}
}
}
const vectorFactory = new VectorFactory();
const pointsById = new Map();
function ReadSketchPoint(pt): Vector {
return vectorFactory.create(pt.x, pt.y, 0);
}
if (sketch.version !== 3) {
return out;
}
for (const obj of sketch.objects) {
const isConstructionObject = obj.role === 'construction';
// if (isConstructionObject && obj._class !== 'TCAD.TWO.Segment') continue;
const data = obj.data;
let createdObj: SketchPrimitive;
if (obj.type === 'Segment') {
const segA = ReadSketchPoint(data.a);
const segB = ReadSketchPoint(data.b);
createdObj = new sm.Segment(getID(obj), segA, segB);
out.connections.push(createdObj);
} else if (obj.type === 'Arc') {
const arcA = ReadSketchPoint(data.a);
const arcB = ReadSketchPoint(data.b);
const arcCenter = ReadSketchPoint(data.c);
createdObj = new sm.Arc(getID(obj), arcA, arcB, arcCenter);
out.connections.push(createdObj);
} 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);
createdObj = new sm.EllipticalArc(getID(obj), c, rx, ry, rot, a, b);
out.loops.push(createdObj);
} 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);
createdObj = new sm.BezierCurve(getID(obj), a, b, cp1, cp2);
out.connections.push(createdObj);
} else if (obj.type === 'Circle') {
const circleCenter = ReadSketchPoint(data.c);
createdObj = new sm.Circle(getID(obj), circleCenter, readSketchFloat(data.r));
out.loops.push(createdObj);
} 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);
createdObj = new sm.Ellipse(getID(obj), c, rx, ry, rot);
out.loops.push(createdObj);
} else if (obj.type === 'Point') {
if (data.ep1) {
continue;
}
ReadSketchPoint(data);
const x = readSketchFloat(data.x);
const y = readSketchFloat(data.y);
const z = 0;
//out.points.push(ReadSketchPoint(data));
createdObj = {
id:getID(obj),
point:{x,y,z}
} as any;
out.points.push(createdObj);
}
createdObj.construction = isConstructionObject;
}
return out;
}
export function FetchContours(geom): Contour[] {
const contours = findClosedContours(geom.connections.filter(c => !c.construction));
for (const loop of geom.loops) {
if (loop.construction) {
continue;
}
const contour = new sm.Contour();
contour.add(loop);
contours.push(contour);
}
for (const 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 (strictEqual2D(s1.a, s2.a) && strictEqual2D(s1.b, s2.b)) {
paired = true;
s2.invert();
} else if (strictEqual2D(s1.a, s2.b) && 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 (const 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 (const 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;
}
}