From 381b725681606c14a0667527e7a121f4d0fa0121 Mon Sep 17 00:00:00 2001 From: Zoe Date: Tue, 29 May 2018 09:18:49 +0800 Subject: [PATCH] =?UTF-8?q?=E5=90=8C=E6=AD=A5=E4=B8=BB=E5=B9=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- __test__/Geometry/GeUtils.test.ts | 36 +++++- .../__snapshots__/GeUtils.test.ts.snap | 109 +++++++++++++++++- .../__snapshots__/intersect.test.ts.snap | 8 +- __test__/Polyline/PointInPolyline.test.ts | 23 ++++ src/Add-on/DrawPolyline.ts | 1 + src/Add-on/Stretch.ts | 1 - src/DatabaseServices/CADFile.ts | 2 +- src/DatabaseServices/Polyline.ts | 2 +- src/Geometry/GeUtils.ts | 61 +++++++++- src/Geometry/Orbit.ts | 5 +- src/Geometry/ThreeCSG.ts | 50 ++++---- src/GraphicsSystem/CameraControl.ts | 7 ++ src/GraphicsSystem/IntersectWith.ts | 29 +---- 13 files changed, 265 insertions(+), 69 deletions(-) diff --git a/__test__/Geometry/GeUtils.test.ts b/__test__/Geometry/GeUtils.test.ts index 0df08ab71..46648b6ca 100644 --- a/__test__/Geometry/GeUtils.test.ts +++ b/__test__/Geometry/GeUtils.test.ts @@ -1,7 +1,6 @@ import { Vector3 } from 'three'; -import { getLoocAtUpVec } from './../../src/Geometry/GeUtils'; -import {rotatePoint} from './../../src/Geometry/GeUtils'; +import { getLoocAtUpVec, rotatePoint, comparePoint } from './../../src/Geometry/GeUtils'; test('getLoocAtUpVec', () => { @@ -17,8 +16,7 @@ test('getLoocAtUpVec', () => expect(getLoocAtUpVec(new Vector3(0, 1, 0)) /*?*/).toMatchSnapshot(); }); - -test('should behave...', () => +test('旋转量', () => { let v = new Vector3(1, 0, 0); @@ -29,3 +27,33 @@ test('should behave...', () => rotatePoint(v, -0.5); expect(v).toMatchSnapshot(); }); + + +describe('排序测试', () => +{ + let pts = [ + new Vector3(6, 2, 4), + new Vector3(1, 4, 3), + new Vector3(2, 2, 2), + new Vector3(3, 3, 1), + new Vector3(1, 3, 1), + new Vector3(1, 2, 1), + ] + test('排序点xyz', () => + { + pts.sort(comparePoint("xyz")); + expect(pts).toMatchSnapshot(); + }); + + test('排序点Xyz', () => + { + pts.sort(comparePoint("Xyz")); + expect(pts).toMatchSnapshot(); + }); + + test('排序点Zx', () => + { + pts.sort(comparePoint("Zx")); + expect(pts).toMatchSnapshot(); + }); +}); diff --git a/__test__/Geometry/__snapshots__/GeUtils.test.ts.snap b/__test__/Geometry/__snapshots__/GeUtils.test.ts.snap index 72ebb847b..d52f83933 100644 --- a/__test__/Geometry/__snapshots__/GeUtils.test.ts.snap +++ b/__test__/Geometry/__snapshots__/GeUtils.test.ts.snap @@ -40,7 +40,112 @@ Vector3 { } `; -exports[`should behave... 1`] = ` +exports[`排序测试 排序点Xyz 1`] = ` +Array [ + Vector3 { + "x": 6, + "y": 2, + "z": 4, + }, + Vector3 { + "x": 3, + "y": 3, + "z": 1, + }, + Vector3 { + "x": 2, + "y": 2, + "z": 2, + }, + Vector3 { + "x": 1, + "y": 2, + "z": 1, + }, + Vector3 { + "x": 1, + "y": 3, + "z": 1, + }, + Vector3 { + "x": 1, + "y": 4, + "z": 3, + }, +] +`; + +exports[`排序测试 排序点Zx 1`] = ` +Array [ + Vector3 { + "x": 6, + "y": 2, + "z": 4, + }, + Vector3 { + "x": 1, + "y": 4, + "z": 3, + }, + Vector3 { + "x": 2, + "y": 2, + "z": 2, + }, + Vector3 { + "x": 1, + "y": 2, + "z": 1, + }, + Vector3 { + "x": 1, + "y": 3, + "z": 1, + }, + Vector3 { + "x": 3, + "y": 3, + "z": 1, + }, +] +`; + +exports[`排序测试 排序点xyz 1`] = ` +Array [ + Vector3 { + "x": 1, + "y": 2, + "z": 1, + }, + Vector3 { + "x": 1, + "y": 3, + "z": 1, + }, + Vector3 { + "x": 1, + "y": 4, + "z": 3, + }, + Vector3 { + "x": 2, + "y": 2, + "z": 2, + }, + Vector3 { + "x": 3, + "y": 3, + "z": 1, + }, + Vector3 { + "x": 6, + "y": 2, + "z": 4, + }, +] +`; + +exports[`旋转量 1`] = ` Vector3 { "x": 0.8775825618903728, "y": 0.479425538604203, @@ -48,7 +153,7 @@ Vector3 { } `; -exports[`should behave... 2`] = ` +exports[`旋转量 2`] = ` Vector3 { "x": 1, "y": 0, diff --git a/__test__/Geometry/__snapshots__/intersect.test.ts.snap b/__test__/Geometry/__snapshots__/intersect.test.ts.snap index 39c1d7a14..4852179c6 100644 --- a/__test__/Geometry/__snapshots__/intersect.test.ts.snap +++ b/__test__/Geometry/__snapshots__/intersect.test.ts.snap @@ -140,9 +140,9 @@ Vector3 { exports[`三维空间直线相交测试 2`] = ` Vector3 { - "x": 1.5, - "y": 1.5, - "z": 1.5, + "x": 4.5, + "y": 4.5, + "z": 4.5, } `; @@ -164,7 +164,7 @@ Vector3 { exports[`相交测试 2`] = ` Vector3 { - "x": 3, + "x": 2, "y": 0, "z": 0, } diff --git a/__test__/Polyline/PointInPolyline.test.ts b/__test__/Polyline/PointInPolyline.test.ts index 39ecf5ee9..a31786ee5 100644 --- a/__test__/Polyline/PointInPolyline.test.ts +++ b/__test__/Polyline/PointInPolyline.test.ts @@ -2,6 +2,7 @@ import { Vector2, Vector3 } from 'three'; import { IsPointInPolyLine } from '../../src/DatabaseServices/PointInPolyline'; import { Polyline } from '../../src/DatabaseServices/Polyline'; +import { CADFile } from '../../src/DatabaseServices/CADFile'; test('点在多段线内', () => @@ -141,4 +142,26 @@ describe("", () => expect(IsPointInPolyLine(pl, new Vector3(5, 2))).toBeTruthy(); }); + + + test('点在曲线外精度问题', () => + { + let plData = [["Polyline", 1, 1, 4317, false, 3, -1, + [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1], + 2, 5, + [-3, 3.6739403974420594e-16], 0.9999999999999999, + [3, 3.6739403974420594e-16], 0, [3, 10], 0.9999999999999999, + [-3, 10], 0, [-3, -3.6739403974420594e-16], 0, + false]]; + + let f = new CADFile(); + f.Data = plData; + let pl = f.ReadObject(undefined) as Polyline; + + + let p = new Vector3(-3, -0.16000000000000014, 0); + + + expect(pl.PtInCurve(p)).toBeFalsy(); + }); }) diff --git a/src/Add-on/DrawPolyline.ts b/src/Add-on/DrawPolyline.ts index 6d8931cff..b683b21f6 100644 --- a/src/Add-on/DrawPolyline.ts +++ b/src/Add-on/DrawPolyline.ts @@ -4,6 +4,7 @@ import { Vec2DTo3D, Vec3DTo2D, getCirAngleByChordAndTangent } from '../Common/Cu import { Polyline, PolylineProps } from '../DatabaseServices/Polyline'; import { Command } from '../Editor/CommandMachine'; import { PromptStatus, PromptSsgetResult } from '../Editor/PromptResult'; +import { rotatePoint } from '../Geometry/GeUtils'; import { GetPointPrompt } from '../Common/InputState'; enum PolylineModel diff --git a/src/Add-on/Stretch.ts b/src/Add-on/Stretch.ts index 8e4e25e1f..b8a10bff3 100644 --- a/src/Add-on/Stretch.ts +++ b/src/Add-on/Stretch.ts @@ -10,7 +10,6 @@ import { SelectSet, SelectType } from '../Editor/SelectSet'; import { MoveMatrix } from '../Geometry/GeUtils'; import { Command_Move } from './Move'; - //拉伸的解析数据 interface StretchData { diff --git a/src/DatabaseServices/CADFile.ts b/src/DatabaseServices/CADFile.ts index 00d3c2617..a46ce20c9 100644 --- a/src/DatabaseServices/CADFile.ts +++ b/src/DatabaseServices/CADFile.ts @@ -55,7 +55,7 @@ export class CADFile this.Write(tempFile.Data); tempFile.Destroy();//GC } - ReadObject(db: Database, obj?: CADObject): CADObject + ReadObject(db?: Database, obj?: CADObject): CADObject { let data = this.Read(); let tempFile = new CADFile(); diff --git a/src/DatabaseServices/Polyline.ts b/src/DatabaseServices/Polyline.ts index e6640e7f8..2bcee060b 100644 --- a/src/DatabaseServices/Polyline.ts +++ b/src/DatabaseServices/Polyline.ts @@ -6,7 +6,7 @@ import { ColorMaterial } from '../Common/ColorPalette'; import { Vec2DTo3D, Vec3DTo2D, getDeterminantFor2V } from '../Common/CurveUtils'; import { matrixAlignCoordSys } from '../Common/Matrix4Utils'; import { FixIndex } from '../Common/Utils'; -import { equal, equaln, updateGeometry } from '../Geometry/GeUtils'; +import { equal, equaln, rotatePoint, updateGeometry } from '../Geometry/GeUtils'; import { RenderType } from '../GraphicsSystem/Enum'; import { IntersectOption, IntersectPolylineAndCurve } from '../GraphicsSystem/IntersectWith'; import { PolyOffestUtil3 } from '../GraphicsSystem/OffestPolyline'; diff --git a/src/Geometry/GeUtils.ts b/src/Geometry/GeUtils.ts index 6ba89dacd..92d076e09 100644 --- a/src/Geometry/GeUtils.ts +++ b/src/Geometry/GeUtils.ts @@ -67,9 +67,8 @@ export function polar(v: T, an: number, dis: number export function angle(v: Vector3 | Vector2) { - if (equaln(v.y, 0) && v.x > 0) - return 0; let angle = Math.atan2(v.y, v.x); + if (equaln(angle, 0, 1e-8)) return 0; if (angle < 0) angle += Math.PI * 2; return angle; } @@ -189,8 +188,7 @@ export function GetBox(obj: THREE.Object3D, updateMatrix?: boolean): THREE.Box3 if (itemBox) sumBox.union(itemBox); return sumBox; - }, new THREE.Box3()) - if (box) box.applyMatrix4(obj.matrixWorld); + }, new THREE.Box3()); return box; } else @@ -287,3 +285,58 @@ export function updateGeometry(l: THREE.Line | THREE.Mesh, geometry: Geometry) geometry.verticesNeedUpdate = true; geometry.computeBoundingSphere(); } + + +type compareVectorFn = (v1: Vector, v2: Vector3) => number; + +const comparePointCache: Map = new Map(); + +/** + * 构建返回一个用来排序的函数.根据key创建排序规则. + * + * 当key = "xyz" 时,点集按 x从小到大,y从小到大 z从小到大 + * key = "X" 时,点集按 x从大到小 + * 以此类推. + * + * 例子: + * let pts:Vector3[] =...; + * pts.sort(comparePoint("x")); //x从小到大排序 + * pts.sort(comparePoint("zX")); //z从小到大 x从大到小 + * + * @export + * @param {string} sortKey + * @returns {compareVectorFn} + */ +export function comparePoint(sortKey: string): compareVectorFn +{ + if (comparePointCache.has(sortKey)) + return comparePointCache.get(sortKey); + + let sortIndex = []; + + const keys = ['x', 'X', 'y', 'Y', 'z', 'Z']; + for (let char of sortKey) + { + let index = keys.indexOf(char); + + let i2 = index / 2; + let ci = Math.floor(i2); + sortIndex.push([ci, i2 > ci ? 1 : -1]); + } + + let compareFunction = (v1: Vector, v2: Vector3): number => + { + for (let s of sortIndex) + { + let vv1 = v1.getComponent(s[0]); + let vv2 = v2.getComponent(s[0]); + if (equaln(vv1, vv2)) continue; + if (vv2 > vv1) return s[1]; + else return -s[1]; + } + return 0; + }; + + comparePointCache.set(sortKey, compareFunction); + return compareFunction; +} diff --git a/src/Geometry/Orbit.ts b/src/Geometry/Orbit.ts index 26f8ae211..61e3d096e 100644 --- a/src/Geometry/Orbit.ts +++ b/src/Geometry/Orbit.ts @@ -48,11 +48,12 @@ export class Orbit /** * 使用观察向量,计算旋转角度 * - * @param {THREE.Vector3} dir + * @param {THREE.Vector3} dir 这个向量会被修改成单位向量. * @memberof Orbit */ UpdateRoValue(dir: THREE.Vector3) { + dir.normalize(); this.m_RoX = Math.asin(dir.z); if (dir.x < 1e-4 && dir.y < 1e-4) this.RoZ = Math.PI * 0.5; @@ -90,4 +91,4 @@ export class Orbit } return upRes; } -} \ No newline at end of file +} diff --git a/src/Geometry/ThreeCSG.ts b/src/Geometry/ThreeCSG.ts index 9d211bf85..0fa1fc2b2 100644 --- a/src/Geometry/ThreeCSG.ts +++ b/src/Geometry/ThreeCSG.ts @@ -18,7 +18,7 @@ export default class ThreeBSP constructor(geometry) { // Convert THREE.Geometry to ThreeBSP - var i, _length_i, + let i, _length_i, face, vertex, faceVertexUvs, uvs, polygon, polygons = [], @@ -111,7 +111,7 @@ export default class ThreeBSP //减 subtract(other_tree) { - var a = this.tree.clone(), + let a = this.tree.clone(), b = other_tree.tree.clone(); a.invert(); @@ -130,7 +130,7 @@ export default class ThreeBSP //结合 union(other_tree) { - var a = this.tree.clone(), + let a = this.tree.clone(), b = other_tree.tree.clone(); a.clipTo(b); @@ -147,7 +147,7 @@ export default class ThreeBSP //相交 intersect(other_tree) { - var a = this.tree.clone(), + let a = this.tree.clone(), b = other_tree.tree.clone(); a.invert(); @@ -164,7 +164,7 @@ export default class ThreeBSP toGeometry() { - var i, j, + let i, j, matrix = new THREE.Matrix4().getInverse(this.matrix), geometry = new THREE.Geometry(), polygons = this.tree.allPolygons(), @@ -241,7 +241,7 @@ export default class ThreeBSP toMesh(material) { - var geometry = this.toGeometry(), + let geometry = this.toGeometry(), mesh = new THREE.Mesh(geometry, material); mesh.position.setFromMatrixPosition(this.matrix); @@ -276,7 +276,7 @@ class Polygon calculateProperties() { - var a = this.vertices[0], + let a = this.vertices[0], b = this.vertices[1], c = this.vertices[2]; @@ -291,7 +291,7 @@ class Polygon clone() { - var i, vertice_count, + let i, vertice_count, polygon = new Polygon(); for (i = 0, vertice_count = this.vertices.length; i < vertice_count; i++) @@ -305,7 +305,7 @@ class Polygon flip() { - var i, vertices = []; + let i, vertices = []; this.normal.multiplyScalar(-1); this.w *= -1; @@ -322,7 +322,7 @@ class Polygon //划分? classifyVertex(vertex) { - var side_value = this.normal.dot(vertex) - this.w; + let side_value = this.normal.dot(vertex) - this.w; if (side_value < -EPSILON) { @@ -339,7 +339,7 @@ class Polygon //划分边? classifySide(polygon) { - var i, vertex, classification, + let i, vertex, classification, num_positive = 0, num_negative = 0, vertice_count = polygon.vertices.length; @@ -375,7 +375,7 @@ class Polygon //分解 分离 区域? splitPolygon(polygon, coplanar_front, coplanar_back, front, back) { - var classification = this.classifySide(polygon); + let classification = this.classifySide(polygon); if (classification === COPLANAR) { @@ -395,7 +395,7 @@ class Polygon } else { - var vertice_count, + let vertice_count, i, j, ti, tj, vi, vj, t, v, f = [], @@ -477,7 +477,7 @@ class Vertex //×乘 cross(vertex) { - var x = this.x, + let x = this.x, y = this.y, z = this.z; @@ -490,7 +490,7 @@ class Vertex normalize() { - var length = Math.sqrt(this.x * this.x + this.y * this.y + this.z * this.z); + let length = Math.sqrt(this.x * this.x + this.y * this.y + this.z * this.z); this.x /= length; this.y /= length; @@ -534,9 +534,9 @@ class Vertex // input: THREE.Matrix4 affine matrix - var x = this.x, y = this.y, z = this.z; + let x = this.x, y = this.y, z = this.z; - var e = m.elements; + let e = m.elements; this.x = e[0] * x + e[4] * y + e[8] * z + e[12]; this.y = e[1] * x + e[5] * y + e[9] * z + e[13]; @@ -554,7 +554,7 @@ class Node polygons: any[]; constructor(polygons?) { - var i, polygon_count, + let i, polygon_count, front = [], back = []; @@ -584,7 +584,7 @@ class Node //是凸的? 凸包? isConvex(polygons) { - var i, j; + let i, j; for (i = 0; i < polygons.length; i++) { for (j = 0; j < polygons.length; j++) @@ -600,7 +600,7 @@ class Node build(polygons) { - var i, polygon_count, + let i, polygon_count, front = [], back = []; @@ -629,7 +629,7 @@ class Node allPolygons() { - var polygons = this.polygons.slice(); + let polygons = this.polygons.slice(); if (this.front) polygons = polygons.concat(this.front.allPolygons()); if (this.back) polygons = polygons.concat(this.back.allPolygons()); return polygons; @@ -637,7 +637,7 @@ class Node clone() { - var node = new Node(); + let node = new Node(); node.divider = this.divider.clone(); node.polygons = this.polygons.map(function (polygon) @@ -653,7 +653,7 @@ class Node //反转 invert() { - var i, polygon_count, temp; + let i, polygon_count, temp; for (i = 0, polygon_count = this.polygons.length; i < polygon_count; i++) { @@ -674,7 +674,7 @@ class Node // clipPolygons(polygons) { - var i, polygon_count, + let i, polygon_count, front, back; if (!this.divider) return polygons.slice(); @@ -700,4 +700,4 @@ class Node if (this.front) this.front.clipTo(node); if (this.back) this.back.clipTo(node); } -} \ No newline at end of file +} diff --git a/src/GraphicsSystem/CameraControl.ts b/src/GraphicsSystem/CameraControl.ts index b8a40bcff..93a31591e 100644 --- a/src/GraphicsSystem/CameraControl.ts +++ b/src/GraphicsSystem/CameraControl.ts @@ -156,6 +156,13 @@ export class CameraControl } this.Update(); } + + /** + * 设置相机的观察向量. + * + * @param {THREE.Vector3} dir 方向向量,这个向量传入后会被更改为单位向量 + * @memberof CameraControl + */ LookAt(dir: THREE.Vector3) { this.m_Orbit.UpdateRoValue(dir); diff --git a/src/GraphicsSystem/IntersectWith.ts b/src/GraphicsSystem/IntersectWith.ts index 138c97faf..3d70b3cbd 100644 --- a/src/GraphicsSystem/IntersectWith.ts +++ b/src/GraphicsSystem/IntersectWith.ts @@ -5,7 +5,7 @@ import { Circle } from '../DatabaseServices/Circle'; import { Curve } from '../DatabaseServices/Curve'; import { Line } from '../DatabaseServices/Line'; import { Polyline } from '../DatabaseServices/Polyline'; -import { equal, equaln, midPoint } from '../Geometry/GeUtils'; +import { comparePoint, equal, equaln, midPoint } from '../Geometry/GeUtils'; /** @@ -241,30 +241,9 @@ export function IntersectLAndLFor3D(p1: Vector3, p2: Vector3, p3: Vector3, p4: V if (equaln(Math.abs(v1.dot(v2)), 1, 1e-6) && equaln(Math.abs(v1.dot(w)), 1, 1e-6)) //平行共线 { - const selectPt = (line: Line, p1: Vector3, p2: Vector3) => - { - let tmpP: Vector3; - if (line.PtOnCurve(p1)) - { - tmpP = p1; - } else if (line.PtOnCurve(p2)) - tmpP = p2; - else - { - let dist1 = line.EndPoint.distanceToSquared(p1); - let dist2 = line.EndPoint.distanceToSquared(p2); - tmpP = dist1 > dist2 ? p1 : p2; - } - return tmpP; - } - - let tmpLine = new Line(p1, p2); - let tmpLine2 = new Line(p3, p4); - - let tmpP1 = selectPt(tmpLine, p3, p4); - let tmpP2: Vector3 = selectPt(tmpLine2, p1, p2); - - pt = midPoint(tmpP1, tmpP2); + let pts = [p1, p2, p3, p4]; + pts.sort(comparePoint('xyz')); + pt = midPoint(pts[1], pts[2]); } else if (Math.abs(v1.dot(v2)) === 1) //平行不共线 {