28. Revit API:尺寸标注(Dimension)

一、前言

前面写了文字注释(TextNote)在视图中的包围盒的问题,然后想到尺寸标注上也是有文字的,那它的文字包围盒怎么获取呢?

哎嘿,这就瞅瞅。

二、尺寸标注

看图:

在"注释"菜单下的"尺寸标注"栏中,存在多种尺寸标注。

其实它们就分为三类:线性标注、弧度标注、高程标注。因为参照线(点)的不同,能够做出不同的动作。

  • Dimension:基类,用来表示线性标注,对齐、线性、半径直径 都是这个。
  • AngularDimension:子类,用来表示弧度标注,角度、弧长 是这个。
  • SpotDimension:子类,用来表示高程标注,三个高程都是这个。

2.1. Diemension

方法不写,就几个,看一眼得了。

至于属性,Revit中能手动编辑的,都能拿到。这就完事儿了~

留意几个Position的位置

至于高程标注的属性,只多了 Location 和 SpotDimensionType。

2.2. 创建标注

我们看文档,发现就AngularDimension类中有个Create()方法,其它两类的没有。

记得以前提到过,类中没有提供构造方法的,都可以去Creation中找找。而在17. Revit API: Creation这篇中的某张图上,就有写出标注的创建的方法,分别是

  • NewDimension():创建对齐标注
  • NewSpotElevation():创建高程标注

有眼睛亮的小伙伴就看见了,FamilyItemFactory类中不是有吗?是有,但那个是在「族文档」中才能用的,是用在建模上的。

至于通过代码来创建一个参变族,以后再说。

2.2.1. 对齐标注

接口的使用逻辑,和手动进行标注的逻辑是一样的。从参照线、参照点出发,再选择一个位置将标注放到那里。

csharp 复制代码
// Document.Create
public Dimension NewDimension(
	View view,  // 标注所在的视图
	Line line,  // 标注所在的直线
	ReferenceArray references // 标注参照
)

如果参照超过2个,那么就会有分段。

Revit工具栏长的"对齐"是通过这个方法实现的,是由参照线的方向决定的。至于"线性"标注,可以用这个代替。

备注:目前无法在非族文档中,创建半径、直径标注

可以尝试使用线性标注充当半径、直径标注,但不具备绕弧线移动的效果。

2.2.2. 弧度标注

和线性标注一样使用

csharp 复制代码
// AngularDimension
public static AngularDimension Create(
	Document document,
	View dbView,
	Arc arc,  // 标注所在的弧
	IList<Reference> references,  // 参照
	DimensionType dimensionStyle
)

备注:目前无法在非族文档中,创建弧长标注

2.2.3. 高程标注

三、尺寸标注文字的包围盒

11. Revit 文字(TextNote)包围盒中,写了如何计算视图中TextNote的包围盒。

各种Dimension上,也是有文字的,它的包围盒的计算,与TextNote类似,但也有些不同。

3.1. 文字位置为「内嵌」

  • LeaderEndPosition引线端点(终点),在文字「侧边中间」
  • TextPosition在文字「底部中间」
  • Origin在各段的线条的中间,也是引线的起点

如上图,这里以弧度标注为例,线性标注是一样的。

