mirror of
https://github.com/xibyte/jsketcher
synced 2025-12-06 08:25:19 +01:00
feat: add support for dxf blocks (#200)
This commit is contained in:
parent
563ff9a166
commit
322d47f802
2 changed files with 137 additions and 33 deletions
|
|
@ -139,7 +139,7 @@
|
|||
"webpack-dev-server": "^4.11.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"@dxfjs/parser": "^0.0.3",
|
||||
"@dxfjs/parser": "^0.2.0",
|
||||
"@tarikjabiri/dxf": "^2.6.2",
|
||||
"@types/three": "^0.146.0",
|
||||
"browser-xml2js": "^0.4.19",
|
||||
|
|
|
|||
|
|
@ -1,8 +1,21 @@
|
|||
import { ArcEntity, CircleEntity, DxfGlobalObject, EllipseEntity, LineEntity, LWPolylineEntity, Parser, PointEntity } from '@dxfjs/parser';
|
||||
import {
|
||||
ArcEntity,
|
||||
Block,
|
||||
CircleEntity,
|
||||
DxfGlobalObject,
|
||||
EllipseEntity,
|
||||
InsertEntity,
|
||||
LineEntity,
|
||||
LWPolylineEntity,
|
||||
Parser,
|
||||
PointEntity,
|
||||
PolylineEntity,
|
||||
SplineEntity
|
||||
} from "@dxfjs/parser";
|
||||
import { Colors, DLine, DxfWriter, point3d, SplineArgs_t, SplineFlags, Units, vec3_t } from '@tarikjabiri/dxf';
|
||||
import { SketchFormat_V3 } from './io';
|
||||
import { Arc, SketchArcSerializationData } from './shapes/arc';
|
||||
import { BezierCurve } from './shapes/bezier-curve';
|
||||
import { BezierCurve } from "./shapes/bezier-curve";
|
||||
import { Circle } from './shapes/circle';
|
||||
import { AngleBetweenDimension, DiameterDimension, HDimension, LinearDimension, VDimension } from './shapes/dim';
|
||||
import { Ellipse } from './shapes/ellipse';
|
||||
|
|
@ -29,6 +42,12 @@ interface SketchEllipseSerializationData extends SketchObjectSerializationData {
|
|||
rot: number;
|
||||
}
|
||||
|
||||
interface ITransform {
|
||||
translation: IPoint;
|
||||
rotation: number;
|
||||
origin: IPoint;
|
||||
}
|
||||
|
||||
const {PI, cos, sin, atan2} = Math
|
||||
|
||||
export function deg(angle: number): number {
|
||||
|
|
@ -52,6 +71,27 @@ function angle(fp: IPoint, sp: IPoint) {
|
|||
return angle
|
||||
}
|
||||
|
||||
function translate(p: IPoint, t: IPoint): IPoint {
|
||||
return {
|
||||
x: p.x + t.x,
|
||||
y: p.y + t.y,
|
||||
}
|
||||
}
|
||||
|
||||
function rotatePoint(p: IPoint, t: ITransform): IPoint {
|
||||
const { cos, sin } = Math;
|
||||
const ox = p.x - t.origin.x;
|
||||
const oy = p.y - t.origin.y;
|
||||
return {
|
||||
x: t.origin.x + (ox * cos(t.rotation) - oy * sin(t.rotation)),
|
||||
y: t.origin.y + (ox * sin(t.rotation) + oy * cos(t.rotation))
|
||||
}
|
||||
}
|
||||
|
||||
function applyTransformPoint(p: IPoint, t: ITransform) {
|
||||
return rotatePoint(translate(p, t.translation), t);
|
||||
}
|
||||
|
||||
export class DxfWriterAdapter {
|
||||
writer: DxfWriter;
|
||||
|
||||
|
|
@ -225,26 +265,87 @@ export class DxfParserAdapter {
|
|||
}
|
||||
}
|
||||
|
||||
private _createSketchFormat(dxfObject: DxfGlobalObject): SketchFormat_V3 {
|
||||
private _createSketchFormat(obj: DxfGlobalObject): SketchFormat_V3 {
|
||||
DxfParserAdapter._seed = 0;
|
||||
const sketch: SketchFormat_V3 = {
|
||||
version: 3, objects: [], dimensions: [], labels: [],
|
||||
stages: [], constants: null, metadata: {}
|
||||
};
|
||||
const transform: ITransform = {
|
||||
translation: { x: 0, y: 0 },
|
||||
rotation: 0,
|
||||
origin: { x: 0, y: 0 }
|
||||
}
|
||||
|
||||
const {arcs, circles, ellipses, lines, points, lwPolylines} = dxfObject.entities
|
||||
|
||||
arcs.forEach(a => sketch.objects.push(this._arc(a)));
|
||||
circles.forEach(c => sketch.objects.push(this._circle(c)));
|
||||
ellipses.forEach(e => sketch.objects.push(this._ellipse(e)));
|
||||
lines.forEach(l => sketch.objects.push(this._segment(l)));
|
||||
points.forEach(p => sketch.objects.push(this._point(p)));
|
||||
lwPolylines.forEach(p => sketch.objects.push(...this._lwPolyline(p)));
|
||||
this.handleEntities(obj.entities, sketch, transform)
|
||||
obj.entities.inserts.forEach(i => this._insert(obj.blocks, i, sketch));
|
||||
|
||||
return sketch;
|
||||
}
|
||||
|
||||
private _lwPolyline(p: LWPolylineEntity) {
|
||||
private handleEntities(entities: Omit<DxfGlobalObject["entities"], "inserts">, sketch: SketchFormat_V3, t: ITransform) {
|
||||
entities.arcs.forEach(a => sketch.objects.push(this._arc(a, t)));
|
||||
entities.circles.forEach(c => sketch.objects.push(this._circle(c, t)));
|
||||
entities.ellipses.forEach(e => sketch.objects.push(this._ellipse(e, t)));
|
||||
entities.lines.forEach(l => sketch.objects.push(this._segment(l, t)));
|
||||
entities.points.forEach(p => sketch.objects.push(this._point(p, t)));
|
||||
entities.lwPolylines.forEach(p => sketch.objects.push(...this._lwPolyline(p, t)));
|
||||
entities.polylines.forEach(p => sketch.objects.push(...this._polyline(p, t)));
|
||||
entities.splines.forEach(s => sketch.objects.push(...this._spline(s, t)));
|
||||
}
|
||||
|
||||
private _insert(blocks: Block[], i: InsertEntity, sketch: SketchFormat_V3) {
|
||||
const block = blocks.find(block => {
|
||||
return block.name === i.blockName || block.name2 === i.blockName
|
||||
});
|
||||
|
||||
if(block) {
|
||||
const transform: ITransform = {
|
||||
translation: {
|
||||
x: block.basePointX + i.x,
|
||||
y: block.basePointY + i.y
|
||||
},
|
||||
rotation: rad(i.rotation ?? 0),
|
||||
origin: { x: i.x, y: i.y },
|
||||
}
|
||||
this.handleEntities(block.entities, sketch, transform);
|
||||
block.entities.inserts.forEach(i => this._insert(blocks, i, sketch));
|
||||
}
|
||||
}
|
||||
|
||||
private _spline(s: SplineEntity, t: ITransform) {
|
||||
const objects = [];
|
||||
for (let i = 0; i < s.controlPoints.length;) {
|
||||
const p1 = s.controlPoints[i];
|
||||
const p2 = s.controlPoints[++i];
|
||||
const p3 = s.controlPoints[++i];
|
||||
const p4 = s.controlPoints[++i];
|
||||
if(p1 && p2 && p3 && p4) {
|
||||
if(p1.x === p2.x && p3.x === p4.x && p1.y === p2.y && p3.y === p4.y) {
|
||||
const data: SketchSegmentSerializationData = {
|
||||
a: applyTransformPoint({ x: p1.x, y: p1.y }, t),
|
||||
b: applyTransformPoint({ x: p4.x, y: p4.y }, t)
|
||||
};
|
||||
objects.push(this._createSketchObject(Segment.prototype.TYPE, data));
|
||||
} else {
|
||||
const data = {
|
||||
cp4: applyTransformPoint({ x: p1.x, y: p1.y }, t),
|
||||
cp3: applyTransformPoint({ x: p2.x, y: p2.y }, t),
|
||||
cp2: applyTransformPoint({ x: p3.x, y: p3.y }, t),
|
||||
cp1: applyTransformPoint({ x: p4.x, y: p4.y }, t)
|
||||
};
|
||||
objects.push(this._createSketchObject(BezierCurve.prototype.TYPE, data));
|
||||
}
|
||||
}
|
||||
}
|
||||
return objects;
|
||||
}
|
||||
|
||||
private _polyline(p: PolylineEntity, t: ITransform) {
|
||||
return this._lwPolyline(p, t);
|
||||
}
|
||||
|
||||
private _lwPolyline(p: LWPolylineEntity | PolylineEntity, t: ITransform) {
|
||||
const objects = [];
|
||||
for (let i = 0; i < p.vertices.length;) {
|
||||
const curr = p.vertices[i];
|
||||
|
|
@ -256,8 +357,8 @@ export class DxfParserAdapter {
|
|||
if(curr && next) {
|
||||
if(!curr.bulge || curr.bulge === 0) {
|
||||
const data: SketchSegmentSerializationData = {
|
||||
a: {x: curr.x, y: curr.y},
|
||||
b: {x: next.x, y: next.y}
|
||||
a: applyTransformPoint({ x: curr.x, y: curr.y }, t),
|
||||
b: applyTransformPoint({x: next.x, y: next.y}, t)
|
||||
};
|
||||
objects.push(this._createSketchObject(Segment.prototype.TYPE, data));
|
||||
} else {
|
||||
|
|
@ -266,9 +367,9 @@ export class DxfParserAdapter {
|
|||
const radius = (Math.hypot(curr.x - next.x, curr.y - next.y) / 2) / Math.sin(theta / 2);
|
||||
const center = polar(curr, beta + (Math.PI - theta) / 2, radius);
|
||||
const data: SketchArcSerializationData = {
|
||||
a: curr.bulge > 0 ? {x: curr.x, y: curr.y} : {x: next.x, y: next.y},
|
||||
b: curr.bulge > 0 ? {x: next.x, y: next.y} : {x: curr.x, y: curr.y},
|
||||
c: center,
|
||||
a: applyTransformPoint(curr.bulge > 0 ? {x: curr.x, y: curr.y} : {x: next.x, y: next.y}, t),
|
||||
b: applyTransformPoint(curr.bulge > 0 ? {x: next.x, y: next.y} : {x: curr.x, y: curr.y}, t),
|
||||
c: applyTransformPoint(center, t),
|
||||
};
|
||||
objects.push(this._createSketchObject(Arc.prototype.TYPE, data));
|
||||
}
|
||||
|
|
@ -277,41 +378,44 @@ export class DxfParserAdapter {
|
|||
return objects;
|
||||
}
|
||||
|
||||
private _arc(a: ArcEntity) {
|
||||
private _arc(a: ArcEntity, t: ITransform) {
|
||||
const center: IPoint = {x: a.centerX, y: a.centerY};
|
||||
const data: SketchArcSerializationData = {
|
||||
a: polar(center, rad(a.startAngle), a.radius),
|
||||
b: polar(center, rad(a.endAngle), a.radius),
|
||||
c: center,
|
||||
a: applyTransformPoint(polar(center, rad(a.startAngle), a.radius), t),
|
||||
b: applyTransformPoint(polar(center, rad(a.endAngle), a.radius), t),
|
||||
c: applyTransformPoint(center, t),
|
||||
};
|
||||
return this._createSketchObject(Arc.prototype.TYPE, data);
|
||||
}
|
||||
|
||||
private _circle(c: CircleEntity) {
|
||||
const center: IPoint = {x: c.centerX, y: c.centerY};
|
||||
const data: SketchCircleSerializationData = { c: center, r: c.radius };
|
||||
private _circle(c: CircleEntity, t: ITransform) {
|
||||
const data: SketchCircleSerializationData = {
|
||||
c: applyTransformPoint({ x: c.centerX, y: c.centerY }, t),
|
||||
r: c.radius
|
||||
};
|
||||
return this._createSketchObject(Circle.prototype.TYPE, data);
|
||||
}
|
||||
|
||||
private _ellipse(e: EllipseEntity) {
|
||||
const c: IPoint = {x: e.centerX, y: e.centerY};
|
||||
const rot = atan2(e.majorAxisY, e.majorAxisX);
|
||||
private _ellipse(e: EllipseEntity, t: ITransform) {
|
||||
const c: IPoint = applyTransformPoint({x: e.centerX, y: e.centerY}, t);
|
||||
let rot = atan2(e.majorAxisY, e.majorAxisX);
|
||||
const rx = e.majorAxisX / cos(rot);
|
||||
const ry = e.ratioOfMinorAxisToMajorAxis * rx;
|
||||
rot += t.rotation;
|
||||
const data: SketchEllipseSerializationData = { c, rx, ry, rot };
|
||||
return this._createSketchObject(Ellipse.prototype.TYPE, data);
|
||||
}
|
||||
|
||||
private _segment(l: LineEntity) {
|
||||
private _segment(l: LineEntity, t: ITransform) {
|
||||
const data: SketchSegmentSerializationData = {
|
||||
a: {x: l.startX, y: l.startY},
|
||||
b: {x: l.endX, y: l.endY}
|
||||
a: applyTransformPoint({x: l.startX, y: l.startY}, t),
|
||||
b: applyTransformPoint({x: l.endX, y: l.endY}, t)
|
||||
};
|
||||
return this._createSketchObject(Segment.prototype.TYPE, data);
|
||||
}
|
||||
|
||||
private _point(p: PointEntity) {
|
||||
const data: SketchPointSerializationData = { x: p.x, y: p.y };
|
||||
private _point(p: PointEntity, t: ITransform) {
|
||||
const data: SketchPointSerializationData = applyTransformPoint(p, t);
|
||||
return this._createSketchObject(EndPoint.prototype.TYPE, data);
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue