文章目录

  • 需要生成的效果
  • 折线多边形的原位缩放两种办法
    • 6.10 多边形放大、缩小及移动 P309
      • c#实现
      • 缺点
      • 分析
    • 向量缩放办法
      • 算法剖析
      • 算法步骤
      • c#代码
    • Revit API 方法

需要生成的效果

吊坑或集水坑的基本原理是按照板边界外侧生成一圈墙体进行封堵

折线多边形的原位缩放两种办法

一种是周培德的计算几何-算法设计与分析(第三版)中的办法另外一种是引用自折线平行线的计算方法的办法,最后第二种可以解决项目问题,但是两种算法都写了一遍就都分析一下,这种情况以后还会遇到方便回查。

6.10 多边形放大、缩小及移动 P309

教材中记载了一种方法,通过封闭多边形内部的一个点向每个点做向量,并基于向量的值向外侧偏移指定距离实现偏移,此处需要计算的值

  1. 多边形内部点与边界点的向量 v
  2. 偏移值是两个平行线段的垂线距离所以遇到斜向线段时需要计算实际长度

c#实现

        /// <summary>/// 偏移指定路径值/// </summary>/// <param name="array">楼板轮廓线集合</param>/// <param name="insidePoint">内部点,使用时将face origin处理后传入</param>/// <param name="k">缩放系数</param>/// <returns></returns>public static CurveLoop OffsetPath(CurveLoop array,XYZ insidePoint,double k){//get all vertexes var curves = new List<Curve>();var iEnumerator = array.GetEnumerator();while (iEnumerator.MoveNext()){//将所有线段取出var curve = iEnumerator.Current;curves.Add(curve);}if (curves.Count == 0) throw new ArgumentNullException();var points = new List<XYZ>();//遍历每个线段取线段的1点作为偏移点,求线段线段向量的垂直向量并求出角度cos theta//求出实际偏移距离kt,从而求出延长点,加入到集合points中foreach (var curve in curves){if (curve is Line line){var vec = line.Direction.Normalize();var targetVec = GetVerticalVector(vec);//取线段的1点作为参照点var referencePoint = line.GetEndPoint(1);var dir = new XYZ(insidePoint.X - referencePoint.X, insidePoint.Y - referencePoint.Y, 0).Normalize();//var angle = dir.AngleTo(targetVec);if (angle > Math.PI / 2){var count = Math.Floor(angle / (Math.PI / 2)); angle -= Math.PI / 2 * count;}//在多边形内部角度都为锐角。因为他们与向量的垂直向量组成锐角三角形,角度最大为90°//实际偏移值,根据一直向量求延长线上此点位置var tk = k / Math.Cos(angle);//求已知向量上的延长线,此处仅讨论向外侧延申,Z都一致,为二维向量//输入:原点o , 边界点 vp , 延长距离 tk//输出:延长点 tp// tp.x = o.x + abs(vp.x - o.x) / L(vp , o) * (tk + L(vp,o))// tp.y = o.y + abs(vp.y - o.y) / L(vp , o) * (tk + L(vp,o))//垂直三角形三个边 a,b,c c最长 ,每个延长线均可视为一个三角形,通过比较c的比值,从而获得a,b的长度,并从原点增加相应长度//L(vp,o)//可求出具体的x,y偏移值,但是生成的复杂吊坑面会出现整体偏移的情况,原因是向外部做射线,并//从referencePoint 开始偏移会导致最终生成生成错误var lVpO = Line.CreateBound(referencePoint, insidePoint).Length;var x = Math.Abs(referencePoint.X - insidePoint.X) / lVpO * (tk + lVpO);var y = Math.Abs(referencePoint.Y - insidePoint.Y) / lVpO * (tk + lVpO);var subtractionVec = (referencePoint - insidePoint).Normalize();//取单位向量做下面判定if (subtractionVec.X <= 0){if (subtractionVec.Y >= 0){var targetPoint = new XYZ((insidePoint.X - x).ReduceDouble(4), (insidePoint.Y + y).ReduceDouble(4), referencePoint.Z);points.Add(targetPoint);}else{var targetPoint = new XYZ((insidePoint.X - x).ReduceDouble(4), (insidePoint.Y - y).ReduceDouble(4), referencePoint.Z);points.Add(targetPoint);}}else{if (subtractionVec.Y >= 0){var targetPoint = new XYZ((insidePoint.X + x).ReduceDouble(4), (insidePoint.Y + y).ReduceDouble(4), referencePoint.Z);points.Add(targetPoint);}else{var targetPoint = new XYZ((insidePoint.X + x).ReduceDouble(4), (insidePoint.Y - y).ReduceDouble(4), referencePoint.Z);points.Add(targetPoint);}}}}

缺点

这种方法无法适用于板边界复杂的情况,但是对于凸包集合可以使用,这种理解起来相对简单,但是需要增加象限的加减,有兴趣的可以根据目录查找一下书籍详细阅读一下

分析

第一张可以看到大部分不准确,原因是对于中心点向边界方向偏移,会出现错误详图,此处下方边界需要向两侧分别偏移但是出现了凸角集体偏移的情况.所以 在实际项目中会出现项目吊坑生成错误的情况。

向量缩放办法

其实第一方法也是使用向量进行修改,但是为了区分随便叫了一个名字,原文链接,此处增加了自己的解释和c#代码

算法剖析

  1. 两组偏移线段的可以组成一个菱形
  2. 我们可以使用三角函数求出其中一个边的边长
  3. 根据单位向量与长度的比值可以求出中心PiQi的长度
  • 输入:偏移的实际距离,边界点集合
  • 输出:偏移后的点集合

算法步骤

  1. 根据点集合求出单位向量normal v1 , normal v2
  2. 整理公式1 :|a X b| = |a|*|b|*sin(θ)
  3. 可以获得关于角度的计算公式,但是由于∠θ与另一个角共线,根据定理可以推出sin(Π - θ) = sin(θ)
  4. 根据3与h距离,可以通过三角函数求出v2方向的菱形边长度,Lb为菱形边长度,L代表h,即:L/Lb = sin(Π - θ) 又 sin(Π - θ) = sin(θ)
  5. 整理2,3的公式之后可以获得最终公式:Lb = L/|a X b|/|a|/|b|
  6. 又因为是单位向量|a|,|b|的模为1
  7. 最后通过向量相加公式: Qi = Pi + L/|a x b| x (v1 + v2)
  8. 向量的方向代表缩小和放大,主要是原文中对于L/sin(θ)这一步会让人疑惑,所以在这解释一下

