Commit b0925c4c authored by hucy's avatar hucy

fix:计算计算

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