Commit b0925c4c authored by hucy's avatar hucy

fix:计算计算

parent 4485971c
......@@ -29,27 +29,31 @@ onMounted(() => {
drawGrid();
const pointO = { x: 500, y: 300, name: 'O' };
const pointA = { x: 600, y: 200, name: 'A' };
const pointB = { x: 400, y: 200, name: 'B' };
const pointO = { x: 600, y: 200, name: 'O' };
const pointA = { x: 500, y: 300, name: 'A' };
const pointB = { x: 800, y: 300, name: 'B' };
drawVector(pointO, pointA);
drawVector(pointO, pointB);
// 加法
const pointC = new Vector(pointO, pointA).add(pointB);
const pointC = new Vector(pointO, pointA).add(pointB) as any;
pointC.name = 'C';
const len = new Vector(pointO, pointB).length;
console.log('OB向量长度', len);
const len2 = new Vector(pointA, pointB).length;
console.log('AB向量的长度', len2);
drawVector(pointO, pointC, '#21BA45');
// 减
// const pointD = new Vector(pointO, pointB).subtract(pointA);
// console.log('pointD', pointD);
// drawVector(pointO, pointD, '#FFA000');
const pointD = new Vector(pointO, pointB).subtract(pointA);
console.log('pointD', pointD);
drawVector(pointO, pointD, '#FFA000');
// 求夹角
const angle = new Vector(pointO, pointA).dotProduct(pointB);
console.log('夹角', angle);
console.log('OA向量到OB向量的夹角', angle);
});
function drawVector(pointX: Point, pointY: Point, color = '#F44336') {
......
......@@ -42,7 +42,13 @@ export class Vector {
};
}
// 向量夹角
// 向量点乘:(内积)
//
// 数学公式
// a向量(x1,y1) b向量(x2,y2)
// a向量 点乘 b向量 = x1*x2 + y1*y2
// = a向量的模 * b向量的模 * cos(夹角)
// https://zhuanlan.zhihu.com/p/359975221
dotProduct(components: any) {
const pointO = this.components[0];
......@@ -89,6 +95,13 @@ export class Vector {
return result;
}
// 向量叉乘
// a向量(x1,y1) b向量(x2,y2)
// a向量 叉乘 b向量 = c向量
// c向量的模 = x1*y2 - x2*y1
// = a向量的模 * b向量的模 * sin(夹角)
// 如果以向量a和向量b边构成一个平行四边形,那么这两个向量外积的模长与这个平行四边形的面积相等。
}
/**
......
......@@ -11,6 +11,7 @@ import Konva from 'konva';
import Decimal from 'decimal.js';
const startSelected = ref(true);
const state = reactive({
stage: null as any,
layer: null as any,
......@@ -25,10 +26,10 @@ const state = reactive({
color: '#00D2FF',
selected: true,
path: [
{ x: 100, y: 100, gap: 20 },
{ x: 200, y: 100, gap: 10 },
{ x: 200, y: 200, gap: 40 },
{ x: 0, y: 300, gap: 10 },
{ x: 100, y: 100, gap: 100 },
{ x: 200, y: 100, gap: 100 },
{ x: 200, y: 200, gap: 100 },
{ x: 0, y: 300, gap: 100 },
],
},
// {
......@@ -159,8 +160,9 @@ function createShape(itemData: any) {
// strokeWidth: 10,
});
// 向外扩大 start
/* 向外扩大 start */
const extraPath = scalePolygon(path) as any[];
// 扩展后的轮廓线
const shape2: any = new Konva.Shape({
sceneFunc: function (context, shape) {
context.beginPath();
......@@ -186,7 +188,7 @@ function createShape(itemData: any) {
stroke: '#21BA45',
strokeWidth: 2,
});
// 向外扩大 end
/* 向外扩大 end */
// 先添加的边界框矩形,再添加的自定义图像,
// 顺序和下面layerDragmove时获取children的顺序保持一致
......@@ -232,9 +234,11 @@ function handleData() {
}
}
// 1.一条线上有多个点,只保留起点和终点
// 2.计算边距上的点
// 注意!path的最后一个点不与第一个点重合
/**
* 1.一条线上有多个点,只保留起点和终点
* 2.计算边距上的点
* 注意!path的最后一个点不与第一个点重合
*/
function removeAngleRepeat(path: any[]) {
let length = path.length;
......@@ -364,21 +368,23 @@ function getAngle(
return res.toNumber();
}
/**
* 计算边距
* param里面包含3个点的坐标,及2条边距
* A [x1,y1] 当前目标点
* B [x2,y2] 在A点下一条邻边上的点
* C [last_x,last_y] 在A点上一条邻边上的点
* gap_1 AB上的边距; du1 AB与-X轴的夹角,传入角度值
* gap_2 AC上的边距; du2 AC与-X轴的夹角,传入角度值
*/
// /**
// * 计算边距
// * param里面包含3个点的坐标,及2条边距
// * A [x1,y1] 当前目标点
// * B [x2,y2] 在A点下一条邻边上的点
// * C [last_x,last_y] 在A点上一条邻边上的点
// * gap_1 AB上的边距; du1 AB与-X轴的夹角,传入角度值
// * gap_2 AC上的边距; du2 AC与-X轴的夹角,传入角度值
// */
// function handleGap(param: any) {
// const { x1, y1, x2, y2, last_x, last_y, gap_1, gap_2, du1, du2 } = param;
// // console.log('du1', du1);
// }
// 批量选择
/**
* 批量选择
*/
function batchSelection(value: boolean) {
if (value) {
startSelected.value = true;
......@@ -388,7 +394,9 @@ function batchSelection(value: boolean) {
}
}
// 网格线
/**
* 绘制网格线
*/
function drawGrid() {
let canvas: any = document.getElementById('canvas-grid');
let pen = canvas.getContext('2d');
......@@ -432,8 +440,8 @@ function drawGrid() {
:height="stageSize.height"
style="position: absolute"
></canvas>
<div id="stage-container"></div>
<!-- ======================== 复选框 ======================== -->
<template v-for="(item, index) in state.shapePath" :key="index">
<q-checkbox
v-model="item.selected"
......
......@@ -3,6 +3,8 @@
* 源码Gitee:https://gitee.com/dhzx/js-polygon-algorithm
*/
import { toRadian, Vector } from 'src/modules/vector/utils';
interface Point {
x: number;
y: number;
......@@ -86,130 +88,138 @@ export function isInPolygon(point: Point, points: Point[]) {
return nCross % 2 === 1;
}
/**
* 缩放多边形坐标
* @decoration 需配合顺时针判断方法一起使用
* @param {Point[]} points 点坐标数组 [{x:0,y:0}...]
* @param {number} extra 外延大小。为正: 向外扩; 为负: 向内缩
* @return {Point[]} 扩展或缩小后的多边形点坐标数组
*/
export function scalePolygon2(points: Point[], extra: number) {
if (!Array.isArray(points) || points.length < 3) {
console.error('多边形坐标集合不能少于3个');
return;
}
const ps = points;
// 通过顺时针判断取正值还是负值
const extra0 = isClockwise(ps) ? -extra : extra;
// /**
// * 缩放多边形坐标
// * https://blog.csdn.net/sun_and_breeze/article/details/107517088
// * @decoration 需配合顺时针判断方法一起使用
// * @param {Point[]} points 点坐标数组 [{x:0,y:0}...]
// * @param {number} extra 外延大小。为正: 向外扩; 为负: 向内缩
// * @return {Point[]} 扩展或缩小后的多边形点坐标数组
// */
// export function scalePolygon2(points: Point[], extra: number) {
// if (!Array.isArray(points) || points.length < 3) {
// console.error('多边形坐标集合不能少于3个');
// return;
// }
// const ps = points;
// // 通过顺时针判断取正值还是负值
// const extra0 = isClockwise(ps) ? -extra : extra;
const norm = (x: number, y: number) => Math.sqrt(x * x + y * y);
// const norm = (x: number, y: number) => Math.sqrt(x * x + y * y);
const len = ps.length;
const polygon = [];
for (let i = 0; i < len; i++) {
const point = ps[i];
const point1 = ps[i === 0 ? len - 1 : i - 1];
const point2 = ps[i === len - 1 ? 0 : i + 1];
// const len = ps.length;
// const polygon = [];
// for (let i = 0; i < len; i++) {
// const point = ps[i];
// const point1 = ps[i === 0 ? len - 1 : i - 1];
// const point2 = ps[i === len - 1 ? 0 : i + 1];
// 向量PP1
const vectorX1 = point1.x - point.x; // 向量PP1 横坐标
const vectorY1 = point1.y - point.y; // 向量PP1 纵坐标
const n1 = norm(vectorX1, vectorY1); // 向量的平方根 为了对向量PP1做单位化
let vectorUnitX1 = vectorX1 / n1; // 向量单位化 横坐标
let vectorUnitY1 = vectorY1 / n1; // 向量单位化 纵坐标
// // 向量PP1
// const vectorX1 = point1.x - point.x; // 向量PP1 横坐标
// const vectorY1 = point1.y - point.y; // 向量PP1 纵坐标
// const n1 = norm(vectorX1, vectorY1); // 向量的平方根 为了对向量PP1做单位化
// let vectorUnitX1 = vectorX1 / n1; // 向量单位化 横坐标
// let vectorUnitY1 = vectorY1 / n1; // 向量单位化 纵坐标
// 向量PP2
const vectorX2 = point2.x - point.x; // 向量PP2 横坐标
const vectorY2 = point2.y - point.y; // 向量PP2 纵坐标
const n2 = norm(vectorX2, vectorY2); // 向量的平方根 为了对向量PP1做单位化
let vectorUnitX2 = vectorX2 / n2; // 向量单位化 横坐标
let vectorUnitY2 = vectorY2 / n2; // 向量单位化 纵坐标
// // 向量PP2
// const vectorX2 = point2.x - point.x; // 向量PP2 横坐标
// const vectorY2 = point2.y - point.y; // 向量PP2 纵坐标
// const n2 = norm(vectorX2, vectorY2); // 向量的平方根 为了对向量PP1做单位化
// let vectorUnitX2 = vectorX2 / n2; // 向量单位化 横坐标
// let vectorUnitY2 = vectorY2 / n2; // 向量单位化 纵坐标
// PQ距离
const vectorLen =
-extra0 /
Math.sqrt(
(1 - (vectorUnitX1 * vectorUnitX2 + vectorUnitY1 * vectorUnitY2)) / 2
);
// // PQ距离
// const vectorLen =
// -extra0 /
// Math.sqrt(
// (1 - (vectorUnitX1 * vectorUnitX2 + vectorUnitY1 * vectorUnitY2)) / 2
// );
// 根据向量的叉乘积来判断角是凹角还是凸角
if (vectorX1 * vectorY2 + -1 * vectorY1 * vectorX2 < 0) {
vectorUnitX2 *= -1;
vectorUnitY2 *= -1;
vectorUnitX1 *= -1;
vectorUnitY1 *= -1;
}
// // 根据向量的叉乘积来判断角是凹角还是凸角
// if (vectorX1 * vectorY2 + -1 * vectorY1 * vectorX2 < 0) {
// vectorUnitX2 *= -1;
// vectorUnitY2 *= -1;
// vectorUnitX1 *= -1;
// vectorUnitY1 *= -1;
// }
// PQ的方向
const vectorX = vectorUnitX1 + vectorUnitX2;
const vectorY = vectorUnitY1 + vectorUnitY2;
const n = vectorLen / norm(vectorX, vectorY);
const vectorUnitX = vectorX * n;
const vectorUnitY = vectorY * n;
// // PQ的方向
// const vectorX = vectorUnitX1 + vectorUnitX2;
// const vectorY = vectorUnitY1 + vectorUnitY2;
// const n = vectorLen / norm(vectorX, vectorY);
// const vectorUnitX = vectorX * n;
// const vectorUnitY = vectorY * n;
const polygonX = vectorUnitX + point.x;
const polygonY = vectorUnitY + point.y;
// const polygonX = vectorUnitX + point.x;
// const polygonY = vectorUnitY + point.y;
polygon[i] = { x: polygonX, y: polygonY };
}
// polygon[i] = { x: polygonX, y: polygonY };
// }
return polygon;
}
// return polygon;
// }
/**
* 缩放多边形坐标
* https://blog.csdn.net/sun_and_breeze/article/details/107517088
* @decoration 需配合顺时针判断方法一起使用
* @param {Point[]} points 点坐标数组 [{x:0,y:0}...]
* @param {number} extra 外延大小。为正: 向外扩; 为负: 向内缩
* @return {Point[]} 扩展或缩小后的多边形点坐标数组
*/
export function scalePolygon(points: Point[], extra = 0) {
export function scalePolygon(points: Point[]) {
if (!Array.isArray(points) || points.length < 3) {
console.error('多边形坐标集合不能少于3个');
return;
}
const ps = points;
// 通过顺时针判断取正值还是负值
// const extra0 = isClockwise(ps) ? -extra : extra;
const norm = (x: number, y: number) => Math.sqrt(x * x + y * y);
const ps = points;
const len = ps.length;
const polygon = [];
const polygon: any[] = [];
for (let i = 0; i < len; i++) {
let extra0;
if (extra) {
extra0 = isClockwise(ps) ? -extra : extra;
} else {
const _gap = ps[i].gap || 0;
extra0 = isClockwise(ps) ? -_gap : _gap;
}
const pointP = ps[i]; // 当前点
const pointP1 = ps[i === len - 1 ? 0 : i + 1]; // 后一个点
const pointP2 = ps[i === 0 ? len - 1 : i - 1]; // 前一个点
const point = ps[i];
const point1 = ps[i === 0 ? len - 1 : i - 1];
const point2 = ps[i === len - 1 ? 0 : i + 1];
// 边距
const extraNum = pointP.gap || 10;
// 通过顺时针判断取正值还是负值
const is_clockwise = isClockwise(ps);
const extra0 = is_clockwise ? -extraNum : extraNum;
// const l1Num = pointP.gap || 10;
// const l2Num = pointP2.gap || 10;
// const L1 = is_clockwise ? -l1Num : l1Num;
// const L2 = is_clockwise ? -l2Num : l2Num;
// 向量PP1
const vectorX1 = point1.x - point.x; // 向量PP1 横坐标
const vectorY1 = point1.y - point.y; // 向量PP1 纵坐标
const vectorX1 = pointP1.x - pointP.x; // 向量PP1 横坐标
const vectorY1 = pointP1.y - pointP.y; // 向量PP1 纵坐标
const n1 = norm(vectorX1, vectorY1); // 向量的平方根 为了对向量PP1做单位化
let vectorUnitX1 = vectorX1 / n1; // 向量单位化 横坐标
let vectorUnitY1 = vectorY1 / n1; // 向量单位化 纵坐标
// 向量PP2
const vectorX2 = point2.x - point.x; // 向量PP2 横坐标
const vectorY2 = point2.y - point.y; // 向量PP2 纵坐标
const n2 = norm(vectorX2, vectorY2); // 向量的平方根 为了对向量PP1做单位化
const vectorX2 = pointP2.x - pointP.x; // 向量PP2 横坐标
const vectorY2 = pointP2.y - pointP.y; // 向量PP2 纵坐标
const n2 = norm(vectorX2, vectorY2); // 向量的平方根 为了对向量PP2做单位化
let vectorUnitX2 = vectorX2 / n2; // 向量单位化 横坐标
let vectorUnitY2 = vectorY2 / n2; // 向量单位化 纵坐标
// PQ距离
const vectorLen =
-extra0 /
extra0 /
Math.sqrt(
(1 - (vectorUnitX1 * vectorUnitX2 + vectorUnitY1 * vectorUnitY2)) / 2
);
const angle = new Vector(pointP, pointP1).dotProduct(pointP2);
const hudu = toRadian(angle);
const c = Math.cos(hudu);
console.log('PQ距离', vectorLen, '角度', c);
// 根据向量的叉乘积来判断角是凹角还是凸角
if (vectorX1 * vectorY2 + -1 * vectorY1 * vectorX2 < 0) {
vectorUnitX2 *= -1;
......@@ -225,12 +235,12 @@ export function scalePolygon(points: Point[], extra = 0) {
const vectorUnitX = vectorX * n;
const vectorUnitY = vectorY * n;
const polygonX = vectorUnitX + point.x;
const polygonY = vectorUnitY + point.y;
const polygonX = vectorUnitX + pointP.x;
const polygonY = vectorUnitY + pointP.y;
polygon[i] = { x: polygonX, y: polygonY };
}
console.log('polygon', polygon);
return polygon;
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment