1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864 |
- import Constant from "../Constant";
- import bezierUtil from "./bezierUtil.js";
- export default class MathUtil {
- constructor() {}
- getFixed(num, decimal) {
- if (!decimal) {
- decimal = 5;
- }
- // return Math.floor(num * 10000) / 10000;
- return parseFloat(num.toFixed(decimal));
- }
- // 求两个点的距离
- getDistance(p1, p2) {
- const x1 = p1.x;
- const y1 = p1.y;
- const x2 = p2.x;
- const y2 = p2.y;
- const num = Math.sqrt(Math.pow(x1 - x2, 2) + Math.pow(y1 - y2, 2));
- return this.getFixed(num);
- }
- createLine1(point1, point2) {
- if (point1.x == point2.x && point1.y == point2.y) {
- return null;
- } else if (this.getFixed(Math.abs(point1.x - point2.x)) == 0) {
- return { x: point1.x };
- } else if (this.getFixed(Math.abs(point1.y - point2.y)) == 0) {
- return { y: point1.y };
- }
- const parametera = (point1.y - point2.y) / (point1.x - point2.x);
- const parameterb =
- (point1.x * point2.y - point2.x * point1.y) / (point1.x - point2.x);
- if (this.getFixed(parametera) == 0) {
- return { y: this.getFixed(parameterb) };
- }
- const parameter = {
- a: this.getFixed(parametera),
- b: this.getFixed(parameterb),
- };
- return parameter;
- }
- createLine2(point, angle) {
- if (angle == 90 || angle == 270) {
- return { x: point.x };
- }
- let a = Math.tan((angle / 180) * Math.PI);
- let b = point.y - a * point.x;
- if (a != 0) {
- return { a: a, b: b };
- } else {
- return { y: point.y };
- }
- }
- // 与lineA平行并且point在线上
- createLine3(lineA, point) {
- const parameter = {};
- if (typeof lineA.a === "undefined") {
- if (typeof lineA.x !== "undefined") {
- parameter.x = point.x;
- } else if (typeof lineA.y !== "undefined") {
- parameter.y = point.y;
- }
- } else {
- parameter.a = lineA.a;
- parameter.b = point.y - point.x * lineA.a;
- }
- return parameter;
- }
- create2AngleLine(point, angle, driftAngle) {
- let line1 = this.createLine2(point, angle - driftAngle / 2);
- let line2 = this.createLine2(point, angle + driftAngle / 2);
- return { line1: line1, line2: line2 };
- }
- distanceForPoints(point1, point2) {
- return Math.sqrt(
- Math.pow(point1.x - point2.x, 2) + Math.pow(point1.y - point2.y, 2)
- );
- }
- //与line平行且两条线直接的距离是distance的两条线
- getParallelLineForDistance(line, distance) {
- let line1 = {};
- let line2 = {};
- if (!line.hasOwnProperty("a")) {
- if (line.hasOwnProperty("x")) {
- let x = line.x;
- line1.x = x + distance;
- line2.x = x - distance;
- } else if (line.hasOwnProperty("y")) {
- let y = line.y;
- line1.y = y + distance;
- line2.y = y - distance;
- }
- } else {
- line1.a = line.a;
- line1.b = line.b;
- line2.a = line.a;
- line2.b = line.b;
- let angle = Math.atan(line.a);
- let db = Math.abs(distance / Math.cos(angle));
- let b = line.b;
- line1.b = b + db;
- line2.b = b - db;
- }
- return { line1: line1, line2: line2 };
- }
- //获取扇形的两个端点
- getEndpoint(point, angle, sectorAngle) {
- const distance = 15;
- //line1是减,line2是加
- let lines1 = this.create2AngleLine(point, angle, sectorAngle);
- let line = this.createLine2(point, angle);
- line = this.getLineForPoint(line, point);
- let lines2 = this.getParallelLineForDistance(line, distance);
- let point1 = this.getIntersectionPoint(lines1.line1, lines2.line1);
- let point2 = this.getIntersectionPoint(lines1.line1, lines2.line2);
- let point3 = this.getIntersectionPoint(lines1.line2, lines2.line1);
- let point4 = this.getIntersectionPoint(lines1.line2, lines2.line2);
- let angle1 = this.Angle(point, point1, { x: point.x + 1, y: point.y });
- let angle2 = this.Angle(point, point2, { x: point.x + 1, y: point.y });
- let angle3 = this.Angle(point, point3, { x: point.x + 1, y: point.y });
- let angle4 = this.Angle(point, point4, { x: point.x + 1, y: point.y });
- if (angle > 180) {
- angle = 360 - angle;
- }
- if (
- Math.abs((angle1 + angle3) / 2 - angle) <
- Math.abs((angle2 + angle4) / 2 - angle)
- ) {
- return { p1: point1, p2: point3 };
- } else {
- return { p1: point2, p2: point4 };
- }
- }
- // true表示逆时针,false表示顺时针
- isClockwise(vertices) {
- let area = 0;
- for (let i = 0; i < vertices.length; i++) {
- const j = (i + 1) % vertices.length;
- area += vertices[i].x * vertices[j].y;
- area -= vertices[j].x * vertices[i].y;
- }
- const sub = area / 2;
- if (sub > 0) {
- // 逆时针
- return true;
- } else {
- // 顺时针
- return false;
- }
- }
- reverse(points) {
- const _points = [];
- for (let i = points.length - 1; i > -1; --i) {
- _points.push(points[i]);
- }
- return _points;
- }
- //两条线的交点
- getIntersectionPoint(parameter1, parameter2) {
- if (this.isParallel(parameter1, parameter2)) {
- return null;
- }
- if (
- typeof parameter1.a == "undefined" &&
- typeof parameter2.a != "undefined"
- ) {
- if (parameter1.x) {
- return {
- x: parameter1.x,
- y: parameter2.a * parameter1.x + parameter2.b,
- };
- } else if (parameter1.y) {
- return {
- x: (parameter1.y - parameter2.b) / parameter2.a,
- y: parameter1.y,
- };
- }
- } else if (
- typeof parameter2.a == "undefined" &&
- typeof parameter1.a != "undefined"
- ) {
- if (parameter2.x) {
- return {
- x: parameter2.x,
- y: parameter1.a * parameter2.x + parameter1.b,
- };
- } else if (parameter2.y) {
- return {
- x: (parameter2.y - parameter1.b) / parameter1.a,
- y: parameter2.y,
- };
- }
- } else if (
- typeof parameter2.a == "undefined" &&
- typeof parameter1.a == "undefined"
- ) {
- if (parameter1.hasOwnProperty("x") && parameter2.hasOwnProperty("y")) {
- return { x: parameter1.x, y: parameter2.y };
- } else if (
- parameter1.hasOwnProperty("y") &&
- parameter2.hasOwnProperty("x")
- ) {
- return { x: parameter2.x, y: parameter1.y };
- } else {
- return null;
- }
- }
- if (parameter1.a == parameter2.a) {
- return null;
- }
- let joinpointx =
- (parameter2.b - parameter1.b) / (parameter1.a - parameter2.a);
- let joinpointy =
- (parameter1.a * parameter2.b - parameter2.a * parameter1.b) /
- (parameter1.a - parameter2.a);
- let point = { x: joinpointx, y: joinpointy };
- return point;
- }
- // 直线的交点
- getIntersectionPoint2(a, b, c, d) {
- /** 1 解线性方程组, 求线段交点. **/
- // 如果分母为0 则平行或共线, 不相交
- const denominator = (b.y - a.y) * (d.x - c.x) - (a.x - b.x) * (c.y - d.y);
- if (denominator == 0) {
- return null;
- }
- // 线段所在直线的交点坐标 (x , y)
- const x =
- ((b.x - a.x) * (d.x - c.x) * (c.y - a.y) +
- (b.y - a.y) * (d.x - c.x) * a.x -
- (d.y - c.y) * (b.x - a.x) * c.x) /
- denominator;
- const y =
- -(
- (b.y - a.y) * (d.y - c.y) * (c.x - a.x) +
- (b.x - a.x) * (d.y - c.y) * a.y -
- (d.x - c.x) * (b.y - a.y) * c.y
- ) / denominator;
- return { x: x, y: y };
- }
- //两条线段交点
- getIntersectionPoint3(a, b, c, d) {
- const join = this.getIntersectionPoint2(a, b, c, d);
- if (join) {
- const x = join.x;
- const y = join.y; // 交点在线段1上 且交点也在线段2上
- /** 2 判断交点是否在两条线段上 **/
- if (
- (x - a.x) * (x - b.x) <= 0.001 &&
- (y - a.y) * (y - b.y) <= 0.001 &&
- (x - c.x) * (x - d.x) <= 0.001 &&
- (y - c.y) * (y - d.y) <= 0.001
- ) {
- // 返回交点p
- return {
- x: x,
- y: y,
- };
- }
- return null;
- }
- return null;
- }
- // 线段和直线是否相交
- getIntersectionPoint4(point1, point2, line) {
- const line1 = this.createLine1(point1, point2);
- const join = this.getIntersectionPoint(line1, line);
- if (join == null) {
- return null;
- }
- if (this.PointInSegment(join, point1, point2)) {
- return join; // 相交
- } else {
- return null;
- }
- }
- //返回true表示平行
- isParallel(line1, line2) {
- if (typeof line1.a == "undefined" && typeof line2.a == "undefined") {
- if (line1.hasOwnProperty("x") && line2.hasOwnProperty("x")) {
- return true;
- } else if (line1.hasOwnProperty("y") && line2.hasOwnProperty("y")) {
- return true;
- } else {
- return false;
- }
- } else if (typeof line1.a == "undefined" || typeof line2.a == "undefined") {
- return false;
- } else if (this.getFixed(line1.a) == this.getFixed(line2.a)) {
- return true;
- } else {
- return false;
- }
- }
- //两条相交的线段的夹角,永远小于180度
- Angle(o, s, e) {
- let cosfi = 0,
- fi = 0,
- norm = 0;
- let dsx = s.x - o.x;
- let dsy = s.y - o.y;
- let dex = e.x - o.x;
- let dey = e.y - o.y;
- cosfi = dsx * dex + dsy * dey;
- norm = (dsx * dsx + dsy * dsy) * (dex * dex + dey * dey);
- cosfi /= Math.sqrt(norm);
- if (cosfi >= 1.0) return 0;
- //if (cosfi <= -1.0) return Math.PI;
- if (cosfi <= -1.0) return 180;
- fi = Math.acos(cosfi);
- if ((180 * fi) / Math.PI < 180) {
- //return 180 * fi / Math.PI;
- return (fi * 180) / Math.PI;
- } else {
- //return 360 - 180 * fi / Math.PI;
- return ((2 * Math.PI - fi) * 180) / Math.PI;
- }
- }
- Angle1(o, s, e) {
- let cosfi = 0,
- fi = 0,
- norm = 0;
- let dsx = s.x - o.x;
- let dsy = s.y - o.y;
- let dex = e.x - o.x;
- let dey = e.y - o.y;
- cosfi = dsx * dex + dsy * dey;
- norm = (dsx * dsx + dsy * dsy) * (dex * dex + dey * dey);
- cosfi /= Math.sqrt(norm);
- if (cosfi >= 1.0) return 0;
- //if (cosfi <= -1.0) return Math.PI;
- if (cosfi <= -1.0) return 180;
- fi = Math.acos(cosfi);
- return (fi * 180) / Math.PI;
- }
- getArrow(start, end, ange = 30, L = 20) {
- let a = Math.atan2(end.y - start.y, end.x - start.x);
- let xC = end.x - L * Math.cos(a + (ange * Math.PI) / 180); // θ=30
- let yC = end.y - L * Math.sin(a + (ange * Math.PI) / 180);
- let xD = end.x - L * Math.cos(a - (ange * Math.PI) / 180);
- let yD = end.y - L * Math.sin(a - (ange * Math.PI) / 180);
- return [{ x: xC, y: yC }, end, { x: xD, y: yD }];
- }
- //经过point且与line垂直的线
- getLineForPoint(line, point) {
- let parameter = {};
- if (line.a == 0 || typeof line.a == "undefined") {
- if (line.hasOwnProperty("x")) {
- parameter.x = line.x;
- parameter.y = point.y;
- } else if (line.hasOwnProperty("y")) {
- parameter.x = point.x;
- parameter.y = line.y;
- }
- } else {
- parameter.a = -1 / line.a;
- parameter.b = point.y - point.x * parameter.a;
- }
- return parameter;
- }
- // 经过point且与line垂直的直线,该直线与line的交点
- getJoinLinePoint(point, line) {
- const verticalLine = this.getVerticalLine(line, point);
- const join = this.getIntersectionPoint(line, verticalLine);
- return join;
- }
- // 点到直线的距离
- getDisForPoinLine(point, line) {
- const join = this.getJoinLinePoint(point, line);
- return this.getDistance(point, join);
- }
- // 垂直线
- getVerticalLine(line, point) {
- if (typeof line.a === "undefined") {
- if (line.hasOwnProperty("x")) {
- return { y: point.y };
- } else if (line.hasOwnProperty("y")) {
- return { x: point.x };
- } else {
- return null;
- }
- } else if (line.a == 0) {
- return { x: point.x };
- } else {
- const tl = {};
- tl.a = -1 / line.a;
- const result = this.createLine3(tl, point);
- return result;
- }
- }
- //point在直线上,只是不确定是否在线段上
- //方法:point到startPoint和endPoint的距离之和与startPoint和endPoint之间的距离对比
- isContainForSegment(point, startPoint, endPoint, minDis) {
- if (!minDis) {
- minDis = Constant.minLen;
- }
- let dis1 =
- this.getDistance(startPoint, point) + this.getDistance(endPoint, point);
- let dis2 = this.getDistance(startPoint, endPoint);
- if (Math.abs(dis1 - dis2) < minDis) {
- return true;
- } else {
- return false;
- }
- }
- /*
- //minDis
- isPointInPoly(point, points, minDis) {
- if (!minDis) {
- minDis = Constant.minRealDis
- }
- const x = point.x
- const y = point.y
- let inside = false
- // 是否在顶点附近
- for (let i = 0; i < points.length; ++i) {
- let distance = this.getDistance(point, points[i])
- if (distance < minDis) {
- return true
- }
- }
- // 是否在边沿
- for (let i = 0, j = points.length - 1; i < points.length; j = i++) {
- let pt1 = points[i]
- let pt2 = points[j]
- const flag = this.isContainForSegment(point, pt1, pt2, minDis)
- if (flag) {
- return true
- }
- }
- for (let i = 0, j = points.length - 1; i < points.length; j = i++) {
- let pt1 = points[i]
- let pt2 = points[j]
- const xi = pt1.x
- const yi = pt1.y
- const xj = pt2.x
- const yj = pt2.y
- const intersect = yi > y != yj > y && x < ((xj - xi) * (y - yi)) / (yj - yi) + xi
- if (intersect) inside = !inside
- }
- return inside
- }
- */
- isPointInPoly(point, points) {
- const x = point.x;
- const y = point.y;
- let inside = false;
- for (let i = 0, j = points.length - 1; i < points.length; j = i++) {
- let pt1 = points[i];
- let pt2 = points[j];
- const xi = pt1.x;
- const yi = pt1.y;
- const xj = pt2.x;
- const yj = pt2.y;
- const intersect =
- yi > y != yj > y && x < ((xj - xi) * (y - yi)) / (yj - yi) + xi;
- if (intersect) inside = !inside;
- }
- return inside;
- }
- //a表示横轴,b表示竖轴
- isPointInElliptic(point, center, a, b) {
- let r =
- Math.pow((point.x - center.x) / a, 2) +
- Math.pow((point.y - center.y) / b, 2);
- if (r <= 1) {
- return true;
- } else {
- return false;
- }
- }
- // 点到线段的距离
- // 在minDistance范围内,会吸附到point1/point2上
- // 返回值:type是1表示吸附在point1,是2表示吸附在point2,是0表示在线段point1-point2上;
- getDisForPoinSegment(point, point1, point2, minDistance) {
- const line = this.createLine1(point1, point2);
- const join = this.getJoinLinePoint(point, line);
- const dis = this.getDistance(point1, point2);
- const dis1 = this.getDistance(join, point1);
- const dis2 = this.getDistance(join, point2);
- if (
- this.getDistance(join, point1) > dis ||
- this.getDistance(join, point2) > dis
- ) {
- // 在线段外
- if (dis1 < dis2 && dis1 < minDistance) {
- return { type: 1, join: point1 };
- } else if (dis2 < dis1 && dis2 < minDistance) {
- return { type: 2, join: point2 };
- } else {
- return null;
- }
- } else {
- if (dis1 < minDistance) {
- return { type: 1, join: point1 };
- } else if (dis2 < minDistance) {
- return { type: 2, join: point2 };
- } else if (this.getDistance(point, join) < minDistance) {
- return { type: 0, join: join };
- }
- }
- }
- PointInSegment(Q, pi, pj, minDis) {
- if (
- this.getDistance(Q, pi) < Constant.minAdsorbPix ||
- this.getDistance(Q, pj) < Constant.minAdsorbPix
- ) {
- return true;
- }
- if (!minDis) {
- minDis = 0.1;
- }
- minDis = minDis / 2;
- const offset1 = (Q.x - pi.x) * (pj.y - pi.y) - (pj.x - pi.x) * (Q.y - pi.y);
- const offset2 = Math.min(pi.x, pj.x) - Q.x;
- const offset3 = Q.x - Math.max(pi.x, pj.x);
- const offset4 = Math.min(pi.y, pj.y) - Q.y;
- const offset5 = Q.y - Math.max(pi.y, pj.y);
- if (
- Math.abs(offset1) < minDis &&
- (offset2 <= 0 || Math.abs(offset2) < minDis) &&
- (offset3 <= 0 || Math.abs(offset3) < minDis) &&
- (offset4 <= 0 || Math.abs(offset4) < minDis) &&
- (offset5 <= 0 || Math.abs(offset5) < minDis)
- ) {
- return true;
- } else {
- return false;
- }
- }
- //点p是否在线段AB上
- isPointOnSegment(p, A, B) {
- // 计算向量 AP 和 BP
- const AP = {
- x: p.x - A.x,
- y: p.y - A.y,
- };
- const BP = {
- x: p.x - B.x,
- y: p.y - B.y,
- };
- // 计算向量 AB 的长度和方向
- const AB = {
- x: B.x - A.x,
- y: B.y - A.y,
- };
- const AB_length = this.getDistance(A, B);
- const AB_direction = {
- x: AB.x / AB_length,
- y: AB.y / AB_length,
- };
- // 检查 AP 和 BP 的方向是否与 AB 相同,并检查它们的长度是否小于等于 AB 的长度
- const dot_product_AP = AP.x * AB_direction.x + AP.y * AB_direction.y;
- const dot_product_BP = BP.x * AB_direction.x + BP.y * AB_direction.y;
- //return dot_product_AP >= 0 && dot_product_BP <= 0 && Math.abs(AP.x * BP.y - AP.y * BP.x) <= AB_length * Number.EPSILON;
- return (
- dot_product_AP >= 0 &&
- dot_product_BP <= 0 &&
- Math.abs(AP.x * BP.y - AP.y * BP.x) <= 0.01
- );
- }
- clonePoint(p1, p2) {
- p1.x = p2.x;
- p1.y = p2.y;
- }
- clonePoints(points1, points2) {
- for (let i = 0; i < points1.length; ++i) {
- this.clonePoint(points1[i], points2[i]);
- }
- }
- equalPoint(p1, p2) {
- if (p1.x == p2.x && p1.y == p2.y) {
- return true;
- } else {
- return false;
- }
- }
- equalPoints(points1, points2) {
- if (points1.length != points2.length) {
- return false;
- }
- for (let i = 0; i < points1.length; ++i) {
- let flag = this.equalPoint(points1[i], points2[i]);
- if (!flag) {
- return false;
- }
- }
- return true;
- }
- equalJSON(json1, json2) {
- for (let key in json1) {
- if (json2.hasOwnProperty(key) && json1[key] == json2[key]) {
- continue;
- } else {
- return false;
- }
- }
- for (let key in json2) {
- if (json1.hasOwnProperty(key) && json1[key] == json2[key]) {
- continue;
- } else {
- return false;
- }
- }
- return true;
- }
- crossTwoLines(point1, point2, point3, point4, dis) {
- if (typeof dis == "undefined") {
- dis = Constant.minAdsorbPix;
- }
- const join = this.getIntersectionPoint2(point1, point2, point3, point4);
- if (join != null) {
- if (
- this.getDistance(point1, join) > dis &&
- this.getDistance(point2, join) > dis &&
- this.getDistance(point3, join) > dis &&
- this.getDistance(point4, join) > dis
- ) {
- if (
- this.getDistance(point1, join) < this.getDistance(point1, point2) &&
- this.getDistance(point2, join) < this.getDistance(point1, point2) &&
- this.getDistance(point3, join) < this.getDistance(point3, point4) &&
- this.getDistance(point4, join) < this.getDistance(point3, point4)
- ) {
- return true;
- } else {
- return false;
- }
- }
- } else {
- if (
- this.PointInSegment(point1, point3, point4) ||
- this.PointInSegment(point2, point3, point4)
- ) {
- return true;
- }
- }
- return false;
- }
- getDisPointsLine(line, point, distance1, distance2) {
- const newpoint1 = {};
- const newpoint2 = {};
- const result = {};
- if (line.hasOwnProperty("x")) {
- newpoint1.x = line.x;
- newpoint1.y = point.y - distance1;
- newpoint2.x = line.x;
- newpoint2.y = point.y + distance2;
- } else if (line.hasOwnProperty("y")) {
- newpoint1.y = line.y;
- newpoint1.x = point.x - distance1;
- newpoint2.y = line.y;
- newpoint2.x = point.x + distance2;
- } else {
- const a = Math.atan(line.a);
- const t_line = { a: -1 / line.a };
- const line_ab2 = this.createLine3(t_line, point);
- const join = this.getIntersectionPoint(line, line_ab2);
- newpoint1.x = join.x - distance1 * Math.cos(a);
- newpoint1.y = join.y - distance1 * Math.sin(a);
- newpoint2.x = join.x + distance2 * Math.cos(a);
- newpoint2.y = join.y + distance2 * Math.sin(a);
- }
- result.newpoint1 = newpoint1;
- result.newpoint2 = newpoint2;
- return result;
- }
- getBoundingBox(points) {
- let minX = points[0].x;
- let maxX = points[0].x;
- let minY = points[0].y;
- let maxY = points[0].y;
- for (let i = 1; i < points.length; ++i) {
- const point = points[i];
- if (minX > point.x) {
- minX = point.x;
- }
- if (minY > point.y) {
- minY = point.y;
- }
- if (maxX < point.x) {
- maxX = point.x;
- }
- if (maxY < point.y) {
- maxY = point.y;
- }
- }
- const box = {};
- box.minX = minX;
- box.minY = minY;
- box.maxX = maxX;
- box.maxY = maxY;
- return box;
- }
- getBoundingBox2(points) {
- let minX = null;
- let maxX = null;
- let minY = null;
- let maxY = null;
- for (let key in points) {
- const point = points[key];
- if (minX == null || minX > point.x) {
- minX = point.x;
- }
- if (minY == null || minY > point.y) {
- minY = point.y;
- }
- if (maxX == null || maxX < point.x) {
- maxX = point.x;
- }
- if (maxY == null || maxY < point.y) {
- maxY = point.y;
- }
- }
- const box = {};
- box.minX = minX;
- box.minY = minY;
- box.maxX = maxX;
- box.maxY = maxY;
- return box;
- }
- ComputePolygonArea(points) {
- const point_num = points.length;
- if (point_num < 3) {
- return 0;
- }
- let s = points[0].y * (points[point_num - 1].x - points[1].x);
- for (let i = 1; i < point_num; ++i)
- s += points[i].y * (points[i - 1].x - points[(i + 1) % point_num].x);
- return Math.abs(s / 2.0);
- }
- // 获取多边形重心
- getPolygonCore(points) {
- function Area(p0, p1, p2) {
- let area = 0.0;
- area =
- p0.x * p1.y +
- p1.x * p2.y +
- p2.x * p0.y -
- p1.x * p0.y -
- p2.x * p1.y -
- p0.x * p2.y;
- return area / 2;
- }
- let sum_x = 0;
- let sum_y = 0;
- let sum_area = 0;
- let p1 = points[1];
- for (let i = 2; i < points.length; i++) {
- const p2 = points[i];
- const area = Area(points[0], p1, p2);
- sum_area += area;
- sum_x += (points[0].x + p1.x + p2.x) * area;
- sum_y += (points[0].y + p1.y + p2.y) * area;
- p1 = p2;
- }
- const xx = sum_x / sum_area / 3;
- const yy = sum_y / sum_area / 3;
- return {
- x: xx,
- y: yy,
- };
- }
- // points1是否在points2里
- isPolyInPoly(points1, points2, minDis) {
- for (let i = 0; i < points1.length; ++i) {
- let flag = false;
- for (let j = 0; j < points2.length; ++j) {
- if (this.equalPoint(points1[i], points2[j])) {
- flag = true;
- break;
- }
- }
- if (!flag) {
- if (!this.isPointInPoly(points1[i], points2, minDis)) {
- return false;
- }
- } else {
- const nextIndex = i == points1.length - 1 ? 0 : i + 1;
- const mid = {
- x: (points1[i].x + points1[nextIndex].x) / 2,
- y: (points1[i].y + points1[nextIndex].y) / 2,
- };
- if (!this.isPointInPoly(mid, points2, minDis)) {
- return false;
- }
- }
- }
- return true;
- }
- dotPoints(pt1, pt2, point1, point2) {
- let vt1 = {};
- let vt2 = {};
- vt1.start = {};
- vt1.end = {};
- vt1.start.x = 0;
- vt1.start.y = 0;
- vt1.end.x = pt2.x - pt1.x;
- vt1.end.y = pt2.y - pt1.y;
- vt2.start = {};
- vt2.end = {};
- vt2.start.x = 0;
- vt2.start.y = 0;
- vt2.end.x = point2.x - point1.x;
- vt2.end.y = point2.y - point1.y;
- let result = vt1.end.x * vt2.end.x + vt1.end.y * vt2.end.y;
- return result;
- }
- //start是起点,target是朝着目标移动,distance是移动的距离
- translate(start, target, point, distance) {
- let dx = target.x - start.x;
- let dy = target.y - start.y;
- let dis = Math.sqrt(Math.pow(dx, 2) + Math.pow(dy, 2));
- let result = {
- x: point.x + (dx * distance) / dis,
- y: point.y + (dy * distance) / dis,
- };
- return result;
- }
- //射线与线段相交
- // intersection(rayStart, rayEnd, segmentStart, segmentEnd) {
- // // 计算射线和线段的方向向量
- // const rayDirection = {
- // x:rayEnd.x - rayStart.x,
- // y:rayEnd.y - rayStart.y,
- // };
- // const segmentDirection = {
- // x:segmentEnd.x - segmentStart.x,
- // y:segmentEnd.y - segmentStart.y,
- // };
- // // 计算射线和线段的起点之间的向量
- // const startPointVector = {
- // x:rayStart.x - segmentStart.x,
- // y:rayStart.y - segmentStart.y,
- // };
- // // 计算射线和线段的叉积
- // const crossProduct = rayDirection.x * segmentDirection.y - rayDirection.y * segmentDirection.x;
- // // 如果叉积为0,则表示射线和线段平行
- // if (crossProduct === 0) {
- // return null;
- // }
- // // 计算线段起点到射线的交点的向量
- // const t = (startPointVector.x * segmentDirection.y - startPointVector.y * segmentDirection.x) / crossProduct;
- // // 如果t的值小于0,则交点在射线的起点之后
- // if (t < 0) {
- // return null;
- // }
- // // 计算交点的坐标
- // const intersectionX = rayStart.x + t * rayDirection.x;
- // const intersectionY = rayStart.y + t * rayDirection.y;
- // // 如果交点在线段的范围内,则返回交点坐标
- // if ((intersectionX >= Math.min(segmentStart.x, segmentEnd.x)) &&
- // (intersectionX <= Math.max(segmentStart.x, segmentEnd.x)) &&
- // (intersectionY >= Math.min(segmentStart.y, segmentEnd.y)) &&
- // (intersectionY <= Math.max(segmentStart.y, segmentEnd.y))) {
- // //return [intersectionX, intersectionY];
- // return {
- // x:intersectionX,
- // y:intersectionY,
- // };
- // }
- // // 否则返回null
- // return null;
- // }
- // raySegmentIntersection(rayOrigin, rayDirection, segmentStart, segmentEnd) {
- // // 计算射线和线段的交点
- // const x1 = rayOrigin.x
- // const y1 = rayOrigin.y
- // const x2 = segmentStart.x
- // const y2 = segmentStart.y
- // const dx1 = rayDirection.x
- // const dy1 = rayDirection.y
- // const dx2 = segmentEnd.x - x2
- // const dy2 = segmentEnd.y - y2
- // const crossProduct = dx1 * dy2 - dx2 * dy1
- // if (Math.abs(crossProduct) < 1e-8) {
- // // 射线和线段平行或共线
- // return null
- // }
- // const t1 = (dx2 * (y1 - y2) - dy2 * (x1 - x2)) / crossProduct
- // const t2 = (dx1 * (y1 - y2) - dy1 * (x1 - x2)) / crossProduct
- // if (t1 >= 0 && t2 >= 0 && t2 <= 1) {
- // // 有交点,计算交点坐标
- // const intersectionX = x1 + t1 * dx1
- // const intersectionY = y1 + t1 * dy1
- // return {
- // x: intersectionX,
- // y: intersectionY,
- // }
- // } else {
- // // 没有交点
- // return null
- // }
- // }
- raySegmentIntersection(rayOrigin, rayDirection, segmentStart, segmentEnd) {
- const end = {
- x: rayOrigin.x + rayDirection.x,
- y: rayOrigin.y - rayDirection.z,
- };
- const line = this.createLine1(rayOrigin, end);
- const join = this.getIntersectionPoint4(segmentStart, segmentEnd, line);
- if (join == null) {
- return null;
- } else {
- const dis = this.getDistance(end, join);
- const dis1 = this.getDistance(rayOrigin, join);
- const dis2 = this.getDistance(rayOrigin, end);
- if (dis - (dis1 + dis2) + 0.01 > 0) {
- return null;
- } else {
- return join;
- }
- }
- }
- RectangleVertex(startPoint, endPoint, width) {
- let line = this.createLine1(startPoint, endPoint);
- let lines = this.getParallelLineForDistance(line, width / 2);
- let leftEdgeStart, rightEdgeStart, rightEdgeEnd, leftEdgeEnd;
- let point = null;
- let points = [];
- //先计算start部分
- point = startPoint;
- points.push(endPoint);
- points.push(startPoint);
- let point1 = this.getJoinLinePoint(point, lines.line1);
- let point2 = this.getJoinLinePoint(point, lines.line2);
- points[2] = point1;
- if (this.isClockwise(points)) {
- rightEdgeStart = point1;
- leftEdgeStart = point2;
- } else {
- rightEdgeStart = point2;
- leftEdgeStart = point1;
- }
- //再计算end部分
- points = [];
- point = endPoint;
- points.push(startPoint);
- points.push(endPoint);
- point1 = this.getJoinLinePoint(point, lines.line1);
- point2 = this.getJoinLinePoint(point, lines.line2);
- points[2] = point1;
- if (this.isClockwise(points)) {
- rightEdgeEnd = point2;
- leftEdgeEnd = point1;
- } else {
- rightEdgeEnd = point1;
- leftEdgeEnd = point2;
- }
- return {
- leftEdgeStart: leftEdgeStart,
- rightEdgeStart: rightEdgeStart,
- rightEdgeEnd: rightEdgeEnd,
- leftEdgeEnd: leftEdgeEnd,
- };
- }
- //start到end的射线中取一点point,start-end和end-point的距离相同
- getPositionForExtendedLine(start, end) {
- const dx = end.x - start.x;
- const dy = end.y - start.y;
- const point = {
- x: end.x + dx,
- y: end.y + dy,
- };
- return point;
- }
- isOnRay(start, dir, position) {
- const v1 = { x: dir.x - start.x, y: dir.y - start.y };
- const v2 = { x: position.x - start.x, y: position.y - start.y };
- return v1.x * v2.y - v1.y * v2.x;
- }
- //向量是否同样的方向
- isSameDirForVector(point1, point2, p1, p2) {
- const v1 = {
- x: point2.x - point1.x,
- y: point2.y - point1.y,
- };
- const v2 = {
- x: p2.x - p1.x,
- y: p2.y - p1.y,
- };
- const value = this.dot(v1, v2);
- if (value > 0) {
- return true;
- }
- {
- return false;
- }
- }
- //生成五角星
- createFivePointedStar(position, r) {
- let deg = Math.PI / 180; //角度
- let points = [];
- points[0] = {
- x: position.x - r * Math.cos(54 * deg),
- y: position.y + r * Math.sin(54 * deg),
- };
- points[1] = {
- x: position.x,
- y: position.y - r,
- };
- points[2] = {
- x: position.x + r * Math.cos(54 * deg),
- y: position.y + r * Math.sin(54 * deg),
- };
- points[3] = {
- x: position.x - r * Math.cos(18 * deg),
- y: position.y - r * Math.sin(18 * deg),
- };
- points[4] = {
- x: position.x + r * Math.cos(18 * deg),
- y: position.y - r * Math.sin(18 * deg),
- };
- return points;
- }
- createSixPoint(position, r) {
- let deg = Math.PI / 180; //角度
- let points = [];
- points[0] = {
- x: position.x,
- y: position.y + r,
- };
- points[1] = {
- x: position.x + r * Math.sin(60 * deg),
- y: position.y + r * Math.cos(60 * deg),
- };
- points[2] = {
- x: position.x + r * Math.cos(30 * deg),
- y: position.y - r * Math.sin(30 * deg),
- };
- points[3] = {
- x: position.x,
- y: position.y - r,
- };
- points[4] = {
- x: position.x - r * Math.cos(30 * deg),
- y: position.y - r * Math.sin(30 * deg),
- };
- points[5] = {
- x: position.x - r * Math.sin(60 * deg),
- y: position.y + r * Math.cos(60 * deg),
- };
- return points;
- }
- //求圆和直线之间的交点
- /**
- * 求圆和直线之间的交点
- * 直线方程:y = kx + b
- * 圆的方程:(x - m)² + (x - n)² = r²
- * x1, y1 = 线坐标1, x2, y2 = 线坐标2, m, n = 圆坐标, r = 半径
- */
- getInsertPointBetweenCircleAndLine(x1, y1, x2, y2, m, n, radius) {
- let insertPoints = [];
- if (Math.abs(x1 - x2) < 0.5) {
- insertPoints[0] = {
- x: x1,
- y: n - Math.sqrt(radius * radius - Math.pow(x1 - m, 2)),
- };
- insertPoints[1] = {
- x: x1,
- y: n + Math.sqrt(radius * radius - Math.pow(x1 - m, 2)),
- };
- return insertPoints;
- }
- // console.log(x1, y1, x2, y2, m, n, radius)
- let kbArr = this.binaryEquationGetKB(x1, y1, x2, y2);
- let k = kbArr[0];
- let b = kbArr[1];
- let aX = 1 + k * k;
- let bX = 2 * k * (b - n) - 2 * m;
- let cX = m * m + (b - n) * (b - n) - radius * radius;
- let xArr = this.quadEquationGetX(aX, bX, cX);
- xArr.forEach((x) => {
- let y = k * x + b;
- insertPoints.push({ x: x, y: y });
- });
- return insertPoints;
- }
- /**
- * 求二元一次方程的系数
- * y1 = k * x1 + b => k = (y1 - b) / x1
- * y2 = k * x2 + b => y2 = ((y1 - b) / x1) * x2 + b
- */
- binaryEquationGetKB(x1, y1, x2, y2) {
- let k = (y1 - y2) / (x1 - x2);
- let b = (x1 * y2 - x2 * y1) / (x1 - x2);
- return [k, b];
- }
- /**
- * 一元二次方程求根
- * ax² + bx + c = 0
- */
- quadEquationGetX(a, b, c) {
- let xArr = [];
- let result = Math.pow(b, 2) - 4 * a * c;
- if (result > 0) {
- xArr.push((-b + Math.sqrt(result)) / (2 * a));
- xArr.push((-b - Math.sqrt(result)) / (2 * a));
- }
- //else if (result == 0) {
- else {
- xArr.push(-b / (2 * a));
- }
- return xArr;
- }
- angleTo(v1, v2) {
- const denominator = Math.sqrt(this.lengthSq(v1) * this.lengthSq(v2));
- if (denominator === 0) return 90;
- const theta = this.dot(v1, v2) / denominator;
- //return Math.acos(this.clamp(theta, -1, 1));
- return (Math.acos(this.clamp(theta, -1, 1)) / Math.PI) * 180;
- }
- //点乘
- dot(v1, v2) {
- return v1.x * v2.x + v1.y * v2.y;
- }
- //叉乘
- cross(v1, v2) {
- return v1.x * v2.y - v1.y * v2.x;
- }
- // 两点相减
- pointMinus(v1, v2) {
- return {
- x: v1.x - v2.x,
- y: v1.y - v2.y,
- };
- }
- // 两点相加
- pointPlus(v1, v2) {
- return {
- x: v1.x + v2.x,
- y: v1.y + v2.y,
- };
- }
- // 中心点
- lineCenter(v1, v2) {
- const point = this.pointPlus(v1, v2);
- return {
- x: point.x / 2,
- y: point.y / 2,
- };
- }
- // 点放大
- pointScale(v, a) {
- return {
- x: v.x * a,
- y: v.y * a,
- };
- }
- clamp(value, min, max) {
- return Math.max(min, Math.min(max, value));
- }
- lengthSq(v) {
- return v.x * v.x + v.y * v.y;
- }
- // 当前点 下一个点 下下个点
- getCurvesControls(p1, pt, p2, scale = 0.3) {
- const vec1T = this.pointMinus(p1, pt);
- const vecT2 = this.pointMinus(p1, pt);
- const len1 = Math.hypot(vec1T.x, vec1T.y);
- const len2 = Math.hypot(vecT2.x, vecT2.y);
- const v = len1 / len2;
- let delta;
- if (v > 1) {
- delta = this.pointMinus(
- p1,
- this.pointPlus(pt, this.pointScale(this.pointMinus(p2, pt), 1 / v))
- );
- } else {
- delta = this.pointMinus(
- this.pointPlus(pt, this.pointScale(this.pointMinus(p1, pt), v)),
- p2
- );
- }
- delta = this.pointScale(delta, scale);
- const control1 = {
- x: this.pointPlus(pt, delta).x,
- y: this.pointPlus(pt, delta).y,
- };
- const control2 = {
- x: this.pointMinus(pt, delta).x,
- y: this.pointMinus(pt, delta).y,
- };
- return { control1, control2 };
- }
- getCurvesByPoints(points, scale = 0.2) {
- const curves = [];
- let preControl1, preControl2;
- for (let i = 0; i < points.length - 2; i++) {
- const { control1, control2 } = this.getCurvesControls(
- points[i],
- points[i + 1],
- points[i + 2],
- scale
- );
- curves.push({
- start: points[i],
- end: points[i + 1],
- controls: i === 0 ? [control1] : [preControl2, control1],
- });
- preControl1 = control1;
- preControl2 = control2;
- }
- curves.push({
- start: points[points.length - 2],
- controls: [preControl2],
- end: points[points.length - 1],
- });
- return curves;
- }
- /**
- * 已知四个控制点,及曲线中的某一个点的 x/y,反推求 t
- * @param {number} x1 起点 x/y
- * @param {number} x2 控制点1 x/y
- * @param {number} x3 控制点2 x/y
- * @param {number} x4 终点 x/y
- * @param {number} X 曲线中的某个点 x/y
- * @returns {number[]} t[]
- */
- getThreeBezierT(x1, x2, x3, x4, X) {
- const a = -x1 + 3 * x2 - 3 * x3 + x4;
- const b = 3 * x1 - 6 * x2 + 3 * x3;
- const c = -3 * x1 + 3 * x2;
- const d = x1 - X;
- // 盛金公式, 预先需满足, a !== 0
- // 判别式
- const A = Math.pow(b, 2) - 3 * a * c;
- const B = b * c - 9 * a * d;
- const C = Math.pow(c, 2) - 3 * b * d;
- const delta = Math.pow(B, 2) - 4 * A * C;
- let t1 = -100,
- t2 = -100,
- t3 = -100;
- // 3个相同实数根
- if (A === B && A === 0) {
- t1 = -b / (3 * a);
- t2 = -c / b;
- t3 = (-3 * d) / c;
- return [t1, t2, t3];
- }
- // 1个实数根和1对共轭复数根
- if (delta > 0) {
- const v = Math.pow(B, 2) - 4 * A * C;
- const xsv = v < 0 ? -1 : 1;
- const m1 = A * b + (3 * a * (-B + (v * xsv) ** (1 / 2) * xsv)) / 2;
- const m2 = A * b + (3 * a * (-B - (v * xsv) ** (1 / 2) * xsv)) / 2;
- const xs1 = m1 < 0 ? -1 : 1;
- const xs2 = m2 < 0 ? -1 : 1;
- t1 =
- (-b - (m1 * xs1) ** (1 / 3) * xs1 - (m2 * xs2) ** (1 / 3) * xs2) /
- (3 * a);
- // 涉及虚数,可不考虑。i ** 2 = -1
- }
- // 3个实数根
- if (delta === 0) {
- const K = B / A;
- t1 = -b / a + K;
- t2 = t3 = -K / 2;
- }
- // 3个不相等实数根
- if (delta < 0) {
- const xsA = A < 0 ? -1 : 1;
- const T = (2 * A * b - 3 * a * B) / (2 * (A * xsA) ** (3 / 2) * xsA);
- const theta = Math.acos(T);
- if (A > 0 && T < 1 && T > -1) {
- t1 = (-b - 2 * A ** (1 / 2) * Math.cos(theta / 3)) / (3 * a);
- t2 =
- (-b +
- A ** (1 / 2) *
- (Math.cos(theta / 3) + 3 ** (1 / 2) * Math.sin(theta / 3))) /
- (3 * a);
- t3 =
- (-b +
- A ** (1 / 2) *
- (Math.cos(theta / 3) - 3 ** (1 / 2) * Math.sin(theta / 3))) /
- (3 * a);
- }
- }
- return [t1, t2, t3];
- }
- /**
- * @desc 获取三阶贝塞尔曲线的线上坐标
- * B(t) = P0 * (1-t)^3 + 3 * P1 * t * (1-t)^2 + 3 * P2 * t^2 * (1-t) + P3 * t^3, t ∈ [0,1]
- * @param {number} t 当前百分比
- * @param {Array} p1 起点坐标
- * @param {Array} p2 终点坐标
- * @param {Array} cp1 控制点1
- * @param {Array} cp2 控制点2
- */
- getThreeBezierPoint(t, p1, cp1, cp2, p2) {
- const { x: x1, y: y1 } = p1;
- const { x: x2, y: y2 } = p2;
- const { x: cx1, y: cy1 } = cp1;
- const { x: cx2, y: cy2 } = cp2;
- const x =
- x1 * (1 - t) * (1 - t) * (1 - t) +
- 3 * cx1 * t * (1 - t) * (1 - t) +
- 3 * cx2 * t * t * (1 - t) +
- x2 * t * t * t;
- const y =
- y1 * (1 - t) * (1 - t) * (1 - t) +
- 3 * cy1 * t * (1 - t) * (1 - t) +
- 3 * cy2 * t * t * (1 - t) +
- y2 * t * t * t;
- return { x, y };
- }
- getHitInfoForThreeBezier(position, curve, rang = 3) {
- // 定义三次贝塞尔曲线的控制点和目标点
- var p0 = curve.start;
- var p1 = curve.controls[0];
- var p2 = curve.controls[1];
- var p3 = curve.end;
- var target = position;
- // 参数化方式在曲线上取一系列的点
- var pointsOnCurve = [];
- for (var t = 0; t <= 1; t += 0.01) {
- var x =
- Math.pow(1 - t, 3) * p0.x +
- 3 * Math.pow(1 - t, 2) * t * p1.x +
- 3 * (1 - t) * Math.pow(t, 2) * p2.x +
- Math.pow(t, 3) * p3.x;
- var y =
- Math.pow(1 - t, 3) * p0.y +
- 3 * Math.pow(1 - t, 2) * t * p1.y +
- 3 * (1 - t) * Math.pow(t, 2) * p2.y +
- Math.pow(t, 3) * p3.y;
- pointsOnCurve.push({ x: x, y: y });
- }
- // 计算每个点与目标点的距离
- var shortestDistance = Number.MAX_VALUE;
- var closestPoint;
- for (var i = 0; i < pointsOnCurve.length; i++) {
- var distance = Math.sqrt(
- Math.pow(pointsOnCurve[i].x - target.x, 2) +
- Math.pow(pointsOnCurve[i].y - target.y, 2)
- );
- if (distance < shortestDistance) {
- shortestDistance = distance;
- closestPoint = pointsOnCurve[i];
- }
- }
- return {
- position: closestPoint,
- distance: shortestDistance,
- };
- console.log("最短距离:", shortestDistance);
- console.log("最近点:", closestPoint);
- const { x: offsetX, y: offsetY } = position;
- let results = [];
- // 用 x 求出对应的 t,用 t 求相应位置的 y,再比较得出的 y 与 offsetY 之间的差值
- const tsx = this.getThreeBezierT(
- curve.start.x,
- curve.controls[0].x,
- curve.controls[1].x,
- curve.end.x,
- offsetX
- );
- console.log(tsx);
- for (let x = 0; x < 3; x++) {
- if (tsx[x] <= 1 && tsx[x] >= 0) {
- const point = this.getThreeBezierPoint(
- tsx[x],
- curve.start,
- curve.controls[0],
- curve.controls[1],
- curve.end
- );
- // if (Math.abs(point.y - offsetY) < rang) {
- results.push({
- position: point,
- distance: this.getDistance(point, position),
- });
- // }
- }
- }
- // 如果上述没有结果,则用 y 求出对应的 t,再用 t 求出对应的 x,与 offsetX 进行匹配
- const tsy = this.getThreeBezierT(
- curve.start.y,
- curve.controls[0].y,
- curve.controls[1].y,
- curve.end.y,
- offsetY
- );
- for (let y = 0; y < 3; y++) {
- if (tsy[y] <= 1 && tsy[y] >= 0) {
- const point = this.getThreeBezierPoint(
- tsy[y],
- curve.start,
- curve.controls[0],
- curve.controls[1],
- curve.end
- );
- // if (Math.abs(point.x - offsetX) < rang) {
- results.push({
- position: point,
- distance: this.getDistance(point, position),
- });
- // }
- }
- }
- console.log(results);
- return results.sort((a, b) => a.distance - b.distance)[0];
- }
- // 二次曲线
- getHitInfoForTwoBezier(position, curve) {
- let bezierData = [];
- bezierData.push(curve.start.x);
- bezierData.push(curve.start.y);
- bezierData.push(curve.controls[0].x);
- bezierData.push(curve.controls[0].y);
- bezierData.push(curve.end.x);
- bezierData.push(curve.end.y);
- const { isHit, getInfo } = bezierUtil.measureBezier(...bezierData);
- const { point } = getInfo(position);
- return {
- position: {
- x: point[0],
- y: point[1],
- },
- distance: this.getDistance(position, {
- x: point[0],
- y: point[1],
- }),
- };
- }
- getHitInfoForCurves(pos, curves, roadWidth) {
- let joinInfo;
- for (const curve of curves) {
- const tempJoinInfo =
- curve.controls.length === 2
- ? this.getHitInfoForThreeBezier(pos, curve, roadWidth / 2)
- : this.getHitInfoForTwoBezier(pos, curve);
- if (
- !joinInfo ||
- (tempJoinInfo && tempJoinInfo.distance < joinInfo.distance)
- ) {
- joinInfo = tempJoinInfo;
- }
- }
- return joinInfo;
- }
- getHitInfoForCurve(pos, curve, roadWidth) {
- let joinInfo;
- const tempJoinInfo =
- curve.controls.length === 2
- ? this.getHitInfoForThreeBezier(pos, curve, roadWidth / 2)
- : this.getHitInfoForTwoBezier(pos, curve);
- if (
- !joinInfo ||
- (tempJoinInfo && tempJoinInfo.distance < joinInfo.distance)
- ) {
- joinInfo = tempJoinInfo;
- }
- return joinInfo;
- }
- getIndexForCurvesPoints(position, points) {
- let minDis = null;
- let minDisToPoint = null;
- let minPointIndex = -1;
- let index = -1;
- for (let i = 0; i < points.length - 1; ++i) {
- const line = this.createLine1(points[i], points[i + 1]);
- const join = this.getJoinLinePoint(position, line);
- const dis = this.getDistance(position, join);
- if (this.isContainForSegment(join, points[i], points[i + 1])) {
- if (minDis == null || minDis > dis) {
- minDis = dis;
- index = i + 1;
- }
- }
- if (minDisToPoint == null) {
- minDisToPoint = mathUtil.getDistance(position, points[i]);
- minPointIndex = i;
- } else if (minDisToPoint > mathUtil.getDistance(position, points[i])) {
- minDisToPoint = mathUtil.getDistance(position, points[i]);
- minPointIndex = i;
- }
- }
- if (index == -1) {
- if (
- minDisToPoint >
- mathUtil.getDistance(position, points[points.length - 1])
- ) {
- return points.length;
- } else {
- return minPointIndex;
- }
- } else {
- return index;
- }
- }
- getCurvesIndexForCurvesPoints(position, points) {
- let minDis = null;
- let minDisToPoint = null;
- let minPointIndex = -1;
- let index = -1;
- for (let i = 0; i < points.length - 1; ++i) {
- const line = this.createLine1(points[i], points[i + 1]);
- const join = this.getJoinLinePoint(position, line);
- const dis = this.getDistance(position, join);
- if (this.isContainForSegment(join, points[i], points[i + 1])) {
- if (minDis == null || minDis > dis) {
- minDis = dis;
- index = i;
- }
- }
- if (minDisToPoint == null) {
- minDisToPoint = mathUtil.getDistance(position, points[i]);
- minPointIndex = i;
- } else if (minDisToPoint > mathUtil.getDistance(position, points[i])) {
- minDisToPoint = mathUtil.getDistance(position, points[i]);
- minPointIndex = i;
- }
- }
- if ((index = -1)) {
- if (
- minDisToPoint >
- mathUtil.getDistance(position, points[points.length - 1])
- ) {
- return points.length - 2;
- } else {
- return minPointIndex;
- }
- } else {
- return index;
- }
- }
- // //获取一组点的偏移
- // getOffset(points, leftWidth, rightWidth, dir) {
- // //斜边长度d已知,角度angle已知
- // //对边长度就是y的偏移量 就是 d * sin(angle) ==> d * Math.sin(angle * Math.PI / 180)
- // //邻边长度就是x的偏移量 就是 d * cos(angle) ==> d * Math.cos(angle * Math.PI / 180)
- // let result = {};
- // if (dir == "left" || !dir) {
- // let angle = 90;
- // let d = leftWidth;
- // result.leftEdgePoints = points.map((coords) => {
- // let ox = d * Math.cos((angle * Math.PI) / 180);
- // let oy = d * Math.sin((angle * Math.PI) / 180);
- // return {
- // x: coords.x + ox,
- // y: coords.y + oy,
- // };
- // });
- // }
- // if (dir == "right" || !dir) {
- // let angle = -90;
- // let d = rightWidth;
- // result.rightEdgePoints = points.map((coords) => {
- // let ox = d * Math.cos((angle * Math.PI) / 180);
- // let oy = d * Math.sin((angle * Math.PI) / 180);
- // return {
- // x: coords.x + ox,
- // y: coords.y + oy,
- // };
- // });
- // }
- // return result;
- // }
- getOffset(points, leftWidth, rightWidth, dir) {
- let leftEdgePoints = [];
- let rightEdgePoints = [];
- for (let i = 0; i < points.length - 1; ++i) {
- if (dir == "left" || !dir) {
- let leftEdgePoins1 = this.RectangleVertex(
- points[i],
- points[i + 1],
- leftWidth * 2
- );
- let leftLine1 = mathUtil.createLine1(
- leftEdgePoins1.leftEdgeStart,
- leftEdgePoins1.leftEdgeEnd
- );
- if (i != points.length - 2) {
- let leftEdgePoins2 = this.RectangleVertex(
- points[i + 1],
- points[i + 2],
- leftWidth * 2
- );
- let leftLine2 = mathUtil.createLine1(
- leftEdgePoins2.leftEdgeStart,
- leftEdgePoins2.leftEdgeEnd
- );
- let join = mathUtil.getIntersectionPoint(leftLine1, leftLine2);
- if (join != null) {
- leftEdgePoints[i + 1] = join;
- } else {
- leftEdgePoints[i + 1] = mathUtil.getJoinLinePoint(
- points[i + 1],
- leftLine1
- );
- }
- } else {
- leftEdgePoints[i + 1] = mathUtil.getJoinLinePoint(
- points[i + 1],
- leftLine1
- );
- }
- if (!leftEdgePoints[0]) {
- leftEdgePoints[0] = mathUtil.getJoinLinePoint(points[0], leftLine1);
- }
- }
- if (dir == "right" || !dir) {
- let rightEdgePoins1 = this.RectangleVertex(
- points[i],
- points[i + 1],
- rightWidth * 2
- );
- let rightLine1 = mathUtil.createLine1(
- rightEdgePoins1.rightEdgeStart,
- rightEdgePoins1.rightEdgeEnd
- );
- if (i != points.length - 2) {
- let rightEdgePoins2 = this.RectangleVertex(
- points[i + 1],
- points[i + 2],
- rightWidth * 2
- );
- let rightLine2 = mathUtil.createLine1(
- rightEdgePoins2.rightEdgeStart,
- rightEdgePoins2.rightEdgeEnd
- );
- let join = mathUtil.getIntersectionPoint(rightLine1, rightLine2);
- if (join != null) {
- rightEdgePoints[i + 1] = join;
- } else {
- rightEdgePoints[i + 1] = mathUtil.getJoinLinePoint(
- points[i + 1],
- rightLine1
- );
- }
- } else {
- rightEdgePoints[i + 1] = mathUtil.getJoinLinePoint(
- points[i + 1],
- rightLine1
- );
- }
- if (!rightEdgePoints[0]) {
- rightEdgePoints[0] = mathUtil.getJoinLinePoint(points[0], rightLine1);
- }
- }
- }
- return {
- leftEdgePoints: leftEdgePoints,
- rightEdgePoints: rightEdgePoints,
- };
- }
- twoOrderBezier(t, p1, cp, p2) {
- //参数分别是t,起始点,控制点和终点
- var x1 = p1.x;
- var y1 = p1.y;
- var cx = cp.x;
- var cy = cp.y;
- var x2 = p2.x;
- var y2 = p2.y;
- // var [x1, y1] = p1,
- // [cx, cy] = cp,
- // [x2, y2] = p2;
- var x = (1 - t) * (1 - t) * x1 + 2 * t * (1 - t) * cx + t * t * x2,
- y = (1 - t) * (1 - t) * y1 + 2 * t * (1 - t) * cy + t * t * y2;
- return {
- x: x,
- y: y,
- };
- }
- //t是0.5,求cp。p是曲线上的点
- twoOrderBezier2(t, p1, p, p2) {
- var x1 = p1.x;
- var y1 = p1.y;
- var x2 = p2.x;
- var y2 = p2.y;
- let cx = (p.x - t * t * x2 - (1 - t) * (1 - t) * x1) / (2 * t * (1 - t));
- let cy = (p.y - t * t * y2 - (1 - t) * (1 - t) * y1) / (2 * t * (1 - t));
- return {
- x: cx,
- y: cy,
- };
- }
- rgb() {
- //rgb颜色随机
- const r = Math.floor(Math.random() * 256);
- const g = Math.floor(Math.random() * 256);
- const b = Math.floor(Math.random() * 256);
- return `rgb(${r},${g},${b})`;
- }
- }
- const mathUtil = new MathUtil();
- export { mathUtil };
|