合并多段线偏移分支

pull/768274/MERGE
ChenX 6 years ago
commit 2a1d70b99e

@ -9,13 +9,6 @@
"webRoot": "${workspaceRoot}" //,
// "runtimeExecutable": "C:\\Program Files (x86)\\Google\\Chrome\\Application\\chrome.exe"
},
{
"type": "chrome",
"request": "attach",
"name": "Attach to Chrome",
"port": 7778,
"webRoot": "${workspaceRoot}"
},
//Ref: https://github.com/Microsoft/vscode-recipes/blob/master/debugging-jest-tests/.vscode/launch.json
{
"type": "node",

@ -40,7 +40,7 @@ Vector3 {
}
`;
exports[`排序点Xyz 1`] = `
exports[`排序测试 排序点Xyz 1`] = `
Array [
Vector3 {
"x": 6,
@ -75,7 +75,7 @@ Array [
]
`;
exports[`排序点Zx 1`] = `
exports[`排序测试 排序点Zx 1`] = `
Array [
Vector3 {
"x": 6,
@ -110,7 +110,7 @@ Array [
]
`;
exports[`排序点xyz 1`] = `
exports[`排序测试 排序点xyz 1`] = `
Array [
Vector3 {
"x": 1,

@ -143,3 +143,11 @@ Vector3 {
"z": 0,
}
`;
exports[`最近点2 1`] = `
Vector3 {
"x": 10,
"y": 0,
"z": 0,
}
`;

@ -60,15 +60,7 @@ Array [
]
`;
exports[`三维空间圆圆相交测试 5`] = `
Array [
Vector3 {
"x": 2.5,
"y": 0,
"z": 0,
},
]
`;
exports[`三维空间圆圆相交测试 5`] = `Array []`;
exports[`三维空间直线和圆相交测试 1`] = `
Array [
@ -140,9 +132,9 @@ Vector3 {
exports[`三维空间直线相交测试 2`] = `
Vector3 {
"x": 4.75,
"y": 4.75,
"z": 4.75,
"x": 4.5,
"y": 4.5,
"z": 4.5,
}
`;
@ -164,7 +156,7 @@ Vector3 {
exports[`相交测试 2`] = `
Vector3 {
"x": 2.5,
"x": 2,
"y": 0,
"z": 0,
}

@ -129,3 +129,11 @@ test('最近点', () =>
expect(circle.GetClosestPointTo(new Vector3(8, 0, 0), true)/*?*/).toMatchSnapshot();//10,0,0.
});
test('最近点2', () =>
{
let circle = new Circle(new Vector3(5, 0, 0), 5);
let pt = circle.GetClosestPointTo(new Vector3(5), true);
expect(pt).toMatchSnapshot();
});

@ -1,12 +1,12 @@
import * as THREE from 'three';
import { IntersectLAndLFor3D, IntersectCircleAndCircle, IntersectOption } from '../../src/GraphicsSystem/IntersectWith';
import { Vector3 } from 'three';
import { Arc } from '../../src/DatabaseServices/Arc';
import { CADFile } from '../../src/DatabaseServices/CADFile';
import { Curve } from '../../src/DatabaseServices/Curve';
import { Circle } from '../../src/DatabaseServices/Circle';
import { Arc } from '../../src/DatabaseServices/Arc';
import { Curve } from '../../src/DatabaseServices/Curve';
import { Line } from '../../src/DatabaseServices/Line';
import { IntersectCircleAndCircle, IntersectLAndLFor3D, IntersectOption } from '../../src/GraphicsSystem/IntersectWith';
test('相交测试', () =>
{
@ -90,7 +90,19 @@ test('三维空间直线和圆相交测试', () =>
testLineAndCirIntersect(data);
})
test('补充相交测试', () =>
{
let data = [["Line", 1, 1, 2308, false, 7, -1, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1.3934337707580937, 0.039495588796686576, 0, 1], 1, [12.270990240675426, 8.520323796959827, 0], [12.270990240675426, 4.4951100391838885, 0]], ["Arc", 1, 1, 2313, false, 7, -1, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 13.662687223232803, 4.584664645783669, 0, 1], 2, 0.003163048700428762, 6.156784789283385, 3.3367334474492862, true]]
let cus = loadFile(data);
let [cu1, cu2] = cus[0] instanceof Line ? cus : cus.reverse();
let pts = cu1.IntersectWith(cu2, 0);
expect(pts.length).toBe(1);
data = [["Line", 1, 1, 2308, false, 7, -1, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1.3934337707580937, 0.039495588796686576, 0, 1], 1, [12.270990240675426, 8.520323796959827, 0], [12.270990240675426, 4.4951100391838885, 0]], ["Circle", 1, 1, 2320, false, 7, -1, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 13.662687223232803, 4.584664645783669, 0, 1], 1, 0.0031630487004287015]];
cus = loadFile(data);
[cu1, cu2] = cus[0] instanceof Line ? cus : cus.reverse();
pts = cu1.IntersectWith(cu2, 0);
expect(pts.length).toBe(2);
})
function loadFile(data)
{
let file = new CADFile();
@ -116,4 +128,14 @@ function testLineAndCirIntersect(data)
expect(pts).toMatchSnapshot();
}
test('直线和圆 圆心和直线重合的时候', () =>
{
let c = new Circle(new Vector3(0, 0, 0), 1);
let l = new Line(new Vector3(), new Vector3());
let pts = c.IntersectWith(l, IntersectOption.ExtendBoth);
expect(pts.length).toBe(0);
});

@ -164,4 +164,46 @@ describe("", () =>
expect(pl.PtInCurve(p)).toBeFalsy();
});
test('精度过低导致的错误', () =>
{
let f = new CADFile();
f.Data =
[1, ["Polyline", 1, 1, 18237, false, 2, -1, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.7938671363300003, 0.39666461398798525, 0, 1], 2, 5, [12.414545456418505, 8.796498405316765], 0, [12.015990240675425, 8.743859037199755], 0, [12.23362472371057, 8.552710046188702], 0, [12.233990240675425, 8.552758322014249], 0, [12.414545456418505, 8.796498405316765], 0, false]]
let p = new Vector3().fromArray([13.027857377005425, 8.947146562082409, 0]);
f.Read();
let pl = f.ReadObject() as Polyline;
expect(pl.PtInCurve(p)).toBeFalsy();
});
test('圆弧起点切线与直线相切IKOTO', () =>
{
let f = new CADFile();
f.Data =
[1, ["Polyline", 1, 1, 4, false, 2, -1, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 2.1413261486708848, -0.2136470533821324, 0, 1], 2, 5, [376.7856405585377, -104.2720901386406], -0.9999999999999999, [378.6693614887703, -104.2720901386406], 0, [378.4693614887703, -104.2720901386406], 0.9999999999999999, [376.9856405585377, -104.2720901386406], 0, [376.7856405585377, -104.2720901386406], 0, false]]
let p = new Vector3().fromArray([380.6106876374412, -106.61364416876692, 0]);
f.Read();
let pl = f.ReadObject() as Polyline;
expect(pl.PtInCurve(p)).toBeFalsy();
});
test('大圆弧', () =>
{
let f = new CADFile();
f.Data =
[1, ["Polyline", 1, 1, 5, false, 7, -1, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1], 2, 3, [5.113122171945702, 3.235294117647059], 2.037852023242286, [6.69683257918552, 0.7918552036199095], 0, [5.113122171945702, 3.235294117647059], 0, false]]
let p = new Vector3().fromArray([5.113122171945701, 0.7239819004524888, 0]);
f.Read();
let pl = f.ReadObject() as Polyline;
expect(pl.PtInCurve(p)).toBeTruthy();
});
})

@ -0,0 +1,243 @@
import { CADFile } from '../../src/DatabaseServices/CADFile';
import { Polyline } from '../../src/DatabaseServices/Polyline';
import { GetPointAtCurveDir } from '../../src/Common/CurveUtils';
import { Vector3, Vector2 } from 'three';
import { Factory } from '../../src/DatabaseServices/CADFactory';
Factory(Polyline);
test('2个大圆中间', () =>
{
let f = new CADFile();
f.Data =
[1, ["Polyline", 1, 1, 17, false, 7, -1, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1], 2, 3, [108.37693694676932, 28.257776463252547], 0.4472440944881872, [108.37693694676932, 17.68555707305448], 3.5940684866260213, [111.70676982557188, 14.089337563947739], 0.5086040192926764, false]]
f.Read();
let pl = f.ReadObject() as Polyline;
let isR = GetPointAtCurveDir(pl, new Vector3(110.19, 17.4));
expect(isR).toBeFalsy();
let p = new Vector3().fromArray([84.89024786541306, 11.031154321671167, 0]);
isR = GetPointAtCurveDir(pl, p);
expect(isR).toBeTruthy();
});
test('点在端点且端点平行', () =>
{
let f = new CADFile();
f.Data =
[1, ["Polyline", 1, 1, 16, false, 7, -1, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 43.1743189069092, -3.552713678800501e-15, 0, 1], 2, 3, [35.26780526232293, 5.878508963172803], -0.8898689681740283, [35.26780526232293, 13.326990467988661], 0, [35.26780526232293, 23.770222268555234], 0, false]]
f.Read();
let pl = f.ReadObject() as Polyline;
let p = new Vector3(81.8, 12.06);
let isR = GetPointAtCurveDir(pl, p);
expect(isR).toBeTruthy();
});
test('点在和端点平行', () =>
{
let pl = new Polyline();
pl.AddVertexAt(0, new Vector2(0, 0));
pl.AddVertexAt(1, new Vector2(0, 5));
pl.AddVertexAt(2, new Vector2(0, 10));
let p = new Vector3(5, 5, 0);
let isR = GetPointAtCurveDir(pl, p);
expect(isR).toBeTruthy();
});
test('点在端点上且点在圆心上', () =>
{
let f = new CADFile();
f.Data =
[1, ["Polyline", 1, 1, 31, false, 7, -1, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1], 2, 5, [17.513342658829444, 9.06588623278316], 0, [19.513342658829444, 9.06588623278316], 0.9999999999999999, [19.513342658829444, 7.06588623278316], -0.9999999999999999, [19.513342658829444, 5.06588623278316], 0, [17.513342658829444, 5.06588623278316], 0, true]]
f.Read();
let pl = f.ReadObject() as Polyline;
let p = new Vector3(19.48, 8.1097);
let isR = GetPointAtCurveDir(pl, p);
expect(isR).toBeFalsy();
});
test('存在精度误差,并且点在圆内', () =>
{
let f = new CADFile();
f.Data =
[1, ["Polyline", 1, 1, 3, false, 7, -1, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1], 2, 5, [0, 0], 0, [2, 0], 1, [2, 2], -1, [2, 4], 0, [0, 4], 0, true]]
f.Read();
let pl = f.ReadObject() as Polyline;
let p = new Vector3().fromArray([2, 3.8, 0]);
for (let i = 0; i < 5; i++)
{
p.x -= 0.01;
let isR = GetPointAtCurveDir(pl, p);
expect(isR).toBeTruthy();
}
pl.Reverse();
for (let i = 0; i < 10; i++)
{
p.x += 0.01;
let isR = GetPointAtCurveDir(pl, p);
expect(isR).toBeFalsy();
}
});
test('大于1凸度的圆', () =>
{
let f = new CADFile();
f.Data =
[1, ["Polyline", 1, 1, 46, false, 7, -1, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1], 2, 4, [0, 0], 0, [1, 0], 3.7050811739160006, [1, 1.7149500468022372], 0, [0, 1.7149500468022374], 0, true]]
f.Read();
let pl = f.ReadObject() as Polyline;
let pt = new Vector3().fromArray([1.5998555184265881, 0.9127879590514852, 0]);
let isR = GetPointAtCurveDir(pl, pt);
expect(isR).toBeFalsy();
});
test('盲区计算', () =>
{
let f = new CADFile();
f.Data =
[1, ["Polyline", 1, 1, 65, false, 7, -1, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1], 2, 3, [0, 0], 0, [1, 0], 0.6998085535161632, [1, -1], -1.9959956751332304, false]]
f.Read();
let pl = f.ReadObject() as Polyline;
let pt = new Vector3().fromArray([1.3789363811285338, -0.34949587695820905, 0]);
let isR = GetPointAtCurveDir(pl, pt);
expect(isR).toBeFalsy();
pl.Reverse();
isR = GetPointAtCurveDir(pl, pt);
expect(isR).toBeTruthy();
});
test('参数点在终点上', () =>
{
let f = new CADFile();
f.Data =
[1, ["Polyline", 1, 1, 38, false, 7, -1, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1], 2, 9, [26.388805509867886, 5.284389892538414], 0, [28.388805509867886, 5.284389892538414], 0.9999999999999999, [28.388805509867886, 7.284389892538414], -0.9999999999999999, [28.388805509867886, 9.284389892538414], 0, [24.129449189553043, 9.284389892538414], 0, [24.129449189553043, 13.772242014802323], 0, [33.10581078647962, 13.772242014802321], 0, [33.10581078647962, 0.368763303745288], 0, [27.762738407356657, 0.36876330374528865], 0, true]]
f.Read();
let pl = f.ReadObject() as Polyline;
let pt = new Vector3().fromArray([24.40481807693597, 4.679455426066854, 0]);
let isR = GetPointAtCurveDir(pl, pt);
expect(isR).toBeFalsy();
pt = new Vector3().fromArray([30.314368267468268, 10.71117601112483, 0]);
isR = GetPointAtCurveDir(pl, pt);
expect(isR).toBeTruthy();
pl.Reverse();
isR = GetPointAtCurveDir(pl, pt);
expect(isR).toBeFalsy();
pt = new Vector3().fromArray([24.40481807693597, 4.679455426066854, 0]);
isR = GetPointAtCurveDir(pl, pt);
expect(isR).toBeTruthy();
});
test('点在小角内', () =>
{
let f = new CADFile();
f.Data =
[1, ["Polyline", 1, 1, 27, false, 7, -1, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -47.5997122622927, 10.897558314909338, 0, 1], 2, 4, [-0.906131771640112, 6.969061295372345], 3.7897716494829594, [4.660056657223795, 6.487252124645892], 0, [20.106696883852685, 18.393201133144473], 0, [9.169563739376775, 22.583048158640217], 0, false]]
f.Read();
let pl = f.ReadObject() as Polyline;
let pt = new Vector3().fromArray([-45.25245903106504, 20.057300217471017, 0]);
let isR = GetPointAtCurveDir(pl, pt);
expect(isR).toBeFalsy();
pl.Reverse();
isR = GetPointAtCurveDir(pl, pt);
expect(isR).toBeTruthy();
});
test('首尾点相等', () =>
{
let f = new CADFile();
f.Data =
[1, ["Polyline", 1, 1, 264, false, 7, -1, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1], 2, 6, [0, 0], 0, [5, 0], 0.9999999999999999, [5, 5], -0.9999999999999999, [5, 10], 0, [0, 10], 0, [0, 0], 0, false]]
f.Read();
let pl = f.ReadObject() as Polyline;
let pt = new Vector3().fromArray([-0.4662687082606203, -0.5388413229688394, 0]);
let isR = GetPointAtCurveDir(pl, pt);
expect(isR).toBeTruthy();
pl.Reverse();
isR = GetPointAtCurveDir(pl, pt);
expect(isR).toBeFalsy();
});
test('点在圆弧的弦中心上', () =>
{
let f = new CADFile();
f.Data =
[1, ["Polyline", 1, 1, 264, false, 7, -1, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1], 2, 6, [0, 0], 0, [5, 0], 0.9999999999999999, [5, 5], -0.9999999999999999, [5, 10], 0, [0, 10], 0, [0, 0], 0, false]]
f.Read();
let pl = f.ReadObject() as Polyline;
let pt = new Vector3().fromArray([4.999999999999999, 2.5, 0]);
let isR = GetPointAtCurveDir(pl, pt);
expect(isR).toBeFalsy();
pt = new Vector3().fromArray([5, 9.5, 0]);
isR = GetPointAtCurveDir(pl, pt);
expect(isR).toBeTruthy();
pt = new Vector3().fromArray([5, 5.5, 0]);
isR = GetPointAtCurveDir(pl, pt);
expect(isR).toBeTruthy();
pt = new Vector3().fromArray([6, 10, 0]);
isR = GetPointAtCurveDir(pl, pt);
expect(isR).toBeTruthy();
});
test('圆弧过大导致直线小角错误', () =>
{
let f = new CADFile();
f.Data =
[1, ["Polyline", 1, 1, 3, false, 7, -1, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.028011204481791063, 0.028011204481792618, 0, 1], 2, 4, [-2241.358078364921, -214.80916327845875], -1.1401903887488165, [-2190.503423306555, -220.10318099746846], -1.1044015866963386, [-2231.667025600985, -212.01859443849355], 0, [-2241.358078364921, -214.80916327845875], 0, false]]
f.Read();
let pl = f.ReadObject() as Polyline;
let pt = new Vector3().fromArray([-2246.7733894227954, -220.1844621837422, 0]);
let isR = GetPointAtCurveDir(pl, pt);
expect(isR).toBeFalsy();
pt = new Vector3().fromArray([-2184.668414731696, -221.35723534211996, 0]);
//[1,["Circle",1,1,4,false,7,-1,[1,0,0,0,0,1,0,0,0,0,1,0,-2184,-221.357,0,1],1,1]]
isR = GetPointAtCurveDir(pl, pt);
expect(isR).toBeFalsy();
});

@ -0,0 +1,147 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`IKKGK圆与直线补圆弧 1`] = `1`;
exports[`IKKGK圆与直线补圆弧 2`] = `44.998097679646904`;
exports[`IKKGK圆与直线补圆弧 3`] = `1`;
exports[`IKKGK圆与直线补圆弧 4`] = `44.998097679647046`;
exports[`IKKGK圆与直线补圆弧 5`] = `1`;
exports[`IKKGK圆与直线补圆弧 6`] = `52.52605376818708`;
exports[`中间区域需要圆裁剪 1`] = `1`;
exports[`中间区域需要圆裁剪 2`] = `24.711300177428036`;
exports[`圆求交错误导致的线丢失 1`] = `4148.643109243218`;
exports[`圆求交错误导致的线丢失 2`] = `4425.268216257021`;
exports[`圆求交错误导致的线丢失 3`] = `4021.8883370297244`;
exports[`圆求交错误导致的线丢失 4`] = `4581.211434067452`;
exports[`圆求交错误导致的线丢失 5`] = `3900.596094685299`;
exports[`圆求交错误导致的线丢失 6`] = `4757.455448859379`;
exports[`圆求交错误导致的线丢失 7`] = `3783.7370117939813`;
exports[`圆求交错误导致的线丢失 8`] = `4971.999047743294`;
exports[`拱门偏移 1`] = `1`;
exports[`拱门偏移 2`] = `4.314156035548454`;
exports[`拱门偏移 3`] = `1`;
exports[`拱门偏移 4`] = `6.827404319936081`;
exports[`简单图形因为点在线内算法错误导致的丢失 1`] = `8.675026988029915`;
exports[`简单图形因为点在线内算法错误导致的丢失 2`] = `8.252659494518674`;
exports[`简单图形因为点在线内算法错误导致的丢失 3`] = `6.802593049888034`;
exports[`简单图形因为点在线内算法错误导致的丢失 4`] = `6.045525633131274`;
exports[`补圆弧测试 补圆弧测试1 1`] = `1`;
exports[`补圆弧测试 补圆弧测试1 2`] = `202.39234999237357`;
exports[`补圆弧测试 补圆弧测试1 3`] = `1`;
exports[`补圆弧测试 补圆弧测试1 4`] = `202.97100463130596`;
exports[`补圆弧测试 补圆弧测试1 5`] = `1`;
exports[`补圆弧测试 补圆弧测试1 6`] = `203.6334701054305`;
exports[`补圆弧测试 补圆弧测试1 7`] = `1`;
exports[`补圆弧测试 补圆弧测试1 8`] = `204.40220678622498`;
exports[`补圆弧测试 补圆弧测试1 9`] = `1`;
exports[`补圆弧测试 补圆弧测试1 10`] = `205.30911616294793`;
exports[`补圆弧测试 补圆弧测试1 11`] = `1`;
exports[`补圆弧测试 补圆弧测试1 12`] = `206.4013429179738`;
exports[`补圆弧测试 补圆弧测试1 13`] = `1`;
exports[`补圆弧测试 补圆弧测试1 14`] = `207.75214121305123`;
exports[`补圆弧测试 补圆弧测试1 15`] = `1`;
exports[`补圆弧测试 补圆弧测试1 16`] = `209.48307101962268`;
exports[`补圆弧测试 补圆弧测试1 17`] = `1`;
exports[`补圆弧测试 补圆弧测试1 18`] = `211.81505991717293`;
exports[`补圆弧测试 补圆弧测试1 19`] = `1`;
exports[`补圆弧测试 补圆弧测试1 20`] = `215.20865129706962`;
exports[`补圆弧测试 补圆弧测试1 21`] = `1`;
exports[`补圆弧测试 补圆弧测试1 22`] = `220.89085248936073`;
exports[`补圆弧测试 补圆弧测试1 23`] = `1`;
exports[`补圆弧测试 补圆弧测试1 24`] = `243.05075247271324`;
exports[`补圆弧测试 补圆弧测试1 25`] = `1`;
exports[`补圆弧测试 补圆弧测试1 26`] = `236.6991306483004`;
exports[`补圆弧测试 补圆弧测试1 27`] = `1`;
exports[`补圆弧测试 补圆弧测试1 28`] = `236.69932095661932`;
exports[`补圆弧测试 补圆弧测试1 29`] = `1`;
exports[`补圆弧测试 补圆弧测试1 30`] = `205.62990409788847`;
exports[`补圆弧测试 补圆弧测试1 31`] = `1`;
exports[`补圆弧测试 补圆弧测试1 32`] = `198.55214618601138`;
exports[`补圆弧测试 补圆弧测试1 33`] = `1`;
exports[`补圆弧测试 补圆弧测试1 34`] = `195.91344487061264`;
exports[`补圆弧测试 补圆弧测试1 35`] = `1`;
exports[`补圆弧测试 补圆弧测试1 36`] = `194.55183899140644`;
exports[`补圆弧测试 补圆弧测试1 37`] = `1`;
exports[`补圆弧测试 补圆弧测试1 38`] = `193.73991606924534`;
exports[`补圆弧测试 补圆弧测试1 39`] = `1`;
exports[`补圆弧测试 补圆弧测试1 40`] = `193.2116315246781`;
exports[`补圆弧测试 补圆弧测试1 41`] = `1`;
exports[`补圆弧测试 补圆弧测试1 42`] = `192.84670578048616`;
exports[`补圆弧测试 补圆弧测试1 43`] = `1`;
exports[`补圆弧测试 补圆弧测试1 44`] = `192.58324938493251`;
exports[`闭合多段线判断精度和重复交点参数导致偏移丢失 1`] = `54789.14760701891`;
exports[`闭合多段线判断精度和重复交点参数导致偏移丢失 2`] = `54907.17933624483`;
exports[`闭合多段线判断精度和重复交点参数导致偏移丢失 3`] = `55497.39792073307`;
exports[`闭合多段线判断精度和重复交点参数导致偏移丢失 4`] = `56678.13326318633`;
exports[`闭合多段线判断精度和重复交点参数导致偏移丢失 5`] = `57859.26303559798`;

@ -0,0 +1,19 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`多段线 优化参数在端点上的时候 1`] = `
Vector3 {
"x": 0,
"y": 0,
"z": 0,
}
`;
exports[`多段线 存在大圆弧的多段线面积 1`] = `-24.019436375469752`;
exports[`多段线 最近点精度 1`] = `
Vector3 {
"x": 1.987500976448074,
"y": 3.9999218841540816,
"z": 0,
}
`;

@ -0,0 +1,835 @@
import { Factory } from "../../src/DatabaseServices/CADFactory";
import { CADFile } from "../../src/DatabaseServices/CADFile";
import { Curve } from "../../src/DatabaseServices/Curve";
import { Polyline } from "../../src/DatabaseServices/Polyline";
Factory(Polyline);
function loadFile(data)
{
let file = new CADFile();
file.Data = data;
let cus: Curve[] = [];
let count = file.Read();
for (let i = 0; i < count; i++)
{
cus.push(file.ReadObject(undefined) as Curve);
}
return cus;
}
function EntityToMatchSnapshot(ens: Curve[])
{
expect(ens.length).toMatchSnapshot();
for (let c of ens)
{
expect(c.Length).toMatchSnapshot();
}
}
test('IKKGK圆与直线补圆弧', () =>
{
let f = new CADFile();
f.Data =
[1, ["Polyline", 1, 1, 5, false, 7, -1, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -47.808747539346534, 10.92028558763661, 0, 1], 2, 3, [-0.906131771640112, 6.969061295372345], 3.7897716494829594, [4.660056657223795, 6.487252124645892], 0, [18.466397865202012, 17.128892766521286], 0, false]]
f.Read();
let pl = f.ReadObject() as Polyline;
//负1 左边. 禁止补圆弧
let cus = pl.GetOffsetCurves(-1);
EntityToMatchSnapshot(cus);
pl.GetOffsetCurves(-5.654208780429431);
//
//翻转曲线后测试
pl.Reverse();
cus = pl.GetOffsetCurves(1);
EntityToMatchSnapshot(cus);
//圆丢失的问题
cus = pl.GetOffsetCurves(-1.926388985025112);
EntityToMatchSnapshot(cus);
});
describe("闭合多段线", () =>
{
test('闭合多段线偏移测试1', () =>
{
let data =
[1, ["Polyline", 1, 1, 3, false, 7, -1, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1], 2, 4, [6.059716713881022, 3.983456090651555], 1.1217395195062214, [6.383002832861191, 4.064022662889515], 0, [4.929178470254959, 8.399433427762037], 1.2642365052895204, [5.750708215297452, 4.050991501416427], 0.7171789779484218, true]]
let cus = loadFile(data);
for (let i = 1; i < 10; i += 1)
{
expect(cus[0].GetOffsetCurves(i).length).toBe(1);
}
for (let i = -0.5; i < -0.15; i += 0.05)
{
expect(cus[0].GetOffsetCurves(i).length).toBe(1);
}
for (let i = 2; i < 10; i += 2)
{
expect(cus[0].GetOffsetCurves(-i).length).toBe(0);
}
})
test('闭合多段线偏移测试2', () =>
{
let data =
[1, ["Polyline", 1, 1, 734, false, 7, -1, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1], 2, 4, [8.176442643449754, 4.003694129881114], 0.6482011490054378, [8.554554536583165, 4.090460859042256], 0, [7.7292787370841225, 8.733182129315965], 0, [7.8227800907745895, 4.037582052934876], 1.223388515290821, true]]
let cus = loadFile(data);
expect(cus[0].GetOffsetCurves(-0.1799).length).toBe(2);
for (let i = 0.2; i < 10; i += 2)
{
expect(cus[0].GetOffsetCurves(i).length).toBe(1);
}
for (let i = -0.17; i < 0; i += 0.03)
{
expect(cus[0].GetOffsetCurves(i).length).toBe(1);
}
for (let i = -0.2; i > -0.34; i -= 0.02)
{
expect(cus[0].GetOffsetCurves(i).length).toBe(1);
}
for (let i = 0.35; i < 0.5; i += 0.05)
{
expect(cus[0].GetOffsetCurves(-i).length).toBe(0);
}
})
test('闭合多段线偏移测试3', () =>
{
let data =
[1, ["Polyline", 1, 1, 1172, false, 7, -1, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1], 2, 5, [12.52535684411379, 4.512623511896158], 0.39558516940595195, [13.121416971132648, 4.487590129452889], 0, [12.414545456418505, 8.796498405316765], 0, [12.015990240675425, 8.743859037199755], 0, [12.015990240675425, 4.4951100391838885], 0.8508932598252141, true]]
let cus = loadFile(data);
for (let i = 0.5; i < 10; i += 1)
{
expect(cus[0].GetOffsetCurves(i).length).toBe(1);
}
for (let i = 0.1; i <= 0.5; i += 0.01)
{
expect(cus[0].GetOffsetCurves(-i).length).toBe(1);
}
for (let i = 0.51; i <= 1; i += 0.1)
{
expect(cus[0].GetOffsetCurves(-i).length).toBe(0);
}
})
test('闭合多段线偏移测试4', () =>
{
let data =
[1, ["Polyline", 1, 1, 1453, false, 7, -1, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1], 2, 5, [17.138593827490823, 4.9429359111242475], 0.6262511063576436, [18.12066066115083, 4.8347623552068075], 0, [18.12066066115083, 10.450468898178228], 0, [16.250318720818097, 10.450468898178228], 0, [16.250318720818097, 4.952028938447833], 0.8739221457690426, true]];
let cus = loadFile(data);
for (let i = 1; i < 10; i += 2)
{
expect(cus[0].GetOffsetCurves(i).length).toBe(1);
}
for (let i = 0.4; i <= 0.6; i += 0.02)
{
expect(cus[0].GetOffsetCurves(-i).length).toBe(1);
}
for (let i = 1; i <= 2; i += 0.2)
{
expect(cus[0].GetOffsetCurves(-i).length).toBe(0);
}
//变换曲线顺序
data = [1, ["Polyline", 1, 1, 1891, false, 7, -1, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1], 2, 5, [22.178278439318607, -1.9155229050126357], 0, [22.83746943877066, -1.800164480108526], 0, [23.79329638797614, -6.11786552651948], -0.871731137783436, [23.348342463346004, -6.282663276382493], -0.7430788314178012, [22.903388538715866, -6.267501883395095], 0, true]];
cus = loadFile(data);
for (let i = 0.01; i <= 0.33; i += 0.03)
{
expect(cus[0].GetOffsetCurves(i).length).toBe(1);
}
for (let i = 0.34; i <= 1; i += 0.1)
{
expect(cus[0].GetOffsetCurves(i).length).toBe(0);
}
})
test('闭合多段线偏移测试5', () =>
{
let data =
[1, ["Polyline", 1, 1, 264, false, 7, -1, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1], 2, 6, [0, 0], 0, [5, 0], 0.9999999999999999, [5, 5], -0.9999999999999999, [5, 10], 0, [0, 10], 0, [0, 0], 0, false]];
let cus = loadFile(data);
for (let i = 0.5; i < 10; i += 1.5)
{
expect(cus[0].GetOffsetCurves(i).length).toBe(1);
}
expect(cus[0].GetOffsetCurves(-1.3).length).toBe(2);
expect(cus[0].GetOffsetCurves(-1.2).length).toBe(1);
expect(cus[0].GetOffsetCurves(-2).length).toBe(1);
for (let i = 2; i <= 2.8; i += 0.1)
{
expect(cus[0].GetOffsetCurves(-i).length).toBe(1);
}
for (let i = 2.9; i <= 6; i += 0.5)
{
let len = cus[0].GetOffsetCurves(-i).length;
expect(len).toBe(0);
}
//反转曲线
cus[0].Reverse();
for (let i = 0.5; i < 10; i += 1.5)
{
expect(cus[0].GetOffsetCurves(-i).length).toBe(1);
}
expect(cus[0].GetOffsetCurves(1.3).length).toBe(2);
expect(cus[0].GetOffsetCurves(1.2).length).toBe(1);
expect(cus[0].GetOffsetCurves(2).length).toBe(1);
for (let i = 2; i <= 2.8; i += 0.2)
{
expect(cus[0].GetOffsetCurves(i).length).toBe(1);
}
for (let i = 2.9; i <= 6; i += 1)
{
let len = cus[0].GetOffsetCurves(i).length;
expect(len).toBe(0);
}
})
test('闭合多段线偏移测试6', () =>
{
let data =
[1, ["Polyline", 1, 1, 11080, false, 7, -1, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -2.007355593658339, -15.226898894860806, 0, 1], 2, 6, [0.06393073988345588, -13.474722415885717], 0, [0.06393073988345643, -4.4950563800695225], 0, [6.069811270331949, -4.495056380069524], -0.9999999999999999, [6.0698112703319484, -9.101508437403805], 0.8261854469247998, [6.069811270331948, -13.53303193559881], 0, [0.06393073988345588, -13.474722415885717], 0, false]];
let cus = loadFile(data);
for (let i = 0.5; i < 10; i += 0.5)
{
expect(cus[0].GetOffsetCurves(-i).length).toBe(1);
}
for (let i = 0.1; i <= 2.9; i += 0.1)
{
expect(cus[0].GetOffsetCurves(i).length).toBe(1);
}
for (let i = 3; i <= 6; i += 0.1)
{
let len = cus[0].GetOffsetCurves(i).length;
expect(len).toBe(0);
}
})
test('闭合多段线偏移测试7', () =>
{
let data =
[1, ["Polyline", 1, 1, 3103, false, 7, -1, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1], 2, 6, [7.068575921553821, 19.385189367549113], 0, [17.866251977281493, 27.179961431447197], -0.7242773730087224, [27.449988121418478, 20.215779833374317], -0.5496546648274403, [21.06083069199382, 18.554598901723907], 0.7351204491094537, [17.802360402987244, 16.70174324719076], -1.609719383557213, [7.068575921553821, 19.385189367549113], 0, true]];
let cus = loadFile(data);
//外偏移
for (let i = 0.5; i < 5.5; i += 1)
{
expect(cus[0].GetOffsetCurves(-i).length).toBe(1);
}
//内偏移
for (let i = 3.6; i > 0; i -= 0.6)
{
expect(cus[0].GetOffsetCurves(i).length).toBe(1);
}
for (let i = 3.7; i <= 4.7; i += 0.2)
{
expect(cus[0].GetOffsetCurves(i).length).toBe(2);
}
expect(cus[0].GetOffsetCurves(5).length).toBe(1);
for (let i = 6.1; i < 10; i += 1)
{
expect(cus[0].GetOffsetCurves(i).length).toBe(0);
}
})
test('闭合多段线偏移测试8', () =>
{
let data =
[1, ["Polyline", 1, 1, 8895, false, 7, -1, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1], 2, 9, [-35.77751476623335, 275.4953263952156], 0, [220.87993293360785, 358.6317790975911], 0, [317.8724610863793, 154.43698298649332], 0, [128.26300755464567, 91.72000989522755], 0, [202.6482547094027, 193.81740795077644], 0, [96.90452100901277, 149.33211308371583], 0, [167.64343251892882, 238.30270281783706], 0, [-5.9221441755043855, 147.87357882577945], 0, [115.1361992332179, 265.2855865896607], 0, true]];
let cus = loadFile(data);
//外偏移 -
for (let i = 20; i < 200; i += 100)
{
expect(cus[0].GetOffsetCurves(-i).length).toBe(1);
}
//内偏移+
expect(cus[0].GetOffsetCurves(15).length).toBe(1);
expect(cus[0].GetOffsetCurves(17.8).length).toBe(2);
expect(cus[0].GetOffsetCurves(19).length).toBe(3);
for (let i = 20; i <= 40; i += 10)
{
expect(cus[0].GetOffsetCurves(i).length).toBe(3);
}
for (let i = 41.3; i <= 44.3; i += 1)
{
expect(cus[0].GetOffsetCurves(i).length).toBe(2);
}
expect(cus[0].GetOffsetCurves(45).length).toBe(1);
for (let i = 50; i <= 250; i += 100)
{
expect(cus[0].GetOffsetCurves(i).length).toBe(0);
}
})
test('闭合多段线偏移测试9', () =>
{
let data =
[1, ["Polyline", 1, 1, 12283, false, 2, -1, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -2494.1602062139054, -154.37421492307953, 0, 1], 2, 4, [-835.9056689963722, -81.71614968554674], -1.404257507243489, [-2.5205246091134654, -224.3682931983378], -0.7704346688180675, [-677.9527382520764, -55.635630094036955], 0, [-835.9056689963722, -81.71614968554674], 0, false]];
let cus = loadFile(data);
//外偏移 -
//内偏移+
for (let i = -350; i <= 350; i += 100)
{
expect(cus[0].GetOffsetCurves(i).length).toBe(1);
}
for (let i = 360; i <= 460; i += 50)
{
expect(cus[0].GetOffsetCurves(i).length).toBe(0);
}
cus[0].Reverse();
for (let i = -350; i <= 350; i += 100)
{
expect(cus[0].GetOffsetCurves(-i).length).toBe(1);
}
for (let i = 360; i <= 460; i += 50)
{
expect(cus[0].GetOffsetCurves(-i).length).toBe(0);
}
})
test('闭合多段线偏移测试10', () =>
{
let data =
[1, ["Polyline", 1, 1, 4133, false, 7, -1, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -38.7066882611841, -36.73336766355714, 0, 1], 2, 10, [57.916496677407835, -1.0361149153581897], 0, [57.916496677407835, 9.149866136686853], 0, [63.00948720343037, 6.40233177396418], 0, [67.96845166297861, 11.696361399698116], 0, [67.96845166297861, 5.866227508067071], 0, [76.41209385085804, 8.144670638129776], -0.6438035714487224, [82.13500688930966, 1.215523001409662], -0.16133386709235895, [73.7315725213725, -7.388950466238915], -0.24328993833238707, [62.473382937533245, -7.388950466238914], 0.16864648307761998, [53.5472469103464, -6.102300228085856], -1.9523252757782097, true]];
let cus = loadFile(data);
//外偏移 -
for (let i = 5; i < 20; i += 5)
{
expect(cus[0].GetOffsetCurves(-i).length).toBe(1);
}
//内偏移+
expect(cus[0].GetOffsetCurves(2.3).length).toBe(1);
for (let i = 2.5; i < 4; i += 1)
{
expect(cus[0].GetOffsetCurves(i).length).toBe(2);
}
for (let i = 4.2; i <= 7.2; i += 0.8)
{
expect(cus[0].GetOffsetCurves(i).length).toBe(1);
}
for (let i = 7.5; i <= 17.5; i += 5)
{
expect(cus[0].GetOffsetCurves(i).length).toBe(0);
}
})
test('闭合多段线偏移测试11', () =>
{
let data =
[1, ["Polyline", 1, 1, 109, false, 7, -1, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1], 2, 9, [8.533519553072624, 3.044692737430166], 0, [8.198324022346368, 5.782122905027932], 0, [9.483240223463685, 4.594972067039105], 0, [10.293296089385473, 4.958100558659217], 0, [11.298882681564244, 3.50558659217877], 0, [11.648044692737429, 3.1424581005586587], 0, [9.525139664804467, 2.3324022346368705], 0, [9.748603351955305, 3.589385474860334], 0, [8.519553072625698, 1.3268156424580995], 0, true]];
let cus = loadFile(data);
//外偏移 -
for (let i = 0.1; i <= 0.3; i += 0.1)
{
expect(cus[0].GetOffsetCurves(-i).length).toBe(1);
}
//内偏移+
expect(cus[0].GetOffsetCurves(0.15).length).toBe(1);
for (let i = 0.2; i <= 0.7; i += 0.1)
{
expect(cus[0].GetOffsetCurves(i).length).toBe(2);
}
for (let i = 0.8; i <= 3.8; i++)
{
expect(cus[0].GetOffsetCurves(i).length).toBe(0);
}
})
test('闭合多段线偏移测试12', () =>
{
let data =
[1, ["Polyline", 1, 1, 4132, false, 7, -1, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1], 2, 12, [13.549363225511495, 3.33570646745377], 0, [14.34284463241268, 4.996139781895137], 0, [14.523074259257426, 3.9557232996550056], 0, [15.838887129162556, 4.9814356943054605], 0, [15.943612070431213, 3.9627476292376005], 0, [17.33950450111622, 4.461280640196535], 0, [18.123624596131165, 2.7156799524846913], 0, [17.99903152781382, 1.6177035379380693], 0, [16.03466125512531, 2.900960499995888], 0, [15.014220997727234, 1.7794865537465168], 0, [14.332835411729478, 2.6268506799232134], 0, [13.549363225511495, 3.33570646745377], 0, false]];
let cus = loadFile(data);
//外偏移 -
for (let i = 0.5; i <= 2; i += 0.5)
{
expect(cus[0].GetOffsetCurves(-i).length).toBe(1);
}
//内偏移+
expect(cus[0].GetOffsetCurves(0.3).length).toBe(1);
expect(cus[0].GetOffsetCurves(0.4).length).toBe(2);
expect(cus[0].GetOffsetCurves(0.46).length).toBe(3);
expect(cus[0].GetOffsetCurves(0.5).length).toBe(2);
expect(cus[0].GetOffsetCurves(0.9).length).toBe(1);
for (let i = 0.55; i <= 0.85; i++)
{
expect(cus[0].GetOffsetCurves(i).length).toBe(2);
}
for (let i = 1; i <= 2; i += 0.2)
{
expect(cus[0].GetOffsetCurves(i).length).toBe(0);
}
})
test('闭合多段线偏移测试13', () =>
{
let data =
[1, ["Polyline", 1, 1, 2689, false, 7, -1, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 13.053732578466253, -1.845982384833612, 0, 1], 2, 12, [10.73237450059647, 5.925995426719515], 0, [14.934000173256667, 9.279899014962986], 0, [15.443475259425389, 6.338838290261696], 0, [16.902963217271246, 7.476549375511614], 0, [17.07910144494388, 5.7632047972414195], 0, [18.04054823840169, 6.106578652047782], 0, [19.469515702452366, 2.925424892792106], 0, [19.064111106000592, -0.6472031134391991], 0, [17.253277279358528, 2.956832838161076], 0, [14.95258895308757, 3.1324290048358128], 0, [13.37431523183268, 1.7225442000746034], 0, [10.73237450059647, 5.925995426719515], 0, false]];
let cus = loadFile(data);
//外偏移 -
for (let i = 0.5; i <= 2; i += 0.5)
{
expect(cus[0].GetOffsetCurves(-i).length).toBe(1);
}
//内偏移+
expect(cus[0].GetOffsetCurves(1).length).toBe(1);
expect(cus[0].GetOffsetCurves(1.2).length).toBe(3);
})
test('闭合多段线偏移测试14', () =>
{
let data =
[1, ["Polyline", 1, 1, 1625, false, 7, -1, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1], 2, 14, [340.820007357324, -3.870032999900914], 0, [431.6163856609081, 116.2815653567217], 0, [485.54806901416487, 54.84040710617603], 0, [533.3356365423672, 67.81131829240235], 0, [624.1320148459513, 40.504136847715344], 0, [656.9006325795757, 23.43714844478601], -0.783383849320176, [633.0068488154745, -74.86870475608706], 0.4462700081240285, [605.0169878346704, -106.27196341747704], -0.8416099256631104, [529.9222388617812, -128.11770857322662], 0, [510.1245323143834, -22.98506001118185], 0, [430.251026588674, -129.48306764546098], 0, [430.251026588674, -65.99387078656383], 0, [351.74287993519897, -145.86737651227318], 0, [303.2726328708796, -87.83961594231337], 0, true]];
let cus = loadFile(data);
//外偏移 -
for (let i = 10; i <= 90; i += 10)
{
expect(cus[0].GetOffsetCurves(-i).length).toBe(1);
}
//内偏移+
for (let i = 5; i <= 25; i += 10)
{
expect(cus[0].GetOffsetCurves(i).length).toBe(1);
}
expect(cus[0].GetOffsetCurves(26.5).length).toBe(2);
expect(cus[0].GetOffsetCurves(36).length).toBe(2);
expect(cus[0].GetOffsetCurves(36.1).length).toBe(3);
expect(cus[0].GetOffsetCurves(45).length).toBe(2);
expect(cus[0].GetOffsetCurves(60).length).toBe(1);
for (let i = 71; i <= 101; i += 10)
{
expect(cus[0].GetOffsetCurves(i).length).toBe(0);
}
})
test('闭合多段线偏移测试15', () =>
{
let data =
[1, ["Polyline", 1, 1, 394, false, 7, -1, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1], 2, 8, [-3.096429035694039, 1.977370035127478], 0, [2.646251476487261, 5.186031066288948], -0.5113280232193118, [8.158566581303122, 2.619102241359773], 0.23700604598013766, [11.103952861189804, -1.2148363240793185], -1.4842976346055852, [7.994019861756378, -4.028585228328609], 0.5402454464135219, [3.1398916351274853, -2.8932128634560885], -1.0879771453350477, [1.4615150957507161, -0.803469525212464], -0.082022192610066, [-3.096429035694039, 1.977370035127478], 0, true]];
let cus = loadFile(data);
//外偏移 -
for (let i = 0.5; i <= 5.5; i += 1)
{
expect(cus[0].GetOffsetCurves(-i).length).toBe(1);
}
//内偏移+
for (let i = 0.1; i <= 1.8; i += 0.3)
{
expect(cus[0].GetOffsetCurves(i).length).toBe(1);
}
for (let i = 1.9; i <= 2.2; i += 0.05)
{
expect(cus[0].GetOffsetCurves(i).length).toBe(2);
}
for (let i = 2.3; i <= 3.7; i += 0.2)
{
expect(cus[0].GetOffsetCurves(i).length).toBe(1);
}
for (let i = 3.9; i <= 6.9; i += 0.5)
{
expect(cus[0].GetOffsetCurves(i).length).toBe(0);
}
})
test('闭合多段线偏移测试16', () =>
{
let data =
[1, ["Polyline", 1, 1, 4, false, 7, -1, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1], 2, 5, [-6.203966005665723, -0.056657223796033884], 0, [-1.8834846458923415, -0.923353563739375], -1.4125691360015384, [-1.9069913201133035, -1.5932937790368253], 0, [-6.189801699716714, -2.2096317280453257], -2.3881275241710798, [-6.203966005665723, -0.056657223796033884], 0, true]];
let cus = loadFile(data);
//外偏移 -
//内偏移+
for (let i = -1.5; i <= 1.5; i += 0.2)
{
expect(cus[0].GetOffsetCurves(i).length).toBe(1);
}
expect(cus[0].GetOffsetCurves(1.6).length).toBe(0);
for (let i = 1.6; i <= 4.6; i++)
{
expect(cus[0].GetOffsetCurves(i).length).toBe(0);
}
})
})
describe("补圆弧测试", () =>
{
test("补圆弧测试1", () =>
{
let data =
[1, ["Polyline", 1, 1, 8815, false, 7, -1, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1], 2, 5, [-99.60068327971061, 80.69599512140186], 0, [-48.362234971168355, 80.69599512140186], -0.9874208089640422, [-14.972250883848176, 88.46675505445091], -1.1745224194600496, [18.29631507951812, 78.51046889023182], 0, [89.44733571649859, 78.5104688902318], 0, false]];
let cus = loadFile(data);
// 向上-
// 向下+
expect(cus[0].GetOffsetCurves(17.45).length).toBe(2);
for (let i = -55; i <= 55; i += 5)
{
if (i === 0) continue;
EntityToMatchSnapshot(cus[0].GetOffsetCurves(i));
}
})
test("补圆弧测试2", () =>
{
let data =
[1, ["Polyline", 1, 1, 12266, false, 7, -1, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1], 2, 5, [-869.4193524531552, -50.92359793870933], 0, [-609.861025770732, -50.92359793870939], -0.8167984427288847, [-480.7149315189898, -23.068558002059024], -1.4042575072434897, [-317.9835774160859, -50.92359793870939], 0, [-92.77019349218811, -50.92359793870939], 0, false]];
let cus = loadFile(data);
// 向上-
// 向下+
expect(cus[0].GetOffsetCurves(83.24).length).toBe(2);
expect(cus[0].GetOffsetCurves(86.46).length).toBe(2);
for (let i = 364; i <= 395; i++)
{
expect(cus[0].GetOffsetCurves(i).length).toBe(1);
}
})
test("补圆弧测试3", () =>
{
let data =
[1, ["Polyline", 1, 1, 12272, false, 7, -1, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1], 2, 4, [-894.3165541673695, -331.80629190023], 0, [-671.3300245231958, -331.80629190023], -1.0058680701224356, [-535.7124860261546, -329.1982623137485], 0, [-214.92484688892245, -329.1982623137485], 0, false]];
let cus = loadFile(data);
// 向上-
// 向下+
expect(cus[0].GetOffsetCurves(-1200).length).toBe(1);
for (let i = 63; i <= 94; i++)
{
expect(cus[0].GetOffsetCurves(i).length).toBe(1);
}
})
test("补圆弧测试3", () =>
{
let data =
[1, ["Polyline", 1, 1, 195, false, 7, -1, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1], 2, 23, [-25.572010711696727, -62.383195892823124], 0, [-10.312959798454724, -40.55427583637971], 0, [0.28360333574111785, -55.81332674962171], 0, [9.820510156517361, -48.18380129300071], 0, [18.721623189241864, -65.13830230771404], 0, [29.530117586121616, -60.47581452866788], 0, [39.06702440689787, -79.97349069558823], 0, [51.78290016793288, -70.64851513749588], -0.6227891115113805, [70.85671380948538, -80.60928448363998], 0.3759603135798005, [86.75155851077912, -99.68309812519247], -1.1383492019405204, [81.45327694368122, -117.6972554533254], 0.6271394112393051, [57.2931129977147, -138.2545879336653], -1.2933960333754264, [21.68866086681669, -138.2545879336653], -0.8106183277649434, [-17.73055399239181, -132.9563063665674], 0, [-43.37423677714574, -105.82910474302606], 0, [-51.003762233766736, -83.5763221612148], 0, [-48.67251834424364, -64.07864599429448], 0, [-62.65998168138215, -50.09118265715597], 0, [-86.39628310198083, -65.35023357039795], 0, [-86.39628310198083, -33.13668164244262], 0, [-73.68040734094582, -13.639005475522275], 0, [-43.16230551446182, -13.639005475522275], 0, [-33.62539869368556, -11.307761585999202], 0, false]];
let cus = loadFile(data);
// 向外-
// 向内+
expect(cus[0].GetOffsetCurves(18).length).toBe(3);
for (let i = 50; i <= 80; i += 5)
{
expect(cus[0].GetOffsetCurves(-i).length).toBe(1);
}
//需要删除一个无效的线段 ref #IKO6L
expect(cus[0].GetOffsetCurves(27.3).length).toBe(1);
})
test("补圆弧测试3", () =>
{
let data =
[1, ["Polyline", 1, 1, 3, false, 7, -1, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1], 2, 10, [-5.637393767705383, -1.586402266288952], 0, [-0.84985835694051, 1.954674220963173], -0.5207626681247078, [1.728045325779038, 1.0906515580736542], -1.2136457904456304, [4.060938624362605, 1.3838754084985838], -1.0694858869096764, [6.891142200566573, -0.047681051558073895], -1.4716493502287318, [9.178341602266286, -2.976612659490083], -1.5003222663355726, [8.09233325325779, -7.040916632294616], -0.9628743606456998, [4.53257790368272, -7.478753541076488], -1.076087427994497, [2.3229461756373926, -7.478753541076488], 0, [-5.39660056657224, -7.478753541076487], 0, false]];
let cus = loadFile(data);
// 向外-
// 向内+
expect(cus[0].GetOffsetCurves(1.88).length).toBe(2);
expect(cus[0].GetOffsetCurves(2.12).length).toBe(2);
expect(cus[0].GetOffsetCurves(3.2).length).toBe(1);
for (let i = 0.5; i <= 3.5; i += 0.5)
{
expect(cus[0].GetOffsetCurves(-i).length).toBe(1);
}
for (let i = 3.3; i <= 5.3; i += 0.5)
{
expect(cus[0].GetOffsetCurves(i).length).toBe(0);
}
for (let i = 2.33; i <= 3.2; i += 0.2)
{
expect(cus[0].GetOffsetCurves(i).length).toBe(1);
}
})
})
describe("不规则不闭合多段线测试", () =>
{
test("test1", () =>
{
let data =
[1, ["Polyline", 1, 1, 3135, false, 7, -1, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1], 2, 6, [16.034190840579708, -16.545186318840567], 0, [36.985943188405784, -16.545186318840567], 0, [31.311510260869554, -12.507609043478254], 0, [48.334809043478245, -12.507609043478254], 0, [43.969860637681144, -16.6543100289855], 0, [56.84645843478259, -16.654310028985503], 0, false]];
let cus = loadFile(data);
for (let i = 1.27; i <= 2.96; i += 0.2)
{
expect(cus[0].GetOffsetCurves(i).length).toBe(2);
}
expect(cus[0].GetOffsetCurves(9.16).length).toBe(2);
for (let i = 0.5; i <= 7.5; i++)
{
expect(cus[0].GetOffsetCurves(-i).length).toBe(1);
}
})
test("test2-共线线段", () =>
{
let data =
[1, ["Polyline", 1, 1, 8814, false, 7, -1, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1], 2, 7, [15.642409533480423, -31.01626057276902], 0, [38.129771973149346, -31.016260572769028], 0, [32.85929640135194, -26.50707591689791], 0, [47.440945483324754, -26.50707591689791], 0, [45.33685543194063, -31.016260572769028], 0, [61.52187596164093, -31.016260572769035], 0, [70.31099992504923, -35.88209931313313], 0, false]];
let cus = loadFile(data);
for (let i = 1.82; i <= 3.37; i += 0.3)
{
expect(cus[0].GetOffsetCurves(i).length).toBe(2);
}
expect(cus[0].GetOffsetCurves(18).length).toBe(2);
for (let i = 1; i <= 27; i += 5)
{
expect(cus[0].GetOffsetCurves(-i).length).toBe(1);
}
cus[0].Reverse();
expect(cus[0].GetOffsetCurves(-18).length).toBe(2);
data = [1, ["Polyline", 1, 1, 22696, false, 7, -1, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1], 2, 7, [21.944751443449043, -31.01626057276902], 0, [38.129771973149346, -31.016260572769028], 0, [32.85929640135194, -26.50707591689791], 0, [47.440945483324754, -26.50707591689791], 0, [45.33685543194063, -31.016260572769028], 0, [61.52187596164093, -31.016260572769035], 0, [70.31099992504923, -35.88209931313313], 0, false]];
cus = loadFile(data);
expect(cus[0].GetOffsetCurves(11.4).length).toBe(1);
data = [1, ["Polyline", 1, 1, 24383, false, 7, -1, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -56.21146708819905, -48.62279820279199, 0, 1], 2, 7, [26.333787338902418, -31.01626057276902], 0, [35.05226039203026, -31.016260572769013], 0, [32.85929640135194, -26.50707591689791], 0, [47.440945483324754, -26.50707591689791], 0, [41.54871106124796, -31.016260572769013], 0, [61.52187596164093, -31.016260572769035], 0, [70.31099992504923, -35.88209931313313], 0, false]]
cus = loadFile(data);
expect(cus[0].GetOffsetCurves(5.2).length).toBe(1);
data = [1, ["Polyline", 1, 1, 4, false, 7, -1, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1], 2, 6, [-3.158640226628895, -0.9915014164305944], 0, [-1.0906515580736538, -0.991501416430595], 0, [-1.983002832861189, 0.18413597733711037], 0, [1.0906515580736549, 0.3966005665722377], 0, [0.2974504249291776, -0.9915014164305944], 0, [3.966005665722378, -0.9915014164305953], 0, false]];
cus = loadFile(data);
expect(cus[0].GetOffsetCurves(2.01133).length).toBe(1);
})
test("test3", () =>
{
let data =
[1, ["Polyline", 1, 1, 4308, false, 7, -1, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1], 2, 5, [-41.52354973772388, -163.989590203395], 0, [-41.5235497377239, -231.3399374277236], 0, [21.016058399152634, -231.3399374277236], 0, [21.016058399152623, -294.68133541250876], 1.378670046466899, [261.5530127717545, -216.10593031745873], 0, false]];
let cus = loadFile(data);
for (let i = -100; i <= 181; i += 30)
{
expect(cus[0].GetOffsetCurves(i).length).toBe(1);
}
expect(cus[0].GetOffsetCurves(-122.6).length).toBe(2);
})
test("test4", () =>
{
let data =
[1, ["Polyline", 1, 1, 14565, false, 7, -1, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -131.50093441946296, -806.1569163328921, 0, 1], 2, 24, [256.5228611988947, -38.705370748164505], 0, [372.1955588024039, 31.844231195771492], 0, [372.1955588024039, -31.54297461172431], 0, [450.9819163032461, 37.57414810492366], 0, [423.0485713711294, -54.10452244151095], 0, [589.216161736542, 52.97329979827009], 0, [611.0614699526845, -2.177150452319474], 0, [672.6580767260702, 61.21005535517633], 0, [678.0298738284004, 13.938240854670997], 0, [735.329042919922, 21.100636991111184], 0, [684.1179105443746, -21.515620020708024], 0, [730.6734854312358, -32.61733403219032], 0, [815.1897598412304, 38.29038771856768], 0, [835.6025888300849, -8.981426781937659], 0, [862.1034545349137, 74.4604882075907], 0, [943.4539498526012, 74.46048820759069], 0, [986.972668777612, -29.064785548515978], 0, [924.5022496755805, -66.26627108118637], 0, [1001.0109652050348, -106.27541589934134], 0, [965.9152241364777, -128.73669018321777], 0, [1006.6262837760039, -176.46689803645526], 0, [904.1467198558175, -189.8032796425069], 0, [981.3573502066429, -242.44689124534239], 0, [1004.5205393118904, -256.48518767276516], 0, false]];
let cus = loadFile(data);
expect(cus[0].GetOffsetCurves(-100).length).toBe(1);
expect(cus[0].GetOffsetCurves(46.8).length).toBe(2);
expect(cus[0].GetOffsetCurves(49.6).length).toBe(3);
expect(cus[0].GetOffsetCurves(86.6).length).toBe(2);
expect(cus[0].GetOffsetCurves(102.3).length).toBe(2);
expect(cus[0].GetOffsetCurves(110).length).toBe(1);
})
test("test5", () =>
{
let data =
[1, ["Polyline", 1, 1, 3, false, 7, -1, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1], 2, 18, [-3.895184135977337, 0.7648725212464592], 0, [0.8215297450424939, 0.7648725212464592], 0, [-2.1246458923512743, -2.1388101983002827], 0, [5.311614730878187, -2.1388101983002827], 0, [1.89801699716714, 3.4844192634560907], 0, [6.671388101983003, 3.4844192634560907], 0, [6.671388101983002, -3.4985835694051], 0, [10.6657223796034, -0.11331444759206824], 0, [8.810198300283286, 1.161473087818697], 0, [14.674220963172807, 3.30028328611898], 0, [16.713881019830033, -2.521246458923512], 0, [11.55807365439094, -5.773371104815864], 0, [3.8441926345609083, -5.773371104815863], 0, [2.3569405099150167, -8.787535410764873], 0, [-1.5297450424929169, -6.090651558073655], 0, [-6.586402266288951, -12.674220963172807], 0, [-8.113314447592067, -8.767705382436262], 0, [-10.929178470254957, -12.436260623229463], 0, false]];
let cus = loadFile(data);
expect(cus[0].GetOffsetCurves(0.755).length).toBe(3);
expect(cus[0].GetOffsetCurves(1.915).length).toBe(4);
expect(cus[0].GetOffsetCurves(2.36).length).toBe(4);
expect(cus[0].GetOffsetCurves(2.892).length).toBe(2);
expect(cus[0].GetOffsetCurves(3.6850).length).toBe(1);
expect(cus[0].GetOffsetCurves(-1).length).toBe(3);
for (let i = 2; i <= 4; i++)
{
expect(cus[0].GetOffsetCurves(-i).length).toBe(1);
}
})
test("test6", () =>
{
let data =
[1, ["Polyline", 1, 1, 2781, false, 7, -1, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -38.54242746474825, 6.4891615215880964, 0, 1], 2, 3, [18.466397865202012, 17.128892766521286], 0, [4.660056657223795, 6.487252124645892], -3.7897716494829594, [-0.906131771640112, 6.969061295372345], 0, false]];
let cus = loadFile(data);
for (let i = -2.766; i <= 4.57; i++)
{
expect(cus[0].GetOffsetCurves(-i).length).toBe(1);
}
for (let i = 2.9; i <= 5.3; i += 0.5)
{
expect(cus[0].GetOffsetCurves(i).length).toBe(2);
}
for (let i = 6.14; i <= 8; i += 0.5)
{
expect(cus[0].GetOffsetCurves(i).length).toBe(1);
}
cus[0].Reverse();
for (let i = -2.766; i <= 4.57; i++)
{
expect(cus[0].GetOffsetCurves(i).length).toBe(1);
}
for (let i = 2.9; i <= 5.3; i += 0.5)
{
expect(cus[0].GetOffsetCurves(-i).length).toBe(2);
}
for (let i = 6.14; i <= 8; i += 0.5)
{
expect(cus[0].GetOffsetCurves(-i).length).toBe(1);
}
})
test("test7", () =>
{
let data =
[1, ["Polyline", 1, 1, 2347, false, 1, -1, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -86.54515219838936, -34.782221464287886, 0, 1], 2, 5, [-51.274354719855246, 28.573003242461496], 0, [-13.931531095689206, 15.255196629685734], 3.7897716494829594, [-8.365342666825299, 14.77338745895928], 0, [5.4409985411529185, 25.415028100834675], 0.37399715496699776, [29.033295173881022, 23.38858533792915], 0, false]];
let cus = loadFile(data);
expect(cus[0].GetOffsetCurves(-3.133).length).toBe(2);
for (let i = 10; i <= 60; i += 10)
{
expect(cus[0].GetOffsetCurves(i).length).toBe(1);
}
for (let i = 5.9; i <= 43.3; i += 10)
{
expect(cus[0].GetOffsetCurves(-i).length).toBe(1);
}
cus[0].Reverse();
expect(cus[0].GetOffsetCurves(3.133).length).toBe(2);
for (let i = 10; i <= 60; i += 10)
{
expect(cus[0].GetOffsetCurves(-i).length).toBe(1);
}
for (let i = 5.9; i <= 43.3; i += 10)
{
expect(cus[0].GetOffsetCurves(i).length).toBe(1);
}
})
test("test8", () =>
{
let data =
[1, ["Polyline", 1, 1, 395, false, 7, -1, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1], 2, 8, [14.442408344729744, 12.584578126613017], 0, [14.442408344729742, 4.502438174603963], 0, [20.086360825183, 4.502438174603963], 0, [20.086360825183, -0.9157562066311582], 0, [26.226981123916133, -0.9157562066311598], 0.4633692494967541, [33.496391918739924, 7.663051563657783], -0.673355221273594, [51.96340443478295, 18.996108144407916], 0.32851266965536, [64.10919017271836, 18.996108144407913], -1.9784627492130062, false]];
let cus = loadFile(data);
for (let i = -15; i <= 15; i += 5)
{
if (i === 0) continue;
expect(cus[0].GetOffsetCurves(i).length).toBe(1);
}
})
test("test9-2圆弧没交点", () =>
{
let data =
[1, ["Polyline", 1, 1, 23321, false, 7, -1, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1], 2, 3, [-245.7800398731897, -124.83507012637789], 0.47532901948537815, [-247.69480466441718, -117.62074637472406], 0.12615539092932912, [-193.96898890583213, -126.5297489543612], 0, false]]
let cus = loadFile(data);
expect(cus[0].GetOffsetCurves(11.22).length).toBe(1);
expect(cus[0].GetOffsetCurves(-11.22).length).toBe(1);
})
test("test10-共线部分错误裁剪", () =>
{
let data =
[1, ["Polyline", 1, 1, 151, false, 7, -1, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1], 2, 13, [37846.488077851434, 5711.914029035103], 0, [28152.473806690192, 5711.914029035104], 0, [31338.416239942802, 10002.31650581529], 0, [39750.51284565329, 10002.316505815288], 0, [39750.51284565329, 17632.65706309083], 0, [45109.026777541825, 17632.65706309083], 0, [45109.02677754183, 10002.31650581529], 0, [54643.39210261924, 10002.31650581529], -0.8704734266845496, [55266.30970531861, 5526.15551510335], 0, [45201.90603450778, 5526.155515103216], 0, [45201.90603450778, 249.9945243911434], 0, [37846.488077851434, 435.75303832303064], 0, [37846.488077851434, 5711.914029035103], 0, false]]
let cus = loadFile(data);
expect(cus[0].GetOffsetCurves(2700).length).toBe(1);
})
})
test('提前丢失所有的线段', () =>
{
let f = new CADFile();
f.Data =
[1, ["Polyline", 1, 1, 12, false, 7, -1, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -17.386067452264705, 17.11283965241085, 0, 1], 2, 3, [108.37693694676932, 28.257776463252547], 0.4472440944881872, [108.37693694676932, 17.68555707305448], 3.5940684866260213, [111.70676982557188, 14.089337563947739], 0.5086040192926764, false]]
f.Read();
let pl = f.ReadObject() as Polyline;
let cus = pl.GetOffsetCurves(-7.155086190577401);
expect(cus.length).toBe(0);
});
test('中间区域需要圆裁剪', () =>
{
let f = new CADFile();
f.Data =
[1, ["Polyline", 1, 1, 2628, false, 1, -1, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -1325.2800870006804, -703.3564533406019, 0, 1], 2, 5, [-51.274354719855246, 28.573003242461496], 0, [-13.931531095689206, 15.255196629685734], 3.7897716494829594, [-8.365342666825299, 14.77338745895928], 0, [5.4409985411529185, 25.415028100834675], 0.37399715496699776, [29.033295173881022, 23.38858533792915], 0, false]]
f.Read();
let pl = f.ReadObject() as Polyline;
let cus = pl.GetOffsetCurves(-35.6);
EntityToMatchSnapshot(cus);
});
test('拱门偏移', () =>
{
let f = new CADFile();
f.Data =
[1, ["Polyline", 1, 1, 6, false, 7, -1, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1], 2, 4, [0, 0], 0, [0, 2], -1, [1, 2], 0, [1, 0], 0, false]]
f.Read();
let pl = f.ReadObject() as Polyline;
let cus = pl.GetOffsetCurves(0.4);
EntityToMatchSnapshot(cus);
cus = pl.GetOffsetCurves(-0.4);
EntityToMatchSnapshot(cus);
});
test('土偏移因为点在圆弧切线上错误导致的丢失', () =>
{
let f = new CADFile();
f.Data =
[1, ["Polyline", 1, 1, 3, false, 7, -1, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -9159.663865546216, 8361.344537815126, 0, 1], 2, 17, [28900.928792569663, -4648.336577340973], -0.9999999999999999, [28900.928792569663, 580.3540867812549], 0, [37687.5122530782, 580.3540867812552], 0, [37687.5122530782, 5568.3816889128875], 0, [27851.140930176796, 5568.381688912888], 0, [31251.043800494088, 10146.917554273516], 0, [39591.53702088006, 10146.917554273514], 0, [39591.53702088006, 17633.191417258837], -0.9999999999999999, [45238.18434134903, 17633.191417258837], 0, [45238.184341349035, 10146.917554273516], 0, [54628.482972136226, 10146.917554273516], -0.8741669928857767, [55271.13672581777, 5382.623174980927], 0, [45331.063598314984, 5382.623174981001], 0, [45331.063598314984, 1648.4655418896164], 0, [53885.44891640867, 1648.4655418896143], -0.6803347640614656, [56371.20555398866, -4648.336577340822], 0, [28900.928792569663, -4648.336577340976], 0, false]]
f.Read();
let pl = f.ReadObject() as Polyline;
let cus = pl.GetOffsetCurves(-801);
expect(cus.length).toBe(1);
cus = pl.GetOffsetCurves(801);
expect(cus.length).toBe(1);
});
//ISSUE #IKSMH
test('闭合多段线判断精度和重复交点参数导致偏移丢失', () =>
{
let f = new CADFile();
f.Data =
[1, ["Polyline", 1, 1, 3, false, 7, -1, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.042016806722689815, 0.028011204481792618, 0, 1], 2, 11, [15758.920914649752, -1642.832074394305], 1.1432358165627696, [15758.920914649756, -3551.5797508523133], 0.010240353549940432, [20850.68748853413, -2761.478041111637], 0.39873042440013945, [23564.17781148077, 901.7338948663096], 0.029927117999965277, [22452.27083112051, 6973.8467189556395], 0, [31778.947378692996, 6973.846718955635], 0, [31327.636369627562, 7575.594679533537], 0, [31646.066893308867, 7787.881806674935], 0, [20955.832135358123, 7787.881806674936], 0, [21703.795934364476, 5637.485884531684], -0.559029831351755, [15758.920914649752, -1642.832074394304], 0, false]]
f.Read();
let pl = f.ReadObject() as Polyline;
for (let d of [40, 50, 100, 200, 300])
{
let cus = pl.GetOffsetCurves(d);
expect(cus.length).toBe(1);
expect(cus[0].Length).toMatchSnapshot();
}
});
//ISSUE #IKSMH
test('简单图形因为点在线内算法错误导致的丢失', () =>
{
let f = new CADFile();
f.Data =
[1, ["Polyline", 1, 1, 3, false, 7, -1, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.01400560224089542, 0.37815126050420145, 0, 1], 2, 7, [2.075848303393214, 0.09193367302761479], -3.109533447960064, [2.8332320619106284, 1.1077844311377247], 0, [3.542914171656688, 1.1077844311377247], 0, [3.542914171656688, -0.4890219560878247], 0, [2.0758483033932134, -0.4890219560878247], 0, [2.0758483033932134, -0.4890219560878247], 0, [2.0758483033932134, 0.09193367302761501], 0, false]]
f.Read();
let pl = f.ReadObject() as Polyline;
for (let d of [0.2, 0.3, 0.4, 0.5])
{
let cus = pl.GetOffsetCurves(d);
expect(cus.length).toBe(1);
expect(cus[0].Length).toMatchSnapshot();
}
});
test('圆求交错误导致的线丢失', () =>
{
let f = new CADFile();
f.Data =
[1, ["Polyline", 1, 1, 1077, false, 7, -1, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1], 2, 8, [245.62964413684085, 1116.1391538309313], -0.6953179171905909, [357.14209871457234, 1741.1251588427203], -0.6821635222887411, [892.2042303620135, 1596.040230558597], 0.37526047823909664, [1317.3934365017694, 1221.2756098839004], 0.14384173346393453, [1715.0964405621776, 1096.7424042631346], 0.026448384140957723, [1793.2064027435729, 1099.4889679050386], -0.1912121824403452, [733.4339688924879, 1000.3133228797258], -0.3304377553967397, [245.62964413684108, 1116.139153830931], 0, false]]
f.Read();
let pl = f.ReadObject() as Polyline;
for (let d of [10, 20, 30, 40])
{
let cus = pl.GetOffsetCurves(d);
expect(cus.length).toBe(1);
expect(cus[0].Length).toMatchSnapshot();
cus = pl.GetOffsetCurves(-d);
expect(cus.length).toBe(1);
expect(cus[0].Length).toMatchSnapshot();
}
});

@ -470,6 +470,48 @@ describe('多段线', () =>
pl.Reverse();
expect(pl.StartPoint).toEqual(new Vector3(0, 10, 0))
})
//直线和圆的求交的det精度不能为0.1 太大了.请保证这个测试是通过的
test('最近点精度', () =>
{
let f = new CADFile();
f.Data =
[1, ["Polyline", 1, 1, 3, false, 7, -1, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1], 2, 5, [0, 0], 0, [2, 0], 1, [2, 2], -1, [2, 4], 0, [0, 4], 0, true]]
f.Read();
let pl = f.ReadObject() as Polyline;
pl.Reverse();
let cp = pl.GetClosestPointTo(new Vector3(2 - 1e-2, 3.8), false);
expect(cp).toMatchSnapshot();
});
test('优化参数在端点上的时候', () =>
{
let pl = new Polyline();
pl.AddVertexAt(0, new Vector2(0, 0));
pl.AddVertexAt(1, new Vector2(5, 0));
pl.AddVertexAt(2, new Vector2(5, 5));
pl.CloseMark = true;
let p = pl.GetPointAtParam(3);
expect(p).toMatchSnapshot();
});
test('存在大圆弧的多段线面积', () =>
{
let f = new CADFile();
f.Data =
[1, ["Polyline", 1, 1, 1606, false, 7, -1, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -19.17745164184445, -6.335408131680751, 0, 1], 2, 5, [11.884352072596577, -75.64730611519322], -1.9523252757782086, [16.25360183965801, -70.58112080246555], 0, [14.621427950114992, -70.9720172143345], 1.8583004340984604, [11.834326201222096, -73.95002751582643], 0, [11.884352072596577, -75.64730611519322], 0, false]]
f.Read();
let pl = f.ReadObject() as Polyline;
expect(pl.Area2).toMatchSnapshot();
});
})
test('最近点参数刚好在端点上', () =>

@ -7,8 +7,9 @@
"dev": "webpack-dev-server",
"dev2": "webpack-dev-server --config web-cad-view.config.ts",
"dts": "tcm src -o ./src/UI/css_dts",
"build": "npm run type && webpack --config dll.config.js &&webpack",
"build2": "webpack --config dll.config.js &&webpack --config web-cad-view.config.ts",
"buildview": "webpack --config dll.config.js &&webpack --config web-cad-view.config.ts",
"prebuild": "npm run type && webpack --config dll.config.js",
"build": "webpack",
"i": "npm i && npm i -dev",
"test": "jest",
"ser": "node ./utils/server.js",

@ -0,0 +1,14 @@
import { app } from "../ApplicationServices/Application";
import { copyTextToClipboard } from "../Common/Utils";
import { PromptStatus } from "../Editor/PromptResult";
export class Command_CopyPoint
{
async exec()
{
let ptRes = await app.m_Editor.GetPoint();
if (ptRes.Status === PromptStatus.OK)
copyTextToClipboard(`new Vector3().fromArray(${JSON.stringify(ptRes.Value.toArray())});`);
}
}

@ -42,7 +42,7 @@ export class DrawPolyline
{
ops = nextOps;
ops.BasePoint = pl.EndPoint;
if (pl.NumberOfVertices > 3)
if (pl.NumberOfVertices >= 3 || (pl.NumberOfVertices === 2 && this.model === PolylineModel.Arc))
nextOps.KeyWordList = keywords2;
else
nextOps.KeyWordList = keywords;

@ -5,6 +5,7 @@ import { Command } from '../Editor/CommandMachine';
import { PromptStatus } from '../Editor/PromptResult';
import { DynamicInputManage } from '../UI/DynamicPrompt/DynamicInputManage';
import { PromptBlock } from '../UI/DynamicPrompt/PromptBlock';
import { Polyline } from '../DatabaseServices/Polyline';
//演示了如何单选图形
@ -23,7 +24,8 @@ export class Entsel implements Command
vcs.add(new Vector3(0, -20, 0));
dyn.SetPostion(vcs);
dyn.updatePrompt(res.Entity.constructor.name + ",id:" + res.Entity.Id.Index);
if (res.Entity instanceof Polyline)
dyn.updatePrompt(res.Entity.constructor.name + ",area:" + res.Entity.Area2);
}
else
dyn.Visible = false;

@ -1,6 +1,6 @@
import { Vector3 } from 'three';
import { app } from '../ApplicationServices/Application';
import { KeyWord } from '../Common/InputState';
import { KeyBoard } from '../Common/KeyEnum';
import { Arc } from '../DatabaseServices/Arc';
import { Curve } from '../DatabaseServices/Curve';
@ -182,12 +182,12 @@ export class CommandFillet implements Command
/**
* 线
*
* @param {any} keyword
* @param {KeyWord[]} keyword
* @param {Curve} [oldCurve] 线
* @returns {Promise<PromptEntityResult>}
* @memberof CommandFillet
*/
async SelectCurve(keyword, oldCurve?: Curve): Promise<PromptEntityResult>
async SelectCurve(keyword: KeyWord[], oldCurve?: Curve): Promise<PromptEntityResult>
{
while (true)
{

@ -0,0 +1,45 @@
import { app } from "../ApplicationServices/Application";
import { copyTextToClipboard } from "../Common/Utils";
import { Polyline } from "../DatabaseServices/Polyline";
import { PromptStatus } from "../Editor/PromptResult";
export class Command_Lisp
{
async exec()
{
let ssRes = await app.m_Editor.GetEntity();
if (ssRes.Status != PromptStatus.OK) return;
let pl = ssRes.Entity as Polyline;
if (!pl) return;
let { pts, buls } = pl.PtsBuls;
let fun = `
(defun cx-make-pline (pts buls closeMark)
(entmakeX
(append
(list
'(0 . "LWPOLYLINE")
'(100 . "AcDbEntity")
'(100 . "AcDbPolyline")
(cons 90 (length pts))
(cons 70 closeMark)
)
(apply 'append(mapcar '(lambda (pt bul) (list (cons 10 pt) (cons 42 bul))) pts buls))
)
)
)
`
let str = fun + "(cx-make-pline '(";
pts.forEach(p => str += `(${p.x} ${p.y})`)
str += ") '(";
buls.forEach(b => str += `${b} `);
str += `)`;
str += pl.CloseMark ? "1" : "0";
str += ")";
copyTextToClipboard(str);
}
}

@ -25,13 +25,11 @@ export class Command_Move implements Command
Msg: "请点击移动终点:",
Callback: (p: THREE.Vector3) =>
{
let moveMat = new THREE.Matrix4();
let moveVec = p.clone().sub(pt1);
moveMat.makeTranslation(moveVec.x, moveVec.y, moveVec.z);
let moveMatrix = MoveMatrix(moveVec);
ens.forEach(e =>
{
e.ApplyMatrix(moveMat);
e.ApplyMatrix(moveMatrix);
})
pt1 = p.clone();
},

@ -1,26 +1,31 @@
import { app } from '../ApplicationServices/Application';
import { GetPointAtCurveDir } from '../Common/CurveUtils';
import { Curve } from '../DatabaseServices/Curve';
import { Command } from '../Editor/CommandMachine';
import { PromptStatus } from '../Editor/PromptResult';
import { Polyline } from '../DatabaseServices/Polyline';
import { IsPointInPolyLine } from '../DatabaseServices/PointInPolyline';
export class Command_Offset implements Command
{
offsetDis: number = 1;
async exec()
{
let dis = await app.m_Editor.GetDistance({
Msg: "指定偏移距离:",
KeyWordList: [{ msg: "通过", key: "T" }]
KeyWordList: [{ msg: "通过", key: "T" }],
Default: this.offsetDis
});
if (dis.Status != PromptStatus.OK) return;
this.offsetDis = dis.Value;
while (true)
{
let enRes = await app.m_Editor.GetEntity({
Msg: "选择要偏移的对象:"
});
if (enRes.Status != PromptStatus.OK)
if (enRes.Status === PromptStatus.Cancel)
break;
else if (enRes.Status !== PromptStatus.OK)
continue;
let pt = await app.m_Editor.GetPoint({
Msg: "指定要偏移的那一侧的点"
});
@ -29,17 +34,8 @@ export class Command_Offset implements Command
if (cu instanceof Curve)
{
let ptClose = cu.GetClosestPointTo(pt.Value, false);
let toPtVec = pt.Value.clone().sub(ptClose); //点击处向量
let d = cu.GetFistDeriv(cu.GetParamAtPoint(ptClose));//切线。
let c = toPtVec.cross(d);
if (cu instanceof Polyline && cu.EndParam > 1 && cu.Area > 0)
{
c.z = (IsPointInPolyLine(cu, pt.Value) ? -1 : 1) * Math.sign(cu.Area2);
}
let offCurs = cu.GetOffsetCurves(dis.Value * Math.sign(c.z));
let dir = GetPointAtCurveDir(cu, pt.Value) ? 1 : -1
let offCurs = cu.GetOffsetCurves(this.offsetDis * dir);
offCurs.forEach((offCur) =>
{
app.m_Database.ModelSpace.Append(offCur);
@ -63,7 +59,11 @@ export class Command_TestOffset implements Command
Msg: "选择要偏移的对象:"
});
if (enRes.Status != PromptStatus.OK)
{
//结束偏移后打开点捕捉
app.m_Editor.m_GetpointServices.snapServices.m_Disabled = false;
break;
}
let cu = enRes.Entity as Curve;
let lastpls: Curve[];
@ -73,37 +73,14 @@ export class Command_TestOffset implements Command
Callback: (p) =>
{
if (lastpls) lastpls.forEach(cu => cu.Erase());
let dist = p.distanceTo(cu.GetClosestPointTo(p, !cu.IsClose));
if (cu instanceof Polyline && cu.EndParam > 1 && cu.Area > 0)
{
let pls1 = cu.GetOffsetCurves(dist);
let pls2 = cu.GetOffsetCurves(-dist);
let dis1 = Math.min.apply(undefined, pls1.map(c => p.distanceTo(c.GetClosestPointTo(p, false))));
let dis2 = Math.min.apply(undefined, pls2.map(c => p.distanceTo(c.GetClosestPointTo(p, false))));
if (dis1 < dis2)
lastpls = pls1;
else
lastpls = pls2;
}
else
{
let ptClose = cu.GetClosestPointTo(p, false);
let toPtVec = p.clone().sub(ptClose); //点击处向量
let d = cu.GetFistDeriv(cu.GetParamAtPoint(ptClose));//切线。
let c = toPtVec.cross(d);
lastpls = cu.GetOffsetCurves(p.distanceTo(cu.GetClosestPointTo(p, !cu.IsClose)) * Math.sign(c.z));
}
let dir = GetPointAtCurveDir(cu, p) ? 1 : -1
lastpls = cu.GetOffsetCurves(p.distanceTo(cu.GetClosestPointTo(p, false)) * dir);
lastpls.forEach((offCur) =>
{
app.m_Database.ModelSpace.Append(offCur);
})
app.m_Viewer.m_bNeedUpdate = true;
}
});
}

@ -0,0 +1,69 @@
import { app } from "../ApplicationServices/Application";
import { Polyline } from "../DatabaseServices/Polyline";
import { Command } from "../Editor/CommandMachine";
import { PromptStatus } from "../Editor/PromptResult";
import { Vector3 } from "three";
//无限内偏移
export class OffsetX implements Command
{
offsetDis: number = 1;
async exec()
{
let ssRes = await app.m_Editor.GetEntity();
if (ssRes.Status != PromptStatus.OK) return;
let pl = ssRes.Entity as Polyline;
if (!pl) return;
let dis: number, step: number;
if (window["autoDis"])
{
this.offsetDis = 1.2 * Math.max(...pl.BoundingBox.getSize(new Vector3()).toArray());
dis = -this.offsetDis;
step = this.offsetDis / 20;
}
else
{
let disRes = await app.m_Editor.GetDistance({
Msg: "指定偏移距离:",
KeyWordList: [{ msg: "通过", key: "T" }],
Default: this.offsetDis
});
if (disRes.Status != PromptStatus.OK) return;
this.offsetDis = disRes.Value;
dis = -this.offsetDis;
if (pl.IsClockWise) dis = -dis;
let disRes1 = await app.m_Editor.GetDistance({
Msg: "步长:",
KeyWordList: [{ msg: "通过", key: "T" }],
Default: 1
});
if (disRes1.Status != PromptStatus.OK) return;
step = disRes1.Value;
}
// let step = 0.5;
let offRes: Polyline[] = [];
// offRes.push(...pl.GetOffsetCurves(dis) as Polyline[]);
// for (let i = 0; i < offRes.length; i++)
// {
// let offpl = offRes[i];
// if (offpl.IsClose)
// {
// offRes.push(...offpl.GetOffsetCurves(dis) as Polyline[]);
// }
// }
for (let i = 0; i <= Math.abs(dis); i += step)
{
offRes.push(...pl.GetOffsetCurves(i) as Polyline[]);
offRes.push(...pl.GetOffsetCurves(-i) as Polyline[]);
}
offRes.forEach(c => app.m_Database.ModelSpace.Append(c));
}
}

@ -9,15 +9,18 @@ export class Open implements Command
{
let store = await IndexedDbStore.CADStore();
let file = await store.Get(StoreName.Dwg, "1");
if (file)
let fid = window.sessionStorage.getItem("fid");
if (fid)
{
let cadF = new CADFile();
cadF.Data = file;
let file = await store.Get(StoreName.Dwg, fid);
app.m_Database.FileRead(cadF);
}
if (file)
{
let cadF = new CADFile();
cadF.Data = file;
app.m_Database.FileRead(cadF);
}
}
}
}

@ -1,6 +1,6 @@
import { Vector3 } from 'three';
import { app } from '../ApplicationServices/Application';
import { GetPointAtCurveDir } from '../Common/CurveUtils';
import { Arc } from '../DatabaseServices/Arc';
import { Circle } from '../DatabaseServices/Circle';
import { Curve } from '../DatabaseServices/Curve';
@ -9,12 +9,15 @@ import { IsPointInBowArc, IsPointInPolyLine } from '../DatabaseServices/PointInP
import { Polyline } from '../DatabaseServices/Polyline';
import { Command } from '../Editor/CommandMachine';
import { PromptStatus } from '../Editor/PromptResult';
import { PromptBlock } from '../UI/DynamicPrompt/PromptBlock';
import { DynamicInputManage } from '../UI/DynamicPrompt/DynamicInputManage';
export class Command_ClosePt implements Command
{
async exec()
{
let dyn = new PromptBlock(DynamicInputManage.GetManage());
let cuRes = await app.m_Editor.GetEntity();
@ -55,8 +58,14 @@ export class Command_ClosePt implements Command
if (cu instanceof Polyline)
{
dyn.Visible = true;
let vcs = app.m_Editor.m_MouseCtrl.m_CurMousePointVCS.clone();
vcs.add(new Vector3(0, -20, 0));
dyn.SetPostion(vcs);
dyn.updatePrompt("点在线内外?:" + IsPointInPolyLine(cu, p));
closeCir.Center = p;
closeCir.ColorIndex = IsPointInPolyLine(cu, p) ? 1 : 2;
closeCir.ColorIndex = GetPointAtCurveDir(cu, p) ? 1 : 2;
}
}
})
@ -65,9 +74,10 @@ export class Command_ClosePt implements Command
extend = !extend;
}
if (p.Status === PromptStatus.Cancel)
return;
break;
}
}
dyn.Destroy();
}
}

@ -1,10 +1,15 @@
import { Vector3 } from 'three';
import { app } from '../ApplicationServices/Application';
import { GetPointAtCurveDir } from '../Common/CurveUtils';
import { matrixAlignCoordSys } from '../Common/Matrix4Utils';
import { copyTextToClipboard } from '../Common/Utils';
import { Circle } from '../DatabaseServices/Circle';
import { Curve } from '../DatabaseServices/Curve';
import { Polyline } from '../DatabaseServices/Polyline';
import { Region } from '../DatabaseServices/Region';
import { Command } from "../Editor/CommandMachine";
import { PromptStatus } from "../Editor/PromptResult";
import { Polyline } from '../DatabaseServices/Polyline';
import { IntersectOption } from '../GraphicsSystem/IntersectWith';
@ -14,23 +19,74 @@ export class Test implements Command
{
app.m_Editor.m_CommandStore.Prompt("载入成功!");
}
async exec()
async exec1()
{
let ssRes = await app.m_Editor.GetSelection({ UseSelect: true });
let e1Res = await app.m_Editor.GetEntity();
let e2Res = await app.m_Editor.GetEntity();
let e1 = e1Res.Entity as Curve;
let e2 = e2Res.Entity as Curve;
if (ssRes.Status === PromptStatus.OK)
let pts = e1.IntersectWith(e2, IntersectOption.OnBothOperands);
for (let p of pts)
{
for (let en of ssRes.SelectSet.SelectEntityList)
{
if (en instanceof Curve)
{
if (en.Length < 0.1)
{
console.log(".....");
}
}
}
let c = new Circle(p, 0.01);
app.m_Database.ModelSpace.Append(c);
}
}
//将多段线转换为cad图形
async exec4()
{
// let d = [["Polyline", 1, 1, 12839, false, 7, -1, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1], 2, 24, [256.5228611988947, -38.705370748164505], 0, [372.1955588024039, 31.844231195771492], 0, [372.1955588024039, -31.54297461172431], 0, [450.9819163032461, 37.57414810492366], 0, [423.0485713711294, -54.10452244151095], 0, [589.216161736542, 52.97329979827009], 0, [611.0614699526845, -2.177150452319474], 0, [672.6580767260702, 61.21005535517633], 0, [678.0298738284004, 13.938240854670997], 0, [735.329042919922, 21.100636991111184], 0, [684.1179105443746, -21.515620020708024], 0, [730.6734854312358, -32.61733403219032], 0, [815.1897598412304, 38.29038771856768], 0, [835.6025888300849, -8.981426781937659], 0, [862.1034545349137, 74.4604882075907], 0, [943.4539498526012, 74.46048820759069], 0, [986.972668777612, -29.064785548515978], 0, [924.5022496755805, -66.26627108118637], 0, [1001.0109652050348, -106.27541589934134], 0, [965.9152241364777, -128.73669018321777], 0, [1006.6262837760039, -176.46689803645526], 0, [904.1467198558175, -189.8032796425069], 0, [981.3573502066429, -242.44689124534239], 0, [1004.5205393118904, -256.48518767276516], 0, false]]
// let cadf = new CADFile();
// cadf.Data = d;
// let en = cadf.ReadObject() as Entity;
// if (en)
// {
// app.m_Database.ModelSpace.Append(en);
// return;
// }
// let d = [["Polyline", 1, 1, 8987, false, 7, -1, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1], 2, 14, [340.820007357324, -3.870032999900914], 0, [431.6163856609081, 116.2815653567217], 0, [485.54806901416487, 54.84040710617603], 0, [533.3356365423672, 67.81131829240235], 0, [624.1320148459513, 40.504136847715344], 0, [656.9006325795757, 23.43714844478601], -0.783383849320176, [633.0068488154745, -74.86870475608706], 0.4462700081240285, [605.0169878346704, -106.27196341747704], -0.8416099256631104, [529.9222388617812, -128.11770857322662], 0, [510.1245323143834, -22.98506001118185], 0, [430.251026588674, -129.48306764546098], 0, [430.251026588674, -65.99387078656383], 0, [351.74287993519897, -145.86737651227318], 0, [303.2726328708796, -87.83961594231337], 0, true]];
// let cadf = new CADFile();
// cadf.Data = d;
// let en = cadf.ReadObject() as Entity;
// if (en)
// {
// app.m_Database.ModelSpace.Append(en);
// return;
// }
}
async execn()
{
let ssRes = await app.m_Editor.GetEntity();
if (ssRes.Status != PromptStatus.OK) return;
let ptRes = await app.m_Editor.GetPoint();
if (ptRes.Status != PromptStatus.OK) return;
let cu = ssRes.Entity as Polyline;
let p = ptRes.Value;
console.log(cu.PtOnCurve(p));
console.log(cu.PtInCurve(p))
// if (ssRes.Status === PromptStatus.OK)
// {
// for (let en of ssRes.SelectSet.SelectEntityList)
// {
// if (en instanceof Curve)
// {
// if (en.Length < 0.1)
// {
// console.log(".....");
// }
// }
// }
// }
}
async exec3()
@ -70,4 +126,42 @@ export class Test implements Command
r1.ShapeManager.ShapeList.forEach(s => s.Explode().forEach(c => app.m_Database.ModelSpace.Append(c)));
r2.ShapeManager.ShapeList.forEach(s => s.Explode().forEach(c => app.m_Database.ModelSpace.Append(c)));
}
async exec()
{
let e = await app.m_Editor.GetEntity();
if (e.Status === PromptStatus.OK)
{
let box = e.Entity.BoundingBox;
if (e.Entity instanceof Polyline)
{
console.log(GetPointAtCurveDir(e.Entity, new Vector3(5, 5.5)));
this.drawPtDirTestCir(e.Entity);
}
return;
}
}
private drawPtDirTestCir(pl: Polyline)
{
let box = pl.BoundingBox;
let size = box.getSize(new Vector3());
box.min.sub(size.clone().multiplyScalar(0.2));
box.max.add(size.clone().multiplyScalar(0.2));
size.multiplyScalar(0.05);
app.m_Database.ModelSpace.Append(pl);
for (let j = 0; j < 14 * 2; j++)
{
let p = box.min.clone();
p.x += j * size.x;
for (let k = 0; k < 14 * 2; k++)
{
p.y += size.y;
let c = new Circle(p, 0.1);
c.ColorIndex = GetPointAtCurveDir(pl, p) ? 3 : 1;
app.m_Database.ModelSpace.Append(c);
}
}
}
}

@ -1,11 +1,11 @@
import { Line } from "three";
import { app } from "../../ApplicationServices/Application";
import { Arc } from "../../DatabaseServices/Arc";
import { Circle } from "../../DatabaseServices/Circle";
import { Curve } from "../../DatabaseServices/Curve";
import { Command } from "../../Editor/CommandMachine";
import { PromptStatus } from "../../Editor/PromptResult";
import { IntersectLAndLFor3D, IntersectOption, IntersectCircleAndCircle } from "../../GraphicsSystem/IntersectWith";
import { Line } from "three";
import { Arc } from "../../DatabaseServices/Arc";
import { IntersectCircleAndCircle, IntersectLAndLFor3D, IntersectOption } from "../../GraphicsSystem/IntersectWith";
export class TestIntersect implements Command
{
@ -15,6 +15,7 @@ export class TestIntersect implements Command
// this.testLineAndLine();
// this.testLineAndCirOrArc();
// this.testCirAndCir()
this.testInter();
app.m_Editor.UpdateScreen();
}
@ -113,4 +114,24 @@ export class TestIntersect implements Command
}
}
}
async testInter()
{
let exRefSsRes = await app.m_Editor.GetSelection({ Msg: "请选择对象<全部选择>:", UseSelect: true });
if (exRefSsRes.Status !== PromptStatus.OK) return;
let cus = exRefSsRes.SelectSet.SelectEntityList as Curve[];
if (cus.length === 2)
{
let pt = cus[0].IntersectWith(cus[1], 3);
console.log('pt: ', pt);
if (pt.length)
{
pt.forEach(p =>
{
let cir = new Circle(p, 10);
cir.ColorIndex = 2;
app.m_Database.ModelSpace.Append(cir);
})
}
}
}
}

@ -1,37 +0,0 @@
import { app } from "../../ApplicationServices/Application";
import { Circle } from "../../DatabaseServices/Circle";
import { Curve } from "../../DatabaseServices/Curve";
import { Polyline } from "../../DatabaseServices/Polyline";
import { Command } from "../../Editor/CommandMachine";
import { PromptStatus } from "../../Editor/PromptResult";
import { isTargetCurInSourceCur } from "../../GraphicsSystem/BoolOperateUtils";
export class TestBoolOperationUtil implements Command
{
async exec()
{
let ssRes = await app.m_Editor.GetSelection(
{
Msg: "选择曲线"
},
);
let source = ssRes.SelectSet.SelectEntityList[0] as Polyline | Circle;
ssRes = await app.m_Editor.GetSelection(
{
Msg: "选择目标曲线"
},
);
if (ssRes.Status === PromptStatus.OK)
{
let target = ssRes.SelectSet.SelectEntityList as Curve[];
target.forEach(l =>
{
if (!isTargetCurInSourceCur(source, l))
{
l.ColorIndex = 1;
} else
l.ColorIndex = 2;
})
}
}
}

@ -0,0 +1,130 @@
import { Vector3 } from "three";
import { app } from "../../ApplicationServices/Application";
import { arrayLast, arrayRemoveIf, arraySortByNumber } from "../../Common/ArrayExt";
import { Circle } from "../../DatabaseServices/Circle";
import { Contour } from "../../DatabaseServices/Contour";
import { Curve } from "../../DatabaseServices/Curve";
import { Polyline } from "../../DatabaseServices/Polyline";
import { Command } from "../../Editor/CommandMachine";
import { PromptStatus } from "../../Editor/PromptResult";
import { equaln } from "../../Geometry/GeUtils";
import { IsPtsAllOutOrOnReg } from "../../GraphicsSystem/BoolOperateUtils";
export class TestTargeOnCurve implements Command
{
async exec()
{
try
{
let ssRes = await app.m_Editor.GetSelection(
{
Msg: "选择曲线"
},
);
let source = ssRes.SelectSet.SelectEntityList[0] as Polyline | Circle;
ssRes = await app.m_Editor.GetSelection(
{
Msg: "选择目标曲线"
},
);
if (ssRes.Status === PromptStatus.OK && source.Length)
{
let target = ssRes.SelectSet.SelectEntityList[0] as Curve;
// let con1 = Contour.CreateContour([source]);
// let con2 = Contour.CreateContour([target]);
// let res = con1.getOperatedCurves(con2);
// testCurve(res.unionList, 1);
// testCurve(res.intersectionList, 2);
// testCurve(res.subtractList, 3);
// this.testClip(source as Polyline, target).forEach((c, i) =>
// {
// c.ColorIndex = i + 1;
// app.m_Database.ModelSpace.Append(c);
// })
this.testPtIn(source as Polyline, target);
// target.Erase();
// source.Erase();
}
} catch (err)
{
console.log(err);
}
}
testClip(outline: Polyline, l: Curve)
{
let tmpCus = [];
//交点参数列表
let iParams = l.IntersectWith(outline, 0)
.map(p => l.GetParamAtPoint(p));
arraySortByNumber(iParams);
//需要计算的点列表
let needCaclPts: Vector3[] = [];
for (let i = 0; i < iParams.length - 1; i++)
{
needCaclPts.push(l.GetPointAtParam((iParams[i] + iParams[i + 1]) / 2));
}
//如果交点不是首尾点,就加入首尾点
if (!equaln(iParams[0], 0, 1e-6))
needCaclPts.unshift(l.StartPoint);
if (!equaln(arrayLast(iParams), 1, 1e-6))
needCaclPts.push(l.EndPoint);
//切割曲线,缓存切割后曲线包围盒
if (IsPtsAllOutOrOnReg(outline, needCaclPts))
{
tmpCus.push(l);
}
else
{
let cus = l.GetSplitCurves(iParams);
//移除0长度线和在轮廓内的线.
arrayRemoveIf(cus, cu => equaln(cu.Length, 0, 1e-6)
|| outline.PtInCurve(cu.GetPointAtParam(0.5))
);
tmpCus.push(...cus);
}
return tmpCus;
}
testPtIn(outline: Polyline, l: Curve)
{
if (outline.PtInCurve(l.EndPoint))
{
l.ColorIndex = 3
} else
l.ColorIndex = 1;
}
}
export function testPts(pts: Vector3[], color = 2)
{
pts.forEach(p =>
{
let cir = new Circle(p, 0.5);
cir.ColorIndex = color;
app.m_Database.ModelSpace.Append(cir);
});
}
export function testContours(cons: Contour[], color = 2)
{
cons.forEach(c =>
{
c.Outline.ColorIndex = color;
app.m_Database.ModelSpace.Append(c.Outline);
});
}
export function testCurve(cons: Curve[], color: number = 2)
{
cons.forEach(c =>
{
c.ColorIndex = color;
app.m_Database.ModelSpace.Append(c);
});
}

@ -87,18 +87,13 @@ export function arraySortByNumber<T>(arr: Array<T>): Array<T>
* @param {(e1, e2) => boolean} [checkFuction]
* @returns {Array<T>}
*/
export function arrayRemoveDuplicateBySort<T>(arr: Array<T>, checkFuction?: (e1, e2) => boolean): Array<T>
export function arrayRemoveDuplicateBySort<T>(arr: Array<T>, checkFuction: (e1, e2) => boolean = checkEqual): Array<T>
{
checkFuction = checkFuction || checkEqual;
if (arr.length < 2) return arr;
let j = 1;
for (let i = 1, l = arr.length; i < l; i++)
{
if (!checkFuction(arr[i], arr[j - 1]))
{
arr[j++] = arr[i];
}
}
arr.length = j;
return arr;
}

@ -3,11 +3,13 @@ import { Arc } from '../DatabaseServices/Arc';
import { Circle } from '../DatabaseServices/Circle';
import { Curve } from '../DatabaseServices/Curve';
import { Line } from '../DatabaseServices/Line';
import { IsPointInBowArc } from '../DatabaseServices/PointInPolyline';
import { Polyline } from '../DatabaseServices/Polyline';
import { Count } from '../Geometry/Count';
import { CurveMap } from '../Geometry/CurveMap';
import { equal, equaln } from '../Geometry/GeUtils';
import { Stand } from '../Geometry/RegionParse';
import { FixIndex } from './Utils';
//3点获取圆心
export function getCircleCenter(pt1: Vector3, pt2: Vector3, pt3: Vector3)
@ -103,10 +105,9 @@ export function curveLinkGroup(cus: Curve[]): Array<Array<Curve>>
let isClose = c.IsClose;
if (isClose)
groupCus.push([c]);
return !isClose;
});
if (cus.length === 0) return groupCus;
//曲线节点图
let cuMap = new CurveMap();
cus.forEach(c => cuMap.addCurveToMap(c));
@ -211,3 +212,138 @@ export function equalCurveAndCurve(cu1: Curve, cu2: Curve)
}
return false;
}
/**
* 线,
*
* @param {Curve} cu
* @param {Vector3} pt
* @returns {boolean} false,true
*/
export function GetPointAtCurveDir(cu: Curve, pt: Vector3): boolean
{
//最近点
let cp = cu.GetClosestPointTo(pt, false);
//最近点参数
let cparam = cu.GetParamAtPoint(cp);
//归一化最近点参数
let floorParam = Math.floor(cparam + 0.5);
//当最近点在参数上时,可能产生退化,在这里重新计算合适的最近点和切线.
if (
cu instanceof Polyline
&& equaln(floorParam, cparam, 1e-2)
&&
(
cu.IsClose ||
(
floorParam !== 0
&& floorParam !== cu.EndParam
)
)
)
{
let plVerCount = cu.NumberOfVertices;
if (equal(cu.GetPoint2dAt(0), cu.GetPoint2dAt(plVerCount - 1)))
plVerCount--;
//分三点,本点,前一个点,后一个点
if (floorParam === cu.EndParam) floorParam = 0;
let fIndex = FixIndex(floorParam - 1, plVerCount);
let nIndex = FixIndex(floorParam + 1, plVerCount);
let fpInCir = PointInPolylineArc(cu, fIndex, pt);
if (fpInCir !== 0) return fpInCir < 0;
let npInCir = PointInPolylineArc(cu, floorParam, pt);
if (npInCir !== 0) return npInCir < 0;
let p = cu.GetPointAtParam(floorParam);
let fDer = cu.GetFistDeriv(fIndex + 0.99).normalize();
let nDer = cu.GetFistDeriv(floorParam + 0.01).normalize();
let l1 = new Line(p.clone().sub(fDer), p);
let l2 = new Line(p, p.clone().add(nDer));
let cp1 = l1.GetClosestPointTo(pt, true);
let cp2 = l2.GetClosestPointTo(pt, true);
if (equal(fDer, nDer.clone().negate()))
return true;
if (equal(fDer, nDer))
return fDer.cross(pt.clone().sub(cp1)).z < 0;
let adir = Math.sign(fDer.clone().cross(nDer).z);
//判断点是否在小角内.
if (
Math.sign(fDer.cross(pt.clone().sub(cp1)).z) === adir
&& Math.sign(nDer.cross(pt.clone().sub(cp2)).z) === adir
)
return adir < 0;
else return adir > 0;
}
let dri = cu.GetFistDeriv(cparam);
let cross = dri.cross(pt.clone().sub(cp));
return cross.z < 0;
}
/**
* 线()
*
* @param {Polyline} pl
* @param {number} index
* @param {Vector3} pt
* @returns {number}
*/
function PointInPolylineArc(pl: Polyline, index: number, pt: Vector3): number
{
let bul = pl.GetBuilgeAt(index);
if (bul === 0) return 0;
let arc = pl.GetCurveAtIndex(index) as Arc;
if (IsPointInBowArc(arc, pt, true))
return Math.sign(bul);
return 0;
}
/**
* 线,.
* ,0.5
*
* @export
* @param {Polyline} pl
* @returns {Polyline} 线
*/
export function BreakPolylineAtArc(pl: Polyline): Polyline
{
let { pts, buls } = pl.PtsBuls;
let npl = new Polyline();
for (let i = 0; i < pts.length; i++)
{
let bul = buls[i];
npl.AddVertexAt(npl.NumberOfVertices, pts[i]);
if (i !== pts.length - 1 && Math.abs(bul) > 0.5)
{
let divCount = Math.floor(Math.abs(bul) / 0.5) + 1;
let arc = new Arc().ParseFromBul(pts[i], pts[i + 1], bul);
let bulDiv = Math.tan(Math.atan(bul) / divCount);
npl.SetBulgeAt(npl.NumberOfVertices - 1, bulDiv);
for (let i = 0; i < divCount - 1; i++)
{
npl.AddVertexAt(npl.NumberOfVertices, Vec3DTo2D(arc.GetPointAtParam((i + 1) / divCount)));
npl.SetBulgeAt(npl.NumberOfVertices - 1, bulDiv);
}
}
else
{
npl.SetBulgeAt(npl.NumberOfVertices - 1, 0);
}
}
return npl;
}

@ -29,13 +29,13 @@ export function clamp(value, min, max)
export function FixIndex(index: number, arr: Array<any> | number)
{
let cout = (arr instanceof Array) ? arr.length : arr;
let count = (arr instanceof Array) ? arr.length : arr;
if (index < 0)
return cout - 1;
else if (index >= cout)
return 0
return count - 1;
else if (index >= count)
return index - count;
else
return index
return index;
}
//格式化日期
export function formateDate(date: Date, fmt: string)

@ -119,6 +119,10 @@ export class Arc extends Curve
{
return this.m_Clockwise;
}
set IsClockWise(v: boolean)
{
this.m_Clockwise = v;
}
get StartAngle()
{
@ -200,7 +204,7 @@ export class Arc extends Curve
{
if (this.m_Radius == 0 ||
this.AllAngle == 0 ||
!equaln(pt.distanceToSquared(this.Center), this.m_Radius * this.m_Radius, 1e-6))
!equaln(pt.distanceToSquared(this.Center), this.m_Radius * this.m_Radius, 1e-4))
return NaN;
let ptTmp = pt.clone().applyMatrix4(this.OCSInv);

@ -1,10 +1,10 @@
import * as THREE from 'three';
import { Box3, EllipseCurve, Geometry, Matrix4, Object3D, Vector3 } from 'three';
import { arrayFirst, arraySortByNumber, arrayRemoveDuplicateBySort, arrayLast } from '../Common/ArrayExt';
import { Box3, EllipseCurve, Geometry, Object3D, Vector3 } from 'three';
import { arrayLast, arrayRemoveDuplicateBySort } from '../Common/ArrayExt';
import { ColorMaterial } from '../Common/ColorPalette';
import { clamp } from '../Common/Utils';
import { Arc } from '../DatabaseServices/Arc';
import { angle, equaln, polar, MoveMatrix } from '../Geometry/GeUtils';
import { MoveMatrix, angle, equaln, polar } from '../Geometry/GeUtils';
import { RenderType } from '../GraphicsSystem/Enum';
import { IntersectCircleAndArc, IntersectCircleAndCircle, IntersectLineAndCircle, IntersectOption, IntersectPolylineAndCurve, reverseIntersectOption } from '../GraphicsSystem/IntersectWith';
import { Factory } from './CADFactory';
@ -134,7 +134,7 @@ export class Circle extends Curve
{
let sa = anglelist[i];
let ea = anglelist[i + 1];
if (!equaln(sa, ea))
if (!equaln(sa, ea, 1e-6))
{
let arc = new Arc(new Vector3(), this.m_Radius, sa, ea);
arc.ApplyMatrix(this.OCS);
@ -155,7 +155,7 @@ export class Circle extends Curve
PtOnCurve(pt: Vector3)
{
return equaln(pt.distanceToSquared(this.Center), this.m_Radius * this.m_Radius, 1e-6);
return equaln(pt.distanceToSquared(this.Center), this.m_Radius * this.m_Radius, 1e-4);
}
GetOffsetCurves(offsetDist: number)
{
@ -293,6 +293,7 @@ export class Circle extends Curve
}
GetClosestPointTo(pt: Vector3, extend: boolean): Vector3
{
if (pt.distanceToSquared(this.Center) == 0) return this.GetPointAtParam(0);
let l = new Line(this.Center, pt);
let pts = l.IntersectWith(this, IntersectOption.ExtendBoth);
let ptIns = pt.distanceTo(pts[0]) < pt.distanceTo(pts[1]) ? pts[0] : pts[1];

@ -1,14 +1,14 @@
import * as THREE from "three";
import { CreateBoardUtil } from "../ApplicationServices/mesh/createBoard";
import { Vec2DTo3D, Vec3DTo2D, curveLinkGroup, equalCurveAndCurve } from "../Common/CurveUtils";
import { RegionParse, Route } from "../Geometry/RegionParse";
import { isTargetCurInSourceCur } from "../GraphicsSystem/BoolOperateUtils";
import { isTargetCurInOrOnSourceCur } from "../GraphicsSystem/BoolOperateUtils";
import { IntersectOption } from "../GraphicsSystem/IntersectWith";
import { Arc } from "./Arc";
import { Circle } from "./Circle";
import { Curve } from "./Curve";
import { Ellipse } from "./Ellipse";
import { Polyline } from "./Polyline";
import { rotatePoint } from "../Geometry/GeUtils";
export class Contour
{
@ -29,6 +29,16 @@ export class Contour
}
}
}
static CreateContour(cus: Curve[])
{
let con = new Contour();
con.m_Outline = Contour.Combine(cus ? cus : [])[0] as Polyline | Circle;
if (con.m_Outline && !con.m_Outline.IsClose)
{
return undefined;
}
return con;
}
get Outline(): Polyline | Circle
{
return this.m_Outline;
@ -67,7 +77,7 @@ export class Contour
* @returns {intersectionList //交集曲线表, unionList //并集曲线表, subtractList 差集曲线表}
* @memberof Contour
*/
private getOperatedCurves(target: Contour)
getOperatedCurves(target: Contour)
{
let intersectionList: Curve[] = [];
let unionList: Curve[] = [];
@ -77,6 +87,7 @@ export class Contour
let targetOutline = target.Outline;
let interPts = sourceOutline.IntersectWith(targetOutline, IntersectOption.OnBothOperands);
let sourceContainerTarget = this.CuInOutline(targetOutline);
let targetContainerSource = target.CuInOutline(sourceOutline);
@ -105,15 +116,29 @@ export class Contour
let sourceCus: Array<Polyline | Arc> = sourceOutline.GetSplitCurves(pars1);
let targetCus: Array<Polyline | Arc> = targetOutline.GetSplitCurves(pars2);
//是否有相等的曲线
let hasEqualCus = false;
//共同线段是否连接2区域
let disLink = false;
for (let pl of sourceCus)
{
//在目标分离曲线数组从若有相等的曲线则直接加入合并和相交集合中在目标数组中就直接跳过不在添加在2轮廓有共线部分时需此判断
let hasEqualCus = targetCus.some(l => equalCurveAndCurve(pl, l));
//在目标分离曲线数组从若有相等的曲线,且相等的线段不连接2区域则直接加入合并和相交集合中
//在目标数组中就直接跳过不在添加在2轮廓有共线部分时需此判断
hasEqualCus = targetCus.some(l => equalCurveAndCurve(pl, l));
if (hasEqualCus)
{
unionList.push(pl);
intersectionList.push(pl);
continue;
//获得共有线段中点2侧的点,判断是否有存在2区域外的点
let tmpPt = pl.GetPointAtParam(0.5);
let tmpDerv = rotatePoint(pl.GetFistDeriv(0.5), Math.PI / 2);
let sidePts = [tmpPt.clone().add(tmpDerv), tmpPt.add(tmpDerv.negate())];
disLink = sidePts.some(p => !sourceOutline.PtInCurve(p) && !targetOutline.PtInCurve(p));
if (disLink)
{
unionList.push(pl);
intersectionList.push(pl);
continue;
}
}
if (target.CuInOutline(pl))
@ -130,7 +155,7 @@ export class Contour
for (let pl of targetCus)
{
let hasEqualCus = sourceCus.some(l => equalCurveAndCurve(pl, l));
if (hasEqualCus)
if (hasEqualCus && disLink)
{
continue;
}
@ -145,32 +170,22 @@ export class Contour
}
}
}
return { intersectionList, unionList, subtractList };
}
//获得所有闭合的轮廓.
static GetAllContour(cus: Curve[])
{
const getSealCurByRoutes = (route: Set<Route>) =>
{
let cus: Curve[] = [];
for (let r of route)
{
cus.push(r.curve);
}
return new Contour(cus);
}
let regPar = new RegionParse(cus);
let cuGroups = curveLinkGroup(cus);
let contours: Contour[] = []
for (let routes of regPar.m_RegionsOutline)
{
contours.push(getSealCurByRoutes(routes));
}
for (let routes of regPar.m_RegionsInternal)
cuGroups.forEach(cus =>
{
contours.push(getSealCurByRoutes(routes));
}
return contours;
contours.push(Contour.CreateContour(cus));
})
return contours.filter(c => c !== undefined);
}
/**
* 线
@ -234,7 +249,7 @@ export class Contour
}
CuInOutline(targetCur: Curve)
{
return isTargetCurInSourceCur(this.m_Outline, targetCur);
return isTargetCurInOrOnSourceCur(this.m_Outline, targetCur);
}
Equal(tar: Contour)
{

@ -43,8 +43,10 @@ export abstract class Curve extends Entity
super();
}
get StartPoint(): Vector3 { return; }
set StartPoint(v: Vector3) { return; }
get StartParam(): number { return; }
get EndPoint(): Vector3 { return; }
set EndPoint(v: Vector3) { return; }
get EndParam(): number { return; }
get Area(): number { return 0; }
//获得曲线的面积,逆时针为正,顺时针为负.
@ -83,6 +85,12 @@ export abstract class Curve extends Entity
* @memberof Curve
*/
GetSplitCurves(param: number[] | number): Array<Curve> { return; }
GetSplitCurvesByPts(pt: Vector3[] | Vector3): Array<Curve>
{
let pts = Array.isArray(pt) ? pt : [pt];
let pars = pts.map(p => this.GetParamAtPoint(p))
return this.GetSplitCurves(pars);
}
protected SplitParamSort(param: number[] | number): number[]
{
//切割参数列表
@ -92,7 +100,7 @@ export abstract class Curve extends Entity
params = param.filter(param => this.ParamOnCurve(param));
params.push(0, this.EndParam);
arraySortByNumber(params);
arrayRemoveDuplicateBySort(params, equaln);
arrayRemoveDuplicateBySort(params, (e1, e2) => equaln(e1, e2, 1e-6));
}
else
params = [0, param, 1];
@ -116,8 +124,8 @@ export abstract class Curve extends Entity
return equal(this.StartPoint, pt) || equal(this.EndPoint, pt) || this.ParamOnCurve(this.GetParamAtPoint(pt));
}
//参数在曲线上
ParamOnCurve(param: number): boolean { return !isNaN(param) && param >= -1e-8 && param <= this.EndParam + 1e-8; }
//参数在曲线上,增加误差范围1e-6
ParamOnCurve(param: number): boolean { return !isNaN(param) && param >= -1e-6 && param <= this.EndParam + 1e-6; }
GetOffsetCurves(offsetDist: number): Array<Curve> { return; }
GetClosestPointTo(pt: Vector3, extend: boolean): Vector3 { return; }

@ -183,7 +183,7 @@ export class Line extends Curve
if (param >= 0 && param <= 1) return pt_int;
if (param < 0) return this.StartPoint;
if (param > 0) return this.EndPoint;
return;
return this.StartPoint;
}
Extend(newParam: number)
@ -239,11 +239,7 @@ export class Line extends Curve
}
get BoundingBox(): Box3
{
let pts = [
this.m_StartPoint,
this.m_EndPoint
];
return new Box3().setFromPoints(pts);
return new Box3().setFromPoints([this.StartPoint, this.EndPoint]);
}
get StartParam()

@ -1,6 +1,5 @@
import { Vector2, Vector3 } from 'three';
import { angle, equal, equaln } from '../Geometry/GeUtils';
import { angle, equaln, equal } from '../Geometry/GeUtils';
import { IntersectOption } from '../GraphicsSystem/IntersectWith';
import { Arc } from './Arc';
import { Line } from './Line';
@ -29,9 +28,10 @@ function IsPointInCircularSector(arc: Arc, pt: Vector3): boolean
*
* @param {Arc} arc
* @param {Vector3} pt
* @param {boolean} isInChrodIsTrue
* @returns {boolean}
*/
export function IsPointInBowArc(arc: Arc, pt: Vector3): boolean
export function IsPointInBowArc(arc: Arc, pt: Vector3, isInChrodIsTrue = false): boolean
{
let pv = pt.clone().sub(arc.StartPoint);
let av = arc.EndPoint.sub(arc.StartPoint);
@ -47,7 +47,7 @@ export function IsPointInBowArc(arc: Arc, pt: Vector3): boolean
// return arc.Center.distanceToSquared(pt) < arc.Radius * arc.Radius;
//简化的代码
if ((pv.z > 0) !== arc.IsClockWise)
if ((pv.z > 0) !== arc.IsClockWise || (isInChrodIsTrue && equaln(pv.z, 0)))
{
return arc.Center.distanceToSquared(pt) < arc.Radius * arc.Radius;
}
@ -70,29 +70,84 @@ export function IsPointInPolyLine(pl: Polyline, pt: Vector3): boolean
for (let i = 0; i < pl.EndParam; i++)
{
let cu = pl.GetCurveAtIndex(i);
let inpts = cu.IntersectWith(insLine, IntersectOption.ExtendArg);
if (equaln(pl.GetBuilgeAt(i), 0))//直线
{
let sp = pl.GetPointAtParam(i);
let ep = pl.GetPointAtParam(i + 1);
//点位于线上面
if (pt.y > Math.max(sp.y, ep.y))
continue;
//线垂直Y轴
let derX = ep.x - sp.x;
if (equaln(derX, 0))
continue;
//起点
if (equaln(sp.x, pt.x))
{
if (sp.y > pt.y && derX < 0) crossings++;
continue;
}
//终点
if (equaln(ep.x, pt.x))
{
if (ep.y > pt.y && derX > 0) crossings++;
continue;
}
for (let pti of inpts)
//快速求交,只验证有没有交点
let [x1, x2] = sp.x > ep.x ? [ep.x, sp.x] : [sp.x, ep.x];
if (pt.x > x1 && pt.x < x2)
{
let derY = ep.y - sp.y;
let k = derY / derX;
if ((pt.x - sp.x) * k + sp.y > pt.y)
crossings++;
}
}
else //圆弧
{
if (pti.y < pt.y)
let arc = pl.GetCurveAtIndex(i) as Arc;
let sp = arc.StartPoint;
let ep = arc.EndPoint;
//如果相切
if (equaln(Math.abs(pt.x - arc.Center.x), arc.Radius))
{
//当点和起点或者终点和点相切时
if (equaln(sp.x, pt.x) && sp.y > pt.y)
{
if (ep.x - sp.x < -1e-5)
crossings++;
}
else if (equaln(ep.x, pt.x) && ep.y > pt.y)
{
if (ep.x - sp.x > 1e-5)
crossings++;
}
continue;
}
if (equal(pti, cu.StartPoint))
if (equaln(sp.x, pt.x) && sp.y > pt.y)
{
let der = cu.GetFistDeriv(0);
if (der.x < -1e-3) //左边+ 右边0
let der = arc.GetFistDeriv(0);
if (der.x < -1e-5)
crossings++;
}
else if (equal(pti, cu.EndPoint))
if (equaln(ep.x, pt.x) && ep.y > pt.y)
{
let der = cu.GetFistDeriv(1);
if (der.x > 1e-3) //左边+ 右边0
let der = arc.GetFistDeriv(1);
if (der.x > 1e-5)
crossings++;
}
else
for (let pti of arc.IntersectWith(insLine, IntersectOption.ExtendArg))
{
let der = cu.GetFistDeriv(pti);
if (pti.y < pt.y || equal(sp, pti) || equal(ep, pti))
continue;
let der = arc.GetFistDeriv(pti);
if (!equaln(der.x, 0)) //相切.
crossings++;
}

@ -3,22 +3,20 @@ import { Box3, Geometry, Matrix4, Object3D, Vector2, Vector3 } from 'three';
import { CreateBoardUtil } from '../ApplicationServices/mesh/createBoard';
import { arrayLast, arrayRemoveDuplicateBySort } from '../Common/ArrayExt';
import { ColorMaterial } from '../Common/ColorPalette';
import { Vec2DTo3D, Vec3DTo2D, getDeterminantFor2V } from '../Common/CurveUtils';
import { getDeterminantFor2V, Vec2DTo3D, Vec3DTo2D } from '../Common/CurveUtils';
import { matrixAlignCoordSys } from '../Common/Matrix4Utils';
import { FixIndex } from '../Common/Utils';
import { equal, equaln, rotatePoint, updateGeometry } from '../Geometry/GeUtils';
import { equal, equaln, updateGeometry } from '../Geometry/GeUtils';
import { RenderType } from '../GraphicsSystem/Enum';
import { IntersectOption, IntersectPolylineAndCurve } from '../GraphicsSystem/IntersectWith';
import { angleTo } from './../Geometry/GeUtils';
import { PolyOffsetUtil } from '../GraphicsSystem/OffsetPolyline';
import { Arc } from './Arc';
import { Factory } from './CADFactory';
import { CADFile } from './CADFile';
import { Circle } from './Circle';
import { Curve, ExtendType } from './Curve';
import { Line } from './Line';
import { IsPointInPolyLine } from './PointInPolyline';
export interface PolylineProps
{
pt: Vector2,
@ -155,6 +153,18 @@ export class Polyline extends Curve
return Vec2DTo3D(this.m_LineData[0].pt).applyMatrix4(this.OCS);
return new Vector3();
}
set StartPoint(v: Vector3)
{
this.SetPointAt(0, Vec3DTo2D(v));
let bul = this.GetBuilgeAt(0)
if (bul !== 0)
{
let arc = this.GetCurveAtParam(0) as Arc;
arc.StartPoint = v;
//前面线的凸度调整
this.SetBulgeAt(0, Math.tan(arc.AllAngle / 4) * Math.sign(bul));
}
}
get EndPoint()
{
if (this.m_ClosedMark) return this.StartPoint;
@ -162,6 +172,18 @@ export class Polyline extends Curve
return Vec2DTo3D(this.m_LineData[this.EndParam].pt).applyMatrix4(this.OCS);
return new Vector3();
}
set EndPoint(v: Vector3)
{
this.SetPointAt(this.EndParam, Vec3DTo2D(v));
let bul = this.GetBuilgeAt(this.EndParam - 1)
if (bul !== 0)
{
let arc = this.GetCurveAtParam(0) as Arc;
arc.EndPoint = v;
//前面线的凸度调整
this.SetBulgeAt(this.EndParam - 1, Math.tan(arc.AllAngle / 4) * Math.sign(bul));
}
}
get StartParam()
{
return 0;
@ -187,27 +209,27 @@ export class Polyline extends Curve
}
get Area2()
{
let { pts, buls } = this.PtsBuls;
let area = 0;
for (let i = 0; i < this.m_LineData.length - 1; i++)
for (let i = 0; i < pts.length - 1; i++)
{
let startV = this.m_LineData[i];
let endV = this.m_LineData[i + 1];
let startV = pts[i];
let endV = pts[i + 1];
let det = getDeterminantFor2V(startV, endV);
area += getDeterminantFor2V(startV.pt, endV.pt) / 2;
if (startV.bul != 0)
let bul = buls[i];
if (bul != 0)
{
let arc = new Arc().ParseFromBul(startV.pt, endV.pt, startV.bul);
area += arc.Area * Math.sign(startV.bul);
let arc = new Arc().ParseFromBul(startV, endV, bul);
let rSq = arc.Radius ** 2;
//弓形面积
let arcArea = rSq * arc.AllAngle * 0.5 - 0.5 * rSq * Math.sin(arc.AllAngle);
//我们可以知道 正的凸度总是增加逆时针的面积, 负的凸度总是增加顺时针的面积
det += arcArea * Math.sign(bul) * 2;
}
area += det;
}
if (!this.IsClose)
{
let startV = arrayLast(this.m_LineData);
let endV = this.m_LineData[0];
area += getDeterminantFor2V(startV.pt, endV.pt) / 2
}
return area;
return area / 2;
}
get Area()
{
@ -221,7 +243,7 @@ export class Polyline extends Curve
//曲线是否闭合
get IsClose(): boolean
{
return this.CloseMark || equal(this.StartPoint, this.EndPoint);
return this.CloseMark || equal(this.StartPoint, this.EndPoint, 1e-5);
}
set CloseMark(v: boolean)
{
@ -245,11 +267,11 @@ export class Polyline extends Curve
*/
GetPointAtParam(param: number): Vector3
{
if (param === Math.floor(param) && this.ParamOnCurve(param))
return Vec2DTo3D(this.GetPoint2dAt(FixIndex(param, this.NumberOfVertices))).applyMatrix4(this.OCS);
let cu: Curve = this.GetCurveAtParam(param);
if (cu)
{
return cu.GetPointAtParam(this.GetCurveParamAtParam(param));
}
return undefined;
}
@ -392,7 +414,6 @@ export class Polyline extends Curve
return pl;
}
GetSplitCurves(param: number[] | number): Array<Polyline>
{
//参数需要转化为参数数组
@ -419,7 +440,7 @@ export class Polyline extends Curve
return [];
//判断是否存在0参数
let hasZeroParam = params[0] == 0;
let hasZeroParam = equaln(params[0], 0, 1e-6);
if (hasZeroParam)
params.shift();
@ -446,7 +467,7 @@ export class Polyline extends Curve
//添加点
for (let i = 0; i < pafloor; i++)
{
if (i == 0 && buls[0] != 0)
if (i == 0 && !equaln(buls[0], 0, 1e-6))
{
buls[0] = Math.tan((1 - prePa) * Math.atan(buls[0]));
}
@ -462,7 +483,7 @@ export class Polyline extends Curve
else //在曲线上
{
let bul: number = buls[0];
if (bul != 0)
if (!equaln(bul, 0, 1e-6))
bul = Math.tan((pa - pafloor - (0 === pafloor ? prePa : 0)) * Math.atan(buls[0])); //->凸度
//加入顶点+凸度
@ -475,7 +496,8 @@ export class Polyline extends Curve
}
prePa = pa - pafloor;
pls.push(new Polyline(plData).ApplyMatrix(this.OCS));
if (plData.length > 1)
pls.push(new Polyline(plData).ApplyMatrix(this.OCS));
}
//当曲线为闭合曲线,并且不存在0切割参数时,首尾连接曲线
@ -684,7 +706,7 @@ export class Polyline extends Curve
//最近点
let ptC = this.StartPoint;
//最近点的距离
//最近点的距离\
let ptCDist = ptC.distanceToSquared(pt);
for (let i = 0; i < this.EndParam; i++)
@ -730,220 +752,11 @@ export class Polyline extends Curve
return ptC;
}
//偏移
GetOffsetCurves(offsetDist: number): Array<Curve>
{
let plList: Array<Polyline> = [];
for (let i = 0; i < this.EndParam; i++)
{
let pl = this.offestCurve(i, offsetDist);
pl && plList.push(pl);
}
//连接全部连接点
let newPlList: Array<Polyline> = this.linkPolylineGroup(plList, offsetDist);
// //分离出自交的线
let outputPls = this.removeSelfIntersect(newPlList, offsetDist);
this.linkPLine(newPlList, offsetDist);
this.cuttingPolyLine(newPlList, offsetDist);
outputPls.push(...this.arrangePlineList(newPlList));
return outputPls;
}
//偏移曲线
private offestCurve(param: number, dist: number)
{
let startV: PolylineProps = {
pt: this.m_LineData[param].pt,
bul: this.m_LineData[param].bul
}
let endV: PolylineProps = {
pt: this.m_LineData[param + 1].pt,
bul: this.m_LineData[param + 1].bul
}
if (equaln(startV.pt.distanceTo(endV.pt), 0)) return;
let tarLine = this.GetFistDeriv(param).normalize();
//偏移向量
let moveVec = rotatePoint(tarLine, Math.PI / 2).multiplyScalar(-dist);
//偏移矩阵
let mat = new Matrix4().makeTranslation(moveVec.x, moveVec.y, moveVec.z);
let originLine = Vec2DTo3D(endV.pt.clone().sub(startV.pt));
startV.pt = Vec3DTo2D(Vec2DTo3D(startV.pt).applyMatrix4(mat));
if (startV.bul !== 0)
{
moveVec = rotatePoint(moveVec, Math.atan(startV.bul) * 4);
}
mat.makeTranslation(moveVec.x, moveVec.y, moveVec.z);
endV.pt = Vec3DTo2D(Vec2DTo3D(endV.pt).applyMatrix4(mat));
let finalLine = Vec2DTo3D(endV.pt.clone().sub(startV.pt));
if (equaln(finalLine.angleTo(originLine), Math.PI))
{
return;
}
let pl = this.copyPolyline([startV, endV]);
pl.CloseMark = false;
return pl;
}
/**
* 线
* @private
* @param {Polyline[]} pls
* @memberof Polyline
*/
private linkPLine(pls: Polyline[], offset: number)
{
for (let i = 0; i < pls.length - 1; i++)
{
let frontLine = pls[i];
let laterLine = pls[i + 1];
let interPts = frontLine.IntersectWith(laterLine, IntersectOption.ExtendBoth);
if (interPts.length > 0)
{
let pt = this.selectPlInterPt(interPts, laterLine.StartPoint);
//调整前后两条多段线的首尾线
this.adjustFrontLine(frontLine.LineData[1], pt, frontLine.LineData[0]);
frontLine.LineData[1].pt = Vec3DTo2D(pt);
this.adjustLaterLine(laterLine.LineData[1], pt, laterLine.LineData[0]);
}
}
}
/**
* 线
* 线,,
* @private
* @param {Array<Polyline>} plList
* @param {number} offsetDist
* @returns
* @memberof Polyline
*/
private removeSelfIntersect(plList: Polyline[], offsetDist: number)
{
let plLists: Polyline[] = [];
let deletePlList: Polyline[] = [];
let deleteCount = 0;
for (let i = 0; i < plList.length - 1; i++)
{
//前一根线
let frontLine = plList[i];
//要删除自交线的索引
let deleteIndex: number;
//截取到的自交线交点
let insertPt = new Vector3();
for (let j = i + 1; j < plList.length; j++)
{
// 后一根线
let laterLine = plList[j];
let intPts = frontLine.IntersectWith(laterLine, IntersectOption.OnBothOperands);
if (intPts.length === 2)
{
intPts[0].distanceTo(frontLine.StartPoint) < intPts[1].distanceTo(frontLine.StartPoint) ? intPts.pop() : intPts.shift();
}
if (intPts.length > 0 && !equal(intPts[0], laterLine.StartPoint) && !equal(intPts[0], laterLine.EndPoint))
{
deleteIndex = j;
insertPt.copy(intPts[0]);
}
}
if (deleteIndex)
{
// 删除的自交线
let deleteLine = plList[deleteIndex];
let clonedeleteLine = deleteLine.Clone() as Polyline;
let cloneStartLine = frontLine.Clone() as Polyline
this.adjustFrontLine(frontLine.LineData[1], insertPt, frontLine.LineData[0]);
frontLine.LineData[1].pt = Vec3DTo2D(insertPt);
//留下剩余的
this.adjustLaterLine(cloneStartLine.LineData[1], insertPt, cloneStartLine.LineData[0]);
this.adjustLaterLine(deleteLine.LineData[1], insertPt, deleteLine.LineData[0]);
//留下剩余的
this.adjustFrontLine(clonedeleteLine.LineData[1], insertPt, clonedeleteLine.LineData[0]);
clonedeleteLine.LineData[1].pt = Vec3DTo2D(insertPt);
//分离出的线
deletePlList = plList.splice(i + 1 - deleteCount, deleteIndex - i - 1);
if (deletePlList.length >= 2)
{
//添加自交开始结束的部分
deletePlList.unshift(cloneStartLine);
deletePlList.push(clonedeleteLine);
plLists.push(this.AssemblePolyline(this.handleRemoveLine(deletePlList)));
}
//已删除元素数量
deleteCount += (deleteIndex - i - 1);
i = deleteIndex - 1;
}
}
return plLists;
}
//处理分离出的多段线,把相交的部分提取出来
private handleRemoveLine(plList: Polyline[])
{
let startIndex: number;
let endIndex: number;
let insertPt = new Vector3();
for (let i = 0; i < plList.length - 1; i++)
{
//前一根线
let frontLine = plList[i];
//截取到的自交线交点
for (let j = i + 1; j < plList.length; j++)
{
// 后一根线
let laterLine = plList[j];
let intPts = frontLine.IntersectWith(laterLine, IntersectOption.OnBothOperands);
if (intPts.length === 2)
{
intPts[0].distanceTo(laterLine.StartPoint) < intPts[1].distanceTo(laterLine.StartPoint) ? intPts.pop() : intPts.shift();
}
if (intPts.length > 0 && !equal(intPts[0], laterLine.StartPoint) && !equal(intPts[0], laterLine.EndPoint))
{
startIndex = i;
endIndex = j;
insertPt.copy(intPts[0]);
}
}
}
if (startIndex !== undefined)
{
// 删除的自交线
let startLine = plList[startIndex];
let endLine = plList[endIndex];
this.adjustFrontLine(endLine.LineData[1], insertPt, endLine.LineData[0]);
endLine.LineData[1].pt = Vec3DTo2D(insertPt);
this.adjustLaterLine(startLine.LineData[1], insertPt, startLine.LineData[0]);
return plList.slice(startIndex, endIndex + 1);
} else return plList
}
// 根据交点调整前面线段的凸度
private adjustFrontLine(endV: PolylineProps, insertPt: Vector3, startV: PolylineProps)
{
if (startV.bul !== 0)
{
let arc = new Arc().ParseFromBul(startV.pt, endV.pt, startV.bul);
arc.EndPoint = insertPt;
//前面线的凸度调整
startV.bul = Math.tan(arc.AllAngle / 4) * Math.sign(startV.bul);
}
}
// 根据交点调整后面线段的凸度和起始点
private adjustLaterLine(endV: PolylineProps, interPt: Vector3, startV: PolylineProps)
{
let bul = 0;
if (startV.bul !== 0)
{
let arc = new Arc().ParseFromBul(startV.pt, endV.pt, startV.bul);
arc.StartPoint = interPt;
bul = Math.tan(arc.AllAngle * 0.25) * Math.sign(startV.bul);
}
// 调整后面线起始点和凸度
startV.pt = Vec3DTo2D(interPt);
startV.bul = bul;
let polyOffestUtil = new PolyOffsetUtil(this, offsetDist);
return polyOffestUtil.GetOffsetCurves();
}
/**
*
@ -1018,388 +831,6 @@ export class Polyline extends Curve
return new Arc().ParseFromBul(d1.pt, d2.pt, d1.bul).ApplyMatrix(this.OCS);
}
}
// 组合多段线数组组合为一多段线
AssemblePolyline(pls: Array<Polyline>)
{
if (pls.length === 0) return;
let plDataList: PolylineProps[] = [];
plDataList.push(pls[0].LineData[0]);
for (let i = 0; i < pls.length - 1; i++)
{
let frontLine = pls[i];
let laterLine = pls[i + 1];
if (equal(frontLine.EndPoint, laterLine.StartPoint))
{
plDataList.push(laterLine.LineData[0]);
}
}
plDataList.push(pls[pls.length - 1].LineData[1]);
return new Polyline(plDataList);
}
//整理多段线数组,把相连的组合成多段线,返回多段线数组
private arrangePlineList(pls: Array<Polyline>)
{
if (pls.length === 0) return [];
let plDataList: PolylineProps[] = [];
let plList: Polyline[] = [];
plDataList.push(pls[0].LineData[0]);
for (let i = 0; i < pls.length - 1; i++)
{
let frontLine = pls[i];
let laterLine = pls[i + 1];
if (equal(frontLine.EndPoint, laterLine.StartPoint))
{
plDataList.push(laterLine.LineData[0]);
}
else
{
plDataList.push(frontLine.LineData[1]);
plList.push(new Polyline(plDataList));
plDataList = [laterLine.LineData[0]];
}
}
plDataList.push(pls[pls.length - 1].LineData[1]);
plList.push(new Polyline(plDataList));
return plList;
}
/**
* 线
* ,线
*
* @private
* @param {Array<Polyline>} plList
* @param {number} [offsetDist]
* @returns
* @memberof Polyline
*/
private linkPolylineGroup(plList: Array<Polyline>, offsetDist?: number)
{
if (plList.length === 1)
{
return plList;
}
let newPlList: Array<Polyline> = [];
let startV = plList[0].LineData[0];
//原先的斜率
let oldSlope: Vector3;
//新斜率
let newSlope: Vector3;
for (let i = 0; i < plList.length; i++)
{
//前面线
let frontLine = plList[i];
//原先的斜率
oldSlope = frontLine.GetFistDeriv(0);
//后面线
let laterLine = plList[i + 1];
if (i === plList.length - 1)
{
if (this.IsClose)
laterLine = plList[0];
else break;
}
//终点data
let endV = this.clonePlData(laterLine.LineData[0]);
//交点
let interPt = Vec2DTo3D(endV.pt);
// 如果两线结合点不相等
if (!equal(frontLine.EndPoint, laterLine.StartPoint))
{
// 多段线交点数组
let interPts = frontLine.IntersectWith(laterLine, IntersectOption.ExtendBoth);
//如果没有交点,则用圆弧连接
if (interPts.length === 0)
{
let centerPt;
//取圆心圆心离后面线start点距离等于偏移距离
for (let j = i; j < this.LineData.length; j++)
{
let pt = Vec2DTo3D(this.LineData[j].pt);
if (equaln(pt.distanceTo(laterLine.StartPoint), Math.abs(offsetDist)))
{
centerPt = pt;
break;
}
}
if (!centerPt) throw new Error("找不到圆心");
// 圆心到前面线end点向量
let startLine = frontLine.EndPoint.clone().sub(centerPt);
// 圆心到后面线start点向量
let endLine = laterLine.StartPoint.clone().sub(centerPt);
let circleAngle;
//补圆弧的起始交点
let intPt = Vec2DTo3D(frontLine.LineData[1].pt);
// 如果起始向量和终止向量相等,则都为半径
if (equaln(startLine.lengthSq(), endLine.lengthSq()))
{
circleAngle = angleTo(startLine, endLine);
}
else
{
// 以centerPt为圆心偏移距离为为半径画圆
let tmpCir = new Circle(centerPt, Math.abs(offsetDist));
//只会和前面线相交,因为圆心选取是根据后面线startPoint偏移距离处的点,只会与后面线相切,允许前面线延伸
let pts = tmpCir.IntersectWith(frontLine, IntersectOption.OnBothOperands);
if (pts.length > 0)
{
//选取交点,如果有多个选离前面线start点近的
intPt = this.selectPlInterPt(pts, frontLine.StartPoint);
let insLine = intPt.clone().sub(centerPt);
circleAngle = angleTo(insLine, endLine);
this.adjustFrontLine(frontLine.LineData[1], intPt, startV);
}
else
{
// 与补线圆无交点,放弃补圆弧
newPlList.push(new Polyline([
startV, this.clonePlData(frontLine.LineData[1])
]))
startV = this.clonePlData(laterLine.LineData[0]);
continue;
}
}
let tmpPlData = {
pt: Vec3DTo2D(intPt),
bul: Math.tan(circleAngle / 4)
};
newPlList.push(new Polyline([
startV, tmpPlData
]))
startV = this.clonePlData(tmpPlData);
}
else
{
let pts = frontLine.IntersectWith(laterLine, IntersectOption.OnBothOperands);
interPt = pts.length > 0 ? pts[0] : this.selectPlInterPt(interPts, laterLine.StartPoint)
this.adjustFrontLine(frontLine.LineData[1], interPt, startV);
this.adjustLaterLine(laterLine.LineData[1], interPt, endV);
}
}
let pl = new Polyline([startV, endV])
newSlope = pl.GetFistDeriv(0);
startV = this.clonePlData(endV);
if (i === plList.length - 1)
{
this.adjustLaterLine(newPlList[0].LineData[1], interPt, newPlList[0].LineData[0]);
}
if (equal(pl.StartPoint, pl.EndPoint) || (pl.LineData[0].bul === 0 && equaln(newSlope.angleTo(oldSlope), Math.PI, 1e-7)))
{
continue;
}
newPlList.push(pl);
}
if (!this.IsClose)
{
let frontLine = plList[plList.length - 1];
let endV = this.clonePlData(frontLine.LineData[1]);
if (plList.length >= 3)
{
let laterLine = newPlList[0];
let pts = frontLine.IntersectWith(laterLine, IntersectOption.OnBothOperands);
if (pts.length === 1)
{
this.adjustFrontLine(frontLine.LineData[1], pts[0], startV);
endV.pt = Vec3DTo2D(pts[0]);
if (newPlList.length > 0)
this.adjustLaterLine(newPlList[0].LineData[1], pts[0], newPlList[0].LineData[0]);
}
}
let pl = new Polyline([startV, endV]);
newSlope = pl.GetFistDeriv(0);
if (pl.LineData[0].bul !== 0 || !equaln(newSlope.angleTo(oldSlope), Math.PI, 1e-7))
newPlList.push(pl);
}
return newPlList;
}
/**
* ,线
* //TODO:暂保留,待优化
* @private
* @param {Array<Polyline>} plList
* @returns
* @memberof Polyline
*/
private linkPolyline(plList: Array<Polyline>)
{
let isLine = false;
if (plList.length === 1) return plList;
for (let i = 0; i < plList.length - 1; i++)
{
let frontLine = plList[i];
let laterLine = plList[i + 1];
let interPt: Vector3;
if (equal(frontLine.EndPoint, laterLine.StartPoint))
{
continue;
}
else
{
if (!isLine)
{
let oldSlope = frontLine.GetFistDeriv(0);
let newSlope;
let interpts = frontLine.IntersectWith(laterLine, IntersectOption.ExtendBoth)
do
{
interPt = this.selectPlInterPt(interpts, laterLine.StartPoint);
while (!interPt)
{
plList.splice(i, 1);
i--;
if (i < 0) break;
frontLine = plList[i];
oldSlope = frontLine.GetFistDeriv(0);
}
if (i === -1) break;
this.adjustFrontLine(frontLine.LineData[1], interPt, frontLine.LineData[0]);
frontLine.LineData[1].pt = Vec3DTo2D(interPt);
newSlope = frontLine.GetFistDeriv(0);
if (!equaln(oldSlope.angleTo(newSlope), 0, 1e-7))
{
plList.splice(i, 1);
i--;
if (i < 0) break;
frontLine = plList[i];
oldSlope = frontLine.GetFistDeriv(0);
}
else
{
this.adjustLaterLine(laterLine.LineData[1], interPt, laterLine.LineData[0]);
break;
}
} while (true);
}
else
{
plList.splice(i - 1);
break;
}
isLine = true;
}
}
return plList.length > 1 ? plList : [];
}
/**
* spt
*
* @private
* @param {Vector3[]} pts
* @param {Vector3} spt
* @returns
* @memberof Polyline
*/
private selectPlInterPt(pts: Vector3[], spt: Vector3)
{
let pt: Vector3;
// 多段线交点数组
if (pts.length === 0) return;
else if (pts.length === 1)
{
pt = pts[0];
}
else
{
// 在当前线上不存在交点取离后面线startPt最近的交点
pt = pts[0].distanceTo(spt) < pts[1].distanceTo(spt) ? pts[0] : pts[1];
}
return pt;
}
/**
* 线
* 线,
* 线,
* @private
* @param {Polyline[]} plList
* @param {number} rad
* @returns
* @memberof Polyline
*/
private cuttingPolyLine(plList: Polyline[], rad: number)
{
rad = Math.abs(rad);
// 每个原线段点画圆分割多段线
for (let i = 0; i < this.LineData.length; i++)
{
//圆心点
let centerPt = Vec2DTo3D(this.LineData[i].pt);
let circle = new Circle(centerPt, rad);
for (let j = 0; j < plList.length; j++)
{
let pl = plList[j];
let sDist = pl.StartPoint.distanceTo(centerPt);
let eDist = pl.EndPoint.distanceTo(centerPt);
// 如果线段在圆内,则为无效线
if (sDist - rad <= 1e-7 && eDist - rad <= 1e-7)
{
//该段多段线和切割圆弧是否重合
if (pl.LineData[0].bul !== 0)
{
let center = (pl.GetCurveAtIndex(0) as Arc).Center;
if (equal(center, centerPt)) continue;
}
plList.splice(j, 1);
j--;
continue;
}
// 跟圆弧相交除非相切,否则都为2个交点
let pts = pl.IntersectWith(circle, IntersectOption.ExtendBoth);
if (pts.length <= 1) continue;
// 过滤掉不在线上的点
pts = pts.filter(p => plList[j].PtOnCurve(p));
if (pts.length === 0) continue;
else if (pts.length === 1)
{
// 线段一端在圆上,另一端在圆外而且没有其他交点
if ((equaln(sDist, rad) && eDist > rad) || (equaln(eDist, rad) && sDist > rad))
{
continue;
}
if (sDist < rad)
this.adjustLaterLine(pl.LineData[1], pts[0], pl.LineData[0])
else
{
this.adjustFrontLine(pl.LineData[1], pts[0], pl.LineData[0])
pl.LineData[1].pt = Vec3DTo2D(pts[0]);
}
}
else
{
//有可能误差错误漏掉切点
if (pts[0].distanceToSquared(pts[1]) <= 1e-8) continue;
let dist = pl.StartPoint.distanceTo(pts[0]);
let dist1 = pl.StartPoint.distanceTo(pts[1]);
//区分到pl的startPT近的和远的交点
let [pt, pt1] = dist < dist1 ? [pts[0], pts[1]] : [pts[1], pts[0]]
let clonePl = pl.Clone() as Polyline;
this.adjustFrontLine(pl.LineData[1], pt, pl.LineData[0]);
pl.LineData[1].pt = Vec3DTo2D(pt)
this.adjustLaterLine(clonePl.LineData[1], pt1, clonePl.LineData[0]);
plList.splice(j + 1, 0, clonePl);
j++;
}
}
}
}
private clonePlData(pl: PolylineProps)
{
return {
pt: pl.pt,
bul: pl.bul
}
}
IntersectWith(curve: Curve, intType: IntersectOption): Vector3[]
{
@ -1471,15 +902,18 @@ export class Polyline extends Curve
GetSnapPoints(): Array<THREE.Vector3>
{
let plList: Vector3[] = [];
let ptList: Vector3[] = [];
if (this.m_LineData.length < 2)
return plList;
for (let i = 0; i < this.EndParam + 0.5; i += 0.5)
return ptList;
let enParam = this.EndParam;
if (this.CloseMark) enParam -= 0.5;
for (let i = 0; i < enParam + 0.5; i += 0.5)
{
let p = this.GetPointAtParam(i);
plList.push(p);
ptList.push(p);
}
return plList;
return ptList;
}
MoveSnapPoints(indexList: number[], moveVec: Vector3)
{
@ -1515,12 +949,12 @@ export class Polyline extends Curve
GetStretchPoints(): Array<Vector3>
{
let ocs = this.OCS;
let plList: Vector3[] = [];
let ptList: Vector3[] = [];
for (let data of this.m_LineData)
{
plList.push(Vec2DTo3D(data.pt).applyMatrix4(ocs));
ptList.push(Vec2DTo3D(data.pt).applyMatrix4(ocs));
}
return plList;
return ptList;
}
/**

@ -63,7 +63,7 @@ export class Shape
IntersectionBoolOperation(targetShape: Shape): Shape[]
{
let resOutlines = this.m_Outline.IntersectionBoolOperation(targetShape.m_Outline);
let cus = this.targetOutlineSubHoleOutline(resOutlines, this.mergeHoles([...this.m_Holes, ...targetShape.m_Holes]))
let cus = this.targetOutlineSubHoleOutline(resOutlines, Shape.mergeContours([...this.m_Holes, ...targetShape.m_Holes]))
return this.pairHoleAndOutline(cus);
}
@ -121,7 +121,7 @@ export class Shape
shapes.push(...this.pairHoleAndOutline(this.targetOutlineSubHoleOutline(tmpInterList, this.m_Holes)))
})
let fCus = this.targetOutlineSubHoleOutline(resOutlines, this.mergeHoles([...this.m_Holes, ...targetShape.m_Holes]));
let fCus = this.targetOutlineSubHoleOutline(resOutlines, Shape.mergeContours([...this.m_Holes, ...targetShape.m_Holes]));
shapes.push(...this.pairHoleAndOutline(fCus));
return shapes;
@ -206,7 +206,7 @@ export class Shape
* @returns
* @memberof Shape
*/
private mergeHoles(holes: Contour[]): Contour[]
static mergeContours(holes: Contour[]): Contour[]
{
if (holes.length <= 1) return holes;
let rets: Contour[] = [];//返回的合并轮廓

@ -141,6 +141,9 @@ export class CameraControls
this.m_State = CameraControlState.Rotate;
this.m_Viewer.UpdateLockTarget();
}
//最后一次按中键的时间
lastMiddleClickTime = 0;
//鼠标
onMouseDown = (event: MouseEvent) =>
{
@ -161,6 +164,15 @@ export class CameraControls
}
case MouseKey.Middle:
{
let curTime = Date.now();
let t = curTime - this.lastMiddleClickTime;
this.lastMiddleClickTime = curTime;
if (t < 350)
{
this.m_Viewer.ZoomAll();
return;
}
if (this.m_KeyDown.get(KeyBoard.Control))
{
this.beginRotate();

@ -1,9 +1,12 @@
import { DrawAxis } from '../Add-on/AddAxis';
import { Command_Array } from '../Add-on/Array';
import { IntersectionOperation, SubsractOperation, UnionOperation } from '../Add-on/BoolOperation';
import { Union } from '../Add-on/CSGUnion';
import { Command_ClosePt } from '../Add-on/closetest';
import { Command_Copy } from '../Add-on/Copy';
import { CopyClip } from '../Add-on/CopyClip';
import { Command_CopyPoint } from '../Add-on/CopyPoint';
import { CustomUcs } from '../Add-on/CostumUCS';
import { Union } from '../Add-on/CSGUnion';
import { DrawArc } from '../Add-on/DrawArc';
import { Command_DrawBoard } from '../Add-on/DrawBoard';
import { DrawAlignedDimension } from '../Add-on/DrawDim/DrawAlignedDimension';
@ -14,6 +17,7 @@ import { DrawFloor } from '../Add-on/DrawFloor';
import { DrawGripStretch } from '../Add-on/DrawGripStretch';
import { DrawCircle, DrawLine, DrawSphere, DrawTest, ZoomE } from '../Add-on/DrawLine';
import { DrawPolyline } from '../Add-on/DrawPolyline';
import { DrawRect } from '../Add-on/DrawRec';
import { DrawRegion } from '../Add-on/DrawRegion';
import { DrawSky } from '../Add-on/DrawSky';
import { DrawSpline } from '../Add-on/DrawSpline';
@ -26,41 +30,40 @@ import { Command_Explode } from '../Add-on/Explode';
import { Command_Extend } from '../Add-on/Extends';
import { CommandFillet } from '../Add-on/Fillet';
import { Command_GenerateCode } from '../Add-on/GenerateCode';
import { Command_INsTest } from '../Add-on/instest';
import { Command_Join } from '../Add-on/Join';
import { Command_Lisp } from '../Add-on/Lisp';
import { Fbx } from '../Add-on/loadfbx';
import { LoadImg } from '../Add-on/LoadImg';
import { Command_Move } from '../Add-on/Move';
import { Command_Offset, Command_TestOffset } from '../Add-on/Offset';
import { OffsetX } from '../Add-on/OffsetX';
import { Open } from '../Add-on/Open';
import { PasteClip } from '../Add-on/PasteClip';
import { Pedit } from '../Add-on/Pedit';
import { Command_PLTest } from '../Add-on/polytest';
import { Command_PtInCu } from '../Add-on/ptincu';
import { Command_RevPl } from '../Add-on/RevPl';
import { Command_Rotate } from '../Add-on/Rotate';
import { Save } from '../Add-on/Save';
import { Command_Ssget } from '../Add-on/ssget';
import { Stretch } from '../Add-on/Stretch';
import { Command_SwitchCamera } from '../Add-on/SwitchCamera';
import { Command_SwitchPass } from '../Add-on/SwitchPass';
// import { DrawFloor } from '../Add-on/DrawFloor';
// import { RevTarget, SaveTarget } from '../Add-on/RenderTarget';
import { TestIntersect } from '../Add-on/test/testIntersect';
import { Command_TestBox } from '../Add-on/TestBox';
import { Command_DrawBoard2 } from '../Add-on/TestDrawBoard';
import { TestDrawDirectionalLight } from '../Add-on/TestDrawDirectionalLight';
import { TestDrawPointLight } from '../Add-on/TestDrawPointLight';
import { TestDrawSpotLight } from '../Add-on/TestDrawSpotLight';
import { TestTargeOnCurve } from '../Add-on/testEntity/TestCurve';
import { Command_Trim } from '../Add-on/Trim';
import { Redo, Undo } from '../Add-on/Undo';
import { ViewToFront, ViewToRight, ViewToTop } from '../Add-on/ViewChange';
import { Command_ClosePt } from '../Add-on/closetest';
import { Command_INsTest } from '../Add-on/instest';
import { Fbx } from '../Add-on/loadfbx';
import { Command_PLTest } from '../Add-on/polytest';
import { Command_PtInCu } from '../Add-on/ptincu';
import { Command_Ssget } from '../Add-on/ssget';
// import { DrawFloor } from '../Add-on/DrawFloor';
// import { RevTarget, SaveTarget } from '../Add-on/RenderTarget';
import { TestIntersect } from '../Add-on/test/testIntersect';
import { TestBoolOperationUtil } from '../Add-on/testEntity/TestBoolOperation';
import { Command_DimTest } from '../DatabaseServices/Dimension/dimTest';
import { commandMachine } from './CommandMachine';
import { DrawRect } from '../Add-on/DrawRec';
import { CopyClip } from '../Add-on/CopyClip';
import { PasteClip } from '../Add-on/PasteClip';
export function registerCommand()
{
@ -126,6 +129,8 @@ export function registerCommand()
commandMachine.RegisterCommand("copy", new Command_Copy());
commandMachine.RegisterCommand("lisp", new Command_Lisp());
commandMachine.RegisterCommand("rev", new Command_RevPl());
commandMachine.RegisterCommand("ex", new Command_Extend());
@ -142,8 +147,12 @@ export function registerCommand()
commandMachine.RegisterCommand("ptl", new TestDrawPointLight());
commandMachine.RegisterCommand("pt", new Command_CopyPoint());
commandMachine.RegisterCommand("dl", new TestDrawDirectionalLight());
commandMachine.RegisterCommand("oo", new OffsetX());
commandMachine.RegisterCommand("sl", new TestDrawSpotLight());
commandMachine.RegisterCommand("dal", new DrawAlignedDimension());
commandMachine.RegisterCommand("dli", new DrawLinearDimension());
@ -171,7 +180,7 @@ export function registerCommand()
commandMachine.RegisterCommand("incu", new Command_PtInCu());
commandMachine.RegisterCommand("code", new Command_GenerateCode());
commandMachine.RegisterCommand("testbool", new TestBoolOperationUtil());
commandMachine.RegisterCommand("outcur", new TestTargeOnCurve());
commandMachine.RegisterCommand("join", new Command_Join());
commandMachine.RegisterCommand("testInt", new TestIntersect());

@ -1,7 +1,6 @@
import { KeyBoard } from '../Common/KeyEnum';
export class KeyBoardControls
{
private m_KeyDownMap = new Map<KeyBoard, boolean>();
constructor()
{

@ -151,8 +151,10 @@ export class SnapServices
let vcsP = app.m_Editor.m_MouseCtrl.m_CurMousePointVCS;
for (let obj of app.m_Viewer.Scene.children)
{
if (!this.notSnapEntity.has(obj.userData) && obj.userData && obj.userData instanceof Entity)
if (obj.userData && obj.userData instanceof Entity)
{
if (this.notSnapEntity.has(obj.userData)) continue;
if (obj.userData.IsErase) continue;
for (let p of obj.userData.GetSnapPoints())
{
let pv = p.clone();

@ -0,0 +1,88 @@
import { Box3, Vector3 } from "three";
import { Curve } from "../DatabaseServices/Curve";
import { IntersectOption } from "../GraphicsSystem/IntersectWith";
import { greater } from "./GeUtils";
/**
*
* 线, (33.2 线 p599)
*
* @class CurveIntersection
*/
export class CurveIntersection
{
//用来缓存的曲线包围盒
private boxMap: Map<Curve, Box3> = new Map();
/**
* ,key 线 value (线Map)
*
* @type {Map<Curve, Map<Curve, Vector3[]>>}
* @memberof CurveIntersection
*/
intersect: Map<Curve, Map<Curve, Vector3[]>> = new Map();
/**
* @param {Curve[]} cus ,,
* @memberof CurveIntersection
*/
constructor(cus: Curve[])
{
this.genBox(cus);
//按x排序
this.sortCurve(cus);
let count = cus.length;
for (let i = 0; i < count; i++)
{
let c1 = cus[i];
let c1d = this.GetIntersect(c1);
let c1b = this.boxMap.get(c1);
for (let j = i + 1; j < count; j++)
{
let c2 = cus[j];
//过滤掉不需要计算的曲线
let c2b = this.boxMap.get(c2);
if (greater(c2b.min.x, c1b.max.x, 1e-6))
break;
if (greater(c2b.min.y, c1b.max.y, 1e-6))
continue;
let pts = c1.IntersectWith(c2, IntersectOption.OnBothOperands);
if (pts.length > 0)
{
c1d.set(c2, pts);
this.GetIntersect(c2).set(c1, pts);
}
}
}
}
private genBox(cus: Curve[])
{
cus.forEach(c =>
{
this.boxMap.set(c, c.BoundingBox);
});
}
private sortCurve(cus: Curve[])
{
cus.sort((c1, c2) =>
{
return this.boxMap.get(c1).min.x - this.boxMap.get(c2).min.x;
});
}
GetIntersect(cu: Curve): Map<Curve, Vector3[]>
{
if (this.intersect.has(cu))
return this.intersect.get(cu);
let m = new Map();
this.intersect.set(cu, m);
return m;
}
}

@ -72,7 +72,7 @@ export class CurveMap
*/
private GenerateP(v: Vector3): Vector3
{
let str = v.toArray().map(v => v.toFixed(4)).join(",");
let str = v.toArray().map(v => v.toFixed(3)).join(",");
if (this.m_vecMap.has(str))
return this.m_vecMap.get(str);
this.m_vecMap.set(str, v);

@ -26,11 +26,18 @@ export function equaln(v1: number, v2: number, fuzz = 1e-3)
{
return Math.abs(v1 - v2) < fuzz;
}
export function equal<T extends Vector>(v1: T, v2: T)
export function equal<T extends Vector>(v1: T, v2: T, fuzzSq = 1e-8)
{
return v1.distanceToSquared(v2) < 1e-8;
return v1.distanceToSquared(v2) < fuzzSq;
}
export function less(v1, v2, fuzz = 0)
{
return v1 - v2 < fuzz;
}
export function greater(v1, v2, fuzz = 0)
{
return v1 - v2 > fuzz;
}
export function fixAngle(an: number, fixAngle: number, fuzz: number = 0.1)
{
if (an < 0)

@ -0,0 +1,34 @@
import { Box3 } from "three";
import { equaln } from "./GeUtils";
export interface EBox
{
BoundingBox: Box3;
}
/**
* x
*
* @export
* @param {EBox[]} arr
*/
export function SortEntityByBox(arr: EBox[], sort: boolean = true)
{
let boxMap: Map<EBox, Box3> = new Map();
arr.forEach(e => boxMap.set(e, e.BoundingBox));
if (sort)
arr.sort((e1, e2) =>
{
let b1 = boxMap.get(e1);
let b2 = boxMap.get(e2);
if (!equaln(b1.min.x, b2.min.x))
return b1.min.x - b2.min.x;
else
{
return b2.min.y - b1.min.y;
}
})
return boxMap;
}

@ -13,14 +13,15 @@ export enum BoolOpeartionType
}
//判断曲线是否在源封闭曲线内
export function isTargetCurInSourceCur(sourceCur: Polyline | Circle | Ellipse, targetCur: Curve)
export function isTargetCurInOrOnSourceCur(sourceCur: Polyline | Circle | Ellipse, targetCur: Curve)
{
let pts = [];
getIntPtContextPts(sourceCur, targetCur, pts);
if (pts.length === 0)
if (pts.length <= 1)
{
pts.push(targetCur.StartPoint);
pts.push(targetCur.StartPoint, targetCur.EndPoint);
}
return IsPtsAllInOrOnReg(sourceCur, pts);
}
@ -37,7 +38,6 @@ function getIntPtContextPts(sourceCur: Curve, cu: Curve, pts: Vector3[])
par <= (cu.EndParam - 0.02) && pts.push(cu.GetPointAtParam(par + 0.01));
})
}
}
//判断点点是否全部都在封闭区域内或者在曲线上
function IsPtsAllInOrOnReg(sourceReg: Polyline | Circle | Ellipse, pts: Vector3[])
@ -45,6 +45,16 @@ function IsPtsAllInOrOnReg(sourceReg: Polyline | Circle | Ellipse, pts: Vector3[
return pts.every(pt =>
{
//是否点在封闭曲线内
return sourceReg.PtInCurve(pt) || sourceReg.PtOnCurve(pt);
return sourceReg.PtOnCurve(pt) || sourceReg.PtInCurve(pt);
})
}
//判断点是否全部都在封闭区域外或者在曲线上
export function IsPtsAllOutOrOnReg(sourceReg: Polyline | Circle, pts: Vector3[])
{
return pts.every(pt =>
{
//是否点在封闭曲线内
return sourceReg.PtOnCurve(pt) || !sourceReg.PtInCurve(pt);
})
}

@ -2,6 +2,11 @@ import * as THREE from 'three';
import { Vector3 } from 'three';
import { Orbit } from '../Geometry/Orbit';
const ViewScopeSize = 4e4;
//相机活动范围
const ViewScopeMin = new Vector3(-ViewScopeSize, -ViewScopeSize * 0.7, -ViewScopeSize);
const ViewScopeMax = ViewScopeMin.clone().negate();
/**
*
* .
@ -30,12 +35,16 @@ export class CameraUpdate
//观察的轨道.
private m_Orbit: Orbit = new Orbit();
//最大最小视口高度
m_MinViewHeight = 1e-3;
m_MaxViewHeight = 3e4;
constructor()
{
this.m_CameraArray.set(THREE.OrthographicCamera, new THREE.OrthographicCamera(-2, 2, 2, -2,
-10000, 10000));
-ViewScopeSize, ViewScopeSize));
this.m_CameraArray.set(THREE.PerspectiveCamera, new THREE.PerspectiveCamera(50, 1, 0.01, 10000));
this.m_CameraArray.set(THREE.PerspectiveCamera, new THREE.PerspectiveCamera(50, 1, 0.01, ViewScopeSize));
this.m_CurCamera = this.m_CameraArray.get(THREE.OrthographicCamera);
@ -60,7 +69,7 @@ export class CameraUpdate
}
set ViewHeight(height)
{
this.m_ViewHeight = THREE.Math.clamp(height, 1e-8, 1e8);
this.m_ViewHeight = THREE.Math.clamp(height, this.m_MinViewHeight, this.m_MaxViewHeight);
}
SetSize(width: number, height: number)
@ -81,6 +90,7 @@ export class CameraUpdate
mouseMove.multiplyScalar(-this.m_ViewHeight / this.m_Height);
mouseMove.applyQuaternion(this.Camera.quaternion);
this.m_Target.add(mouseMove);
this.m_Target.clamp(ViewScopeMin, ViewScopeMax);
this.Update();
}
Rotate(mouseMove: THREE.Vector3, target: THREE.Vector3)
@ -114,7 +124,7 @@ export class CameraUpdate
if (this.Camera instanceof THREE.OrthographicCamera)
{
this.ViewHeight *= scale;
if (scaleCenter)
if (scaleCenter && this.m_ViewHeight < this.m_MaxViewHeight)
{
this.m_Target.sub(scaleCenter);
this.m_Target.multiplyScalar(scale);
@ -131,7 +141,7 @@ export class CameraUpdate
}
ZoomExtensBox3(box3: THREE.Box3)
{
if (!box3) return;
if (!box3 || box3.isEmpty()) return;
this.Camera.updateMatrixWorld(false);
//变换到相机坐标系
box3.applyMatrix4(this.Camera.matrixWorldInverse);
@ -148,11 +158,11 @@ export class CameraUpdate
//
if (aspectRatio > viewAspectRatio)
{
this.m_ViewHeight = size.x / viewAspectRatio;
this.ViewHeight = size.x / viewAspectRatio;
}
else
{
this.m_ViewHeight = size.y;
this.ViewHeight = size.y;
}
this.Update();
}

@ -76,8 +76,10 @@ export function IntersectCircleAndCircle(cu1: Circle | Arc, cu2: Circle | Arc)
let pts: Vector3[] = [];
let dist = center2.distanceTo(center1);
if (dist > (radius1 + radius2 + 1e-3))
if (dist < Math.abs(radius1 - radius2)
|| dist > (radius1 + radius2 + 1e-3))
return pts;
if (equaln(dist, 0, 1e-6)) return pts;
let dstsqr = dist * dist;
let r1sqr = radius1 * radius1;
@ -155,6 +157,8 @@ function IntersectLineAndCircleOrArc(line: Line, circle: Circle | Arc)
let radius = circle.Radius;
let a = endPoint.distanceToSquared(startPoint);
if (a == 0)
return [];
let lineV = endPoint.clone().sub(startPoint);
let lineToCir = startPoint.clone().sub(center);
@ -163,7 +167,7 @@ function IntersectLineAndCircleOrArc(line: Line, circle: Circle | Arc)
let c = center.lengthSq() + startPoint.lengthSq() - 2 * center.dot(startPoint) - radius * radius;
let det = b * b - 4 * a * c;
if (equaln(det, 0, 1e-5))
if (equaln(det, 0, 1e-4))
{
let delta = -b / (2 * a);
return [startPoint.add(lineV.multiplyScalar(delta))];
@ -177,7 +181,10 @@ function IntersectLineAndCircleOrArc(line: Line, circle: Circle | Arc)
delta = (-b - sqrt_det) / (2 * a);
let p3 = startPoint.clone().add(lineV.multiplyScalar(delta));
return [p2, p3];
if (!equal(p2, p3, 1e-5))
return [p2, p3];
else
return [p2];
}
return [];
}
@ -238,15 +245,18 @@ export function IntersectLAndLFor3D(p1: Vector3, p2: Vector3, p3: Vector3, p4: V
let v1 = p2.clone().sub(p1).normalize();
let v2 = p4.clone().sub(p3).normalize();
let w = p3.clone().sub(p1);
if (Math.abs(v1.dot(v2)) === 1)
let w = p3.clone().sub(p1).normalize();
if (equaln(Math.abs(v1.dot(v2)), 1, 1e-6) && (equal(w, new Vector3()) || equaln(Math.abs(v1.dot(w)), 1, 1e-6))) //平行共线
{
let tmpLine = new Line(p1, p2);
let par = tmpLine.GetParamAtPoint(p3);
if (par)
{
pt = midPoint(midPoint(p1, p2), midPoint(p3, p4));
}
let pts = [p1, p2, p3, p4];
pts.sort(comparePoint('xyz'));
pt = midPoint(pts[1], pts[2]);
}
else if (equaln(Math.abs(v1.dot(v2)), 1, 1e-6)) //平行不共线
{
return undefined;
}
else if (equaln(getDeterminantFor3V(v1, v2, w), 0, 0.01))
{
@ -267,6 +277,59 @@ export function IntersectLAndLFor3D(p1: Vector3, p2: Vector3, p3: Vector3, p4: V
}
return pt;
}
export function IntersectLAndLFor3D1(p1: Vector3, p2: Vector3, p3: Vector3, p4: Vector3)
{
let x12 = p1.x - p2.x;
let x43 = p4.x - p3.x;
let x42 = p4.x - p2.x;
let y12 = p1.y - p2.y;
let y43 = p4.y - p3.y;
let y42 = p4.y - p2.y;
let z12 = p1.z - p2.z;
let z43 = p4.z - p3.z;
let z42 = p4.z - p2.z;
let pts: Vector3[] = [];
let v1 = p2.clone().sub(p1).normalize();
let v2 = p4.clone().sub(p3).normalize();
let w = p3.clone().sub(p1).normalize();
if (equaln(Math.abs(v1.dot(v2)), 1, 1e-6) && equaln(Math.abs(v1.dot(w)), 1, 1e-6)) //平行共线
{
let tmpPts = [p1, p2, p3, p4];
tmpPts.sort(comparePoint('xyz'));
if (equal(tmpPts[1], p3) || equal(tmpPts[1], p4))
{
pts = [tmpPts[1], tmpPts[2]];
}
else
{
pts = [midPoint(tmpPts[1], tmpPts[2])]
}
}
else if (equaln(Math.abs(v1.dot(v2)), 1, 1e-6)) //平行不共线
{
return [];
}
else if (equaln(getDeterminantFor3V(v1, v2, w), 0, 0.01))
{
let t: number;
if (x12 * y43 - y12 * x43)
{
t = (x42 * y43 - x43 * y42) / (x12 * y43 - y12 * x43);
}
else if (x12 * z43 - x43 * z12)
{
t = (x42 * z43 - x43 * z42) / (x12 * z43 - x43 * z12);
}
else
{
t = (y42 * z43 - y43 * z42) / (y12 * z43 - y43 * z12);
}
pts = [new Vector3(x12 * t + p2.x, y12 * t + p2.y, z12 * t + p2.z)]
}
return pts;
}
//直线和直线
export function IntersectLineAndLine(l1: Line, l2: Line, extType: IntersectOption)
{
@ -307,7 +370,7 @@ export function IntersectPolylineAndCurve(pl: Polyline, cu: Curve, extType: Inte
if ((cu instanceof Polyline && cu.CloseMark) || !(isStart2 || isEnd2))
ext = ext & ~IntersectOption.ExtendArg;
let ipts = cu1.IntersectWith(cu2, ext);
let ipts = cu1.IntersectWith(cu2, ext).filter(p1 => pts.every(p2 => !equal(p1, p2)));
//校验延伸
if (IntersectOption.ExtendThis & ext)

@ -0,0 +1,293 @@
import { Vector3 } from "three";
import { Curve } from "../DatabaseServices/Curve";
import { CurveIntersection } from "../Geometry/CurveIntersection";
import { CurveMap } from "../Geometry/CurveMap";
import { equal, equaln } from "../Geometry/GeUtils";
import { Stand } from "../Geometry/RegionParse";
export class LinkSelf
{
private curveUseData: WeakMap<Curve, boolean> = new WeakMap();
private curveIndexData: WeakMap<Curve, number> = new WeakMap();
sealCus: Set<Curve>[] = [];
noSealCus: Curve[][] = [];
private m_Count;
private cuMap: CurveMap;
constructor(cus: Curve[])
{
this.m_Count = cus.length;
//打断曲线
let breakCus: Curve[] = this.BreakCurve(cus);
// breakCus.forEach(c =>
// {
// c.ColorIndex = 3;
// app.m_Database.ModelSpace.Append(c);
// })
//曲线图 用来快速搜索求交
this.cuMap = this.GenerateCurveMap(breakCus);
//自交曲线表
this.CalCloseCurve(breakCus, this.cuMap);
//非自交曲线连接表
this.CalOrderLink(breakCus, this.cuMap);
}
//打断曲线 并且保存了曲线的索引
private BreakCurve(cus: Curve[]): Curve[]
{
let insMap = new CurveIntersection(cus.concat());
//打断后存储的曲线列表
let breakCus: Curve[] = [];
// let count = cus.length;
for (let i = 0; i < this.m_Count; i++)
{
let cu = cus[i];
//交点数据
let insData = insMap.GetIntersect(cu);
let insPts: Vector3[] = [];
for (let [, pts] of insData)
{
insPts.push(...pts);
}
let params = insPts.map(p => cu.GetParamAtPoint(p));
let spCus = cu.GetSplitCurves(params);
if (spCus.length === 0)
{
this.SetCurveIndex(cu, i);
breakCus.push(cu);
}
else
{
for (let c of spCus)
{
if (!equaln(c.Length, 0, 1e-6))
{
this.SetCurveIndex(c, i);
breakCus.push(c);
}
}
}
}
return breakCus;
}
//计算闭合的区域
private CalCloseCurve(breakCus: Curve[], cuMap: CurveMap)
{
let breakCount = breakCus.length;
//搜索闭合自交
for (let i = 0; i < breakCount; i++)
{
let cu = breakCus[i];
if (this.GetCurveUse(cu)) continue;
let cuIndex = this.GetCurveIndex(cu);
let stand = cuMap.GetStand(cu.EndPoint);
let routeCus = new Set<Curve>();
for (let route of stand.routes)
{
//缓存走过的节点
let ways: Stand[] = [];
ways.push(cuMap.GetStand(cu.StartPoint));
if (equal(route.curve.EndPoint, stand.position))
continue; //如果方向相反,那么退出计算 (不符合)
let routeIndex = this.GetCurveIndex(route.curve);
if (routeIndex === cuIndex)
continue;//自己不和自己计算
if (routeIndex < cuIndex)
continue;//不和小于自己索引的计算
//如果存在闭合区域
if (this.FindCloseCurve(route.to, cuIndex, ways, routeCus, cuMap))
{
routeCus.add(route.curve);
routeCus.add(cu);
//提取闭合区域
for (let c of routeCus)
{
this.SetCurveUse(c);
}
this.sealCus.push(routeCus);
break;
}
}
}
}
//顺序连接.
private CalOrderLink(breakCus: Curve[], cuMap: CurveMap)
{
let breakCount = breakCus.length;
//剩下没有被自交
for (let i = 0; i < breakCount; i++)
{
let cu = breakCus[i];
if (this.GetCurveUse(cu)) continue;
// let cuIndex = this.GetCurveIndex(cu);
this.SetCurveUse(cu);
let cs = [cu];
//顺序连接
this.linkCurve(cu, cuMap, cs);
//拿出第一条进行倒序连接
cu = cs[0];
this.linkCurve(cu, cuMap, cs, true);
}
}
linkCurve(originCu: Curve, cuMap: CurveMap, cs: Curve[], isInv: boolean = false)
{
//FIXME:两线共线时连接有问题
let cuIndex = this.GetCurveIndex(originCu);
while (true)
{
let oldCount = cs.length;
let routes = cuMap.GetStand(isInv ? originCu.StartPoint : originCu.EndPoint).routes;
//把索引相等的站点最后遍历
for (let i = 0; i < routes.length; i++)
{
let index = this.GetCurveIndex(routes[i].curve);
if (index === cuIndex)
{
routes.unshift(routes.splice(i, 1)[0]);
}
}
for (let j = routes.length; j--;) //按照索引从小到大搜索
{
let cu2 = routes[j].curve;
if (this.GetCurveUse(cu2)) continue;
//能够连接
let isLink = isInv ? equal(cu2.EndPoint, originCu.StartPoint) : equal(cu2.StartPoint, originCu.EndPoint);
if (isLink)
{
this.SetCurveUse(cu2);
isInv ? cs.unshift(cu2) : cs.push(cu2);
originCu = cu2;
cuIndex = this.GetCurveIndex(cu2);
break;
}
}
//如果没找到 则退出循环
if (oldCount === cs.length)
{
!isInv && this.noSealCus.push(cs);
break;
}
}
}
//寻找最小索引的路线
private FindMinRoute(nowStand: Stand, nowIndex: number, cs: Curve[], routes: Curve[]): { minIndex: number, routes: Curve[] }
{
//和当前索引一样的 搜索结果
let curIndex: { minIndex: number, routes: Curve[] } = undefined;
for (let j = nowStand.routes.length; j--;) //按照索引从小到大搜索
{
let cu = nowStand.routes[j].curve;
let cuIndex = this.GetCurveIndex(cu);
if (this.GetCurveUse(cu)) continue;
if (!equal(cu.StartPoint, nowStand.position)) continue;
if (nowIndex === cuIndex)
{
let routes2 = routes.concat();//复制数组保证函数有唯一结果
routes2.push(cu);
curIndex = this.FindMinRoute(this.cuMap.GetStand(cu.EndPoint), nowIndex, cs, routes2);
continue;
}
if (cuIndex < nowIndex) //小于 回归自身
if (cs.findIndex((c) => this.GetCurveIndex(c) === cuIndex) === -1)
continue;
if (curIndex && curIndex.minIndex < cuIndex)
return curIndex;
//这里不复制数组,因为数组不会再被改变
routes.push(cu);
return { minIndex: cuIndex, routes };
}
return { minIndex: Infinity, routes };
}
GetCurveUse(curve: Curve): boolean
{
return this.curveUseData.get(curve);
}
SetCurveUse(curve: Curve, use: boolean = true)
{
this.curveUseData.set(curve, use);
}
GetCurveIndex(curve: Curve): number
{
return this.curveIndexData.get(curve);
}
SetCurveIndex(curve: Curve, index: number)
{
this.curveIndexData.set(curve, index);
}
//搜索闭合的区域
private FindCloseCurve(nowStand: Stand, cuIndex: number, ways: Stand[], routes: Set<Curve>, cuMap: CurveMap)
{
for (let route of nowStand.routes)
{
if (equal(route.curve.EndPoint, nowStand.position))
continue; //如果方向相反,那么退出计算 (不符合)
if (this.GetCurveUse(route.curve)) continue;
let routeIndex = this.GetCurveIndex(route.curve);
if (routeIndex === cuIndex)
continue;//自己不和自己计算
if (routeIndex < cuIndex)
continue;//不和小于自己索引的计算
//验证通过,可以连接.
let toStand = route.to;
routes.add(route.curve);
if (ways[0] === toStand)//自交闭合
return true;
else if (ways.indexOf(toStand) !== -1)//中途回路
return false;
else
{
ways.push(toStand);
if (this.FindCloseCurve(toStand, routeIndex, ways, routes, cuMap))
return true;
else
{
routes.delete(route.curve);
return false;
}
}
}
return false;
}
GenerateCurveMap(breakCus: Curve[])
{
let cuMap = new CurveMap();
breakCus.forEach(c => cuMap.addCurveToMap(c));
//所有的站点 逆序排序.
for (let [, stand] of cuMap.m_NodeMap)
{
stand.routes.sort((r1, r2) =>
{
return this.GetCurveIndex(r2.curve) - this.GetCurveIndex(r1.curve); //从大到小
});
}
return cuMap;
}
}

@ -0,0 +1,750 @@
import { Box3, Vector3 } from "three";
import { arrayLast, arrayRemoveDuplicateBySort, arrayRemoveIf, arraySortByNumber } from "../Common/ArrayExt";
import { curveLinkGroup, GetPointAtCurveDir } from "../Common/CurveUtils";
import { FixIndex } from "../Common/Utils";
import { Arc } from "../DatabaseServices/Arc";
import { Circle } from "../DatabaseServices/Circle";
import { Contour } from '../DatabaseServices/Contour';
import { Curve } from "../DatabaseServices/Curve";
import { Line } from "../DatabaseServices/Line";
import { Polyline } from '../DatabaseServices/Polyline';
import { equal, equaln } from "../Geometry/GeUtils";
import { EBox, SortEntityByBox } from "../Geometry/SortEntityByBox";
import { IsPtsAllOutOrOnReg } from "./BoolOperateUtils";
import { IntersectOption } from "./IntersectWith";
interface offsetRes
{
index: number;
curve: Curve;
}
export class PolyOffsetUtil
{
private m_Polyline: Polyline;
private m_OffsetDist: number;
private m_Contours: Contour[] = [];//构建的轮廓
private m_RetCurves: Curve[] = [];//第一步修剪的数组
//偏移距离平方值
private m_dist2: number;
//偏移距离绝对值
private m_AbsDist: number;
//不用裁剪的线段
private unNeedCutCus: Curve[] = [];
//源线段点数量
private m_PtCount: number;
constructor(pl: Polyline, offset: number)
{
this.m_Polyline = pl;
this.m_OffsetDist = offset;
this.m_dist2 = Math.pow(offset, 2);
this.m_AbsDist = Math.abs(this.m_OffsetDist);
this.m_PtCount = pl.EndParam;
}
GetOffsetCurves(): Curve[]
{
let expCus = this.m_Polyline.Explode();
let offres = this.OffestCurve(expCus);
//不闭合曲线传入首尾点构建圆轮廓
if (!this.m_Polyline.IsClose)
{
let cir1 = new Circle(this.m_Polyline.StartPoint, this.m_AbsDist);
let cir2 = new Circle(this.m_Polyline.EndPoint, this.m_AbsDist);
this.m_Contours.push(Contour.CreateContour([cir1]));
this.m_Contours.push(Contour.CreateContour([cir2]));
}
//连接修剪并构建轮廓
this.TrimAndBuildContour(offres);
// 裁剪并优化的曲线
let { boxCurves, outputCus } = this.trimByContours(this.m_RetCurves);
//最后也加入优化数组,避免出错
this.unNeedCutCus.forEach(cu =>
{
boxCurves.set(cu, cu.BoundingBox);
outputCus.push(cu);
})
this.m_RetCurves = this.optimizeCus(boxCurves, outputCus);
this.m_RetCurves = this.linkCurves(this.m_RetCurves);
// 如果源线段闭合只保留闭合的部分
if (this.m_Polyline.IsClose)
return this.m_RetCurves.filter(c => c.IsClose);
return this.m_RetCurves;
}
private CheckPointDir(pt: Vector3)
{
let dir = GetPointAtCurveDir(this.m_Polyline, pt) ? 1 : -1;
return dir === Math.sign(this.m_OffsetDist);
}
/**
*
*线
* @private
* @param {Map<EBox, Box3>} boxCurves 线
* @param {Curve[]} outputCus 线
* @returns
* @memberof PolyOffestUtil
*/
private optimizeCus(boxCurves: Map<EBox, Box3>, outputCus: Curve[])
{
//过滤掉无效的线段
outputCus = outputCus.filter(c =>
{
//与源线段自交
if (c.IntersectWith(this.m_Polyline, IntersectOption.OnBothOperands).length !== 0)
return false;
//删除在反方向的无效线段
return this.CheckPointDir(c.StartPoint) || this.CheckPointDir(c.EndPoint);
});
//处理自交的线段,先根据包围盒排序
outputCus.sort((e1, e2) =>
{
let b1 = boxCurves.get(e1);
let b2 = boxCurves.get(e2);
if (!equaln(b1.min.x, b2.min.x))
return b1.min.x - b2.min.x;
else
{
return b2.min.y - b1.min.y;
}
})
// 寻找自交线段
for (let i = 0; i < outputCus.length; i++)
{
let c1 = outputCus[i];
let c1b = boxCurves.get(c1);
for (let j = i + 1; j < outputCus.length; j++)
{
let c2 = outputCus[j];
let c2b = boxCurves.get(c2);
//过滤掉不需要计算的曲线
if (c2b.min.x - 1e-6 > c1b.max.x)
break;
if (c2b.min.y - 1e-6 > c1b.max.y)
continue;
let c1StartPt = c1.StartPoint;
let c1EndPt = c1.EndPoint;
let c2StartPt = c2.StartPoint;
let c2EndPt = c2.EndPoint;
//被包含的直线删掉
if (c1 instanceof Line && c2 instanceof Line)
{
//c1完全在c2内
if (c2.PtOnCurve(c1StartPt) && c2.PtOnCurve(c1EndPt))
{
outputCus.splice(i, 1);
i--;
break;
}
else if (c1.PtOnCurve(c2StartPt) && c1.PtOnCurve(c2EndPt))
{
// c2完全在c1内
outputCus.splice(j, 1);
j--;
continue;
}
}
//如果线段端点相连,跳过
let isLink = [c1StartPt, c1EndPt].some(p => equal(p, c2StartPt) || equal(p, c2EndPt));
if (isLink) continue;
let pts = c1.IntersectWith(c2, IntersectOption.OnBothOperands);
if (pts.length > 0)
{
//按照从左到右,从上到下,分别取前后部分,即去掉中间部分
[c1, c2].forEach((c, index) =>
{
let cs = c.GetSplitCurvesByPts(pts);
if (cs.length === 2)
{
let box = SortEntityByBox(cs, true);
outputCus[index === 0 ? i : j] = cs[index]
boxCurves.set(cs[index], box.get(cs[index]));
}
})
}
}
}
return outputCus;
}
//偏移曲线
private OffestCurve(pls: Curve[]): offsetRes[]
{
return pls.map((cu, index) =>
{
let curve = cu.GetOffsetCurves(this.m_OffsetDist)[0];
return { curve, index };
});
}
/**
* 2线线
* @private
* @param {Curve} cu
* @param {Curve} [cuOrPt]
* @returns
* @memberof PolyOffestUtil
*/
private BuildContour(cu: Curve, cuOrPt: Curve | Vector3): Contour
{
if (cuOrPt instanceof Curve)
{
let l1 = new Line(cu.StartPoint, cuOrPt.StartPoint);
let l2 = new Line(cu.EndPoint, cuOrPt.EndPoint);
//若2曲线都是圆弧构建轮廓可能裁剪掉圆弧把被裁剪掉的圆弧存入数组跳过后续运算
if (cu instanceof Arc && cuOrPt instanceof Arc)
{
//被起点连线裁剪放入前面那段,被终点连线裁剪放入后面那段
[l1, l2].forEach((l, i) =>
{
let pts = l.IntersectWith(cuOrPt, 0);
if (pts.length === 2)
{
let splitCus = cuOrPt.GetSplitCurvesByPts(pts);
this.unNeedCutCus.push(splitCus[i])
}
})
}
//防止轮廓自交
if (l1.IntersectWith(l2, 0).length > 0)
{
l1 = new Line(cu.StartPoint, cuOrPt.EndPoint);
l2 = new Line(cu.EndPoint, cuOrPt.StartPoint);
}
return Contour.CreateContour([
cu.Clone() as Curve,
cuOrPt.Clone() as Curve,
l1,
l2
]);
}
else
{
let l1 = new Line(cu.StartPoint, cuOrPt);
let l2 = new Line(cu.EndPoint, cuOrPt);
return Contour.CreateContour([
cu,
l1,
l2
]);
}
}
/**
*线
* @private
* @param {(number | Vector3)} iV 线
* @param {Contour[]} cons
* @memberof PolyOffestUtil
*/
private BuildCircleContour(iV: number | Vector3, cons: Contour[])
{
let center: Vector3;
if (iV instanceof Vector3)
center = iV;
else
center = this.m_Polyline.GetPointAtParam(iV);
let cir = new Circle(center, this.m_AbsDist)
cons.push(Contour.CreateContour([cir]));
}
/**
* 线,
*
* @private
* @param {offsetRes[]} offResList
* @memberof PolyOffestUtil
*/
private TrimAndBuildContour(offResList: offsetRes[])
{
arrayRemoveIf(offResList, r => !r.curve || equaln(r.curve.Length, 0, 1e-6));
if (offResList.length <= 1)
{
this.m_RetCurves = offResList.map(r => r.curve);
return;
}
let cirContours: Contour[] = [];
//下一线段起始点
let nextStartPt: Vector3 = offResList[0].curve.StartPoint;
for (let i = 0; i < offResList.length; i++)
{
//源线段对应索引
let startIndex = offResList[i].index;
//后面线对应源线段索引
let endIndex = offResList[FixIndex(i + 1, offResList)].index;
//前面线
let frontLine = offResList[i].curve;
//后面线
let laterLine: Curve;
if (i === 0 && !this.m_Polyline.IsClose)
{
if (startIndex !== 0)
{
this.BuildCircleContour(1, cirContours);
}
}
//3.如果曲线不不闭合,那么最后一段时候退出,如果最后一段丢失,添加圆轮廓
if (i === offResList.length - 1 && !this.m_Polyline.IsClose)
{
if (startIndex !== this.m_PtCount - 1)
{
this.BuildCircleContour(startIndex + 1, cirContours);
}
this.appendNewCuAndContour(frontLine, nextStartPt, frontLine.EndPoint, startIndex);
break;
}
laterLine = offResList[FixIndex(i + 1, offResList)].curve;
//#region 1.中间丢失线段的情况下且循环到尾部,补圆弧.
let isFillArc = FixIndex(startIndex + 1, this.m_PtCount) !== endIndex;
if (isFillArc)
{
//在丢失圆的地方构建圆轮廓
for (let i = startIndex + 1; ; i++)
{
let index = FixIndex(i, this.m_PtCount);
this.BuildCircleContour(index, cirContours);
if (index === endIndex) break;
}
//丢失圆弧时在丢失圆弧的起点构造一个圆
if (startIndex > endIndex)
{
this.fillArc(startIndex, endIndex, nextStartPt, frontLine, laterLine);
continue;
}
}
//#endregion
//#region 2.修剪延伸,根据真假交点
let iPts: Vector3[]; //延伸交点
let tPts: Vector3[]; //都在两条线上的为真交点
if (equal(frontLine.EndPoint, laterLine.StartPoint))
tPts = [frontLine.EndPoint];
else
{
iPts = frontLine.IntersectWith(laterLine, IntersectOption.ExtendBoth);
//过滤掉交点为laterline终点的交点
tPts = iPts.filter(p =>
frontLine.PtOnCurve(p)
&& laterLine.PtOnCurve(p)
);
}
if (tPts.length > 0)//存在真交点情况下直接修剪
{
let iPt = this.selectFitInterPt(tPts, frontLine.EndPoint);
if (isFillArc)
{
//用丢失圆弧和交点构建扇形轮廓
for (let i = startIndex + 1; ; i++)
{
let index = FixIndex(i, this.m_PtCount);
let cu = this.m_Polyline.GetCurveAtParam(index);
cirContours.push(this.BuildContour(cu, iPt));
if (index === endIndex - 1) break;
}
}
this.appendNewCuAndContour(frontLine, nextStartPt, iPt, startIndex);
}
else if (isFillArc || iPts.length === 0)//连交点都没或者圆弧丢失补圆弧
{
this.fillArc(startIndex, endIndex, nextStartPt, frontLine, laterLine);
}
else //iPts.length > 0 有交点,但是都是假交点.
{
let iPt = this.selectFitInterPt(iPts, frontLine.EndPoint);
//通过真假交点连接
this.checkCuAndAppendList(frontLine, laterLine, iPt, nextStartPt, startIndex, endIndex);
}
//#endregion
}
//曲线闭合的时,修改第一条的起点,更新第一个轮廓
if (this.m_Polyline.IsClose)
{
this.m_RetCurves[0].StartPoint = nextStartPt;
this.m_Contours[0] = this.BuildContour(
this.m_Polyline.GetCurveAtParam(offResList[0].index),
this.m_RetCurves[0]);
};
this.m_Contours.push(...cirContours);
}
/**
* 线,
* .
*
* @param {Curve} offsetedCurve 线
* @param {Vector3} startPoint 线
* @param {Vector3} endPoint 线
* @param {number} index 线
* @memberof PolyOffestUtil
*/
appendNewCuAndContour(offsetedCurve: Curve,
startPoint: Vector3,
endPoint: Vector3,
index: number
)
{
//复制一条新曲线,修改起始点和终止点,并修改下一段的起始点
let newCu = offsetedCurve.Clone() as Curve;
newCu.StartPoint = startPoint;
newCu.EndPoint = endPoint;
startPoint.copy(endPoint);
this.m_RetCurves.push(newCu);
let originCu = this.m_Polyline.GetCurveAtParam(index);
this.m_Contours.push(this.BuildContour(originCu, newCu));
}
/**
* 线线
*
* @private
* @param {Curve} frontLine
* @param {Curve} laterLine
* @param {Vector3} intPt
* @param {Vector3} nextPt
* @param {number} endIndex
* @memberof PolyOffestUtil
*/
private checkCuAndAppendList(frontLine: Curve, laterLine: Curve, intPt: Vector3, nextPt: Vector3, startIndex: number, endIndex: number)
{
let par1 = frontLine.GetParamAtPoint(intPt);
//2段都是圆弧和其他情况分开判断
if (frontLine instanceof Arc && laterLine instanceof Arc)
{
let isOnFline = frontLine.PtOnCurve(intPt);
let isOnLline = laterLine.PtOnCurve(intPt);
//交点均不在2圆弧上,直接加入结果数组,否则补圆弧连接
if (!isOnFline && !isOnLline) //可能 isOnFline || isOnLline
{
this.appendNewCuAndContour(frontLine, nextPt, intPt, startIndex);
}
else
{
this.fillArc(startIndex, endIndex, nextPt, frontLine, laterLine);
}
}
else
{
let par2 = laterLine.GetParamAtPoint(intPt);
if (par1 > 1)
{
//laterline是圆弧且都是正假交点,补圆弧,否则连接
if (par2 > 0 && laterLine instanceof Arc)
{
this.fillArc(startIndex, endIndex, nextPt, frontLine, laterLine);
}
else
{
this.appendNewCuAndContour(frontLine, nextPt, intPt, startIndex);
}
}
else if (frontLine instanceof Arc)
{
//其余情况如果frontline是Arc,补圆弧,否则补直线
this.fillArc(startIndex, endIndex, nextPt, frontLine, laterLine);
}
else//frontLine is Line
{
this.appendNewCuAndContour(frontLine, nextPt, frontLine.EndPoint, startIndex);
this.m_RetCurves.push(new Line(frontLine.EndPoint, laterLine.StartPoint));
nextPt.copy(laterLine.StartPoint);
}
}
}
/**
*
*
* @param {number} startIndex 线
* @param {number} endIndex 线
* @param {Vector3} nextPt 线
* @param {Curve} frontLine
* @param {Curve} laterLine
* @returns
* @memberof PolyOffestUtil3
*/
fillArc(startIndex: number, endIndex: number,
nextPt: Vector3,
frontLine: Curve, laterLine: Curve
)
{
let cirs: Circle[] = []; //需要补的圆列表
for (let i = startIndex + 1; ; i++)
{
let index = FixIndex(i, this.m_PtCount);
let center = this.m_Polyline.GetPointAtParam(index);
cirs.push(new Circle(center, this.m_AbsDist));
if (index === endIndex) break;
}
//如果和第二个圆(消失圆弧终点构建圆)相交,则直接连接,否则从第一个圆开始,圆数量要大于1
let iPts = cirs.length > 1 ? frontLine.IntersectWith(cirs[1], 0) : [];
if (iPts.length === 0)
{
//第一个圆肯定和frontline相切,切点为frontline的终点
iPts = [frontLine.EndPoint];
}
else
{
cirs.shift();
}
//#region 避免错误块
//假设我们认为连接一定能成功,那么下面的if不是必要的
// if (!iPts)
// {
// console.error("补圆失败,距离为", this.m_OffestDist);
// }
//#endregion
let iPt = this.selectFitInterPt(iPts, frontLine.EndPoint);
this.appendNewCuAndContour(frontLine, nextPt, iPt, startIndex);
//连接剩下的圆.
//可能的情况 (|)()(|)() 竖线为直线
for (let index = 0; index < cirs.length; index++)
{
let c1 = cirs[index];//已经计算过的圆
let iPtsLater: Vector3[];
if (index === cirs.length - 1)
iPtsLater = [laterLine.StartPoint];
else
{
//和前面圆的交点需要大于偏移距离才能提前相交
iPtsLater = c1.IntersectWith(laterLine, 0).filter(p =>
{
let dist = p.distanceToSquared(this.m_Polyline.GetClosestPointTo(p, false));
return dist + 1e-3 > this.m_dist2;
});
}
if (iPtsLater.length > 0)//直接和最后一条连接
{
let iPt = this.selectFitInterPt(iPtsLater, nextPt);
this.buildArcJoinList(c1, nextPt, iPt, FixIndex(startIndex + 1, this.m_PtCount) === endIndex);
return;
}
let c2 = cirs[index + 1];
let iPts = c1.IntersectWith(c2, 0);
let iPt = this.selectFitInterPt(iPts, nextPt);
this.buildArcJoinList(c1, nextPt, iPt, FixIndex(startIndex + 1, this.m_PtCount) === endIndex);
}
}
/**
*
* @param {Circle} cir
* @param {Vector3} startPt 1
* @param {Vector3} endPt 2
* @param {boolean} isbuildCir
* @returns
* @memberof PolyOffestUtil
*/
buildArcJoinList(cir: Circle, startPt: Vector3, endPt: Vector3, isbuildCir: boolean)
{
let splitCus = cir.GetSplitCurvesByPts([startPt, endPt]);
startPt.copy(endPt);
if (splitCus.length === 2) //2圆相交应该有2段否则相切
{
let arc1 = splitCus[0] as Arc;
let arc2 = splitCus[1] as Arc;
let tmpPts = cir.IntersectWith(this.m_Polyline, IntersectOption.OnBothOperands);
let onCu0Pts = tmpPts.filter(p => arc1.PtOnCurve(p));
let onCu1Pts = tmpPts.filter(p => arc2.PtOnCurve(p));
let lastCu = arrayLast(this.m_RetCurves);
//让圆弧保持和最后一段首尾相连
if (!equal(arc1.StartPoint, lastCu.EndPoint))
arc1.Reverse();
if (!equal(arc2.StartPoint, lastCu.EndPoint))
arc2.Reverse();
//优先选择和源线段不想交的圆弧,如果都相交或者都不相交,选择和最后一段切线接近的圆弧
let cu: Arc;
if (onCu0Pts.length === onCu1Pts.length)
{
let derv = lastCu.GetFistDeriv(1);
let derv1 = arc1.GetFistDeriv(0);
let derv2 = arc2.GetFistDeriv(0);
cu = derv.angleTo(derv1) < derv.angleTo(derv2) ? arc1 : arc2;
}
else
{
cu = onCu0Pts.length < onCu1Pts.length ? arc1 : arc2;
}
this.m_RetCurves.push(cu);
isbuildCir && this.BuildCircleContour(cu.Center, this.m_Contours);
}
}
// 通过构建的轮廓对偏移曲线进行裁剪
private trimByContours(needCutCus: Curve[])
{
let boxContours = SortEntityByBox(this.m_Contours, false);
let boxCurves = SortEntityByBox(needCutCus, false);
this.m_Contours.forEach(c =>
{
let tmpCus: Curve[] = [];
let outline = c.Outline;
for (let l of needCutCus)
{
if (boxCurves.get(l).min.x > boxContours.get(c).max.x
|| boxCurves.get(l).max.x < boxContours.get(c).min.x)
{
tmpCus.push(l);
continue;
}
//交点参数列表
let iParams = l.IntersectWith(outline, IntersectOption.OnBothOperands)
.map(p => l.GetParamAtPoint(p));
arraySortByNumber(iParams);
arrayRemoveDuplicateBySort(iParams, equaln);
//需要计算的点列表
let needCaclPts: Vector3[] = [];
if (iParams.length === 0)
needCaclPts = [l.StartPoint]
else
{
for (let i = 0; i < iParams.length - 1; i++)
{
needCaclPts.push(l.GetPointAtParam((iParams[i] + iParams[i + 1]) / 2));
}
//如果交点不是首尾点,就加入首尾点
if (!equaln(iParams[0], 0, 1e-6))
needCaclPts.unshift(l.StartPoint);
if (!equaln(arrayLast(iParams), 1, 1e-6))
needCaclPts.push(l.EndPoint);
}
//切割曲线,缓存切割后曲线包围盒
if (IsPtsAllOutOrOnReg(outline, needCaclPts))
{
tmpCus.push(l);
}
else
{
let cus = l.GetSplitCurves(iParams);
//移除0长度线和在轮廓内的线.
arrayRemoveIf(cus, cu =>
equaln(cu.Length, 0, 1e-6)
|| outline.PtInCurve(cu.GetPointAtParam(0.5))
);
cus.forEach(c => boxCurves.set(c, c.BoundingBox))
tmpCus.push(...cus);
}
}
needCutCus = tmpCus;
})
return { boxCurves, outputCus: needCutCus };
}
/**
* 线
* @private
* @param {Curve[]} cus
* @returns {Polyline[]}
* @memberof PolyOffestUtil
*/
private linkCurves(cus: Curve[]): Polyline[]
{
let groups = curveLinkGroup(cus);
let resultPls: Polyline[] = [];
for (let g of groups)
{
let pl = new Polyline();
for (let cu of g)
{
pl.Join(cu);
}
resultPls.push(pl)
}
return resultPls;
}
/**
*
*
* 线,,
* @private
* @param {Vector3[]} pts
* @param {Vector3} refPt
* @returns
* @memberof PolyOffestUtil
*/
private selectFitInterPt(pts: Vector3[], refPt: Vector3)
{
if (pts.length > 1)
{
let rad2 = Math.pow(this.m_OffsetDist, 2);
//优先选择交点在偏移方向上同一侧的
let pt1Dir = this.CheckPointDir(pts[0]);
let pt2Dir = this.CheckPointDir(pts[1]);
if (pt1Dir !== pt2Dir)
{
return pt1Dir ? pts[0] : pts[1];
}
//计算到曲线的距离大于偏移距离
let [ptGtRad1, ptGtRad2] = pts.map(p =>
{
let dis = this.m_Polyline.GetClosestPointTo(p, false).distanceToSquared(p);
return dis + 1e-3 > rad2;
});
//都大于或者都小于`偏移距离`
if (ptGtRad1 === ptGtRad2)
{
let dist1 = refPt.distanceToSquared(pts[0]);
let dist2 = refPt.distanceToSquared(pts[1]);
return dist1 <= dist2 ? pts[0] : pts[1];
}
else
return ptGtRad1 ? pts[0] : pts[1];
}
return pts[0];
}
}

@ -129,8 +129,8 @@ export class Viewer
onSize = (width?, height?) =>
{
this._Width = width ? width : this.m_DomEl.scrollWidth;
this._Height = height ? height : this.m_DomEl.scrollHeight;
this._Width = width ? width : this.m_DomEl.clientWidth;
this._Height = height ? height : this.m_DomEl.clientHeight;
//校验.成为2的倍数 避免外轮廓错误.
if (this._Width % 2 == 1)

@ -4365,11 +4365,11 @@
if ( window.Zlib === undefined ) {
// throw new Error( 'THREE.FBXLoader: External library Inflate.min.js required, obtain or import from https://github.com/imaya/zlib.js' );
throw new Error( 'THREE.FBXLoader: External library Inflate.min.js required, obtain or import from https://github.com/imaya/zlib.js' );
}
var inflate = new threeZlib.Zlib.Inflate( new Uint8Array( reader.getArrayBuffer( compressedLength ) ) );
var inflate = new Zlib.Inflate( new Uint8Array( reader.getArrayBuffer( compressedLength ) ) );
var reader2 = new BinaryReader( inflate.decompress().buffer );
switch ( type ) {

@ -2,8 +2,6 @@
import * as THREE from "three";
require('three-FBXLoader');
window["threeZlib"] = require("zlib")
export interface LoaderState
{
State: boolean,

@ -105,6 +105,10 @@ export class FilePanel extends React.Component<FileProps, FileState>
fileData.title = fname;
//切换当前图纸id
store.m_CurrentFileId = fid;
//用于打开上一次打开的图
window.sessionStorage.setItem("fid", fid);
let file = await store.Get(StoreName.Dwg, fid);
if (fileData.isNew || !file)

@ -71,9 +71,9 @@ a {
}
#input-hint ul {
position: absolute;
position: fixed;
left: -1rem;
bottom: 2rem;
bottom: 3.3rem;
list-style: none;
width: 10rem;
background: #fff;

@ -26,7 +26,7 @@ export default class Login extends React.Component<LoginProps, {}> {
onClose={() => this.props.toggleDialog()}
title="请登录"
>
<div className="pt-dialog-body">
<div className="pt-dialog-body" onKeyDown={e => e.stopPropagation()}>
<div
className="pt-input-group .modifier pt-intent-primary"
style={inputStyle}

@ -1,4 +1,3 @@
module.exports = function (wallaby)
{
return {

@ -2,8 +2,8 @@ import * as path from 'path';
import * as webpack from 'webpack';
import * as HtmlWebPackPlugin from "html-webpack-plugin";
import * as AddAssetHtmlPlugin from "add-asset-html-webpack-plugin";
import * as ExtractTextPlugin from 'extract-text-webpack-plugin';
import * as OpenBrowserPlugin from 'open-browser-webpack-plugin';
// import * as ExtractTextPlugin from 'extract-text-webpack-plugin';
// import * as OpenBrowserPlugin from 'open-browser-webpack-plugin';
function getpath(fileName)
{
@ -24,7 +24,6 @@ const config: webpack.Configuration = {
alias: {
"dat.gui": getpath('./node_modules/dat.gui/build/dat.gui.js'),
"three-FBXLoader": getpath("./src/Loader/FBXLoader.js"),
"zlib": getpath("./node_modules/three/examples/js/libs/inflate.min.js"),
"three-CopyShader": getpath("./node_modules/three/examples/js/shaders/CopyShader.js"),
"three-SMAAShader": getpath("./node_modules/three/examples/js/shaders/SMAAShader.js"),
"three-FXAAShader": getpath("./node_modules/three/examples/js/shaders/FXAAShader.js"),
@ -120,17 +119,22 @@ const config: webpack.Configuration = {
context: '.',
manifest: require(getpath("./manifest.json"))
}),
new AddAssetHtmlPlugin({
filepath: getpath("./dist/dll.js")
}),
new AddAssetHtmlPlugin(
[
{ filepath: getpath("./dist/dll.js") },
{
filepath: getpath(getpath("./node_modules//three/examples/js/libs/inflate.min.js")),
includeSourcemap: false
},
]
),
// new ExtractTextPlugin({ filename: 'styles.css' }),
new webpack.ProvidePlugin({
$: "jquery",
jQuery: "jquery",
ReactDOM: 'react-dom',
React: 'react',
THREE: "three",
Zlib: "zlib"
THREE: "three"
}),
new webpack.optimize.ModuleConcatenationPlugin()
]

Loading…
Cancel
Save