mirror of
https://github.com/xibyte/jsketcher
synced 2026-01-29 03:23:49 +01:00
feat: add dimensions in svg export
This commit is contained in:
parent
a54a784e4b
commit
f8ae485ecf
7 changed files with 363 additions and 286 deletions
|
|
@ -1,7 +0,0 @@
|
|||
|
||||
export default function(data, fileName) {
|
||||
const link = document.getElementById("downloader");
|
||||
link.href = "data:application/octet-stream;charset=utf-8;base64," + btoa(data);
|
||||
link.download = fileName;
|
||||
link.click();
|
||||
}
|
||||
5
modules/gems/exportTextData.ts
Normal file
5
modules/gems/exportTextData.ts
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
import { saveAs } from "file-saver";
|
||||
|
||||
export default function (data: string, fileName: string) {
|
||||
saveAs(new File([data], fileName, { type: "text/plain;charset=utf-8" }));
|
||||
}
|
||||
154
package-lock.json
generated
154
package-lock.json
generated
|
|
@ -11,7 +11,7 @@
|
|||
"dependencies": {
|
||||
"@dxfjs/parser": "^0.2.0",
|
||||
"@react-icons/all-files": "^4.1.0",
|
||||
"@tarikjabiri/dxf": "^2.8.9",
|
||||
"@tarikjabiri/dxf": "^3.0.0-alpha.11",
|
||||
"@tauri-apps/api": "^1.4.0",
|
||||
"@types/three": "^0.146.0",
|
||||
"browser-xml2js": "^0.4.19",
|
||||
|
|
@ -19,6 +19,7 @@
|
|||
"clipper-lib": "^6.4.2",
|
||||
"core-js": "^3.32.2",
|
||||
"earcut": "^2.2.4",
|
||||
"file-saver": "^2.0.5",
|
||||
"font-awesome": "4.7.0",
|
||||
"immer": "^9.0.21",
|
||||
"jsketcher-occ-engine": "1.0.1-f505cdcb9f37685cdadb937bc3b11b9b75f9267c",
|
||||
|
|
@ -53,6 +54,7 @@
|
|||
"@babel/preset-stage-2": "^7.8.3",
|
||||
"@babel/preset-typescript": "^7.22.15",
|
||||
"@tauri-apps/cli": "^1.4.0",
|
||||
"@types/file-saver": "^2.0.7",
|
||||
"@types/react": "^18.2.21",
|
||||
"@types/react-dom": "^18.2.7",
|
||||
"@typescript-eslint/eslint-plugin": "^5.62.0",
|
||||
|
|
@ -79,6 +81,7 @@
|
|||
"less-loader": "^11.1.3",
|
||||
"raw-loader": "^4.0.2",
|
||||
"style-loader": "^3.3.3",
|
||||
"ts-loader": "^9.5.1",
|
||||
"typescript": "^4.9.5",
|
||||
"url-loader": "^4.1.1",
|
||||
"wait-on": "^6.0.1",
|
||||
|
|
@ -2451,9 +2454,9 @@
|
|||
"dev": true
|
||||
},
|
||||
"node_modules/@tarikjabiri/dxf": {
|
||||
"version": "2.8.9",
|
||||
"resolved": "https://registry.npmjs.org/@tarikjabiri/dxf/-/dxf-2.8.9.tgz",
|
||||
"integrity": "sha512-ckBkEsWdlFTvqm2ARm23xX3EVouYsnNuZWS7P/oec1WCGTjzdd9jhmtQqyhh7TQSvQo4HunbDv4Vxiv07/8zsQ==",
|
||||
"version": "3.0.0-alpha.11",
|
||||
"resolved": "https://registry.npmjs.org/@tarikjabiri/dxf/-/dxf-3.0.0-alpha.11.tgz",
|
||||
"integrity": "sha512-YSn/wi+sYZ+bFfsImmwu9vLa0QpAxnRgpwo31TPjGUC4CFP4MhsynR/iCcPHvjWrnFrFmT3vZ4oMM8en3tUbcw==",
|
||||
"engines": {
|
||||
"node": ">=16",
|
||||
"pnpm": ">=8"
|
||||
|
|
@ -2752,6 +2755,12 @@
|
|||
"@types/send": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/file-saver": {
|
||||
"version": "2.0.7",
|
||||
"resolved": "https://registry.npmjs.org/@types/file-saver/-/file-saver-2.0.7.tgz",
|
||||
"integrity": "sha512-dNKVfHd/jk0SkR/exKGj2ggkB45MAkzvWCaqLUUgkyjITkGNzH8H+yUwr+BLJUBjZOe9w8X3wgmXhZDRg1ED6A==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@types/http-errors": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.1.tgz",
|
||||
|
|
@ -6641,6 +6650,11 @@
|
|||
"url": "https://opencollective.com/webpack"
|
||||
}
|
||||
},
|
||||
"node_modules/file-saver": {
|
||||
"version": "2.0.5",
|
||||
"resolved": "https://registry.npmjs.org/file-saver/-/file-saver-2.0.5.tgz",
|
||||
"integrity": "sha512-P9bmyZ3h/PRG+Nzga+rbdI4OEpNDzAVyy74uVO9ATgzLK6VtAsYybF/+TOCvrc0MO793d6+42lLyZTw7/ArVzA=="
|
||||
},
|
||||
"node_modules/file-sync-cmp": {
|
||||
"version": "0.1.1",
|
||||
"resolved": "https://registry.npmjs.org/file-sync-cmp/-/file-sync-cmp-0.1.1.tgz",
|
||||
|
|
@ -11860,6 +11874,138 @@
|
|||
"tree-kill": "cli.js"
|
||||
}
|
||||
},
|
||||
"node_modules/ts-loader": {
|
||||
"version": "9.5.1",
|
||||
"resolved": "https://registry.npmjs.org/ts-loader/-/ts-loader-9.5.1.tgz",
|
||||
"integrity": "sha512-rNH3sK9kGZcH9dYzC7CewQm4NtxJTjSEVRJ2DyBZR7f8/wcta+iV44UPCXc5+nzDzivKtlzV6c9P4e+oFhDLYg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"chalk": "^4.1.0",
|
||||
"enhanced-resolve": "^5.0.0",
|
||||
"micromatch": "^4.0.0",
|
||||
"semver": "^7.3.4",
|
||||
"source-map": "^0.7.4"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"typescript": "*",
|
||||
"webpack": "^5.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/ts-loader/node_modules/ansi-styles": {
|
||||
"version": "4.3.0",
|
||||
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
|
||||
"integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"color-convert": "^2.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/chalk/ansi-styles?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/ts-loader/node_modules/chalk": {
|
||||
"version": "4.1.2",
|
||||
"resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
|
||||
"integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"ansi-styles": "^4.1.0",
|
||||
"supports-color": "^7.1.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/chalk/chalk?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/ts-loader/node_modules/color-convert": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
|
||||
"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"color-name": "~1.1.4"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=7.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/ts-loader/node_modules/color-name": {
|
||||
"version": "1.1.4",
|
||||
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
|
||||
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/ts-loader/node_modules/has-flag": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
|
||||
"integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/ts-loader/node_modules/lru-cache": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
|
||||
"integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"yallist": "^4.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/ts-loader/node_modules/semver": {
|
||||
"version": "7.5.4",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz",
|
||||
"integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"lru-cache": "^6.0.0"
|
||||
},
|
||||
"bin": {
|
||||
"semver": "bin/semver.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/ts-loader/node_modules/source-map": {
|
||||
"version": "0.7.4",
|
||||
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz",
|
||||
"integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">= 8"
|
||||
}
|
||||
},
|
||||
"node_modules/ts-loader/node_modules/supports-color": {
|
||||
"version": "7.2.0",
|
||||
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
|
||||
"integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"has-flag": "^4.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/ts-loader/node_modules/yallist": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
|
||||
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/tsconfig-paths": {
|
||||
"version": "3.14.2",
|
||||
"resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.14.2.tgz",
|
||||
|
|
|
|||
|
|
@ -44,6 +44,7 @@
|
|||
"@babel/preset-stage-2": "^7.8.3",
|
||||
"@babel/preset-typescript": "^7.22.15",
|
||||
"@tauri-apps/cli": "^1.4.0",
|
||||
"@types/file-saver": "^2.0.7",
|
||||
"@types/react": "^18.2.21",
|
||||
"@types/react-dom": "^18.2.7",
|
||||
"@typescript-eslint/eslint-plugin": "^5.62.0",
|
||||
|
|
@ -70,6 +71,7 @@
|
|||
"less-loader": "^11.1.3",
|
||||
"raw-loader": "^4.0.2",
|
||||
"style-loader": "^3.3.3",
|
||||
"ts-loader": "^9.5.1",
|
||||
"typescript": "^4.9.5",
|
||||
"url-loader": "^4.1.1",
|
||||
"wait-on": "^6.0.1",
|
||||
|
|
@ -80,7 +82,7 @@
|
|||
"dependencies": {
|
||||
"@dxfjs/parser": "^0.2.0",
|
||||
"@react-icons/all-files": "^4.1.0",
|
||||
"@tarikjabiri/dxf": "^2.8.9",
|
||||
"@tarikjabiri/dxf": "^3.0.0-alpha.11",
|
||||
"@tauri-apps/api": "^1.4.0",
|
||||
"@types/three": "^0.146.0",
|
||||
"browser-xml2js": "^0.4.19",
|
||||
|
|
@ -88,6 +90,7 @@
|
|||
"clipper-lib": "^6.4.2",
|
||||
"core-js": "^3.32.2",
|
||||
"earcut": "^2.2.4",
|
||||
"file-saver": "^2.0.5",
|
||||
"font-awesome": "4.7.0",
|
||||
"immer": "^9.0.21",
|
||||
"jsketcher-occ-engine": "1.0.1-f505cdcb9f37685cdadb937bc3b11b9b75f9267c",
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import Vector, {AXIS, ORIGIN} from 'math/vector';
|
||||
import {RiCamera2Line} from "react-icons/ri";
|
||||
import {ViewMode} from "cad/scene/viewer";
|
||||
import {GiCube, HiCube, HiOutlineCube} from "react-icons/all";
|
||||
import {GiCube, HiCube, HiOutlineCube} from "react-icons";
|
||||
|
||||
const NEG_X = AXIS.X.negate();
|
||||
const NEG_Y = AXIS.Y.negate();
|
||||
|
|
@ -21,7 +21,7 @@ function faceAt(shells, shell, pos) {
|
|||
let i = shellIndex;
|
||||
do {
|
||||
i = (i + 1) % shells.length;
|
||||
shell = shells[i];
|
||||
shell = shells[i];
|
||||
} while(shellIndex !== i && shell.faces.length === 0);
|
||||
return shell.faces[0];
|
||||
} else if (pos < 0) {
|
||||
|
|
@ -32,7 +32,7 @@ function faceAt(shells, shell, pos) {
|
|||
} while(shellIndex !== i && shell.faces.length === 0);
|
||||
return shell.faces[shell.faces.length - 1];
|
||||
} else {
|
||||
return shell.faces[pos];
|
||||
return shell.faces[pos];
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -41,7 +41,7 @@ function getCurrentSelectedOrFirstFace(ctx) {
|
|||
if (!face) {
|
||||
for (const shell of ctx.services.cadRegistry.shells) {
|
||||
if (shell.faces.length !== 0) {
|
||||
return shell.faces[0];
|
||||
return shell.faces[0];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -62,7 +62,7 @@ export default [
|
|||
ctx.services.viewer.zoomOut();
|
||||
ctx.services.viewer.requestRender();
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'LookAtFace',
|
||||
appearance: {
|
||||
|
|
|
|||
|
|
@ -10,12 +10,12 @@ import {
|
|||
Parser,
|
||||
PointEntity,
|
||||
PolylineEntity,
|
||||
SplineEntity
|
||||
} from "@dxfjs/parser";
|
||||
import { Colors, DLine, DxfWriter, point3d, SplineArgs_t, SplineFlags, Units, vec3_t } from '@tarikjabiri/dxf';
|
||||
SplineEntity,
|
||||
} from '@dxfjs/parser';
|
||||
import { dline, Writer, point, SplineFlags, Units } 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';
|
||||
|
|
@ -24,15 +24,16 @@ import { EndPoint, SketchPointSerializationData } from './shapes/point';
|
|||
import { Segment, SketchSegmentSerializationData } from './shapes/segment';
|
||||
import { SketchObject, SketchObjectSerializationData } from './shapes/sketch-object';
|
||||
import { Layer } from './viewer2d';
|
||||
import { calculateAngle, linep } from '@tarikjabiri/dxf/lib/helpers';
|
||||
|
||||
interface IPoint {
|
||||
x: number,
|
||||
y: number
|
||||
x: number;
|
||||
y: number;
|
||||
}
|
||||
|
||||
interface SketchCircleSerializationData extends SketchObjectSerializationData {
|
||||
c: SketchPointSerializationData;
|
||||
r: number
|
||||
r: number;
|
||||
}
|
||||
|
||||
interface SketchEllipseSerializationData extends SketchObjectSerializationData {
|
||||
|
|
@ -48,34 +49,34 @@ interface ITransform {
|
|||
origin: IPoint;
|
||||
}
|
||||
|
||||
const {PI, cos, sin, atan2} = Math
|
||||
const { PI, cos, sin, atan2 } = Math;
|
||||
|
||||
export function deg(angle: number): number {
|
||||
return (angle * 180) / PI
|
||||
return (angle * 180) / PI;
|
||||
}
|
||||
|
||||
export function rad(angle: number): number {
|
||||
return (angle * PI) / 180
|
||||
return (angle * PI) / 180;
|
||||
}
|
||||
|
||||
function polar(origin: IPoint, angle: number, radius: number): IPoint {
|
||||
return {
|
||||
x: origin.x + radius * cos(angle),
|
||||
y: origin.y + radius * sin(angle)
|
||||
}
|
||||
y: origin.y + radius * sin(angle),
|
||||
};
|
||||
}
|
||||
|
||||
function angle(fp: IPoint, sp: IPoint) {
|
||||
let angle = Math.atan2(sp.y - fp.y, sp.x - fp.x)
|
||||
if(angle < 0) angle += 2 * Math.PI
|
||||
return angle
|
||||
let angle = Math.atan2(sp.y - fp.y, sp.x - fp.x);
|
||||
if (angle < 0) angle += 2 * Math.PI;
|
||||
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 {
|
||||
|
|
@ -84,8 +85,8 @@ function rotatePoint(p: IPoint, t: ITransform): IPoint {
|
|||
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))
|
||||
}
|
||||
y: t.origin.y + (ox * sin(t.rotation) + oy * cos(t.rotation)),
|
||||
};
|
||||
}
|
||||
|
||||
function applyTransformPoint(p: IPoint, t: ITransform) {
|
||||
|
|
@ -93,24 +94,42 @@ function applyTransformPoint(p: IPoint, t: ITransform) {
|
|||
}
|
||||
|
||||
export class DxfWriterAdapter {
|
||||
writer: DxfWriter;
|
||||
writer: Writer;
|
||||
|
||||
get modelSpace() {
|
||||
return this.writer.document.modelSpace;
|
||||
}
|
||||
|
||||
get tables() {
|
||||
return this.writer.document.tables;
|
||||
}
|
||||
|
||||
get bbox() {
|
||||
return this.writer.document.modelSpace.bbox();
|
||||
}
|
||||
|
||||
get renderer() {
|
||||
return this.writer.document.renderer;
|
||||
}
|
||||
|
||||
constructor() {
|
||||
this.writer = new DxfWriter();
|
||||
this.writer.setUnits(Units.Millimeters);
|
||||
this.writer = new Writer();
|
||||
this.writer.document.setUnits(Units.Millimeters);
|
||||
|
||||
const header = this.writer.document.header;
|
||||
|
||||
// Dimensions customization
|
||||
// I hard coded these values but I am not sure about them
|
||||
this.writer.setVariable('$DIMTXT', { 40: 10 }); // The text height
|
||||
this.writer.setVariable('$DIMASZ', { 40: 10 }); // Dimensioning arrow size
|
||||
header.add('$DIMTXT').add(40, 10); // The text height
|
||||
header.add('$DIMASZ').add(40, 10); // Dimensioning arrow size
|
||||
|
||||
// Theses for preserving the look like jsketcher
|
||||
this.writer.setVariable('$DIMDEC', { 70: 2 }); // Number of precision places displayed
|
||||
this.writer.setVariable('$DIMTIH', { 70: 0 }); // Text inside horizontal if nonzero
|
||||
this.writer.setVariable('$DIMTOH', { 70: 0 }); // Text outside horizontal if nonzero
|
||||
header.add('$DIMDEC').add(70, 2); // Number of precision places displayed
|
||||
header.add('$DIMTIH').add(70, 0); // Text inside horizontal if nonzero
|
||||
header.add('$DIMTOH').add(70, 0); // Text outside horizontal if nonzero
|
||||
// Do not force text inside extensions
|
||||
this.writer.setVariable('$DIMTIX', { 70: 0 }); // Force text inside extensions if nonzero
|
||||
this.writer.setVariable('$DIMATFIT', { 70: 0 }); // Controls dimension text and arrow placement
|
||||
header.add('$DIMTIX').add(70, 0); // Force text inside extensions if nonzero
|
||||
header.add('$DIMATFIT').add(70, 0); // Controls dimension text and arrow placement
|
||||
|
||||
// For more customization
|
||||
// this.writer.setVariable('$DIMEXE', { 40: 10 }); // Extension line extension
|
||||
|
|
@ -121,50 +140,54 @@ export class DxfWriterAdapter {
|
|||
}
|
||||
|
||||
private _point(shape: EndPoint) {
|
||||
this.writer.addPoint(shape.x, shape.y, 0);
|
||||
this.modelSpace.addPoint(shape);
|
||||
}
|
||||
|
||||
private _segment(shape: Segment) {
|
||||
this.writer.addLine(point3d(shape.a.x, shape.a.y), point3d(shape.b.x, shape.b.y));
|
||||
this.modelSpace.addLine({
|
||||
start: point(shape.a.x, shape.a.y),
|
||||
end: point(shape.b.x, shape.b.y),
|
||||
});
|
||||
}
|
||||
|
||||
private _arc(shape: Arc) {
|
||||
this.writer.addArc(
|
||||
point3d(shape.c.x, shape.c.y),
|
||||
shape.r.get(),
|
||||
deg(shape.getStartAngle()),
|
||||
deg(shape.getEndAngle())
|
||||
);
|
||||
this.modelSpace.addArc({
|
||||
center: point(shape.c.x, shape.c.y),
|
||||
radius: shape.r.get(),
|
||||
startAngle: deg(shape.getStartAngle()),
|
||||
endAngle: deg(shape.getEndAngle()),
|
||||
});
|
||||
}
|
||||
|
||||
private _circle(shape: Circle) {
|
||||
this.writer.addCircle(point3d(shape.c.x, shape.c.y), shape.r.get());
|
||||
this.modelSpace.addCircle({
|
||||
center: point(shape.c.x, shape.c.y),
|
||||
radius: shape.r.get(),
|
||||
});
|
||||
}
|
||||
|
||||
private _ellipse(shape: Ellipse) {
|
||||
const majorX = Math.cos(shape.rotation) * shape.radiusX;
|
||||
const majorY = Math.sin(shape.rotation) * shape.radiusX;
|
||||
this.writer.addEllipse(
|
||||
point3d(shape.centerX, shape.centerY),
|
||||
point3d(majorX, majorY),
|
||||
shape.radiusY / shape.radiusX,
|
||||
0,
|
||||
2 * Math.PI
|
||||
);
|
||||
this.modelSpace.addEllipse({
|
||||
center: point(shape.centerX, shape.centerY),
|
||||
endpoint: point(majorX, majorY),
|
||||
ratio: shape.radiusY / shape.radiusX,
|
||||
start: 0,
|
||||
end: 2 * Math.PI,
|
||||
});
|
||||
}
|
||||
|
||||
private _bezier(shape: BezierCurve) {
|
||||
const controlPoints: vec3_t[] = [
|
||||
point3d(shape.p0.x, shape.p0.y),
|
||||
point3d(shape.p1.x, shape.p1.y),
|
||||
point3d(shape.p2.x, shape.p2.y),
|
||||
point3d(shape.p3.x, shape.p3.y),
|
||||
];
|
||||
const splineArgs: SplineArgs_t = {
|
||||
controlPoints,
|
||||
this.modelSpace.addSpline({
|
||||
controls: [
|
||||
point(shape.p0.x, shape.p0.y),
|
||||
point(shape.p1.x, shape.p1.y),
|
||||
point(shape.p2.x, shape.p2.y),
|
||||
point(shape.p3.x, shape.p3.y),
|
||||
],
|
||||
flags: SplineFlags.Periodic,
|
||||
};
|
||||
this.writer.addSpline(splineArgs);
|
||||
});
|
||||
}
|
||||
|
||||
private _label(shape: Label) {
|
||||
|
|
@ -174,22 +197,39 @@ export class DxfWriterAdapter {
|
|||
const h = shape.textHelper.textMetrics.width / 2;
|
||||
const lx = m.x - h + shape.offsetX;
|
||||
const ly = m.y + shape.marginOffset + shape.offsetY;
|
||||
this.writer.addText(point3d(lx, ly), height, shape.text);
|
||||
}
|
||||
|
||||
private _vdim(shape: VDimension) {
|
||||
this.writer.addLinearDim(point3d(shape.a.x, shape.a.y), point3d(shape.b.x, shape.b.y), {
|
||||
angle: 90, // Make it vertical
|
||||
offset: -shape.offset,
|
||||
this.modelSpace.addText({
|
||||
firstAlignmentPoint: point(lx, ly),
|
||||
height,
|
||||
value: shape.text,
|
||||
});
|
||||
}
|
||||
|
||||
private _vdim(shape: VDimension) {
|
||||
const dim = this.modelSpace.addLinearDim({
|
||||
start: point(shape.a.x, shape.a.y),
|
||||
end: point(shape.b.x, shape.b.y),
|
||||
angle: 90,
|
||||
offset: shape.offset,
|
||||
});
|
||||
this.renderer.addLinear(dim);
|
||||
}
|
||||
|
||||
private _hdim(shape: HDimension) {
|
||||
this.writer.addLinearDim(point3d(shape.a.x, shape.a.y), point3d(shape.b.x, shape.b.y), { offset: -shape.offset });
|
||||
const dim = this.modelSpace.addLinearDim({
|
||||
start: point(shape.a.x, shape.a.y),
|
||||
end: point(shape.b.x, shape.b.y),
|
||||
offset: shape.offset,
|
||||
});
|
||||
this.renderer.addLinear(dim);
|
||||
}
|
||||
|
||||
private _linearDim(shape: LinearDimension) {
|
||||
this.writer.addAlignedDim(point3d(shape.a.x, shape.a.y), point3d(shape.b.x, shape.b.y), { offset: shape.offset });
|
||||
const aligned = this.modelSpace.addAlignedDim({
|
||||
start: point(shape.a.x, shape.a.y),
|
||||
end: point(shape.b.x, shape.b.y),
|
||||
offset: -shape.offset,
|
||||
});
|
||||
this.renderer.addAligned(aligned);
|
||||
}
|
||||
|
||||
private _ddim(shape: DiameterDimension) {
|
||||
|
|
@ -197,39 +237,36 @@ export class DxfWriterAdapter {
|
|||
const radius = shape.obj.distanceA ? shape.obj.distanceA() : shape.obj.r.get();
|
||||
const x = shape.obj.c.x + radius * Math.cos(shape.angle);
|
||||
const y = shape.obj.c.y + radius * Math.sin(shape.angle);
|
||||
this.writer.addRadialDim(point3d(x, y), point3d(shape.obj.c.x, shape.obj.c.y));
|
||||
const dim = this.modelSpace.addRadialDim({
|
||||
first: point(x, y),
|
||||
definition: point(shape.obj.c.x, shape.obj.c.y),
|
||||
leaderLength: 0,
|
||||
});
|
||||
this.renderer.addRadial(dim);
|
||||
}
|
||||
|
||||
private _bwdim(shape: AngleBetweenDimension) {
|
||||
// This is not working as expected.
|
||||
const s: DLine = {
|
||||
start: point3d(shape.a.a.x, shape.a.a.y),
|
||||
end: point3d(shape.a.b.x, shape.a.b.y),
|
||||
};
|
||||
const f: DLine = {
|
||||
start: point3d(shape.b.a.x, shape.b.a.y),
|
||||
end: point3d(shape.b.b.x, shape.b.b.y),
|
||||
};
|
||||
const c = point3d(shape.a.a.x, shape.a.a.y);
|
||||
const offset = shape.offset;
|
||||
const dyf = f.end.y - c.y;
|
||||
const dys = s.end.y - c.y;
|
||||
const df = Math.sqrt(Math.pow(f.end.x - c.x, 2) + Math.pow(f.end.y - c.y, 2));
|
||||
const ds = Math.sqrt(Math.pow(s.end.x - c.x, 2) + Math.pow(s.end.y - c.y, 2));
|
||||
const alphaf = Math.acos(dyf / df);
|
||||
const alphas = Math.acos(dys / ds);
|
||||
const alpham = Math.abs(alphaf - alphas) / 2 + (alphaf > alphas ? alphas : alphaf);
|
||||
const xm = c.x + offset*Math.cos(alpham)
|
||||
const ym = c.y + offset*Math.sin(alpham)
|
||||
this.writer.addAngularLinesDim(f, s, point3d(xm, ym));
|
||||
dline(point(shape.a.a.x, shape.a.a.y), point(shape.a.b.x, shape.a.b.y));
|
||||
const firstLine = dline(point(shape.b.a.x, shape.b.a.y), point(shape.b.b.x, shape.b.b.y));
|
||||
const secondLine = dline(point(shape.a.a.x, shape.a.a.y), point(shape.a.b.x, shape.a.b.y));
|
||||
const fline = linep(firstLine.start, firstLine.end);
|
||||
const sline = linep(secondLine.start, secondLine.end);
|
||||
const intersection = fline.intersect(sline);
|
||||
const angle = calculateAngle(firstLine.start, firstLine.end);
|
||||
const p = polar(intersection, angle, shape.offset);
|
||||
const angular = this.modelSpace.addAngularLinesDim({
|
||||
firstLine,
|
||||
secondLine,
|
||||
positionArc: point(p.x, p.y),
|
||||
});
|
||||
this.renderer.addAngularLines(angular);
|
||||
}
|
||||
|
||||
export(layers: Layer<SketchObject>[]) {
|
||||
layers.forEach(layer => {
|
||||
// this will prevent addLayer from throwing.
|
||||
if (!this.writer.layer(layer.name))
|
||||
this.writer.addLayer(layer.name, Colors.Black);
|
||||
this.writer.setCurrentLayerName(layer.name);
|
||||
const found = this.tables.layer.get(layer.name);
|
||||
if (found == null) this.tables.addLayer(layer);
|
||||
this.modelSpace.currentLayerName = layer.name;
|
||||
|
||||
layer.objects.forEach(shape => {
|
||||
if (shape instanceof EndPoint) this._point(shape);
|
||||
|
|
@ -249,41 +286,51 @@ export class DxfWriterAdapter {
|
|||
}
|
||||
|
||||
stringify(): string {
|
||||
// reset the current layer to 0, because its preserved in the dxf.
|
||||
this.writer.setZeroLayerAsCurrent();
|
||||
this.modelSpace.currentLayerName = this.tables.zeroLayer.name;
|
||||
return this.writer.stringify();
|
||||
}
|
||||
}
|
||||
|
||||
export class DxfParserAdapter {
|
||||
private static _seed = 0; // Used as ids for the shapes.
|
||||
private _seed = 0; // Used as ids for the shapes.
|
||||
|
||||
private _createSketchObject(type: string, data: object) {
|
||||
return {
|
||||
id: (DxfParserAdapter._seed++).toString(),
|
||||
type, role: null, stage: 0, data
|
||||
}
|
||||
id: (this._seed++).toString(),
|
||||
type,
|
||||
role: null,
|
||||
stage: 0,
|
||||
data,
|
||||
};
|
||||
}
|
||||
|
||||
private _createSketchFormat(obj: DxfGlobalObject): SketchFormat_V3 {
|
||||
DxfParserAdapter._seed = 0;
|
||||
const sketch: SketchFormat_V3 = {
|
||||
version: 3, objects: [], dimensions: [], labels: [],
|
||||
stages: [], constants: null, metadata: {}
|
||||
version: 3,
|
||||
objects: [],
|
||||
dimensions: [],
|
||||
labels: [],
|
||||
stages: [],
|
||||
constants: null,
|
||||
metadata: {},
|
||||
};
|
||||
const transform: ITransform = {
|
||||
translation: { x: 0, y: 0 },
|
||||
rotation: 0,
|
||||
origin: { x: 0, y: 0 }
|
||||
}
|
||||
origin: { x: 0, y: 0 },
|
||||
};
|
||||
|
||||
this.handleEntities(obj.entities, sketch, transform)
|
||||
this.handleEntities(obj.entities, sketch, transform);
|
||||
obj.entities.inserts.forEach(i => this._insert(obj.blocks, i, sketch));
|
||||
|
||||
return sketch;
|
||||
}
|
||||
|
||||
private handleEntities(entities: Omit<DxfGlobalObject["entities"], "inserts">, sketch: SketchFormat_V3, t: ITransform) {
|
||||
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)));
|
||||
|
|
@ -296,18 +343,18 @@ export class DxfParserAdapter {
|
|||
|
||||
private _insert(blocks: Block[], i: InsertEntity, sketch: SketchFormat_V3) {
|
||||
const block = blocks.find(block => {
|
||||
return block.name === i.blockName || block.name2 === i.blockName
|
||||
return block.name === i.blockName || block.name2 === i.blockName;
|
||||
});
|
||||
|
||||
if(block) {
|
||||
if (block) {
|
||||
const transform: ITransform = {
|
||||
translation: {
|
||||
x: block.basePointX + i.x,
|
||||
y: block.basePointY + i.y
|
||||
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));
|
||||
}
|
||||
|
|
@ -315,16 +362,16 @@ export class DxfParserAdapter {
|
|||
|
||||
private _spline(s: SplineEntity, t: ITransform) {
|
||||
const objects = [];
|
||||
for (let i = 0; i < s.controlPoints.length;) {
|
||||
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) {
|
||||
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)
|
||||
b: applyTransformPoint({ x: p4.x, y: p4.y }, t),
|
||||
};
|
||||
objects.push(this._createSketchObject(Segment.prototype.TYPE, data));
|
||||
} else {
|
||||
|
|
@ -332,7 +379,7 @@ export class DxfParserAdapter {
|
|||
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)
|
||||
cp1: applyTransformPoint({ x: p4.x, y: p4.y }, t),
|
||||
};
|
||||
objects.push(this._createSketchObject(BezierCurve.prototype.TYPE, data));
|
||||
}
|
||||
|
|
@ -347,28 +394,28 @@ export class DxfParserAdapter {
|
|||
|
||||
private _lwPolyline(p: LWPolylineEntity | PolylineEntity, t: ITransform) {
|
||||
const objects = [];
|
||||
for (let i = 0; i < p.vertices.length;) {
|
||||
for (let i = 0; i < p.vertices.length; ) {
|
||||
const curr = p.vertices[i];
|
||||
let next = p.vertices[++i];
|
||||
|
||||
if(p.flag & 1 && !next) {
|
||||
if (p.flag & 1 && !next) {
|
||||
next = p.vertices[0];
|
||||
}
|
||||
if(curr && next) {
|
||||
if(!curr.bulge || curr.bulge === 0) {
|
||||
if (curr && next) {
|
||||
if (!curr.bulge || curr.bulge === 0) {
|
||||
const data: SketchSegmentSerializationData = {
|
||||
a: applyTransformPoint({ x: curr.x, y: curr.y }, t),
|
||||
b: applyTransformPoint({x: next.x, y: next.y}, t)
|
||||
b: applyTransformPoint({ x: next.x, y: next.y }, t),
|
||||
};
|
||||
objects.push(this._createSketchObject(Segment.prototype.TYPE, data));
|
||||
} else {
|
||||
const beta = angle(curr, next);
|
||||
const theta = 4 * Math.atan(curr.bulge);
|
||||
const radius = (Math.hypot(curr.x - next.x, curr.y - next.y) / 2) / Math.sin(theta / 2);
|
||||
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: 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),
|
||||
const data: SketchArcSerializationData = {
|
||||
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));
|
||||
|
|
@ -379,8 +426,8 @@ export class DxfParserAdapter {
|
|||
}
|
||||
|
||||
private _arc(a: ArcEntity, t: ITransform) {
|
||||
const center: IPoint = {x: a.centerX, y: a.centerY};
|
||||
const data: SketchArcSerializationData = {
|
||||
const center: IPoint = { x: a.centerX, y: a.centerY };
|
||||
const data: SketchArcSerializationData = {
|
||||
a: applyTransformPoint(polar(center, rad(a.startAngle), a.radius), t),
|
||||
b: applyTransformPoint(polar(center, rad(a.endAngle), a.radius), t),
|
||||
c: applyTransformPoint(center, t),
|
||||
|
|
@ -391,13 +438,13 @@ export class DxfParserAdapter {
|
|||
private _circle(c: CircleEntity, t: ITransform) {
|
||||
const data: SketchCircleSerializationData = {
|
||||
c: applyTransformPoint({ x: c.centerX, y: c.centerY }, t),
|
||||
r: c.radius
|
||||
r: c.radius,
|
||||
};
|
||||
return this._createSketchObject(Circle.prototype.TYPE, data);
|
||||
}
|
||||
|
||||
private _ellipse(e: EllipseEntity, t: ITransform) {
|
||||
const c: IPoint = applyTransformPoint({x: e.centerX, y: e.centerY}, t);
|
||||
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;
|
||||
|
|
@ -408,8 +455,8 @@ export class DxfParserAdapter {
|
|||
|
||||
private _segment(l: LineEntity, t: ITransform) {
|
||||
const data: SketchSegmentSerializationData = {
|
||||
a: applyTransformPoint({x: l.startX, y: l.startY}, t),
|
||||
b: applyTransformPoint({x: l.endX, y: l.endY}, t)
|
||||
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);
|
||||
}
|
||||
|
|
@ -423,7 +470,7 @@ export class DxfParserAdapter {
|
|||
return new Promise((resolve, reject) => {
|
||||
new Parser()
|
||||
.parse(dxfString)
|
||||
.then(dxfObject => resolve(this._createSketchFormat(dxfObject)))
|
||||
.then(dxfObject => resolve(this._createSketchFormat(dxfObject)))
|
||||
.catch(error => reject(error));
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,19 +15,15 @@ import {
|
|||
LinearDimension,
|
||||
VDimension,
|
||||
} from './shapes/dim';
|
||||
import Vector from 'math/vector';
|
||||
import exportTextData from 'gems/exportTextData';
|
||||
import {
|
||||
AlgNumConstraint,
|
||||
ConstraintSerialization,
|
||||
} from './constr/ANConstraints';
|
||||
import { AlgNumConstraint, ConstraintSerialization } from './constr/ANConstraints';
|
||||
import { SketchGenerator } from './generators/sketchGenerator';
|
||||
import { BoundaryGeneratorSchema } from './generators/boundaryGenerator';
|
||||
import { ShapesTypes } from './shapes/sketch-types';
|
||||
import { SketchObject } from './shapes/sketch-object';
|
||||
import { Label } from 'sketcher/shapes/label';
|
||||
import { DxfWriterAdapter } from './dxf';
|
||||
import { DEG_RAD } from 'math/commons';
|
||||
import { svg } from '@tarikjabiri/dxf/lib/svg';
|
||||
|
||||
export interface SketchFormat_V3 {
|
||||
version: number;
|
||||
|
|
@ -76,11 +72,11 @@ export class IO {
|
|||
|
||||
viewer: Viewer;
|
||||
|
||||
constructor(viewer) {
|
||||
constructor(viewer: Viewer) {
|
||||
this.viewer = viewer;
|
||||
}
|
||||
|
||||
loadSketch(sketchData) {
|
||||
loadSketch(sketchData: string) {
|
||||
return this._loadSketch(JSON.parse(sketchData));
|
||||
}
|
||||
|
||||
|
|
@ -154,12 +150,7 @@ export class IO {
|
|||
} else if (type === VDimension.prototype.TYPE) {
|
||||
skobj = LinearDimension.load(VDimension, obj.id, obj.data, index);
|
||||
} else if (type === LinearDimension.prototype.TYPE) {
|
||||
skobj = LinearDimension.load(
|
||||
LinearDimension,
|
||||
obj.id,
|
||||
obj.data,
|
||||
index
|
||||
);
|
||||
skobj = LinearDimension.load(LinearDimension, obj.id, obj.data, index);
|
||||
} else if (type === DiameterDimension.prototype.TYPE) {
|
||||
skobj = DiameterDimension.load(obj.id, obj.data, index);
|
||||
} else if (type === AngleBetweenDimension.prototype.TYPE) {
|
||||
|
|
@ -201,9 +192,7 @@ export class IO {
|
|||
stage.addConstraint(constraint);
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
console.error(
|
||||
'skipping errant constraint: ' + constr && constr.typeId
|
||||
);
|
||||
console.error('skipping errant constraint: ' + constr && constr.typeId);
|
||||
}
|
||||
}
|
||||
for (const gen of dataStage.generators) {
|
||||
|
|
@ -235,10 +224,7 @@ export class IO {
|
|||
BoundaryGeneratorSchema
|
||||
);
|
||||
|
||||
this.viewer.parametricManager.addGeneratorToStage(
|
||||
boundaryGenerator,
|
||||
this.viewer.parametricManager.groundStage
|
||||
);
|
||||
this.viewer.parametricManager.addGeneratorToStage(boundaryGenerator, this.viewer.parametricManager.groundStage);
|
||||
}
|
||||
|
||||
cleanUpData() {
|
||||
|
|
@ -333,11 +319,7 @@ export class IO {
|
|||
}
|
||||
|
||||
getWorkspaceToExport() {
|
||||
return [
|
||||
this.viewer.layers,
|
||||
[this.viewer.labelLayer],
|
||||
this.viewer.dimLayers
|
||||
];
|
||||
return [this.viewer.layers, [this.viewer.labelLayer], this.viewer.dimLayers];
|
||||
}
|
||||
|
||||
getLayersToExport() {
|
||||
|
|
@ -354,107 +336,26 @@ export class IO {
|
|||
}
|
||||
|
||||
svgExport() {
|
||||
const T = ShapesTypes;
|
||||
const out = new TextBuilder();
|
||||
const adapter = new DxfWriterAdapter();
|
||||
adapter.export(this.getLayersToExport());
|
||||
|
||||
const bbox = new BBox();
|
||||
// TODO: find a better way
|
||||
const bbox = adapter.bbox;
|
||||
const factor = (bbox.maxX - bbox.minX) / 125;
|
||||
adapter.renderer.arrowSize *= factor;
|
||||
adapter.renderer.extensionOffset *= factor;
|
||||
adapter.renderer.extensionOverShoot *= factor;
|
||||
adapter.renderer.textHeight *= factor;
|
||||
|
||||
const a = new Vector();
|
||||
const b = new Vector();
|
||||
adapter.renderer.draw();
|
||||
|
||||
const prettyColors = new PrettyColors();
|
||||
const toExport = this.getLayersToExport();
|
||||
for (let l = 0; l < toExport.length; ++l) {
|
||||
const layer = toExport[l];
|
||||
const color = prettyColors.next();
|
||||
out.fline('<g id="$" fill="$" stroke="$" stroke-width="$">', [
|
||||
layer.name,
|
||||
'none',
|
||||
color,
|
||||
'2',
|
||||
]);
|
||||
for (let i = 0; i < layer.objects.length; ++i) {
|
||||
const obj = layer.objects[i];
|
||||
if (obj.TYPE !== T.POINT) bbox.check(obj);
|
||||
if (obj instanceof Segment) {
|
||||
out.fline('<line x1="$" y1="$" x2="$" y2="$" />', [
|
||||
obj.a.x,
|
||||
obj.a.y,
|
||||
obj.b.x,
|
||||
obj.b.y,
|
||||
]);
|
||||
} else if (obj instanceof Arc) {
|
||||
a.set(obj.a.x - obj.c.x, obj.a.y - obj.c.y, 0);
|
||||
b.set(obj.b.x - obj.c.x, obj.b.y - obj.c.y, 0);
|
||||
const dir = a.cross(b).z > 0 ? 0 : 1;
|
||||
const r = obj.r.get();
|
||||
out.fline('<path d="M $ $ A $ $ 0 $ $ $ $" />', [
|
||||
obj.a.x,
|
||||
obj.a.y,
|
||||
r,
|
||||
r,
|
||||
dir,
|
||||
1,
|
||||
obj.b.x,
|
||||
obj.b.y,
|
||||
]);
|
||||
} else if (obj instanceof Circle) {
|
||||
out.fline('<circle cx="$" cy="$" r="$" />', [
|
||||
obj.c.x,
|
||||
obj.c.y,
|
||||
obj.r.get(),
|
||||
]);
|
||||
// } else if (obj.TYPE === T.DIM || obj.TYPE === T.HDIM || obj.TYPE === T.VDIM) {
|
||||
} else if (obj instanceof EllipticalArc) {
|
||||
a.set(obj.a.x - obj.c.x, obj.a.y - obj.c.y, 0);
|
||||
b.set(obj.b.x - obj.c.x, obj.b.y - obj.c.y, 0);
|
||||
const dir = a.cross(b).z > 0 ? 0 : 1;
|
||||
out.fline('<path d="M $ $ A $ $ $ $ 1 $ $" />', [
|
||||
obj.a.x,
|
||||
obj.a.y,
|
||||
obj.radiusX,
|
||||
obj.radiusY,
|
||||
obj.rotation / DEG_RAD,
|
||||
dir,
|
||||
obj.b.x,
|
||||
obj.b.y
|
||||
]);
|
||||
} else if (obj instanceof Ellipse) {
|
||||
out.fline('<ellipse cx="$" cy="$" rx="$" ry="$" transform="rotate($, $ $)" />', [
|
||||
obj.c.x,
|
||||
obj.c.y,
|
||||
obj.radiusX,
|
||||
obj.radiusY,
|
||||
obj.rotation / DEG_RAD,
|
||||
obj.c.x,
|
||||
obj.c.y,
|
||||
]);
|
||||
} else if (obj instanceof BezierCurve) {
|
||||
out.fline('<path d="M $ $ C $ $ $ $ $ $" />', [
|
||||
obj.a.x,
|
||||
obj.a.y,
|
||||
obj.cp1.x,
|
||||
obj.cp1.y,
|
||||
obj.cp2.x,
|
||||
obj.cp2.y,
|
||||
obj.b.x,
|
||||
obj.b.y
|
||||
]);
|
||||
}
|
||||
}
|
||||
out.line('</g>');
|
||||
}
|
||||
bbox.inc(20);
|
||||
bbox.bbox[2] -= bbox.bbox[0];
|
||||
bbox.bbox[3] -= bbox.bbox[1];
|
||||
return (
|
||||
_format("<svg viewBox='$ $ $ $' transform='scale(1, -1)'>\n", bbox.bbox) + out.data + '</svg>'
|
||||
);
|
||||
return svg(adapter.writer.document);
|
||||
}
|
||||
|
||||
dxfExport() {
|
||||
const adapter = new DxfWriterAdapter();
|
||||
adapter.export(this.getLayersToExport());
|
||||
adapter.renderer.draw();
|
||||
return adapter.stringify();
|
||||
}
|
||||
}
|
||||
|
|
@ -463,8 +364,7 @@ function _format(str, args) {
|
|||
if (args.length == 0) return str;
|
||||
let i = 0;
|
||||
return str.replace(/\$/g, function () {
|
||||
if (args === undefined || args[i] === undefined)
|
||||
throw 'format arguments mismatch';
|
||||
if (args === undefined || args[i] === undefined) throw 'format arguments mismatch';
|
||||
let val = args[i];
|
||||
if (typeof val === 'number') val = val.toPrecision();
|
||||
i++;
|
||||
|
|
@ -474,14 +374,7 @@ function _format(str, args) {
|
|||
|
||||
/** @constructor */
|
||||
function PrettyColors() {
|
||||
const colors = [
|
||||
'#000000',
|
||||
'#00008B',
|
||||
'#006400',
|
||||
'#8B0000',
|
||||
'#FF8C00',
|
||||
'#E9967A',
|
||||
];
|
||||
const colors = ['#000000', '#00008B', '#006400', '#8B0000', '#FF8C00', '#E9967A'];
|
||||
let colIdx = 0;
|
||||
this.next = function () {
|
||||
return colors[colIdx++ % colors.length];
|
||||
|
|
@ -508,19 +401,13 @@ function TextBuilder() {
|
|||
|
||||
/** @constructor */
|
||||
function BBox() {
|
||||
const bbox = [
|
||||
Number.MAX_VALUE,
|
||||
Number.MAX_VALUE,
|
||||
-Number.MAX_VALUE,
|
||||
-Number.MAX_VALUE,
|
||||
];
|
||||
const bbox = [Number.MAX_VALUE, Number.MAX_VALUE, -Number.MAX_VALUE, -Number.MAX_VALUE];
|
||||
|
||||
const T = ShapesTypes;
|
||||
|
||||
this.checkLayers = function (layers) {
|
||||
for (let l = 0; l < layers.length; ++l)
|
||||
for (let i = 0; i < layers[l].objects.length; ++i)
|
||||
this.check(layers[l].objects[i]);
|
||||
for (let i = 0; i < layers[l].objects.length; ++i) this.check(layers[l].objects[i]);
|
||||
};
|
||||
|
||||
this.check = function (obj) {
|
||||
|
|
@ -534,11 +421,7 @@ function BBox() {
|
|||
} else if (obj.TYPE === T.CIRCLE) {
|
||||
this.checkCircBounds(obj.c.x, obj.c.y, obj.r.get());
|
||||
} else if (obj.TYPE === T.ELLIPSE || obj.TYPE === T.ELL_ARC) {
|
||||
this.checkCircBounds(
|
||||
obj.centerX,
|
||||
obj.centerY,
|
||||
Math.max(obj.radiusX, obj.radiusY)
|
||||
);
|
||||
this.checkCircBounds(obj.centerX, obj.centerY, Math.max(obj.radiusX, obj.radiusY));
|
||||
} else if (obj) {
|
||||
obj.accept(o => {
|
||||
if (o.TYPE == T.POINT) {
|
||||
|
|
|
|||
Loading…
Reference in a new issue