好的,之前的两篇文章大概介绍了一下关于做这个功能的背景和关于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.创建边界多段线
这里面有个自己的 Functionvarcoords=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);BuildRedPolyline主要就是读取坐标点转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篇文章,创建出来的效果如下:
好了,到这里打印基本大差不差了,下一篇估计就是最后且最麻烦的一篇,打印图廓了,有时间再写吧……就这样,债见。