复制代码
1. 根据参照Curve,可以计算出Origin处的切线
2. 根据引线端点位置与原点法向,可以确定切向量方向
3. 根据引线端点位置和文字位置,可以计算出文字的长和宽
4. 由以上信息,可以获得尺寸标注文字的包围盒(如下图)
csharp 复制代码
public List<XYZ> ComputeAngularDimensionTextBounding(ViewSection viewSection, AngularDimension angularDimension)
 {
     List<(XYZ origin, XYZ textPosition, XYZ leaderEndPosition)> infos = [];  // 元组列表

     // 获取角度标注每段的信息
     if (angularDimension.NumberOfSegments == 0)
     {
         var info = (angularDimension.Origin, angularDimension.TextPosition, angularDimension.LeaderEndPosition);
         infos.Add(info);
     }
     else
     {
         foreach (DimensionSegment segment in angularDimension.Segments)
         {
             var info = (segment.Origin, segment.TextPosition, segment.LeaderEndPosition);
             infos.Add(info);
         }
     }

     Arc arc = angularDimension.Curve as Arc;

     var half_pi = Math.PI / 2.0;

     foreach (var info in infos)
     {
         XYZ originDirection = (info.origin - arc.Center).Normalize();
         XYZ leaderDirection = (info.leaderEndPosition - info.origin).Normalize();
         XYZ textDirection = (info.textPosition - info.origin).Normalize();
         XYZ computingDirection = leaderDirection.IsAlmostEqualTo(XYZ.Zero) ? textDirection : leaderDirection;

         double originParameter = arc.Project(info.origin).Parameter;  // warning, 3.1.1
         
         //XYZ tangent = arc.ComputeDerivatives(originParameter, false).BasisX; // error, curve is unbound.
         XYZ tangent = originDirection.RoatetAroundAxis(XYZ.Zero, viewSection.ViewDirection, half_pi).Normalize();  // 扩展方法

         var angle = tangent.AngleTo(computingDirection);

         if (angle > half_pi) { tangent = -tangent; }

         double width = (info.leaderEndPosition.DotProduct(tangent) - info.textPosition.DotProduct(tangent)).Abs();  // 一半的宽
         double height = (info.leaderEndPosition.DotProduct(originDirection) - info.textPosition.DotProduct(originDirection)).Abs(); // 一半的高

         var p0 = info.textPosition + tangent * width;
         var p1 = info.textPosition + tangent * width + originDirection * height * 2;
         var p2 = info.textPosition - tangent * width + originDirection * height * 2;
         var p3 = info.textPosition - tangent * width;

         List<XYZ> points = [p0, p1, p2, p3]; // info, 未处理顺、逆排序
         // ...
     }

    // ...
 }
3.1.1. BUG

当标注的原点处于如图的线上时,会在计算点在线上的投影时报错。

具体的原因,并没有弄清楚😕。

3.2. 文字位置在「上部」

这里以线性标注为例,弧度标注也是一样的

  • LeaderEndPosition在文字「底部侧边」
  • TextPosition在文字「底部中央」
  • Origin在各段的线条的中间

如上图,这里以线性标注为例,弧度标注也是类似的。

※ 取巧的方案:开启事务,将标注样式中的位置改为「内嵌」,使用内嵌的方案计算包围盒,再回滚事务。

可以看到,高度部分数据是缺失的,通过点坐标的差值,只能得到宽度数据。

那么我们是否可获取文字的高度信息?

可以,从「文字大小 」属性中获取,文字本身高度 = 文字大小 * 图纸比例,文字本身高度,即忽略文字边距。至于边距是多少,这个就取决于所用字体和是否为粗体有关了,

文字上下边距:(包围盒高度 - 文字本身高度)÷ 2 。

当字体为粗体时,大小就不准了,还不知道怎么算❌

可以整个配置文件,csv格式的txt就很好。预置一些常用的字体大小数据,用到时查一下,如果没有,再计算下填入。

3.3. 带有Below的标注

带有上、前、后缀的标注的文字不需要特殊处理,引线端点和文字位置会跟着变化,下缀就不一样了,需要额外处理。

标注的前后缀是在同一行,而上下部就"相当于"是换行。

若文字位置为内嵌,引线的端点始装在侧边中间,在计算含有上部是没有影响,而一旦带有下部,就有问题了。

就和"引线的端点始终在侧边中间"一样,TextPosition始终在【主体文字】底部中间。

这样一来,就不能简单的通过引线端点和文字位置坐标差来计算了。

如图,需要根据情况切换者计算,可能不那么准。

如果希望准一点,或是希望分别获取每一行文字的包围盒,就需要用到3.2中的文字边距了。

3.4. 高程标注

四、结尾

相关推荐
客梦24 分钟前
Java 道路信息系统
java·笔记
一只侯子9 小时前
Face AE Tuning
图像处理·笔记·学习·算法·计算机视觉
whale fall12 小时前
【剑雅14】笔记
笔记
星空的资源小屋13 小时前
跨平台下载神器ArrowDL,一网打尽所有资源
javascript·笔记·django
Xudde.13 小时前
Quick2靶机渗透
笔记·学习·安全·web安全·php
AA陈超14 小时前
Git常用命令大全及使用指南
笔记·git·学习
愚戏师15 小时前
Python3 Socket 网络编程复习笔记
网络·笔记
降临-max16 小时前
JavaSE---网络编程
java·开发语言·网络·笔记·学习
大白的编程日记.16 小时前
【计算网络学习笔记】MySql的多版本控制MVCC和Read View
网络·笔记·学习·mysql
IMPYLH18 小时前
Lua 的 require 函数
java·开发语言·笔记·后端·junit·lua