mirror of https://gitee.com/cf-fz/WebCAD.git
!2158 功能:保存成DXF文件,命令SaveToDXF
parent
89f02f4662
commit
02b98a635e
@ -0,0 +1,81 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`椭圆参数翻转 1`] = `
|
||||
Array [
|
||||
1900.8937953675368,
|
||||
-1697.6142762620343,
|
||||
0,
|
||||
]
|
||||
`;
|
||||
|
||||
exports[`椭圆参数翻转 2`] = `
|
||||
Array [
|
||||
1991.7988957905598,
|
||||
-1278.079293799722,
|
||||
0,
|
||||
]
|
||||
`;
|
||||
|
||||
exports[`椭圆参数翻转 3`] = `
|
||||
Array [
|
||||
1719.4574938657072,
|
||||
-690.650537442616,
|
||||
0,
|
||||
]
|
||||
`;
|
||||
|
||||
exports[`椭圆参数翻转 4`] = `
|
||||
Array [
|
||||
1187.8947485844765,
|
||||
-159.70582615004992,
|
||||
0,
|
||||
]
|
||||
`;
|
||||
|
||||
exports[`椭圆参数翻转 5`] = `
|
||||
Array [
|
||||
600.1495614910953,
|
||||
111.95200651121627,
|
||||
0,
|
||||
]
|
||||
`;
|
||||
|
||||
exports[`椭圆参数翻转 6`] = `
|
||||
Array [
|
||||
180.72061733106864,
|
||||
20.55890177471008,
|
||||
0,
|
||||
]
|
||||
`;
|
||||
|
||||
exports[`椭圆参数翻转 7`] = `
|
||||
Array [
|
||||
89.81551690804577,
|
||||
-398.976080687602,
|
||||
0,
|
||||
]
|
||||
`;
|
||||
|
||||
exports[`椭圆参数翻转 8`] = `
|
||||
Array [
|
||||
362.1569188328983,
|
||||
-986.404837044708,
|
||||
0,
|
||||
]
|
||||
`;
|
||||
|
||||
exports[`椭圆参数翻转 9`] = `
|
||||
Array [
|
||||
893.7196641141288,
|
||||
-1517.3495483372742,
|
||||
0,
|
||||
]
|
||||
`;
|
||||
|
||||
exports[`椭圆参数翻转 10`] = `
|
||||
Array [
|
||||
1481.4648512075103,
|
||||
-1789.0073809985404,
|
||||
0,
|
||||
]
|
||||
`;
|
@ -0,0 +1,33 @@
|
||||
import { Ellipse } from "../../src/DatabaseServices/Entity/Ellipse";
|
||||
import { Line } from "../../src/DatabaseServices/Entity/Line";
|
||||
import { equaln } from "../../src/Geometry/GeUtils";
|
||||
import { IntersectOption } from "../../src/GraphicsSystem/IntersectWith";
|
||||
import { LoadEntityFromFileData } from '../Utils/LoadEntity.util';
|
||||
|
||||
test('椭圆参数翻转', () =>
|
||||
{
|
||||
let d =
|
||||
{ "file": [2, "Ellipse", 10, 2, 104, 0, 1, 1, 71, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1040.8072063493028, -838.5276872436621, 0, 1], 0, 0, 1, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -935.6208801731591, -1701.2048253468238, 0, 1], 0, 0, 1, 1, 1215.639217876851, 614.2902515010619, 5.498368818682524, 0, 0, "Line", 10, 2, 107, 0, 1, 7, 71, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1], 0, 0, 1, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1], 0, 0, 1, 1, [850.3191623444072, -2510.7929602864897, 0], [435.01033264443686, 871.6945624563377, 0]], "basePt": { "x": 78.50807304852151, "y": -2510.7929602864897, "z": 0 }, "ucs": [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1] };
|
||||
|
||||
let [el, line] = LoadEntityFromFileData(d) as [Ellipse, Line];
|
||||
|
||||
let ipts = el.IntersectWith2(line, IntersectOption.ExtendNone);
|
||||
|
||||
|
||||
for (let d of ipts)
|
||||
{
|
||||
let pt = el.GetPointAtParam(d.thisParam);
|
||||
let param = el.GetParamAtPoint(d.pt);
|
||||
|
||||
expect(pt.equals(d.pt));
|
||||
expect(param).toBe(d.thisParam);
|
||||
}
|
||||
|
||||
for (let i = 0; i < 10; i++)
|
||||
{
|
||||
let p = el.GetPointAtParam(i / 10);
|
||||
expect(p.toArray()).toMatchSnapshot();
|
||||
let param = el.GetParamAtPoint(p);
|
||||
expect(equaln(param, i / 10)).toBeTruthy();
|
||||
}
|
||||
});
|
@ -0,0 +1,333 @@
|
||||
import
|
||||
{
|
||||
AlignedDimension as DxfAlignedDimension, AlignedDimOptions, AngularDimLines, Arc as DxfArc, Circle as DxfCircle, CommonEntityOptions, DiameterDimension as DxfDiameterDimension, DiameterDimOptions, DxfBlock,
|
||||
DxfWriter, Ellipse as DxfEllipse, FaceOptions, Insert, InsertOptions, InvisibleEdgeFlags, Line as DxfLine, LinearDimension as DxfLinearDimension, LinearDimOptions, LWPolyline, LWPolylineOptions, RadialDimension, RadialDimOptions, Text as DxfText, TextOptions
|
||||
} from "dxf-write";
|
||||
import { BufferGeometry, Float32BufferAttribute, Geometry, Matrix4, Vector3 } from "three";
|
||||
import { MathUtils } from "three/src/math/MathUtils";
|
||||
import { ExtrudeHole } from "../../DatabaseServices/3DSolid/ExtrudeHole";
|
||||
import { RevolveSolid } from "../../DatabaseServices/3DSolid/RevolveSolid";
|
||||
import { SweepSolid } from "../../DatabaseServices/3DSolid/SweepSolid";
|
||||
import { LineAngularDimension } from "../../DatabaseServices/Dimension/2LineAngularDimension";
|
||||
import { AlignedDimension } from "../../DatabaseServices/Dimension/AlignedDimension";
|
||||
import { ArcDimension } from "../../DatabaseServices/Dimension/ArcDimension";
|
||||
import { DiameterDimension } from "../../DatabaseServices/Dimension/DiameterDimension";
|
||||
import { LinearDimension } from "../../DatabaseServices/Dimension/LinearDimension";
|
||||
import { RadiusDimension } from "../../DatabaseServices/Dimension/RadiusDimension";
|
||||
import { Arc } from "../../DatabaseServices/Entity/Arc";
|
||||
import { Board } from "../../DatabaseServices/Entity/Board";
|
||||
import { Circle } from "../../DatabaseServices/Entity/Circle";
|
||||
import { CompositeEntity } from "../../DatabaseServices/Entity/CompositeEntity";
|
||||
import { Curve } from "../../DatabaseServices/Entity/Curve";
|
||||
import { Ellipse } from "../../DatabaseServices/Entity/Ellipse";
|
||||
import { Entity } from "../../DatabaseServices/Entity/Entity";
|
||||
import { Line } from "../../DatabaseServices/Entity/Line";
|
||||
import { Polyline } from "../../DatabaseServices/Entity/Polyline";
|
||||
import { Text } from "../../DatabaseServices/Text/Text";
|
||||
import { angle, AsVector3, polar } from "../../Geometry/GeUtils";
|
||||
import { Orbit } from "../../Geometry/Orbit";
|
||||
|
||||
|
||||
|
||||
//任意轴坐标系
|
||||
function MakeMatrix4FromNormal(nor: Vector3)
|
||||
{
|
||||
let x = new Vector3();
|
||||
let y = new Vector3();
|
||||
Orbit.ComputUpDirection(nor, y, x);
|
||||
return new Matrix4().makeBasis(x, y, nor);
|
||||
}
|
||||
|
||||
|
||||
export function Conver2DxfEntity(e: Entity, dxf: DxfWriter, blkName?: string)
|
||||
{
|
||||
let option: CommonEntityOptions = {
|
||||
colorNumber: e.ColorIndex,
|
||||
};//color
|
||||
|
||||
if (e instanceof Line)
|
||||
{
|
||||
option.extrusion = e.Normal;
|
||||
return new DxfLine(e.StartPoint, e.EndPoint, option);
|
||||
}
|
||||
else if (e instanceof Arc)
|
||||
{
|
||||
option.extrusion = e.Normal;
|
||||
|
||||
let mtx = MakeMatrix4FromNormal(option.extrusion as Vector3);//任意轴坐标系
|
||||
let arc = new Arc();
|
||||
arc.IsClockWise = false;
|
||||
arc.ApplyMatrix(mtx);
|
||||
let center = e.Center.applyMatrix4(arc.OCSInv);
|
||||
|
||||
arc.Center = e.Center;
|
||||
let startAngle = MathUtils.radToDeg(arc.GetAngleAtPoint(e.StartPoint));
|
||||
let endAngle = MathUtils.radToDeg(arc.GetAngleAtPoint(e.EndPoint));
|
||||
if (e.IsClockWise) [startAngle, endAngle] = [endAngle, startAngle];
|
||||
|
||||
return new DxfArc(center, e.Radius, startAngle, endAngle, option);
|
||||
}
|
||||
else if (e instanceof Circle)
|
||||
{
|
||||
option.extrusion = e.Normal;
|
||||
let mtx = MakeMatrix4FromNormal(option.extrusion as Vector3);//任意轴坐标系
|
||||
return new DxfCircle(e.Center.applyMatrix4(new Matrix4().getInverse(mtx)), e.Radius, option);
|
||||
}
|
||||
else if (e instanceof Polyline)
|
||||
{
|
||||
let mtx = MakeMatrix4FromNormal(e.Normal);//任意轴坐标系
|
||||
let mtxInv = new Matrix4().getInverse(mtx);
|
||||
let p = e.Position.applyMatrix4(mtxInv);
|
||||
mtx.setPosition(e.Normal.multiplyScalar(p.z));
|
||||
let { pts, buls } = e.MatrixAlignTo2(mtx);
|
||||
|
||||
let plOption = option as LWPolylineOptions;
|
||||
plOption.flags = e.CloseMark ? 1 : 0;
|
||||
plOption.elevation = p.z;
|
||||
plOption.extrusion = e.Normal;
|
||||
|
||||
return new LWPolyline(
|
||||
pts.map((p, index) =>
|
||||
{
|
||||
return { point: p, bulge: buls[index] };
|
||||
}),
|
||||
option
|
||||
);
|
||||
}
|
||||
else if (e instanceof Ellipse)
|
||||
{
|
||||
option.extrusion = e.Normal;
|
||||
let center = e.Center;
|
||||
let x = polar(new Vector3(1), e.Rotation, e.RadX);
|
||||
x.applyMatrix4(e.OCS.setPosition(0, 0, 0));
|
||||
return new DxfEllipse(
|
||||
center,
|
||||
x,
|
||||
e.RadY / e.RadX,
|
||||
e.StartAngle,
|
||||
e.EndAngle,
|
||||
option
|
||||
);
|
||||
}
|
||||
else if (e instanceof LinearDimension)
|
||||
{
|
||||
option.extrusion = e.Normal;
|
||||
let dimOp = option as LinearDimOptions;
|
||||
dimOp.definitionPoint = e.TextPosition;
|
||||
|
||||
let mtx = MakeMatrix4FromNormal(e.Normal);//任意轴坐标系
|
||||
let mtxInv = new Matrix4().getInverse(mtx);
|
||||
|
||||
dimOp.middlePoint = e.TextPosition.applyMatrix4(mtxInv);
|
||||
dimOp.angle = e.Angle;
|
||||
return new DxfLinearDimension(e.FootP1, e.FootP2, option);
|
||||
}
|
||||
else if (e instanceof AlignedDimension)
|
||||
{
|
||||
option.extrusion = e.Normal;
|
||||
let dimOp = option as AlignedDimOptions;
|
||||
|
||||
dimOp.definitionPoint = e.TextPosition;
|
||||
|
||||
let mtx = MakeMatrix4FromNormal(e.Normal);//任意轴坐标系
|
||||
let mtxInv = new Matrix4().getInverse(mtx);
|
||||
dimOp.middlePoint = e.TextPosition.applyMatrix4(mtxInv);
|
||||
|
||||
return new DxfAlignedDimension(e.FootP1, e.FootP2, option);
|
||||
}
|
||||
else if (e instanceof LineAngularDimension)
|
||||
{
|
||||
option.extrusion = e.Normal;
|
||||
return new AngularDimLines(
|
||||
{
|
||||
start: e.L1StartPoint,
|
||||
end: e.L1EndPoint
|
||||
},
|
||||
{
|
||||
start: e.L2StartPoint,
|
||||
end: e.L2EndPoint
|
||||
},
|
||||
e.DimPoint,
|
||||
option
|
||||
);
|
||||
}
|
||||
else if (e instanceof DiameterDimension)
|
||||
{
|
||||
option.extrusion = e.Normal;
|
||||
let dimOpt = option as DiameterDimOptions;
|
||||
dimOpt.definitionPoint = e.Position;
|
||||
|
||||
let mtx = MakeMatrix4FromNormal(e.Normal);//任意轴坐标系
|
||||
let mtxInv = new Matrix4().getInverse(mtx);
|
||||
dimOpt.middlePoint = e.TextPoint.applyMatrix4(mtxInv);
|
||||
return new DxfDiameterDimension(
|
||||
e.DiameterOrRadiusPoint,
|
||||
e.Center,
|
||||
option
|
||||
);
|
||||
}
|
||||
else if (e instanceof RadiusDimension)
|
||||
{
|
||||
option.extrusion = e.Normal;
|
||||
let dimOpt = option as RadialDimOptions;
|
||||
dimOpt.definitionPoint = e.Position;
|
||||
|
||||
let mtx = MakeMatrix4FromNormal(e.Normal);//任意轴坐标系
|
||||
let mtxInv = new Matrix4().getInverse(mtx);
|
||||
dimOpt.middlePoint = e.TextPoint.applyMatrix4(mtxInv);
|
||||
return new RadialDimension(
|
||||
e.DiameterOrRadiusPoint,
|
||||
e.Center,
|
||||
option
|
||||
);
|
||||
}
|
||||
else if (e instanceof ArcDimension)
|
||||
{
|
||||
//弧长标注 在acad中 使用角度标注 然后改TextString就行了
|
||||
}
|
||||
// else 我们暂时没有实现坐标标注
|
||||
else if (e instanceof Board || e instanceof SweepSolid || e instanceof RevolveSolid || e instanceof ExtrudeHole)
|
||||
{
|
||||
let name = blkName ?? `cf${e.Id.Index}`;
|
||||
let block = (dxf as DxfWriter).addBlock(name);
|
||||
|
||||
// if (false)
|
||||
// {
|
||||
// let cu = e.ContourCurve.Clone();
|
||||
// cu.ColorIndex = e.ColorIndex;
|
||||
// Conver2DxfEntity(cu, block);
|
||||
// cu.Move({ x: 0, y: 0, z: e.Thickness });
|
||||
// Conver2DxfEntity(cu, block);
|
||||
// for (let i = 0; i < cu.EndParam; i++)
|
||||
// {
|
||||
// let p = cu.GetPointAtParam(i);
|
||||
// let line = new Line(p, p.clone().setZ(0));
|
||||
// line.ColorIndex = e.ColorIndex;
|
||||
// Conver2DxfEntity(line, block);
|
||||
// }
|
||||
// }
|
||||
DxfBlockDrawLines(e, block);
|
||||
DxfDraw3DFace(e, block);
|
||||
|
||||
option.extrusion = e.Normal;
|
||||
let blockOpt = option as InsertOptions;
|
||||
|
||||
let mtx = MakeMatrix4FromNormal(e.Normal);
|
||||
let mtxInv = new Matrix4().getInverse(mtx);
|
||||
let x = new Vector3().setFromMatrixColumn(e.OCSNoClone, 0);
|
||||
x.applyMatrix4(mtxInv);
|
||||
|
||||
blockOpt.rotationAngle = MathUtils.RAD2DEG * angle(x);
|
||||
return new Insert(name, e.Position.applyMatrix4(mtxInv), option);
|
||||
}
|
||||
else if (e instanceof Text)
|
||||
{
|
||||
option.extrusion = e.Normal;
|
||||
let textOpt = option as TextOptions;
|
||||
|
||||
let mtx = MakeMatrix4FromNormal(e.Normal);
|
||||
let mtxInv = new Matrix4().getInverse(mtx);
|
||||
let x = new Vector3().setFromMatrixColumn(e.OCSNoClone, 0);
|
||||
x.applyMatrix4(mtxInv);
|
||||
|
||||
textOpt.rotation = MathUtils.RAD2DEG * (angle(x) + e.TextRotation);
|
||||
|
||||
return new DxfText(e.Position.applyMatrix4(mtxInv), e.Height, e.TextString, option);
|
||||
}
|
||||
else if (e instanceof CompositeEntity)
|
||||
{
|
||||
let name = blkName ?? `cf${e.Id.Index}`;
|
||||
let block = (dxf as DxfWriter).addBlock(name);
|
||||
|
||||
let subIndex = 0;
|
||||
for (let subE of e.Entitys)
|
||||
{
|
||||
if (subE instanceof Curve)//块内曲线不支持非Z0
|
||||
{
|
||||
let pts = subE.Shape.getPoints(subE.GetDrawCount()).map(AsVector3);
|
||||
for (let p of pts)
|
||||
p.applyMatrix4(subE.OCSNoClone);
|
||||
for (let i = 0; i < pts.length - 1; i++)
|
||||
block.addLine(pts[i], pts[i + 1], { colorNumber: subE.ColorIndex });
|
||||
}
|
||||
else
|
||||
{
|
||||
let subInsert = Conver2DxfEntity(subE, dxf, `${name}_${subIndex}`);
|
||||
if (subInsert)
|
||||
block.addEntity(subInsert);
|
||||
}
|
||||
subIndex++;
|
||||
}
|
||||
|
||||
option.extrusion = e.Normal;
|
||||
let blockOpt = option as InsertOptions;
|
||||
|
||||
let mtx = MakeMatrix4FromNormal(e.Normal);
|
||||
let mtxInv = new Matrix4().getInverse(mtx);
|
||||
let x = new Vector3().setFromMatrixColumn(e.OCSNoClone, 0);
|
||||
x.applyMatrix4(mtxInv);
|
||||
|
||||
blockOpt.rotationAngle = MathUtils.RAD2DEG * angle(x);
|
||||
return new Insert(name, e.Position.applyMatrix4(mtxInv), option);
|
||||
}
|
||||
}
|
||||
|
||||
type Solid3d = Board | SweepSolid | RevolveSolid | ExtrudeHole;
|
||||
|
||||
function DxfBlockDrawLines(en: Solid3d, block: DxfBlock)
|
||||
{
|
||||
if (en instanceof RevolveSolid)
|
||||
return;
|
||||
|
||||
let meshGeo = en.EdgeGeometry;
|
||||
let option: FaceOptions = {
|
||||
colorNumber: en.ColorIndex,
|
||||
};
|
||||
|
||||
let vertices: Vector3[];
|
||||
if (meshGeo instanceof Geometry)
|
||||
vertices = meshGeo.vertices;
|
||||
else
|
||||
{
|
||||
vertices = [];
|
||||
let vers = meshGeo.getAttribute("position") as Float32BufferAttribute;
|
||||
for (let i = 0; i < vers.count; i++)
|
||||
vertices.push(new Vector3(vers.getX(i), vers.getY(i), vers.getZ(i)));
|
||||
}
|
||||
|
||||
for (let i = 0; i < vertices.length / 2; i++)
|
||||
{
|
||||
block.addLine(
|
||||
vertices[i * 2],
|
||||
vertices[i * 2 + 1],
|
||||
option
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function DxfDraw3DFace(en: Solid3d, block: DxfBlock)
|
||||
{
|
||||
let meshGeo = en.MeshGeometry;
|
||||
let option: FaceOptions = {
|
||||
colorNumber: en.ColorIndex,
|
||||
invisibleEdges: InvisibleEdgeFlags.None
|
||||
};
|
||||
|
||||
let geo: Geometry;
|
||||
if (meshGeo instanceof BufferGeometry)
|
||||
geo = new Geometry().fromBufferGeometry(meshGeo);
|
||||
else
|
||||
geo = meshGeo;
|
||||
|
||||
for (let f of geo.faces)
|
||||
{
|
||||
let face3d = block.add3dFace(
|
||||
geo.vertices[f.a],
|
||||
geo.vertices[f.b],
|
||||
geo.vertices[f.c],
|
||||
geo.vertices[f.c],
|
||||
option
|
||||
);
|
||||
face3d.setEdgesVisible(false);
|
||||
}
|
||||
}
|
Loading…
Reference in new issue