前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >图形编辑器开发:一些会用到的简单几何算法

图形编辑器开发:一些会用到的简单几何算法

作者头像
前端西瓜哥
发布2023-08-18 13:27:03
2000
发布2023-08-18 13:27:03
举报

大家好,我是前端西瓜哥。

开发图形编辑器,你会经常要解决一些算法问题。本文盘点一些我开发图形编辑器时常用到的简单几何算法。

矩形碰撞检测

判断两个矩形是否发生碰撞(或者说相交),即两个矩形有重合的区域。

常见使用场景:

  1. 使用选择工具框选图形(框选策略除了相交,还可以用相交或其他方案);
  2. 遍历图形,通过判断视口矩形和图形包围盒的矩形碰撞,剔除掉视口外的图形渲染操作,提高性能。
代码语言:javascript
复制
export function isRectIntersect2(rect1: IBox2, rect2: IBox2) {
  return (
    rect1.minX <= rect2.maxX &&
    rect1.maxX >= rect2.minX &&
    rect1.minY <= rect2.maxY &&
    rect1.maxY >= rect2.minY
  );
}

关于 IBox2 为包围盒的接口签名:

代码语言:javascript
复制
interface IBox2 {
  minX: number;
  minY: number;
  maxX: number;
  maxY: number;
}

矩形包含检测

该算法用于判断矩形 1 是否包含矩形 2。

常见使用场景:

  1. 使用选择工具框选图形(这次用的是包含策略);
代码语言:javascript
复制
function isRectContain2(rect1: IBox2, rect2: IBox2) {
  return (
    rect1.minX <= rect2.minX &&
    rect1.minY <= rect2.minY &&
    rect1.maxX >= rect2.maxX &&
    rect1.maxY >= rect2.maxY
  );
}

计算旋转后坐标

对图形旋转,是一个非常基础的功能。计算旋转后的点是很常见的需求。

常见使用场景:

  1. 计算包围盒旋转后的坐标,绘制缩放控制点;
  2. 计算光标位置是否落在一个旋转的矩形上,因为旋转的矩形并不是一个正交的矩形,计算出来后判断有点复杂。所以通常我们会将光标给予矩形的中点反过来旋转一下,然后判断点是否在矩形中。

用到三角函数算法。

代码语言:javascript
复制
const transformRotate = (
  x: number,
  y: number,
  radian: number,
  cx: number,
  cy: number,
) => {
  if (!radian) {
    return { x, y };
  }
  const cos = Math.cos(radian);
  const sin = Math.sin(radian);
  return {
    x: (x - cx) * cos - (y - cy) * sin + cx,
    y: (x - cx) * sin + (y - cy) * cos + cy,
  };
}

点是否在矩形中

常见使用场景:

  1. 用于实现图形拾取,判断矩形图形或包围盒是否在光标位置上。
代码语言:javascript
复制
function isPointInRect(point: IPoint, rect: IRect) {
  return (
    point.x >= rect.x &&
    point.y >= rect.y &&
    point.x <= rect.x + rect.width &&
    point.y <= rect.y + rect.height
  );
}

多个矩形组成的大矩形

选中多个矩形时,要计算它们组成的大矩形,然后绘制出大选中框。

代码语言:javascript
复制
function getRectsBBox(...rects: IRect[]): IBox {
  if (rects.length === 0) {
    throw new Error('the count of rect can not be 0');
  }

  const minX = Math.min(...rects.map((rect) => rect.x));
  const minY = Math.min(...rects.map((rect) => rect.y));
  const maxX = Math.max(...rects.map((rect) => rect.x + rect.width));
  const maxY = Math.max(...rects.map((rect) => rect.y + rect.height));

  return {
    x: minX,
    y: minY,
    width: maxX - minX,
    height: maxY - minY,
  };
}

这里用的是另一种包围盒子的表达,所以多了一层转换。

代码语言:javascript
复制
interface IRect = {
  x: number;
  y: number;
  width: number;
  height: number;
}

type IBox = IRect

计算向量夹角

通过旋转控制点旋转图形时,需要通过向量的点积公式来计算移动的夹角,去更新图形的旋转角度。

计算 [x - cx, y - cy][0, -1] 两个向量夹角的算法实现:

代码语言:javascript
复制
/**
 * 求向量到右侧轴(x正半轴)的夹角
 * 范围在 [0, Math.PI * 2)
 */
export function calcVectorRadian(cx: number, cy: number, x: number, y: number) {
  const a = [x - cx, y - cy];
  const b = [0, -1];

  const dotProduct = a[0] * b[0] + a[1] * b[1];
  const d =
    Math.sqrt(a[0] * a[0] + a[1] * a[1]) * Math.sqrt(b[0] * b[0] + b[1] * b[1]);
  let radian = Math.acos(dotProduct / d);

  if (x < cx) {
    radian = Math.PI * 2 - radian;
  }
  return radian;
}

结尾

做图形编辑器,经常要和几何算法打交道,各种相交判断、居中计算、光标缩放、找最近的参照线等等。

这对算法能力有一定要求的,建议多去刷刷 leetcode。此外就是多画图分析。

在开发中,我们还要自己去分析需求,结合图形编辑器的具体实现,抽离出算法问题,并配合合适的数据结构,去解题。解法可能一次不是最优解, 但我们可以慢慢迭代,慢慢优化的。

虽然有点耗脑细胞,但最后把难题解决,还是非常有成就感。

我是前端西瓜哥,欢迎关注我,学习更多图形编辑器知识。

相关阅读,

几何算法:矩形碰撞和包含检测算法

在容器内显示图片的五种方案:contain、cover、fill、none、scale-down

计算机图形学:变换矩阵

求向量的角度

图形编辑器开发:以光标为中心缩放画布

图形编辑器开发:参考线吸附效功能,让图形自动对齐

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2023-07-13,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 前端西瓜哥 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 矩形碰撞检测
  • 矩形包含检测
  • 计算旋转后坐标
  • 点是否在矩形中
  • 多个矩形组成的大矩形
  • 计算向量夹角
  • 结尾
相关产品与服务
容器服务
腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档