Blazor入门-svg绘制-碰撞检测和图形坐标调整

news2024/11/15 9:47:35

上一篇:
Blazor入门-简单svg绘制+导出图像_blazor 画图-CSDN博客
https://blog.csdn.net/pxy7896/article/details/139003443

注意:本文只给出思路和框架,对于具体的计算细节,考虑到日后会写入软件著作权和专利文书,因此不会展示。


目录

  • 问题
  • 解决思路
    • 处理起终位置重叠的元件
      • 处理效果
    • 处理相隔很近但不重叠的元件
      • 碰撞检测
      • 坐标调整
  • 涉及的svg技术
    • 如何将文字写到弧线上
    • 文字/label的书写方向
    • 矩形绘制中的坐标转换

问题

上一篇的结尾提到Label重叠问题。事实上,这个问题很严重。

比如我手边这个文件,按照上一篇的方法绘制之后,会变成:(箭头是新画法,也是简单的三角函数,不展开)
在这里插入图片描述
这种重叠不仅让画面变得不美观、杂乱,更是影响了用户的阅读体验。

有的文件直接无法识别:
在这里插入图片描述
这是因为:

  • 某些元件的起终位置有重叠
  • 在某些区域中,元件彼此相隔太近,因此计算出的坐标彼此间距极小,显示到前台就会重叠

解决思路

处理起终位置重叠的元件

首先是对元件做排序,然后识别出有重叠的元件。

目前我采取一种傻瓜式的解决方案,流程是:

  1. 对元件做排序(可以按先起点后终点或者按中点升序排序),获取排序后的列表 L1
  2. 将可以放置元件的区域分成 N 层(实际是 N 层同心圆环),对于 L1 中每个特征,使用下面的分层方法:
    2.1 将第一个特征 f 0 f_0 f0 放入第一层;
    2.2 对于后续特征 f i f_i fi(起始数值分别为 f i s f_{is} fis f i e f_{ie} fie):遍历当前层的空闲位置,如果对于某个空闲位置 p i p_i pi(起始数值分别为 p i s p_{is} pis p i e p_{ie} pie ),那么满足 f i s > p i s , f i e < p i e f_{is} > p_{is}, f_{ie} < p_{ie} fis>pis,fie<pie ,即可放入当前层,修改当前层的对象列表;
    2.3 如果当前层无法放置 f i f_i fi,那么新建一个层,将 f i f_i fi 直接放入;
    2.4 循环直到遍历结束

在循环中,可以为每个元件记录所属层编号,层数直接与计算坐标时的半径关联。

代码只是简单的三角函数,不会给出。

处理效果

在这里插入图片描述
在这里插入图片描述

处理相隔很近但不重叠的元件

这个主要包含两块:

  1. 碰撞检测:即判断两个label是否有重合
  2. 调整label的位置

碰撞检测

如果有很多对象,需要进行比较高效的碰撞检测,可以考虑 Quadtree (四叉树) 算法。这个算法将空间分为4个象限,可以快速检测碰撞。这里当然可以使用,不过考虑到我的元素没那么多,就使用最简单的碰撞检测函数:

bool isLabelColliding(Rectangle r1, Rectangle r2) {
    double x1 = r1.X;
    double y1 = r1.Y;
    double w1 = r1.Width;
    double x2 = r2.X;
    double y2 = r2.Y; 
    double w2 = r2.Width;
    return x1 < x2 + w2 && 
        x1 + w1 > x2 &&
        y1 < y2 + Constants.charHeight &&
        y1 + Constants.charHeight > y2;
}

其中Rectangle是我定义的一个类,包含四个double类型的变量 X Y Width Height,分别表示矩形左下角顶点的坐标、宽度和高度。其中高度其实是固定的,因为我假设label都只有一行。

另外,因为我对行高留了一点缓冲量,同时可以忽略框本身轻微的重叠,所以我另外写了一个放松版检测函数:

bool isLabelCollidingSlack(Rectangle r1, Rectangle r2, double xo, double yo)
{
    double x1 = r1.X;
    double y1 = r1.Y;
    double w1 = r1.Width;
    double x2 = r2.X;
    double y2 = r2.Y;
    double w2 = r2.Width;
    return x1 + xo < x2 + w2 &&
        x1 + w1 > x2 + xo &&
        y1 + yo < y2 + Constants.charHeight &&
        y1 + Constants.charHeight > y2 + yo;
}