c#代码

        public static CurveLoop OffsetPath(CurveLoop array, double k){/** 第二种方法:来源:https://blog.csdn.net/happy__888/article/details/315762* 此方法适用于平行直线结合形成的折线多边形的原位缩小与放大* 通过缩放前点与缩放后的点及两点形成的向量(a,b)可组成四边相同的菱形形状* 平行四边形面积:|a X b| = |a|*|b|*sin(θ) ,* 已知偏移的长度,及两条平行线段的垂线距离L,可以在菱形边做垂线获得一个直角三角形* 通过三角形定理,L/Lb = sin(Π - θ) 又 sin(Π - θ) = sin(θ)* 所以可以得到最终公式: Lb = L/|a X b|/|a|/|b|* 又最终点是起点(Ps) + 向量方向(a + b) * 向量长度(Lb)[因为之前求取向量将向量简化为单位向量,所以起点到中点的距离应该是菱形边会到未* 单位化之前的值 及 normal(Lb) / Lb = normal(LTargetPoint) / LTargetPoint]* 所以通过上述公式可以将最终点求出* */var vertices = new List<XYZ>();var newVertices = new List<XYZ>();//因为Revit中顶点都是逆时针排序,只需要取出点即可foreach (var curve in array){vertices.Add(curve.GetEndPoint(0));}//每个点遍历获取前一个点与后一个点,获取两个向量,此处位置的**向量方向会与缩放形式有关**for (int i = 0; i < vertices.Count; i++){int iPrevious = -1;int iEnd = -1;if (i == 0){iPrevious = vertices.Count - 1;iEnd = i + 1;}else if (i == vertices.Count - 1){iPrevious = i - 1;iEnd = 0;}else{iPrevious = i - 1;iEnd = i + 1;}XYZ pPrevious = vertices[iPrevious];XYZ point = vertices[i];XYZ pEnd = vertices[iEnd];//normalizevar v1 = (pPrevious - point).Normalize();var v2 = (pEnd - point).Normalize();var cross = (v1.X*v2.Y - v1.Y*v2.X);//叉积 , v1 , v2单位向量模为1var lb = 0.00;if (cross == 0)continue;lb = k / cross;var tPoint = point + lb * (v1 + v2);newVertices.Add(tPoint);}//output var loop = new CurveLoop();for (int i = 0; i < newVertices.Count; i++){if(i == newVertices.Count - 1){var c = Line.CreateBound(newVertices[i], newVertices[0]);loop.Append(c);}else{var c = Line.CreateBound(newVertices[i], newVertices[i + 1]);loop.Append(c);}}return loop;}

相较于我遇到的问题这种方法的代码量更少,准确性更好,学习之路坎坷需要时刻学习!

Revit API 方法

做Revit开发的话,如果不涉及复杂边界,可以使用里面的CurveLoop.CreateViaOffset方法,但是此种办法会出现错误,在复杂边界中会出现外扩变为缩小的情况,如下图

使用方法二的生成:

方法一生成:

折线多边形的原位放大相关推荐

  1. 【高德地图API】从零开始学高德JS API(三)覆盖物——标注|折线|多边形|信息窗口|聚合marker|麻点图|图片覆盖物

    原文地址为: [高德地图API]从零开始学高德JS API(三)覆盖物--标注|折线|多边形|信息窗口|聚合marker|麻点图|图片覆盖物 摘要:覆盖物,是一张地图的灵魂.有覆盖物的地图,才是完整的 ...

  2. 【高德地图API】从头德国高中生JS API(三)覆盖物——大喊|折线|多边形|信息表|聚合marker|点蚀图|照片覆盖...

    覆盖物,是一张地图的灵魂.有覆盖物的地图.才是完整的地图.在一张地图上,除了底层的底图(瓦片图,矢量图),控件(有功能可操作的工具).最重要最必不可少的就是覆盖物了.覆盖物有多种.包含.标注.折线.多 ...

  3. cad坐标归零lisp_在CAD中用LISP实现原位放大数值

    (defun c:fff(/ num) (princ"主要功能为原位数值放大") (setvar "cmdecho" 0) (if(= nil xsz) (c: ...

  4. js添加多marker 高德地图_【高德地图API】从零开始学高德JS API(三)覆盖物——标注|折线|多边形|信息窗口|聚合marker|麻点图|图片覆盖物...

    摘要:覆盖物,是一张地图的灵魂.有覆盖物的地图,才是完整的地图.在一张地图上,除了底层的底图(瓦片图,矢量图),控件(有功能可操作的工具),最重要最不可缺少的就是覆盖物了.覆盖物有多种,包括,标注.折 ...

  5. 用java的事件监听机制实现一个简单的画板应用:通过选择图形按钮和颜色按钮来画出自己想画的图形:直线、空心矩形、圆形、折线、多边形、圆角矩形、弧线、曲线、喷枪

    今天做一个简单的画板,完整代码附在文章末尾处. - 功能:通过选择图形按钮和颜色按钮来画出自己想画的图形. - 界面展示: - 思路: 1.做一个可视化界面:创建JFrame对象,并设置Title.S ...

  6. opencv学习【绘图】多边形polylinesfillPoly

    多边形绘制 >>定义1 >>>回归本源 void cv::polylines ( Mat & img,const Point *const * pts,const ...

  7. Android折线图,柱状图,股票走势图,基金走势图

    相信折线图大家都不陌生,有些数据统计,基金股票都是通过通过折线图的方式去展示数据,接下来就介绍一种方法,去通过代码编写一个类似的功能. 首先看一下效果图 编写之前要了解一下怎么样去入手,首先从界面出发 ...

  8. opencv多边形轮廓等距缩放

    opencv多边形按像素放大或缩小,可用于缩放提取后的轮廓 代码示例如下: #!/usr/bin/env python # -*- encoding: utf-8 -*- ''' @File : 多边 ...

  9. Qt+OpenCV联合开发(十八)--多边形填充与绘制

    一.知识点 API 知识点: 1.polylines&fillPoly 2.drawContours 二.函数原型 1.polylines polylines的c++原型: 参数一:img  ...

最新文章

  1. 《C++语义和性能分析》读书笔记
  2. 介绍一个很好用的Rsa加解密的.Net库 Kalix.ApiCrypto
  3. 小型企业的上网行为管理方案
  4. cpu,内存,虚拟内存,硬盘,缓存之间是什么关系??
  5. 基于ESP32的竞赛裁判系统功能调试-激光信号调试
  6. 开发日记-20190820 关键词 读书笔记《Unix环境高级编程(第二版)》DAY 1
  7. CTFshow 反序列化 web261
  8. 远程恢复服务器,Hyper-V主机启用“远程桌面”功能
  9. JSP简单练习-定时刷新页面
  10. 华为交换机端口隔离配置
  11. 成长为一名Java架构师需要掌握的技术有哪些呢?
  12. python的flask实现第三方登录怎么写_Python语言的Flask框架应用程序实现使用QQ账号登录的方法...
  13. 简单计算机app inventor,app inventor计算器
  14. 中兴通讯遭大股东减持逾两千万股 盘中跌逾6%
  15. zendstudio 的使用过程中出现 Editor could not be initialized. 的问题
  16. 墨者学院 - IIS写权限漏洞分析溯源
  17. vscode写的html网页中文乱码
  18. 无人车系统(八):Udacity ‘s无人驾驶仿真环境(python与c++数据接口)
  19. RK356X系列(RK3568)GL857L芯片 USB驱动开发
  20. python爬虫使用session保持登录状态

热门文章

  1. 论文研读-AI4VIS-可视化推荐-Table2Analysis/Table2Charts
  2. 万字长文解读DeepMind与谷歌的AI拉锯战
  3. 基金定投matlab程序,销售基金定投好简单:如何三分钟让客户理智开户做定投
  4. 必应搜索引擎怎么了?
  5. 前端优化首屏加载速度
  6. prach---发端
  7. windows安全模式_别再用苹果装Windows 因为macOS实在是太好用了
  8. 14. Setting Ta and RTO【设置Ta和RTO】
  9. HiveConf of name hive.metastore.local does not exis问题
  10. 计算机上计算器不见,win10系统自带的计算器不见了的处理教程