- UID
- 745044
- 积分
- 9
- 精华
- 贡献
-
- 威望
-
- 活跃度
-
- D豆
-
- 在线时间
- 小时
- 注册时间
- 2014-12-24
- 最后登录
- 1970-1-1
|
楼主 |
发表于 2014-12-26 19:58:05
|
显示全部楼层
多线程操作可以行的通,但是效率并没有提高,目前新开的文档全部在一个CADapplication下,如果给每一个指定一个单独的application不知道速度是否会快一点,没有时间尝试了。代码献上,有空大家可以试试:
//由于单元网格数量往往很多,所以尝试用多线程开启多文档分块绘制,虽然可行,但实际速度反而有些慢,故放弃
private void Mesh2CADByMultiThread()
{
if(tboxOpenFile.Text == "" || tboxSaveFile.Text == ""||
(cboxCulverts.Checked==false && cboxDikes.Checked==false && cboxWeirs.Checked==false && cboxGates.Checked==false))
{
MessageBox.Show("请检查输入、输出文件及绘制开关设置!", "提示:", MessageBoxButtons.OK);
MainForm.progBarWorker.ReportProgress(100);
return;
}
int i, j;
int proValue = 0;
//读取网格数据,获取网格数据
List<double[]> nodeData = new List<double[]>(); //保存网格全部节点的数据信息(节点编号(有时是有空缺的),x,y,z,节点特性)
List<int[]> eleNodeIndex = new List<int[]>(); //保存每个单元的三个节点编号信息
string projcs = ""; //保存投影坐标信息
if (Mike21.ReadFmMeshData(tboxOpenFile.Text, ref nodeData, ref eleNodeIndex, ref projcs) == false)
{
MessageBox.Show("读取网格mesh文件失败!", "警告:", MessageBoxButtons.OK);
MainForm.progBarWorker.ReportProgress(100);
return;
}
//打开所选择的的CAD文件,绘制网格图形
if (cadcontrol == null)
{
cadcontrol = new CCadControl();
cadcontrol.openandinit(tboxSaveFile.Text);
}
DateTime dtold = DateTime.Now;
//根据网格数量决定是否创建多线程,如创建多线程,给每个新建线程指定一个新建CAD文档
int bcount; //分块绘制的数量,当前线程1块,另外再开bcount-1个子线程
Thread[] sonThread = null;
MeshSonThreadData[] sonThrData = null;
Cad.AcadDocuments docs = cadcontrol.GetAppDocs();
if (eleNodeIndex.Count < 5000)
{
bcount = 1;
sonThrData = new MeshSonThreadData[1];
sonThrData[0].curdoc=cadcontrol.GetActiveDoc(); //获取初始化cadcontrol时的文档对象
}
else
{
bcount = 5; //分多块进行计算,此值必须大于等于2
sonThrData = new MeshSonThreadData[bcount];
for (i = 0; i < bcount; ++i)
{ sonThrData[i] = new MeshSonThreadData(); }
sonThread = new Thread[bcount - 1];
sonThrData[0].curdoc = cadcontrol.GetActiveDoc(); //获取初始化cadcontrol时的文档对象
for (i = 0; i < bcount - 1; i++)
{
sonThread[i] = new Thread(new ParameterizedThreadStart(sonMesh2CAD));
sonThread[i].Priority = ThreadPriority.AboveNormal;
sonThrData[i+1].curdoc = (Cad.AcadDocument)(docs.Add(System.Reflection.Missing.Value));
//给新建的子线程在cadcontrol的CadApp中新建一个cad文档
}
}
proValue += 10;
MainForm.progBarWorker.ReportProgress(proValue);
//下面设置相关变量
double[] pttri = null;// new double[3 * 3];
bool[] isExport = new bool[4]; //0-->网格边线,1--》节点编号,2--》网格高程,3--》单元编号
{ isExport[0] = cboxCulverts.Checked; isExport[1] = cboxDikes.Checked; }
{ isExport[2] = cboxWeirs.Checked; isExport[3] = cboxGates.Checked; }
List<double[]> sonMeshNodeCoords = null; //double[3],分别为网格节点x、y、z
List<double[]> sonNodeIndexTxt = null; //double[4],分别为节点编号,节点编号输出在CAD中的坐标(x、y、z)
List<double[]> sonEleIndexTxt = null; //double[4] 分别为单元编号,单元编号输出在CAD中的坐标(x、y、z)
double[] aIndexTxtData = null; //double[4] 分别为编号,编号输出在CAD中的坐标(x、y、z)
//////////////////////////////////////////////////////////////////////////////////////////////////////
//下面将给每个线程(如果没有子线程就只当前backgroundworker线程),设置绘制参数sonThrData[i]
//首先设置每个单元网格的节点数据
if (isExport[0] == true)
{
if (bcount == 1) //说明网格数量较少不需要,开分线程
{
sonMeshNodeCoords = new List<double[]>();
for (i = 0; i < eleNodeIndex.Count; ++i) //遍历所有单元
{
pttri = new double[3 * 3];
for (j = 0; j < 3; ++j)
{
//三角形重心的坐标,其坐标为((X1+X2+X3)/3,(Y1+Y2+Y3)/3;
pttri[j * 3 + 0] = nodeData[eleNodeIndex[i][j] - 1][1]; //x
pttri[j * 3 + 1] = nodeData[eleNodeIndex[i][j] - 1][2]; //y
pttri[j * 3 + 2] = nodeData[eleNodeIndex[i][j] - 1][3]; //z
}
sonMeshNodeCoords.Add(pttri);
}
sonThrData[0].sonMeshNodeCoords = sonMeshNodeCoords;
}
else if (bcount > 1) //说明网格数量较多,需开子线程
{
for (i = 0; i < eleNodeIndex.Count; ++i) //遍历所有单元
{
if (i % (eleNodeIndex.Count / bcount) == 0 && i / (eleNodeIndex.Count / bcount) < bcount-1 )
{
sonMeshNodeCoords = new List<double[]>();
sonThrData[i / (eleNodeIndex.Count / bcount)].sonMeshNodeCoords = sonMeshNodeCoords;
}
pttri = new double[3 * 3];
for (j = 0; j < 3; ++j)
{
pttri[j * 3 + 0] = nodeData[eleNodeIndex[i][j] - 1][1]; //x
pttri[j * 3 + 1] = nodeData[eleNodeIndex[i][j] - 1][2]; //y
pttri[j * 3 + 2] = nodeData[eleNodeIndex[i][j] - 1][3]; //z
}
sonMeshNodeCoords.Add(pttri);
}//end for
}//end else
}
else
{
if (bcount == 1) //说明网格数量较少不需要,开分线程
{ sonThrData[0].sonMeshNodeCoords = null; }
else if (bcount > 1) //说明网格数量较多,需开子线程
{
for (i = 0; i < bcount; ++i) //遍历所有计算分块
{ sonThrData[i / (eleNodeIndex.Count / bcount)].sonMeshNodeCoords = null; }//end for
}//end else
}//end if (isExport[0] == true)
//设置绘制单元编号文本的数据
if (isExport[3] == true)
{
pttri = new double[3*3];
if (bcount == 1) //说明网格数量较少不需要,开分线程
{
sonEleIndexTxt = new List<double[]>();
for (i = 0; i < eleNodeIndex.Count; ++i) //遍历所有单元
{
aIndexTxtData = new double[4];
aIndexTxtData[0] =(double)( i + 1); //单元编号
for (j = 0; j < 3; ++j)
{
pttri[j * 3 + 0] = nodeData[eleNodeIndex[i][j] - 1][1]; //x
pttri[j * 3 + 1] = nodeData[eleNodeIndex[i][j] - 1][2]; //y
pttri[j * 3 + 2] = nodeData[eleNodeIndex[i][j] - 1][3]; //z
}
aIndexTxtData[1] = (pttri[0] + pttri[3] + pttri[6]) / 3; //单元编号文本绘制点x
aIndexTxtData[2] = (pttri[1] + pttri[4] + pttri[7]) / 3; aIndexTxtData[3] = 0.0; //单元编号文本绘制点y、z
sonEleIndexTxt.Add(aIndexTxtData);
}
sonThrData[0].sonEleIndexTxt = sonEleIndexTxt;
}
else if (bcount > 1) //说明网格数量较多,需开子线程
{
for (i = 0; i < eleNodeIndex.Count; ++i) //遍历所有单元
{
if (i % (eleNodeIndex.Count / bcount) == 0 && i /(eleNodeIndex.Count / bcount) < bcount-1)
{
sonEleIndexTxt = new List<double[]>();
sonThrData[i / (eleNodeIndex.Count / bcount)].sonEleIndexTxt = sonEleIndexTxt;
}
aIndexTxtData = new double[4];
aIndexTxtData[0] = (double)(i + 1); //单元编号
for (j = 0; j < 3; ++j)
{
pttri[j * 3 + 0] = nodeData[eleNodeIndex[i][j] - 1][1]; //x
pttri[j * 3 + 1] = nodeData[eleNodeIndex[i][j] - 1][2]; //y
pttri[j * 3 + 2] = nodeData[eleNodeIndex[i][j] - 1][3]; //z
}
aIndexTxtData[1] = (pttri[0] + pttri[3] + pttri[6]) / 3; //单元编号文本绘制点x
aIndexTxtData[2] = (pttri[1] + pttri[4] + pttri[7]) / 3; aIndexTxtData[3] = 0.0; //单元编号文本绘制点y、z
sonEleIndexTxt.Add(aIndexTxtData);
}//end for
}//end else
}
else
{
if (bcount == 1) //说明网格数量较少不需要,开分线程
{ sonThrData[0].sonEleIndexTxt= null; }
else if (bcount > 1) //说明网格数量较多,需开子线程
{
for (i = 0; i < bcount; ++i) //遍历所有计算分块
{ sonThrData[i / (eleNodeIndex.Count / bcount)].sonEleIndexTxt = null; }//end for
}//end else
}//end if (isExport[3] == true)
//设置绘制节点编号文本的数据
if (isExport[1] == true)
{
if (bcount == 1) //说明网格数量较少不需要,开分线程
{
sonNodeIndexTxt = new List<double[]>();
for (i = 0; i < nodeData.Count; ++i) //遍历所有节点
{
aIndexTxtData = new double[4];
aIndexTxtData[0] = (double)(i + 1); //节点编号
aIndexTxtData[1] = nodeData[i][1]; aIndexTxtData[2] = nodeData[i][2]; aIndexTxtData[3] = 0.0; //节点编号文本绘制点x、y、z
sonNodeIndexTxt.Add(aIndexTxtData);
}
sonThrData[0].sonNodeIndexTxt = sonNodeIndexTxt;
}
else if (bcount > 1) //说明网格数量较多,需开子线程
{
for (i = 0; i < nodeData.Count; ++i) //遍历所有节点
{
if (i % (nodeData.Count / bcount) == 0 && i/(nodeData.Count / bcount) < bcount-1)
{
sonNodeIndexTxt = new List<double[]>();
sonThrData[i / (eleNodeIndex.Count / bcount)].sonNodeIndexTxt = sonNodeIndexTxt;
}
aIndexTxtData = new double[4];
aIndexTxtData[0] = (double)(i + 1); //节点编号
aIndexTxtData[1] = nodeData[i][1]; aIndexTxtData[2] = nodeData[i][2]; aIndexTxtData[3] = 0.0; //节点编号文本绘制点x、y、z
sonNodeIndexTxt.Add(aIndexTxtData);
}//end for
}//end else
}
else
{
if (bcount == 1) //说明网格数量较少不需要,开分线程
{ sonThrData[0].sonNodeIndexTxt = null; }
else if (bcount > 1) //说明网格数量较多,需开子线程
{
for (i = 0; i < bcount; ++i) //遍历所有计算分块
{ sonThrData[i / (eleNodeIndex.Count / bcount)].sonNodeIndexTxt = null; }//end for
}//end else
}//end if (isExport[1] == true)
proValue += 10;
MainForm.progBarWorker.ReportProgress(proValue);
//所有的数据全部准备好
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//下面开始绘制网格
if (bcount == 1) //说明网格数量较少不需要,开分线程
{
sonMesh2CAD((object)sonThrData[0]); //网格数量少。在当前线程绘制全部网格
}
else if (bcount > 1) //说明网格数量较多,需开子线程
{
//其余网格在子线程中绘制
for (i = 0; i < bcount-1; ++i) //遍历所有子线程,并启动他们
{
sonThread[i].Start((object)sonThrData[i+1]);
}
sonMesh2CAD((object)sonThrData[0]); //在当前线程绘制一部分网格
}//end else
proValue += 50;
MainForm.progBarWorker.ReportProgress(proValue);
//将子线程中绘制的网格图形全部复制到当前文档中
List<int> UnCompletedThrIndex = new List<int>();
for (i = 0; i < sonThread.GetLength(0); i++)
{ UnCompletedThrIndex.Add(i); }
i = 0;
while (true)
{
if (UnCompletedThrIndex.Count ==0) { break; }
for (i = UnCompletedThrIndex.Count-1; i >=0; --i)
{
if (sonThread[i].IsAlive == false)
{
cadcontrol.CopyFileAll2ms(sonThrData[UnCompletedThrIndex[i] + 1].curdoc); //将线程中的图形对象拷贝到当前文档
sonThrData[UnCompletedThrIndex[i] + 1].curdoc.Close(DialogResult.No, System.Reflection.Missing.Value);
sonThread[UnCompletedThrIndex[i]].Abort();
UnCompletedThrIndex.RemoveAt(i);
}
}
Thread.Sleep(200);
}
proValue += 20;
MainForm.progBarWorker.ReportProgress(proValue);
//将图形缩放到合适区间
cadcontrol.GetActiveDoc().SendCommand("_.ZOOM _A "); //显示全部
//缩放图形至显示全部网格
//保存文件,并提示写入文件成功
cadcontrol.SaveFile(tboxSaveFile.Text);
cadcontrol.Close(); cadcontrol = null;
DateTime dt = DateTime.Now;
MessageBox.Show(string.Format("耗时{0}分",dt.ToOADate()-dtold.ToOADate()), "", MessageBoxButtons.OK);
proValue = 100;
MainForm.progBarWorker.ReportProgress(proValue);
Thread.Sleep(1000);
}
//由于在CAD中写入大量图形时速度特别慢,所以考虑将需要绘制的图形数据分拆为几个部分,在不同的子线程中执行绘制,最后将各个绘制部分合并到一个图形中
//sonMeshData 为MeshSonThreadData类型,保存需要绘制的单元网格、节点编号、单元编号的数据
private void sonMesh2CAD(object sonMeshData)
{
if(sonMeshData==null) {return;}
MeshSonThreadData sonData=sonMeshData as MeshSonThreadData;
Cad.AcadDocument curdoc=sonData.curdoc; //当前绘制的CAD文档
List<double[]> sonMeshNodeCoords=sonData.sonMeshNodeCoords; //double[3],分别为网格节点x、y、z
List<double[]> sonNodeIndexTxt =sonData.sonNodeIndexTxt; //double[4],分别为节点编号,节点编号输出在CAD中的坐标(x、y、z)
List<double[]> sonEleIndexTxt=sonData.sonEleIndexTxt; //double 分别为单元编号,单元编号输出在CAD中的坐标(x、y、z)
//创建新图层
CadCom.AcadAcCmColor cmcolor = (CadCom.AcadAcCmColor)cadcontrol.GetInterfaceObject("AutoCAD.AcCmColor.17"); //注意CAD2007 中是.17,不同版本不一样
CadCom.AcadLineType linetype = null;
CadCom.ACAD_LWEIGHT linewei;
linetype =CCadControl.AddLinetype(curdoc,"Continuous");
linewei = CadCom.ACAD_LWEIGHT.acLnWt025;
cmcolor.ColorIndex = CadCom.AcColor.acWhite;
CadCom.AcadLayer meshLay = CCadControl.AddLayer(curdoc,"m21_mesh", cmcolor, linetype, linewei);
cmcolor.ColorIndex = CadCom.AcColor.acYellow;
CadCom.AcadLayer nodeIndexLay =CCadControl.AddLayer(curdoc,"m21_NodeIndex", cmcolor, linetype, linewei);
cmcolor.ColorIndex = CadCom.AcColor.acGreen;
CadCom.AcadLayer eleIndexLay = CCadControl.AddLayer(curdoc, "m21_ElementIndex", cmcolor, linetype, linewei);
//下面绘制网格单元边线
int i;
double[] pt = new double[3];
if (sonMeshNodeCoords!=null)
{
curdoc.ActiveLayer=meshLay;
for (i = 0; i < sonMeshNodeCoords.Count; ++i) //遍历当前子线程给定的所有单元
{
curdoc.ModelSpace.AddPolyline(sonMeshNodeCoords[i]).Closed = true;
}
}
//下面绘制网格单元编号
if (sonEleIndexTxt != null)
{
curdoc.ActiveLayer = eleIndexLay;
for (i = 0; i < sonEleIndexTxt.Count; ++i) //遍历所有单元
{
pt[0] = sonEleIndexTxt[i][1]; pt[1] = sonEleIndexTxt[i][2]; pt[2] = sonEleIndexTxt[i][3];
curdoc.ModelSpace.AddText(((int)sonEleIndexTxt[i][0]).ToString(), pt, 10);
}
}
//下面写入节点编号
if (sonNodeIndexTxt != null)
{
curdoc.ActiveLayer = nodeIndexLay;
for (i = 0; i < sonNodeIndexTxt.Count; ++i) //遍历所有节点
{
pt[0] = sonNodeIndexTxt[i][1]; pt[1] = sonNodeIndexTxt[i][2]; pt[2] = sonNodeIndexTxt[i][3];
curdoc.ModelSpace.AddText(((int)sonNodeIndexTxt[i][0]).ToString(), pt, 10);
}
}//end if
}
最后说明下:代码中cadcontrol 是我自己编的一个类对象,用于打开、绘制、选择、保存和关闭CAD图形
不影响整个代码。 |
|