实现点在多段线的左边或者右边的判断算法 #IKIBD

pull/68/head
cx 6 years ago
parent 68a8dc2304
commit b2e95cbcc0

@ -0,0 +1,184 @@
import { CADFile } from '../../src/DatabaseServices/CADFile';
import { Polyline } from '../../src/DatabaseServices/Polyline';
import { GetPointAtCurveDir } from '../../src/Common/CurveUtils';
import { Vector3 } from 'three';
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 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();
});

@ -0,0 +1,9 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`多段线 最近点精度 1`] = `
Vector3 {
"x": 1.987500976448074,
"y": 3.9999218841540816,
"z": 0,
}
`;

@ -2,6 +2,7 @@ import { Vector2, Vector3 } from 'three';
import { Polyline } from '../../src/DatabaseServices/Polyline';
import { equal, equaln } from '../../src/Geometry/GeUtils';
import { CADFile } from '../../src/DatabaseServices/CADFile';
test("多段线点获取参数", () =>
{
@ -469,4 +470,20 @@ 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();
});
})

@ -1,11 +1,11 @@
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';
import { Line } from '../DatabaseServices/Line';
import { IsPointInBowArc, IsPointInPolyLine } from '../DatabaseServices/PointInPolyline';
import { IsPointInBowArc } from '../DatabaseServices/PointInPolyline';
import { Polyline } from '../DatabaseServices/Polyline';
import { Command } from '../Editor/CommandMachine';
import { PromptStatus } from '../Editor/PromptResult';
@ -56,7 +56,7 @@ export class Command_ClosePt implements Command
if (cu instanceof Polyline)
{
closeCir.Center = p;
closeCir.ColorIndex = IsPointInPolyLine(cu, p) ? 1 : 2;
closeCir.ColorIndex = GetPointAtCurveDir(cu, p) ? 1 : 2;
}
}
})

@ -11,8 +11,9 @@ import { Entity } from '../DatabaseServices/Entity';
import { IntersectOption } from '../GraphicsSystem/IntersectWith';
import { Circle } from '../DatabaseServices/Circle';
import { Line } from '../DatabaseServices/Line';
import { Vector3 } from 'three';
import { Vector3, Matrix4 } from 'three';
import { LinkSelf } from '../GraphicsSystem/LinkSelft';
import { GetPointAtCurveDir } from '../Common/CurveUtils';
@ -22,6 +23,42 @@ export class Test implements Command
{
app.m_Editor.m_CommandStore.Prompt("载入成功!");
}
async exec()
{
let e = await app.m_Editor.GetEntity();
if (e.Status === PromptStatus.OK)
{
let box = e.Entity.BoundingBox;
if (e.Entity instanceof Polyline)
{
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) ? 1 : 2;
app.m_Database.ModelSpace.Append(c);
}
}
}
async exec1()
{
let e1Res = await app.m_Editor.GetEntity();
@ -39,7 +76,7 @@ export class Test implements Command
}
//将多段线转换为cad图形
async exec()
async execx()
{
// 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]]

@ -9,6 +9,7 @@ import { CurveMap } from '../Geometry/CurveMap';
import { equal, equaln } from '../Geometry/GeUtils';
import { Stand } from '../Geometry/RegionParse';
import { FixIndex } from './Utils';
import { IsPointInBowArc } from '../DatabaseServices/PointInPolyline';
//3点获取圆心
export function getCircleCenter(pt1: Vector3, pt2: Vector3, pt3: Vector3)
@ -236,3 +237,104 @@ export function cuOffestDir(cu: Curve, p: Vector3)
let derv = caclCu.GetFistDeriv(ptClose);//切线。
return Math.sign(toPtVec.clone().cross(derv).z);
}
/**
* 线,
*
* @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 fp = cu.GetPointAtParam(fIndex);
let np = cu.GetPointAtParam(nIndex);
let l1 = new Line(fp, p);
let l2 = new Line(p, np);
let cp1 = l1.GetClosestPointTo(pt, true);
let cp2 = l2.GetClosestPointTo(pt, true);
//小角的叉积.
let across = l1.GetFistDeriv(0).normalize().cross(l2.GetFistDeriv(0).normalize());
//当2线平行时
if (equaln(across.z, 0, 1e-6))
{
return l1.GetFistDeriv(0).cross(pt.clone().sub(cp1)).z < 0;
}
else
{
let adir = Math.sign(across.z);
//判断点是否在小角内.
if (
Math.sign(l1.GetFistDeriv(0).cross(pt.clone().sub(cp1)).z) === adir
&& Math.sign(l2.GetFistDeriv(0).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))
return Math.sign(bul);
return 0;
}

@ -165,7 +165,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, 0.1))
if (equaln(det, 0))
{
let delta = -b / (2 * a);
return [startPoint.add(lineV.multiplyScalar(delta))];

Loading…
Cancel
Save