其中 xo 和 yo 表示 x 和 y 方向上放松的程度,可以是字的宽度或高度乘一个合适的系数。这个系数就来自实际数据中获得的经验了。

坐标调整

这个其实是最麻烦的一部分,因为盲目的调整可能引入新的碰撞。比如如果 A 和 B 碰撞,则将 B 向下移动一段距离,那么可能原本不重叠的 A 和 C 碰撞了。如果采用调整-碰撞检测-再调整,则需要考虑终止条件,以免超时。

我试过几种调整方式,比如:(当然最后都放弃了,因为调整效果不佳)

  1. 设置一个基础值 b ,然后对于每个label,给一个随机数作为 offset ,计算label位置时,半径是 r = b + o f f s e t r = b + offset r=b+offset,角度仍然使用元件中点( ( s t a r t + e n d ) / 2 (start + end) / 2 (start+end)/2)在圆上偏移的角度;
  2. 1中偏移的角度也可以再加偏移量;
  3. 在1的基础上,进行二次碰撞检测,对于仍然碰撞的,在 x 和 y 上增加一点偏移;
  4. 在3的基础上,偏移采用正负随机;
  5. 在3的基础上,对于偏移量的符号,应该根据label所在圆上的位置进行判断:将圆像坐标轴一样十字分割成四等分,向上需要-y,向下需要+y,向左-x,向右+x;
  6. 使用一个数组记录每个label与其他label碰撞的次数,碰撞次数为0则不需要处理,碰撞次数越多越需要远离圆心。因此不使用随机数和偏移量,而是固定半径,通过碰撞次数的多少调整 x 和 y 上的偏移量;
  7. 偏移量可以采用爬坡的方式,因为svg图是有边界的,超出边界后label是看不到的。爬坡的意思是偏移量先递增,到了边界再递减或者直接归到下边界值。

还有别的方法没记录。以上的方法也可以组合。但是效果仍然是不好的,因为太随机了,反而使得label的位置无法控制,而且调整后仍然可能再次引入碰撞。

最终的方法我不能写哈哈哈哈,是真的在保密。

我只能说用到了上述某两种方法的组合,而且做了两次碰撞检测(有用到放松版碰撞检测函数)。基本在第二次碰撞检测的时候就只剩很少很少 label 了(比如1~2个),然后我用了新的放置方式:将label以弧形的状态放置在圆环内侧,比如下图这样。(当然,其实也考虑了弧形放置的碰撞问题,那个就更复杂一点)
在这里插入图片描述
具体的过程是:

  • 将元件按照中点升序排序
  • 计算元件 label 内容的长度,与箭头中心弧线的长度做比较,如果能放下,说明 label 可以放在元件内部,那后续也不需要考虑碰撞问题;
  • 如果不能放在内部,先根据中点和原始的坐标计算方法,计算label的坐标和宽度
  • 将上述计算后的 label 进行碰撞检测,经过一些处理方法调整坐标,再进行第二轮碰撞检测
  • 如果还有碰撞,将产生碰撞的 label 以弧线的形态放入圆内部

涉及的svg技术

如何将文字写到弧线上

思路:将内容绑定到一条Path上。需要计算 path 的 d 属性,同时需要给该 path 指明 id 。对于blazor,只要在循环里绑定即可。
在这里插入图片描述
上图对应的html代码如下所示。其中 d 的计算与前篇文章中内弧和外弧的计算思路一致,先计算各种数据,然后再拼接。

<text font-size="16" fill="black" >
	<path id="p1" d="M 763.9369985579203 297.9295177580384 A 245 245 36.01448997965174 0 1 838.7345961997676 424.9473653915278 z" />
    <textPath href="#p1">Hello everyone!</textPath>
</text>

文字/label的书写方向

<text>中有一个属性是direction,值为"rtl"表示从右向左书写,"ltr"则相反。

矩形绘制中的坐标转换

在前面进行碰撞检测时,为了直观,我给所有label加了一些防撞框(或者说边界框),如下图所示:
在这里插入图片描述
需要注意的是,前面我的碰撞检测函数,是以左下角为顶点,向右延长width,向上延长height这样的方式构建边界框,再进行检测的。但是在svg绘制rect时,它是向下延长height构建的,所以需要给原本的坐标减去字高(假设只有一行),否则构建的框如下图所示:
在这里插入图片描述
同时,考虑到左右半圆,label中文字的书写方式是不同的,因为处理 rect 的 x 坐标也需要减去相应的宽度。

