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

上一篇:
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.mzph.cn/pingmian/18496.shtml

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

相关文章

STM32-11-电容触摸按键

STM32-01-认识单片机 STM32-02-基础知识 STM32-03-HAL库 STM32-04-时钟树 STM32-05-SYSTEM文件夹 STM32-06-GPIO STM32-07-外部中断 STM32-08-串口 STM32-09-IWDG和WWDG STM32-10-定时器 STM32电容触摸按键 电容触摸按键原理&#xff1a; 无手指触摸&#xff1a;上电时&…

【Java EE】网络原理——HTTP响应

目录 1.认识“状态码”&#xff08;status code&#xff09; 1.1 200 OK 1.2 404 Not Found 1.3 403 Forbodden 1.4 Method Not Allowed 1.5 Internal Sever Error 1.6 504 Gsteway Timeout 1.7 Move temporarily 1.8 Moved Permanently 1.9状态码小结 2.认识响应“报…

树莓派部署harbor_arm64

文章目录 树莓派4b部署Harbor-arm64版本docker-compose维护命令访问harbor 192.168.1.111认用户名密码admin/Harbor12345 树莓派4b部署Harbor-arm64版本 harbor-arm版本 部署&#xff1a;参考 wget https://github.com/hzliangbin/harbor-arm64/releases/download/v1.9.3/ha…

java项目之高校教师科研管理系统源码(springboot+vue+mysql)

风定落花生&#xff0c;歌声逐流水&#xff0c;大家好我是风歌&#xff0c;混迹在java圈的辛苦码农。今天要和大家聊的是一款基于springboot的高校教师科研管理系统源码。项目源码以及部署相关请联系风歌&#xff0c;文末附上联系信息 。 项目简介&#xff1a; 高校教师科研管…

评测 香橙派OrangePi在智能交通上的应用

1、OrangePi应用场景 关于 Orange Pi AI Pro 开发板是香橙派联合华为精心打造的高性能 AI 开发板&#xff0c;其搭载了昇腾 AI 处理器&#xff0c;可提供 8TOPS INT8 的计算能力&#xff0c;内存提供了 8GB 和 16GB两种版本。可以实现图像、视频等多种数据分析与推理计算&#…

OpenMV的VisionBoard视觉识别开发板学习记录

此篇博客仅用于对VisionBoard的开发板的学习研究记录&#xff0c;没有教学内容。 一、资料来源 开发板资料链接 开发板环境搭建手册 开发板视频教程 板子的资料网站 openmv官方的网站 目录 一、资料来源二、针对 VisionBoard的目标识别和定位总结1. 目标识别功能1.1 物体检测…

芯片原厂驱动开发工程师:初学到精通,如何快速成长?

01 前言 大家好&#xff0c;我是XX&#xff0c;来自湖南XX学院&#xff0c;电子信息18级&#xff0c;也曾在创新基地控制组学习过两三年&#xff0c;毕业后就职于一家芯片原厂的解决方案部&#xff0c;担任驱动工程师的职位&#xff0c;算上实习期&#xff0c;我的工作时长已有…

htb-Mailing

因为做windows服务器渗透较少&#xff0c;不妥的地方还请师傅们指出 可先看思路&#xff0c;实在不行再看writeup 任意文件下载拿pop3登录邮箱——》利用邮件服务器漏洞拿下NTLM——》利用组件版本漏洞拿下 拿shell 端口扫描开放服务 Host is up (0.91s latency). Not shown:…

CSS学习笔记:rem实现移动端适配的原理——媒体查询

移动端适配 移动端即手机端&#xff0c;也称M端 移动端适配&#xff1a;同一套移动端页面在不同屏幕尺寸的手机上可以实现宽度和高度的自适应&#xff0c;也就是页面中元素的宽度和高度可以根据屏幕尺寸的变化等比缩放 rem配合媒体查询可实现移动端适配 rem单位 媒体查询 …

SpringAdminClient如何将Httpbasic账号密码告知SpringAdminServer

场景&#xff0c;因为Config Service开了权限校验&#xff0c;注册到eureka之后&#xff0c;SpringAdmin查看信息会报错401&#xff0c;如果想在SpringAdmin中正确的看到Config Service的actuator信息则需要将账号密码告知给SpringAdmin&#xff0c;磁力用的是Eureka作为发现服…

