news 2026/3/17 6:56:36

基于.Net 8创建 CAD勘测定界图(四)——填充及拉线标注

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
基于.Net 8创建 CAD勘测定界图(四)——填充及拉线标注

好的,之前的两篇文章大概介绍了一下关于做这个功能的背景和关于Aspose.CAD For .Net填充无效,转用ACadSharp创建红线、界址点符号、界址点标注以及边长标注的方法,具体看:
基于.Net 8创建 CAD勘测定界图(一)
基于.Net 8创建 CAD勘测定界图(二)
基于.Net 8创建 CAD勘测定界图(三)
那么接下来,我们一步一步开始添加对应的图斑填充和拉线标注

图斑填充

图斑填充的效果要求是实现下图的效果

那么基于这个需求直接开搞就得了,首先先确认填充样式,是下图的这个

这里要注意啊,是ANSI31而不是ANS131,反正当时第一时间被这个编码折腾了挺久的。
那么知道了这个的样式,步骤和之前创建界址点的填充模式一样,甚至比之前的界址点创建还要简单。

绘制轮廓
创建路径
获取样式
填充保存

OK,那么先来第一步,上传的矢量文件中已经有现成的Polygon或者MultiPolygon了,拿到这个要素,转成CAD的LwPolyline(我个人比较习惯这个而不是Ployline,没记错的话,应该是从AutoCAD大概12以后官方都比较推荐这个做2D,如果需要有Z值的,还是乖乖PolyLine比较靠谱)。

  • Step1.创建边界多段线
    varcoords=sonItem.SonGeometry.Coordinates;// 坐标(NTS)varpltList=coords.Select(c=>newXY(c.X,c.Y)).ToList();// 点集ListvarlwPolyline=BuildRedPolyline(pltList);// 创建LwPolyLinelwPolyline.Color=newColor(255,255,255);// 设置颜色lwPolyline.ConstantWidth=0.03;// 线宽lwPolyline.Layer=xzLayer;// 图层doc.ModelSpace.Entities.Add(lwPolyline);
    这里面有个自己的 FunctionBuildRedPolyline主要就是读取坐标点转CAD的过程,之前代码应该也贴过了就不重复水了;
  • Step2.绑定路径
    路径和之前一样
    varboundaryPolyline=newHatch.BoundaryPath.Polyline(lwPolyline.Vertices.Select(v=>newXYZ(v.Location.X,v.Location.Y,v.Bulge)),isClosed:lwPolyline.IsClosed);varpath=newHatch.BoundaryPath();path.Edges.Add(boundaryPolyline);
  • Step3.填充
    varpattern=newHatchPattern("ANSI31");pattern.Lines.Add(newHatchPattern.Line{Angle=MathHelper.DegToRad(45.0),BasePoint=newXY(0,0),// PAT 格式中 offset 是沿线法向的重复偏移,这里直接给出等效的重复向量Offset=newXY(0,10),// 行距为 1,PatternScale 会整体缩放// ANSI31 通常为实线,不需要 dash 断续;如果需要虚线可设置 DashLengths// DashLengths = { 4.0, -2.0 }});varhatch=newHatch{IsSolid=false,Color=newColor(255,255,255),Pattern=pattern,PatternType=HatchPatternType.PatternFill,PatternScale=1.0,PatternAngle=0.0,Layer=xzLayer};hatch.Paths.Add(path);// 添加至少一个位于边界内部的种子点(例如多边形质心或任意内部点)varcentroid=lwPolyline.Vertices.Select(v=>v.Location).Aggregate(newXY(0,0),(acc,p)=>newXY(acc.X+p.X,acc.Y+p.Y));centroid=newXY(centroid.X/lwPolyline.Vertices.Count,centroid.Y/lwPolyline.Vertices.Count);hatch.SeedPoints.Add(centroid);
    这里强调:种子点添加很重要种子点添加很重要种子点添加很重要!重要的事情讲3遍,如果不添加内部种子点,你的填充很有可能失效(几率不明)我测了60几次遇到过10多次,概率不低。

到这里,所有关于图斑填充的问题结束。创建出来的图斑填充效果如下:

至于为什么是白色的,因为每个填充按照不同类型进行填充,我只是用了new Color(255,255,255) // White示例,具体各位需要什么颜色,请使用各位自定义的颜色配置。

拉线标注&中心标注

我得到的需求是:

  • A .小的填充图斑在红线内
  • B. 红线图斑需要中心标注
  • C. 小的填充图斑需要拉线标注

基于这三个需求,开始分别实现拉线标注及中心标注,需要标注的状态示意如下:

分析一下,下面地类名称,上面地块编号 + 面积
可以有2种做法:

  • A .上面的创建下划线文本 + 文本拼接 + 按位置需求创建下方文本
  • B. 创建LwPolyLine + 创建上方文本+创建下方文本

这里说明,我使用的是方法B

拉线标注

按照上面的B方法先拉线:

  • 首先获取需要拉线标注的元素中心点

    varentList=newList<Entity>();varsonGeom=sonItem.SonGeometry;varcenterPoint=sonGeom.Centroid;
  • 计算终点

    varrightPoint=newNetTopologySuite.Geometries.Point(centerPoint.X+98,centerPoint.Y);varrightLine=newNetTopologySuite.Geometries.LineString([newCoordinate(rightPoint.X-40,rightPoint.Y),newCoordinate(rightPoint.X,rightPoint.Y),newCoordinate(rightPoint.X+40,rightPoint.Y)]);varleftPoint=newNetTopologySuite.Geometries.Point(centerPoint.X-98,centerPoint.Y);varleftLine=newNetTopologySuite.Geometries.LineString([newCoordinate(leftPoint.X-40,leftPoint.Y),newCoordinate(leftPoint.X,leftPoint.Y),newCoordinate(leftPoint.X+40,leftPoint.Y)]);varupPoint=newNetTopologySuite.Geometries.Point(centerPoint.X,centerPoint.Y+98);varupLine=newNetTopologySuite.Geometries.LineString([newCoordinate(upPoint.X-40,upPoint.Y),newCoordinate(upPoint.X,upPoint.Y),newCoordinate(upPoint.X+40,upPoint.Y)]);vardownPoint=newNetTopologySuite.Geometries.Point(centerPoint.X,centerPoint.Y-98);vardownLine=newNetTopologySuite.Geometries.LineString([newCoordinate(downPoint.X-40,downPoint.Y),newCoordinate(downPoint.X,downPoint.Y),newCoordinate(downPoint.X+40,downPoint.Y)]);

    我个人比较懒,正常应该是一个动态计算斜率k的终点线,我直接上下左右了。反正原理是这样,需要计算的朋友可以自己设置斜率哈。

  • 方向判断
    按照刚刚创建的4条线,判断哪个方向是最合适的,标注应在红线外。

    varcandidates=newDictionary<string,(NetTopologySuite.Geometries.Point pt,boolinside,XY target)>{["right"]=(rightPoint,fStruct.Geometry.Intersects(rightLine),newXY(rightPoint.X,rightPoint.Y)),["left"]=(leftPoint,fStruct.Geometry.Intersects(leftLine),newXY(leftPoint.X,leftPoint.Y)),["up"]=(upPoint,fStruct.Geometry.Intersects(upLine),newXY(upPoint.X,upPoint.Y)),["down"]=(downPoint,fStruct.Geometry.Intersects(downLine),newXY(downPoint.X,downPoint.Y)),["center"]=(centerPoint,true,newXY(centerPoint.X,centerPoint.Y))};// 找到未包含的方向(若恰有一个为 false,则选该方向)varnotInside=candidates.Where(kv=>!kv.Value.inside).Select(kv=>kv.Key).ToList();varlineCenterPt=newXY();vardir=notInside.Count!=0?notInside[0]:"center";lineCenterPt=candidates[dir].target;

    仍旧日常偷懒,选哪个方向最好应该是可以计算的,反正我还是一个字,懒。

  • 创建文字间的横线
    知道了刚刚创建的多段线的终点,把终点作为横线的终点,创建横线,线长按需

    varconnectLine=newLwPolyline(){Color=newColor(255,255,255),ConstantWidth=0.3,IsClosed=false,Layer=layer};connectLine.Vertices.Add(newLwPolyline.Vertex(newXY(centerPoint.X,centerPoint.Y)));connectLine.Vertices.Add(newLwPolyline.Vertex(newXY(lineCenterPt.X+7.5,lineCenterPt.Y)));entList.Add(connectLine);
  • 创建文字
    创建文字的时候注意中心对齐哈

    varupArea=Math.Round(sonGeom.Area/10000.0,4);vartextUp=newTextEntity{Value=$"{fStruct.DkId}{upArea:F4}hm²",InsertPoint=newXYZ(lineCenterPt.X-30,lineCenterPt.Y+3,0),AlignmentPoint=newXYZ(lineCenterPt.X-30,lineCenterPt.Y+3,0),Color=newColor(255,255,255),Height=6.5,HorizontalAlignment=TextHorizontalAlignment.Center,VerticalAlignment=TextVerticalAlignmentType.Middle,Layer=layer};

    下方文字创建道理同上,Y坐标减去对应值就可以。

到这里,拉线标注创建完成。

中心标注

道理和拉线标注一样,只不过这次不用创建拉线了,直接用NTS或者ACadSharp的元素Center或Centriod都可以,这个点作为文字中间横线的中点。创建方法和之前一样

最终效果

结合之前的3篇文章,创建出来的效果如下:

好了,到这里打印基本大差不差了,下一篇估计就是最后且最麻烦的一篇,打印图廓了,有时间再写吧……就这样,债见。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/3/4 21:23:41

Docker入门

Docker是一款快速构建、运行、管理应用的工具自动搜索并下载应用镜像。镜像不仅包含应用本身&#xff0c;还包含应用运行所需要的环境&#xff0c;配置&#xff0c;系统函数库、Docker会在运行镜像时创建一个隔离环境&#xff0c;称为容器。镜像仓库&#xff1a;Docker Hub入门…

作者头像 李华
网站建设 2026/3/11 16:38:39

22、正则表达式:从基础到高级应用

正则表达式:从基础到高级应用 1. 正则表达式基础 正则表达式除了字面字符外,还包含元字符,用于指定更复杂的匹配规则。常见的元字符有: ^ $ . [ ] { } - ? * + ( ) | \ ,其他字符则被视为字面字符。不过,反斜杠字符在某些情况下用于创建元序列,也可让元字符被当作字…

作者头像 李华
网站建设 2026/3/15 20:20:48

取能模块:无源自取电创新解决方案

提及无源自取电&#xff0c;很多人会第一时间联想到智能手机的无线充电功能&#xff0c;原则上理解的没错&#xff0c;只是相较于无源自取电这种技术&#xff0c;二者本质上应用的领域有所区别。前者目前适用于中高压和低压输电线路上&#xff0c;以非接触式取能的核心优势&…

作者头像 李华
网站建设 2026/3/13 17:47:47

30、编写Shell脚本入门与项目实践

编写Shell脚本入门与项目实践 1. 编写第一个脚本 首先,我们来编写一个简单的“Hello World”脚本。在命令行中输入以下代码: [me@linuxbox ~]$ echo Hello World! # This is a comment too Hello World!这里的注释在命令行中作用不大,但在脚本里是很有用的。脚本的第一行…

作者头像 李华
网站建设 2026/3/11 16:10:47

启动进程,并返回新进程id(C++源码)

1、概述 启动进程,并返回新进程id,支持场景: 1、支持绝对路径: C:\Program Files\Google\Chrome\Application\chrome.exe 2、支持环境变量路径:%localappdata%\\Feishu\\Feishu.exe 1.1、调用示例 // 调用示例// 启动进程,并返回新进程id// 支持绝对路径: C:\Program Fil…

作者头像 李华
网站建设 2026/3/14 1:07:40

PDF压缩

winnzip项目pdf压缩部分/*** 压缩PDF文件* param inputFile 输入PDF文件路径* param outputFile 输出PDF文件路径* param compressionLevel 压缩等级: 0小尺寸, 1中等尺寸, 2大尺寸* param lossless 是否无损压缩* return 压缩是否成功*/使用Ghostscript命令行方式进行pdf压缩&…

作者头像 李华