最后,rect的一种写法是:

<rect x="xx" y="xx" width="xx" height="xx" fill="none" stroke="red" stroke-width="1" />

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1711914.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

被追着问UUID和自增ID做主键哪个好,为什么?

之前无意间看到群友讨论到用什么做主键比较好 其实 UUID 和自增主键 ID 是常用于数据库主键的两种方式&#xff0c;各自具有独特的优缺点。 UUID UUID 是一个由 128 位组成的唯一标识符&#xff0c;通常以字符串形式表示。它可以通过不同的算法生成&#xff0c;例如基于时间…

绝招曝光!3小时高效利用ChatGPT写出精彩论文

在这份指南中&#xff0c;我将深入解析如何利用ChatGPT 4.0的高级功能&#xff0c;指导整个学术研究和写作过程。从初步探索研究主题&#xff0c;到撰写结构严谨的学术论文&#xff0c;我将一步步展示如何在每个环节中有效运用ChatGPT。如果您还未使用PLUS版本&#xff0c;可以…

C++入门 ros自定义msg话题通信

一、 开发环境 ubuntu20.04 ros版本noetic 参考视频 https://www.bilibili.com/video/BV1Ci4y1L7ZZ/?p52&spm_id_from333.1007.top_right_bar_window_history.content.click&vd_source4cd1b6f268e2a29a11bea5d2568836ee 二、 编写msg文件 在功能包下面创建msg文件夹…

【源码】6语言跨境电商PHP源码 精美UI+功能强大开源无授权

6语言跨境电商PHP源码 精美UI功能强大开源无授权 英文&#xff0c;简体中文&#xff0c;繁体中文&#xff0c;日语、泰语、越南语6语言。功能非常强大&#xff0c;UI也很漂亮的跨境电商源码。基于国外成熟电商系统二开的源码&#xff0c;带POS系统。 系统采用Laravel框架开发…

盘点好用的国产传输软件,看看哪个适合你

流动让数据释放价值&#xff0c;无论什么企业&#xff0c;什么行业&#xff0c;业务的正常开展均是以数据和文件的传输为基础&#xff0c;因此&#xff0c;对企业来说&#xff0c;文件传输工具是最基础但也是最举重若轻的。在琳琅满目的多种国产传输软件中&#xff0c;哪个是最…

【运筹学】前言:基础知识

&#x1f49e;&#x1f49e; 前言 hello hello~ &#xff0c;这里是大耳朵土土垚~&#x1f496;&#x1f496; &#xff0c;欢迎大家点赞&#x1f973;&#x1f973;关注&#x1f4a5;&#x1f4a5;收藏&#x1f339;&#x1f339;&#x1f339; &#x1f4a5;个人主页&#x…

CISCN --EzHeap

当时有点着急了&#xff0c;这题没写出来&#xff0c;结束后在ctfshow上做了一下。 使用的方法是environ泄露栈地址&#xff0c;然后在栈上构造orw的rop链。 以下是过程&#xff1a; 只能orw。 堆体开沙盒模式会在heap和bin一开始构造很多垃圾堆。所以分配和free的时候要注意…

1806 jsp防疫物资销售管理系统 Myeclipse开发mysql数据库web结构java编程计算机网页项目

一、源码特点 jsp 防疫物资销售管理系统 是一套完善的web设计系统&#xff0c;对理解JSP java编程开发语言有帮助采用了java设计&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统采用web模式&#xff0c;系统主要采用B/S模式开发。开发环境为TOMCAT7.0,Myeclipse8.…

Ps:消失点滤镜 - 透视平面和网格

Ps菜单&#xff1a;滤镜/消失点 Filter/Vanishing Point 快捷键&#xff1a;Ctrl Alt V “消失点”滤镜中的透视平面 Plane和网格 Grid用于在编辑图像时保持正确的透视效果。 只有定义了与图像透视对齐的矩形平面&#xff0c;才能在消失点中进行编辑。平面的精确度确定了能否…

[自动驾驶技术]-5 Tesla自动驾驶方案之算法(AI Day 2021)

