Dxf文件中的各种数据,相互之间是没有逻辑关系的。你只是看到他们摆在那里,好像是连在一起的,这只是从视觉的角度,而从数据的角度来讲,相互之间没有关系。
要建立图元之间的关系,就得从本身的业务出发,首先确定用到的到底有几个图元,然后建立这几个图元之间的关系。
我的业务,用到的有直线图元、多线段图元(实际是个矩形)、多行文字图元。
多行文字图元,有两种,一种位置上位于多线段图元的内部,要作为多线段图元的属性;另外一种,位于直线的附近,需要作为直线的属性。
而直线,需要给两端建立实体,这种实体一种是多线段图元,第二种是虚拟的,需要手工创建。
最终按直线的属性输出数据。
1、建立多线段图元和多行文字图元的关联关系
多线段图元的类是YxxfEntLwpolyline,本文中指有四个点的多线段图元,四个点指四边形的四个点。多行文字图元指YxxfEntMtext,只有一个坐标。判断多行文字图元是否在多线段图元的内容,就判断四个坐标点和一个坐标点关系。如果YxxfEntMtext的点坐标都在YxxfEntLwpolyline四个点坐标之间,则为在其内部。
//取多线段图元的横坐标和纵坐标的最小值和最大值
double x1=999999999,//最小横坐标
x2=-999999999,//最大横坐标
y1=999999999,//最小纵坐标
y2=-999999999;//最大纵坐标
for(int i=0;i<</span>pline.vtxEntities.size();i++){
YxxfEntVertex vertex = (YxxfEntVertex)pline.vtxEntities.get(i);
if(x1>vertex.pnt.x)x1=vertex.pnt.x;
if(x2<</span>vertex.pnt.x)x2=vertex.pnt.x;
if(y1>vertex.pnt.y)y1=vertex.pnt.y;
if(y2<</span>vertex.pnt.y)y2=vertex.pnt.y;
}
//遍历所有的YxxfEntMtext,并判断其是否在YxxfEntLwpolyline的内部,如果在内部,则为text赋值。
YxxfEntBlock blk = D.secEntities.insMSpace.block;
YxxfEnt ent = null;
int nextToDraw = 0;
while (true)
{
ent = (YxxfEnt)blk.nextEntity(nextToDraw);
if (ent == null)
break;
if(ent.getClass()==YxxfEntMtext.class){//多行文字图元
YxxfEntMtext entMtext = (YxxfEntMtext)ent;
//判断坐标关系
if(entMtext.inspnt.x>=x1 && entMtext.inspnt.x<=x2
&& entMtext.inspnt.y>=y1 && entMtext.inspnt.y<=y2){
text = entMtext.text;//设置文本
entMtext.objId = id;//关联对象的id
break;
}
}
nextToDraw++;
}
2、建立多线段图元和直线图元的关联关系
多线段图元的类是YxxfEntLwpolyline,本文的实例中有四个点;直线图元指YxxfEntLine,有两个坐标点,起点和终点。建立多线段图元和直线图元的关联关系,采用的方法是取YxxfEntLwpolyline的中心点,然后查找距离YxxfEntLine的起点或终点最近的点,然后挂接到YxxfEntLine上。
计算两个点(x1,y1)和(x2,y2)的距离,计算公式是:((x1-x2)^2+(y1-y2)^2)^0.5.
double x1=999999999,//最小横坐标
x2=-999999999,//最大横坐标
y1=999999999,//最小纵坐标
y2=-999999999;//最大纵坐标
for(int i=0;i<</span>pline.vtxEntities.size();i++){
YxxfEntVertex vertex = (YxxfEntVertex)pline.vtxEntities.get(i);
if(x1>vertex.pnt.x)x1=vertex.pnt.x;
if(x2<</span>vertex.pnt.x)x2=vertex.pnt.x;
if(y1>vertex.pnt.y)y1=vertex.pnt.y;
if(y2<</span>vertex.pnt.y)y2=vertex.pnt.y;
}
//中心点的坐标=小的坐标+距离的一半
double x = (x2-x1)/2 + x1;
double y = (y2-y1)/2 + y1;
double minLength = 999999999;//最短距离
int minType = 0;//直线上的点的类型 1起点 2终点
YxxfEntLine minEnt = null;//距离最短的对象
YxxfEntBlock blk = D.secEntities.insMSpace.block;
YxxfEnt ent = null;
int nextToDraw = 0;
while (true)
{
ent = (YxxfEnt)blk.nextEntity(nextToDraw);
if (ent == null)
break;
if(ent.getClass()==YxxfEntLine.class){//直线类型
YxxfEntLine entLine = (YxxfEntLine)ent;
//计算两点间的距离
double tmp1 = Math.sqrt(Math.pow(entLine.begpnt.x-x, 2)+Math.pow(entLine.begpnt.y-y, 2));//起点
if(minLength>tmp1){
minLength = tmp1;
minType = 1;
minEnt = entLine;
}
double tmp2 = Math.sqrt(Math.pow(entLine.endpnt.x-x, 2)+Math.pow(entLine.endpnt.y-y, 2));//终点
if(minLength>tmp2){
minLength = tmp2;
minType = 2;
minEnt = entLine;
}
}
nextToDraw++;
}
if(minType==1)minEnt.begObj = this;
else if(minType==2)minEnt.endObj = this;
3、建立剩余多行文字图元和直线图元的关联关系
一部分多行文字图元在上面已经挂在了多线段图元上,剩余的部分,需要挂在直线上,成为直线的一个属性。
直线有两个坐标点,根据斜率的不同,可以有横向的和纵向的。多行文字有一个坐标点,也有横向的纵向的。首先判断多行文字图元是横向的还是纵向的,然后如果是横向的,循环处理所有的横向直线;如果是纵向的,则循环处理所有的纵向直线。取距离最短的,距离最短的计算方法是取点到直线的垂直距离。这个垂直距离的计算方法在“6、点到直线的垂直距离计算方法”中有详细的描述。
public String objId = null;//关联的对象的id
if(objId!=null) return;//已经有管理对象的,不用再处理了
if(text==null || text.equals("")) return;//没有数据,不用处理
//遍历所有图元
YxxfEntBlock blk = D.secEntities.insMSpace.block;
YxxfEnt ent = null;
int nextToDraw = 0;
double minDistance = 999999999;//最小距离
YxxfEntLine minEnt = null;//最小距离对应的直线
while (true)
{
ent = (YxxfEnt)blk.nextEntity(nextToDraw);
if (ent == null)
break;
if(ent.getClass()==YxxfEntLine.class){
YxxfEntLine entLine = (YxxfEntLine)ent;
if(entLine.diameter != null){
nextToDraw++;
continue;
}
//计算直线的斜率 大于1的为纵向的。等于1为45度倾斜,可以认为是横向的。
double lfSlope0 = Math.abs(entLine.endpnt.y-entLine.begpnt.y)/Math.abs(entLine.endpnt.x-entLine.begpnt.x);
if((xaxisdir.x != 0 && lfSlope0<=1) //文字纵向 直线横向
|| (xaxisdir.x == 0 && lfSlope0>1) //文字横向 直线纵向
){
nextToDraw++;
continue;
}
//计算距离
double distance = PointToSegDist(inspnt.x,inspnt.y,entLine.begpnt.x,entLine.begpnt.y,entLine.endpnt.x,entLine.endpnt.y);
if(minDistance>distance){
minDistance=distance;
minEnt = entLine;
}
}
nextToDraw++;
}
if(minEnt!=null)minEnt.diameter = text;