运行环境Visual Studio 2022 c# cad2016 cass10
通过面积计算得到扩展数据,宗地面积 ,房屋占地面积,房屋使用面积
一、主要步骤
- 获取当前AutoCAD应用中的活动文档、数据库和编辑器对象。
- 创建一个选择过滤器,限制用户只能选择"宗地"图层上的LWPOLYLINE对象作为外部边界。
- 提示用户根据上述规则进行实体选择,并获取选择结果。
- 遍历所有被选中的外部多段线,确保所选多段线是闭合的且至少有一个顶点。
- 创建并填充一个表示外部多段线边界坐标的点集合。
- 使用多边形窗口选择方式让用户选择位于外部多段线内的实体。
- 遍历用户在内部区域所选的所有闭合多段线,计算房屋面积和附属面积。
- 计算宗地面积和输出结果。
二、完整代码
internal class zdfwmj
{
public static List<string> filelist1 = new List<string>();
public static List<string> filelist2 = new List<string>();
public void fwzymj()
{
// 获取当前AutoCAD应用中的活动文档、数据库和编辑器对象
Document doc = Application.DocumentManager.MdiActiveDocument;
Database db = doc.Database;
Editor ed = doc.Editor;
string SelectedLayerName = CreatePalette.SelectedLayerName;
NumberContainer numberContainer = new NumberContainer();
//ed.WriteMessage("选择的图层:" + SelectedLayerName + "\n");
// 创建一个选择过滤器,限制用户只能选择"宗地"图层上的LWPOLYLINE对象作为外部边界
SelectionFilter outerFilter = new SelectionFilter(new TypedValue[] {
new TypedValue((int)DxfCode.Start, "LWPOLYLINE"),
new TypedValue((int)DxfCode.LayerName, SelectedLayerName)
});
// 提示用户根据上述规则进行实体选择,并获取选择结果
PromptSelectionResult outerSelRes = ed.GetSelection(outerFilter);
// 检查用户是否成功选择了实体
if (outerSelRes.Status == PromptStatus.OK)
{
using (Transaction tr = db.TransactionManager.StartTransaction())// 开始事务处理以确保数据一致性
{
foreach (ObjectId outerId in outerSelRes.Value.GetObjectIds())// 遍历所有被选中的外部多段线
{
using (Polyline outerPolyline = (Polyline)tr.GetObject(outerId, OpenMode.ForRead))// 读取所选多段线
{
// 确保所选多段线是闭合的且至少有一个顶点
double totalArea = 0; // 总面积
double totalAreaZdmj = 0; // 总面积
double totalAreaSYmj = 0; // 总面积
if (outerPolyline.Closed && outerPolyline.NumberOfVertices > 0)
{
// 创建并填充一个表示外部多段线边界坐标的点集合
Point3dCollection outerPoints = new Point3dCollection();
for (int i = 0; i < outerPolyline.NumberOfVertices; i++)
{
Point3d point = outerPolyline.GetPoint3dAt(i);
// 获取多边形的中心点
Point3d center = GetCenterOfPolyline(outerPolyline);
// 定义你的扩展因子,比如 1.5 表示扩大1.5倍
double scaleFactor = 1.2;
// 将顶点向中心点平移,然后按比例缩放
Point3d scaledPoint = new Point3d(
(point.X - center.X) * scaleFactor + center.X,
(point.Y - center.Y) * scaleFactor + center.Y,
(point.Z - center.Z) * scaleFactor + center.Z
);
// 创建并设置文本对象
DBText text = new DBText();
text.TextString = i.ToString();
//text.Height = 1; // 文字高度设为1个单位
text.Position = scaledPoint;
将文本添加到模型空间
//using (Transaction transaction = db.TransactionManager.StartTransaction())
//{
// BlockTable bt = transaction.GetObject(db.BlockTableId, OpenMode.ForRead) as BlockTable;
// BlockTableRecord ms = transaction.GetObject(bt[BlockTableRecord.ModelSpace], OpenMode.ForWrite) as BlockTableRecord;
// ms.AppendEntity(text);
// transaction.AddNewlyCreatedDBObject(text, true);
// transaction.Commit();
//}
outerPoints.Add(scaledPoint);
}
// 创建一个窗口选择过滤器,用于选择位于外部多段线内的所有实体
SelectionFilter innerFilter = new SelectionFilter(new TypedValue[] {
new TypedValue((int)DxfCode.Start, "LWPOLYLINE"),
new TypedValue((int)DxfCode.LayerName, "JMD")
});
// 使用多边形窗口选择方式让用户选择位于外部多段线内的实体
PromptSelectionResult innerSelRes = ed.SelectWindowPolygon(outerPoints, innerFilter);
// 检查用户是否成功在内部区域进行了实体选择
if (innerSelRes.Status == PromptStatus.OK)
{
SelectionSet innerSelectionSet = innerSelRes.Value;
// 遍历用户在内部区域所选的所有闭合多段线
foreach (ObjectId id2 in innerSelectionSet.GetObjectIds())
{
using (Polyline polyline2 = (Polyline)tr.GetObject(id2, OpenMode.ForRead))
{
if (polyline2.Closed && polyline2.NumberOfVertices > 0)
{
Entity ent2 = (Entity)tr.GetObject(id2, OpenMode.ForWrite);
//ent2.Color = Color.FromColorIndex(ColorMethod.ByAci, 3); // 示例:将颜色设为黄色
//ed.UpdateScreen(); // 确保颜色更改即时生效
filelist1.Clear();
filelist2.Clear();
int filelist1ii = 0;
if (ent2 != null && ent2.XData != null)
{
List<int> numbers01 = new List<int> { 141161, 141121, 141151 };//房屋编码
List<int> numbers02 = new List<int> { 141800, 140001, 143130, 143111, 143112 };//房屋附属编码
ResultBuffer rb = ent2.GetXDataForApplication("SOUTH");
string xdata = rb.ToString();
foreach (TypedValue tv in rb)
{
filelist1.Add(tv.TypeCode.ToString());//码
filelist2.Add(tv.Value.ToString());//值
}
filelist1ii = filelist1.Count();
//房屋面积
if (filelist1ii == 3)
{
if (numbers01.Contains(Convert.ToInt32(filelist2[1])))
{
string fwjg = numberContainer.GetDescription(Convert.ToInt32(filelist2[1]));
int fileValue;
if (int.TryParse(filelist2[2], out fileValue))
{
double calculatedUsageArea = polyline2.Area * fileValue;
//ed.WriteMessage($"\n房屋面积信息:{fwjg}{fileValue} 占地面积:{polyline2.Area:N2} 使用面积:{calculatedUsageArea:N2}\n");
totalAreaZdmj += polyline2.Area;
totalAreaSYmj += calculatedUsageArea;
using (Transaction transaction = db.TransactionManager.StartTransaction())
{
RegAppTable table02 = (RegAppTable)transaction.GetObject(doc.Database.RegAppTableId, OpenMode.ForWrite, false);
ResultBuffer rb02 = new ResultBuffer();
string appName02 = "扩展数据";
if (!table02.Has(appName02))
{
RegAppTableRecord regAppRec = new RegAppTableRecord();
regAppRec.Name = appName02;
table02.Add(regAppRec);
transaction.AddNewlyCreatedDBObject(regAppRec, true);
}
rb02.Add(new TypedValue((int)DxfCode.ExtendedDataRegAppName, appName02));
rb02.Add(new TypedValue((int)DxfCode.ExtendedDataReal, polyline2.Area));
rb02.Add(new TypedValue((int)DxfCode.ExtendedDataReal, calculatedUsageArea));
ent2.XData = rb02;
transaction.Commit();
}
}
else
{
//ed.WriteMessage("\n无法将文件列表中的值转换为整数以计算使用面积!");
}
}
}
if (filelist1ii == 2)
{
ed.WriteMessage("\n附属编码:" + filelist2[1]);
if (numbers02.Contains(Convert.ToInt32(filelist2[1])))
{
string fwjg = numberContainer.GetDescription(Convert.ToInt32(filelist2[1]));
//double fsmj = FwmjArea(polyline2, db, ed, tr);
TypedValue[] tvs = new TypedValue[]
{
new TypedValue((int)DxfCode.Operator, "<and"),
new TypedValue((int)DxfCode.Start, "TEXT"),
new TypedValue((int)DxfCode.LayerName, "房屋附属1"),
new TypedValue((int)DxfCode.Operator, "and>")
};
SelectionFilter sf = new SelectionFilter(tvs);
PromptSelectionResult psr = ed.SelectAll(sf);
SelectionSet ss = psr.Value;
foreach (SelectedObject so in ss)
{
DBText text = tr.GetObject(so.ObjectId, OpenMode.ForRead) as DBText;
if (IsPointInside(polyline2, text.Position))
{
string input = text.TextString;
//文字分解
string[] parts = input.Split(' ');
foreach (string part in parts)
{
// 按中文逗号分割键值对
string[] keyValue = part.Split(','); // 注意:这里的逗号是中文逗号,不是英文逗号
if (keyValue.Length == 2)
{
string key = keyValue[0];
string value = keyValue[1];
//ed.WriteMessage("键: " + key + ", 值: " + value+ "\n");
bool result = key.Contains("Q");
if (result)
{
totalArea += polyline2.Area;
//ed.WriteMessage($"全:{key}{value} 附属面积:{polyline2.Area:N2}\n");
}
result = key.Contains("B");
if (result)
{
totalArea += polyline2.Area / 2;
//ed.WriteMessage($"半:{key}{value} 附属面积:{polyline2.Area:N2}\n");
}
}
else
{
//ed.WriteMessage("未能分割出键值对:" + part);
}
}
using (Transaction transaction = db.TransactionManager.StartTransaction())
{
RegAppTable table02 = (RegAppTable)transaction.GetObject(doc.Database.RegAppTableId, OpenMode.ForWrite, false);
ResultBuffer rb02 = new ResultBuffer();
string appName02 = "扩展数据";
if (!table02.Has(appName02))
{
RegAppTableRecord regAppRec = new RegAppTableRecord();
regAppRec.Name = appName02;
table02.Add(regAppRec);
transaction.AddNewlyCreatedDBObject(regAppRec, true);
}
rb02.Add(new TypedValue((int)DxfCode.ExtendedDataRegAppName, appName02));
rb02.Add(new TypedValue((int)DxfCode.ExtendedDataAsciiString, input));
rb02.Add(new TypedValue((int)DxfCode.ExtendedDataReal, totalArea));
ent2.XData = rb02;
transaction.Commit();
}
//ed.WriteMessage($"房屋附属:{input} 附属面积:{totalArea:N2}\n");
}
}
}
}
}
}
}
}
}
Entity ent01 = tr.GetObject(outerId, OpenMode.ForWrite) as Entity;
RegAppTable table = (RegAppTable)tr.GetObject(doc.Database.RegAppTableId, OpenMode.ForWrite, false);
ResultBuffer rb01 = new ResultBuffer();
string appName = "扩展数据";
if (!table.Has(appName))
{
RegAppTableRecord regAppRec = new RegAppTableRecord();
regAppRec.Name = appName;
table.Add(regAppRec);
tr.AddNewlyCreatedDBObject(regAppRec, true);
}
rb01.Add(new TypedValue((int)DxfCode.ExtendedDataRegAppName, appName));
rb01.Add(new TypedValue((int)DxfCode.ExtendedDataReal, outerPolyline.Area));
rb01.Add(new TypedValue((int)DxfCode.ExtendedDataReal, totalAreaZdmj));
rb01.Add(new TypedValue((int)DxfCode.ExtendedDataReal, (totalAreaSYmj + totalArea)));
ent01.XData = rb01;
}
//ed.WriteMessage($"\n宗地面积:{outerPolyline.Area:N2} \n\n房屋占地面积:{totalAreaZdmj:N2}\n房屋使用面积:{(totalAreaSYmj + totalArea):N2}\n");
}
}
tr.Commit();
}
}
}
/// <summary>FwmjArea
public double FwmjArea(Polyline polyline, Database db, Editor ed, Transaction tr)
{
Point3dCollection outerPoints = new Point3dCollection(); // 创建并填充一个表示外部多段线边界坐标的点集合
double areaFWFS = 0;//房屋附属面积
for (int i = 0; i < polyline.NumberOfVertices; i++)
{
Point3d point = polyline.GetPoint3dAt(i);
outerPoints.Add(point);
}
// 创建一个窗口选择过滤器,用于选择位于外部多段线内的所有实体
SelectionFilter innerFilter = new SelectionFilter(new TypedValue[] {
new TypedValue((int)DxfCode.Operator, "<and"),
new TypedValue((int)DxfCode.Start, "TEXT"),
new TypedValue((int)DxfCode.LayerName, "房屋附属1"),
new TypedValue((int)DxfCode.Operator, "and>")
});
// 使用多边形窗口选择方式让用户选择位于外部多段线内的实体
PromptSelectionResult innerSelRes = ed.SelectAll(innerFilter);
if (innerSelRes.Status == PromptStatus.OK)
{
SelectionSet innerSelectionSet = innerSelRes.Value;
foreach (SelectedObject so in innerSelectionSet)
{
DBText text = tr.GetObject(so.ObjectId, OpenMode.ForRead) as DBText;
if (IsPointInside(polyline, text.Position))
{
string input = text.TextString;
//ed.WriteMessage("\n房屋附属文字2:", input.ToString());
//ed.WriteMessage("\n房屋附属文字2:", polyline.Area);
}
}
}
return areaFWFS;
}
/// </summary>
/// <param name="polyline"></param>
/// <param name="point"></param>
/// <returns></returns>
// 定义一个方法,输入参数为一个多段线对象和一个三维点,返回值为布尔类型,表示该点是否在多段线内部
public bool IsPointInside(Polyline polyline, Point3d point)
{
// 初始化交叉次数变量为0,用于记录点与多段线各线段相交的次数
int crossings = 0;
// 遍历多段线的所有顶点,从第一个顶点开始到最后一个顶点
for (int i = 0; i < polyline.NumberOfVertices; i++)
{
// 获取当前线段的起点坐标
Point3d start = polyline.GetPoint3dAt(i);
// 计算下一个顶点的索引,并使用取模运算确保最后一个顶点后回到第一个顶点形成闭合循环
int nextIndex = (i + 1) % polyline.NumberOfVertices;
Point3d end = polyline.GetPoint3dAt(nextIndex);
// 如果线段两端点都在检测点Y轴上方或下方,则此线段与过检测点的水平线不相交,跳过此次循环
if (start.Y > point.Y && end.Y > point.Y)
continue;
if (start.Y <= point.Y && end.Y <= point.Y)
continue;
// 如果检测点X坐标小于线段起点和终点的X坐标最小值,则此线段位于检测点左侧,跳过此次循环
if (point.X < Math.Min(start.X, end.X))
continue;
// 计算线段的斜率,并根据直线方程计算线段与过检测点Y坐标水平线的交点横坐标
double slope = (end.Y - start.Y) / (end.X - start.X);
double intersectX = start.X + (point.Y - start.Y) / slope;
// 如果检测点X坐标大于等于交点横坐标,则表示检测点在线段的一侧,增加交叉次数
if (point.X >= intersectX)
crossings++;
}
// 根据奇偶性判断:若交叉次数为奇数,则认为点在多段线内;否则点在多段线外
return (crossings % 2) == 1;
}
//包含字符 出现次数
public static int CountCharacterOccurrences(string str, string substring)
{
if (string.IsNullOrEmpty(str) || string.IsNullOrEmpty(substring))
return 0;
int index = 0, count = 0;
while ((index = str.IndexOf(substring, index)) != -1)
{
count++;
index += substring.Length; // 移动到下一个可能的位置
}
return count;
}
// GetCenterOfPolyline 是一个假设存在的方法,用于计算多边形的中心点
private Point3d GetCenterOfPolyline(Polyline polyline)
{
double xSum = 0, ySum = 0, zSum = 0;
for (int i = 0; i < polyline.NumberOfVertices; i++)
{
Point3d vertex = polyline.GetPoint3dAt(i);
xSum += vertex.X;
ySum += vertex.Y;
zSum += vertex.Z;
}
return new Point3d(xSum / polyline.NumberOfVertices, ySum / polyline.NumberOfVertices, zSum / polyline.NumberOfVertices);
}
}
//有需要cad二次开发可以私信进行联系
//感谢大家的点赞,收藏,转发,关注