有朋友问我&#xff0c;如何有效学习一个新技术。笔者这么多年的经验是&#xff1a;1&#xff09;了解国内外产业应用和标准法规现状&#xff0c;先建立宏观知识图谱及技术系统框架&#xff1b;2&#xff09;根据系统框架逐块进行深入研究&#xff08;横向、纵向&#xff09;&a…

【LLM第7篇】transformer跟bert、gpt、大模型的联系

上一篇讲了transformer的原理&#xff0c;接下来&#xff0c;看看它的衍生物们。 Transformer基本架构 Transformer模型主要由两部分组成&#xff1a;编码器&#xff08;Encoder&#xff09;和解码器&#xff08;Decoder&#xff09;。编码器负责处理输入序列&#xff0c;将其…

正邦科技(day2)

自动校准 问题&#xff1a;电量不准都可以直接去校准 校准方式&#xff1a;可程式变频电压 问题分析&#xff1a;他是通过软件去自动自动校准的&#xff0c;flash 清空的时候有缓存没有清空&#xff0c;或者互感器没有读取到问题 互感器&#xff1a;电流互感器的作用包括电流测…

2024年5月份架构师考试真题完整版

截至2024-5-28 19:24:14已全部收录完成 共75到选择题&#xff0c;5道案例题&#xff0c;4道论文题。题目顺序不分先后。 全网最全的2024年5月份架构师考试真题回忆版&#xff0c;包含答案和解析。 群友 疯狂程序员 花落无声 半夏 鲁迅-三战老兵(预备役) 本次必成 锦鲤附体 2024…

LabVIEW车轮动平衡检测系统

LabVIEW车轮动平衡检测系统 随着汽车行业的快速发展&#xff0c;车轮动平衡问题对乘坐舒适性、操控稳定性及安全性的影响日益凸显&#xff0c;成为了提高汽车性能的一个关键环节。传统的检测系统因精度低、成本高、操作复杂等问题&#xff0c;难以满足现代汽车行业的需求。开发…

100个 Unity小游戏系列四 -Unity 抽奖游戏专题二 水果机游戏

一、演示效果 二、知识点 2.1 布局 private void CreateItems(){for (int i 0; i < rewardDatas.Length; i){var reward_data rewardDatas[i];GameObject fruitOjb;if (i < itemRoot.childCount){fruitOjb itemRoot.GetChild(i).gameObject;}else{fruitOjb Instant…

C++数据结构之:链List

摘要&#xff1a; it人员无论是使用哪种高级语言开发东东&#xff0c;想要更高效有层次的开发程序的话都躲不开三件套&#xff1a;数据结构&#xff0c;算法和设计模式。数据结构是相互之间存在一种或多种特定关系的数据元素的集合&#xff0c;即带“结构”的数据元素的集合&am…

如何恢复已删除/丢失或未保存的 PDF 文件?

许多用户曾因某些问题删除或丢失 PDF 文件。此外&#xff0c;一些用户在关闭应用程序时未保存 PDF 文件&#xff0c;从而丢失 PDF 文件。您可以尝试一些解决方案来恢复已删除的 PDF 文件、恢复未保存的 PDF 文件&#xff0c;以及在任何其他数据丢失情况下挽救丢失的 PDF 文件。…

汇编原理(四)[BX]和loop指令

loop&#xff1a;循环 误区&#xff1a;在编译器里写代码和在debug里写代码是不一样的&#xff0c;此时&#xff0c;对于编译器来说&#xff0c;就需要用到[bx] [bx]: [bx]同样表示一个内存单元&#xff0c;他的偏移地址在bx中&#xff0c;比如下面的指令 move bx, 0 move ax,…

学习笔记——数据通信基础——数据通信网络(基本概念)

数据通信网络基本概念 网络通信&#xff1a;是指终端设备之间通过计算机网络进行的通信。 数据通信网络(Data Communication Network)&#xff1a;由 路由器、交换机、防火墙、无线控制器、无线接入点&#xff0c;以及个人电脑、网络打印机&#xff0c;服务器等设备构成的通信…

Spring Boot集成freemaker快速入门demo

1.什么是freemaker&#xff1f; FreeMarker 是一款模板引擎&#xff1a;即一种基于模板和要改变的数据&#xff0c;并用来生成输出文本(HTML网页&#xff0c;电子邮件&#xff0c;配置文件&#xff0c;源代码等)的通用工具。 它不是面向最终用户的&#xff0c;而是一个Java类库…