javaIO流知识点概况

一、前言&#xff1a; 1.1.流的概念: java将输入与输出比喻为"流"&#xff0c;英文:Stream. 就像生活中的"电流","水流"一样,它是以同一个方向顺序移动的过程.只不过这里流动的是字节(2进制数据).所以在IO中有输入流和输出流之分,我们理解他们…

单点11.2.0.3备份恢复到单点11.2.0.4

保命法则&#xff1a;先备份再操作&#xff0c;磁盘空间紧张无法备份就让满足&#xff0c;给自己留退路。 场景说明&#xff1a; 1.本文档的环境为同平台、不同版本&#xff08;操作系统版本可以不同&#xff0c;数据库小版本不同&#xff09;&#xff0c;源机器和目标机器部…

swiftui基础组件Image加载图片,以及记载gif动图示例

想要在swiftui中展示图片&#xff0c;可以使用Image这个组件&#xff0c;这个组件可以加载本地图片和网络图片&#xff0c;也可以调整图片大小等设置。先大概看一下Image的方法有哪些可以用。 常用的Image属性 1.调整图像尺寸&#xff1a; 使用 resizable() 方法使图像可调整…

量子密钥分发系统基础器件(一):光纤干涉仪

干涉仪的基本原理是利用波的叠加来获得波的相位信息&#xff0c;从而获取实验中所关心的物理量。光纤干涉仪是由光学干涉仪发展而来的&#xff0c;利用光纤实现光的干涉&#xff0c;由于光纤取代透镜系统构成的光路具有柔软、形状可随意变化、传输距离远等特点&#xff0c;当前…

【Linux】23. 线程封装

如何理解C11中的多线程(了解) #include <iostream> #include <unistd.h> #include <thread>void thread_run() {while (true){std::cout << "我是新线程..." << std::endl;sleep(1);} } int main() {// 任何语言需要在Linux上实现多线…

解决IDEA菜单栏找不到VCS的问题,且使用IDEA推送新项目到托管仓库

问题描述&#xff1a; 在idea软件中使用git推送项目&#xff0c;idea页面顶部菜单栏无VCS 解决方案&#xff1a; 一&#xff1a;File->Settings->Version Control-> 点击 ->选择项目->VCS:->点击ok&#xff1a; 二&#xff1a;托管平台创建一个Git仓库来保…

Mysql 8.0 主从复制及读写分离搭建记录

前言 搭建参考&#xff1a;搭建Mysql主从复制 为什么要做主从复制&#xff1f; 做数据的热备&#xff0c;作为后备数据库&#xff0c;主数据库服务器故障后&#xff0c;可切换到从数据库继续工作&#xff0c;避免数据丢失。架构的扩展。业务量越来越大&#xff0c;I/O访问频…

6月来得及!考研数学120分复习规划:660/880/1000/1800怎么刷?

首先&#xff0c;120分是个什么概念&#xff1f; 如果目标120&#xff0c;历年真题就要135以上。这是因为&#xff1a; 1. 习题册里都是历年真题改编&#xff0c;很多题型见过了&#xff1b; 2. 考场发挥有不确定因素&#xff0c;所以需要安全边界。 总体规划 那么&#xff…

[java基础揉碎]文件IO流

目录 文件 什么是文件 文件流​编辑 常用的文件操作 创建文件方式一 创建文件方式二 创建文件方式三 tip:为什么new file 了还有执行createNewFile?new File的时候其实是在内存中创建了文件对象, 还没有在磁盘中, 当执行createNewFile的时候才是往磁盘中写入​编辑 …

WWW24因果论文(1/8) | 利用强化学习(智能体)进行因果问答

【摘要】因果问题询问不同事件或现象之间的因果关系。它们对于各种用例都很重要&#xff0c;包括虚拟助手和搜索引擎。然而&#xff0c;许多当前的因果问答方法无法为其答案提供解释或证据。因此&#xff0c;在本文中&#xff0c;我们旨在使用因果关系图来回答因果问题&#xf…