using Clipper2Lib; using DeepNestLib; using GeoSigma.SigmaDrawerStyle; using GeoSigmaDrawLib; using SigmaDrawerElement; using System; using System.Collections.Generic; using System.Diagnostics; using System.Drawing; using System.IO; using System.Linq; using System.Text; using System.Text.RegularExpressions; using System.Threading; using System.Threading.Tasks; using System.Windows.Forms; using DrawerData = GeoSigmaDrawLib.DrawerData; namespace SmartWells { public partial class Form1 : Form { private NestingContext nest; private double originX = 0; private double originY = 0; private string borderFile = string.Empty; private string faultageFile = string.Empty; private string resultFile = string.Empty; private string mapFile; double partSpacing = 200; double faultInflate = 10; private bool stop = true; WellGroupParameter groupParaSide2; WellGroupParameter groupParaSide1; LocalContour wellBox2; LocalContour wellBox1; DrawerData drawer;// = new DrawerData(); /// /// 控制执行线程 /// ManualResetEvent ma = new ManualResetEvent(false); SvgNestConfig nestConfig; CaculateHelp caculator; private bool newDeployFile = true; public Form1() { InitializeComponent(); toolStripProgressBar1.Width = statusStrip1.Width - stlInfor.Width - 20; nestConfig = new SvgNestConfig(); caculator = new CaculateHelp(); caculator.IterateEvent += updatePlacementsInfo; caculator.ExportPlaceMentsEvent += updateDeployImage; } /// /// 打开工区图件 /// /// 事件按钮 /// 事件参数 private void btnMap_Click(object sender, EventArgs e) { OpenFileDialog ofd = new OpenFileDialog(); ofd.Filter = "*.kev|*.kev|*.dfd|*.dfd"; ofd.Multiselect = false; ofd.RestoreDirectory = true; if (ofd.ShowDialog() == DialogResult.OK) { this.txtMap.Text = ofd.FileName; } } /// /// 打开文件 /// /// 文件全路径 /// private async Task OpenDrawerFile(string fileName) { if (!File.Exists(fileName)) { return false; } bool bResult = false; await Task.Run(() => { if (drawer != null) { drawer.Dispose(); drawer = null; } drawer = new DrawerData(); drawer.OpenWithDraw = true; try { if (drawer.OpenFile(mapFile)) { bResult = true; } } catch (Exception ex) { drawer.Dispose(); drawer = null; bResult = false; } }); return bResult; } private async void txtMap_TextChanged(object sender, EventArgs e) { if (this.stop) { mapFile = this.txtMap.Text; await OpenDrawerFile(mapFile); } newDeployFile = true; } /// /// 边界文件 /// /// /// private async void btnBorderFile_Click(object sender, EventArgs e) { if(drawer == null) { mapFile = this.txtMap.Text; bool bOpen = await this.OpenDrawerFile(mapFile); if (bOpen == false) { return; } } string strLayers = drawer.GetLayers(); FormLayers frmLayers = new FormLayers(strLayers); if(frmLayers.ShowDialog(this)== DialogResult.OK) { List lstChecked = frmLayers.SelectedNodes; if(lstChecked!=null && lstChecked.Count > 0) { this.txtBorderFile.Text = string.Join(",", lstChecked); } } } private async void btnFaultFile_Click(object sender, EventArgs e) { if (drawer == null) { mapFile = this.txtMap.Text; bool bOpen = await this.OpenDrawerFile(mapFile); if (bOpen == false) { return; } } string strLayers = drawer.GetLayers(); FormLayers frmLayers = new FormLayers(strLayers); if (frmLayers.ShowDialog(this) == DialogResult.OK) { List lstChecked = frmLayers.SelectedNodes; if (lstChecked != null && lstChecked.Count > 0) { this.txtFaultage.Text = string.Join(",", lstChecked); } } } /// /// 结果文件 /// /// /// private void btnResultFile_Click(object sender, EventArgs e) { SaveFileDialog sfd = new SaveFileDialog(); sfd.Filter = "Dxf files (*.dxf)|*.dxf|Svg files (*.svg)|*.svg|*.dfd|*.dfd"; sfd.FilterIndex = lastSaveFilterIndex; sfd.AddExtension = true; //sfd.RestoreDirectory = true; if (sfd.ShowDialog() == DialogResult.OK) { lastSaveFilterIndex = sfd.FilterIndex; this.txtResultFile.Text = sfd.FileName; } } int lastSaveFilterIndex = 3; private void btnOutput_Click(object sender, EventArgs e) { //if (nest == null || nest.PlacedPartsCount == 0) //{ // MessageBox.Show("未产生正确的结果!", "保存结果", MessageBoxButtons.OK, MessageBoxIcon.Error); // return; //} //SaveResult(); this.resultFile = this.txtResultFile.Text; if (this.caculator.SaveResult(this.resultFile)) { MessageBox.Show("保存成功!"); } else { MessageBox.Show("未产生正确的结果!", "保存结果", MessageBoxButtons.OK, MessageBoxIcon.Error); } } private void SaveResult() { this.resultFile = this.txtResultFile.Text; string strExt = Path.GetExtension(resultFile).ToUpper(); if (strExt == ".DFD") { drawer.SaveAs(this.resultFile); } else if (strExt == ".DXF") { DxfParser.Export(resultFile, nest.Polygons.ToArray(), nest.Sheets.ToArray(), this.originX, this.originY); } else if (strExt == ".SVG") { SvgParser.Export(resultFile, nest.Polygons.ToArray(), nest.Sheets.ToArray()); } } private void btnPause_Click(object sender, EventArgs e) { if (this.btnPause.Text == "暂停") { this.caculator.Pause(); } else { this.caculator.Continue(); } //// 信号关闭阻,塞当前线程 //if (btnPause.Text == "暂停") //{ // btnPause.Text = "等待暂停"; // this.btnPause.Enabled = false; // ma.Reset(); //} //else if(btnPause.Text =="继续") //{ // btnPause.Text = "暂停"; // // 信号打开,不阻塞当前线程 // ma.Set(); //} } private void btnStop_Click(object sender, EventArgs e) { //stop = true; //btnStop.Text = "等待停止"; //btnPause_Click(null, null); this.caculator.Stop(); } private WellsConfig makeWellConfig() { WellsConfig wellsConfig = new WellsConfig(); wellsConfig.WellNamePrefix = this.txtWellName.Text; if(int.TryParse(this.txtBranchCount.Text, out int count) && double.TryParse(this.txtBranchDistance.Text, out double offset) && double.TryParse(this.txtBranchLength.Text, out double length) && double.TryParse(this.txtBranchSpace.Text, out double space)) { wellsConfig.BranchCount = count; wellsConfig.BranchOffset = offset; wellsConfig.BranchLength = length; wellsConfig.BranchSpace = space; } else { return null; } wellsConfig.DeploySide2 = ckbSide2.Checked; wellsConfig.DeploySide1 = ckbSide1.Checked; wellsConfig.DeployAgain = this.ckbReDeployment.Checked; return wellsConfig; } private CaculateConfig makeCaculateConfig() { CaculateConfig caculateConfig = new CaculateConfig(); if (double.TryParse(this.txtPartsSpace.Text, out double partSpace) && double.TryParse(this.txtMutationRate.Text, out double mutation)) { caculateConfig.WellsSpace = partSpace; caculateConfig.MutationRate = mutation; } else { return null; } if (this.rdbRotationTimes.Checked) { if (int.TryParse(this.txtRotationTimes.Text, out int rotationTimes) && double.TryParse(this.txtAngleStart.Text, out double angleStart) && double.TryParse(this.txtAngleEnd.Text, out double angleEnd)) { caculateConfig.SpecifyAngles = false; caculateConfig.Rotations = rotationTimes; caculateConfig.AngleStart = angleStart; caculateConfig.AngleEnd = angleEnd; } else { return null; } } if (this.rdbRotationAngles.Checked) { List specfiedAngles = new List(); foreach (string strLine in txtRotationAngles.Lines) { string[] saLine = strLine.Split(','); foreach (string strItem in saLine) { double fAngle = 0; if (double.TryParse(strItem, out fAngle)) { specfiedAngles.Add(fAngle); } } } caculateConfig.SpecifyAngles = true; caculateConfig.SpeciaAngles = specfiedAngles.ToArray(); } caculateConfig.IgnoreMiniFault = ckbMiniFaultLength.Checked; if (ckbMiniFaultLength.Checked) { caculateConfig.MiniFaultLength = double.TryParse(this.txtMinFaultLength.Text, out double miniLength) ? miniLength : 1000; } return caculateConfig; } /// /// 执行计算 /// /// /// private void btnPlay_Click(object sender, EventArgs e) { string strDeployFile = this.txtMap.Text; string strBorderLayer = this.txtBorderFile.Text; string strFaultLayer = this.txtFaultage.Text; WellsConfig wellsConfig = makeWellConfig(); CaculateConfig caculateConfig = makeCaculateConfig(); this.caculator.DeployFile = strDeployFile; this.caculator.BorderLayer = strBorderLayer; this.caculator.FaultLayer = strFaultLayer; this.caculator.WellParameters = wellsConfig; this.caculator.CaculateParameter = caculateConfig; this.caculator.ImageWidth = this.pictureBox1.Width; this.caculator.ImageHeight = this.pictureBox1.Height; bool bReopenDraw = newDeployFile; newDeployFile = false; this.caculator.DisplayProgressAction = displayProgress; if (this.caculator.Excute(bReopenDraw) == false) { MessageBox.Show("执行错误!", this.Text); } return; if (stop == true) { this.btnPlay.Enabled = false; stop = false; this.btnPause.Enabled = true; ma.Set(); } else { return; } this.stlInfor.Text = string.Empty; // 计算配置 // 部件旋转数 if (rdbRotationTimes.Checked) { nestConfig.SpecfiedAngles = null; int nRotations = 8; if (int.TryParse(this.txtRotationTimes.Text, out nRotations)) { nestConfig.rotations = nRotations; } if (float.TryParse(this.txtAngleStart.Text, out float fAngleStart)) { nestConfig.AngleStart = fAngleStart; } if (float.TryParse(this.txtAngleEnd.Text, out float fAngleEnd)) { nestConfig.AngleEnd = fAngleEnd; } } else if (this.rdbRotationAngles.Checked) { List specfiedAngles = new List(); foreach(string strLine in txtRotationAngles.Lines) { string[] saLine = strLine.Split(','); foreach(string strItem in saLine) { float fAngle = 0; if(float.TryParse(strItem, out fAngle)) { specfiedAngles.Add(fAngle); } } } nestConfig.SpecfiedAngles = specfiedAngles.ToArray(); } // 部件间间距设置 double dSpacing = 0; if (double.TryParse(this.txtPartsSpace.Text, out dSpacing)) { nestConfig.spacing = 0; partSpacing = dSpacing; } this.borderFile = this.txtBorderFile.Text; this.faultageFile = this.txtFaultage.Text; // 加载边界数据 RawDetail detail = loadLayersDetail(this.borderFile);// loadDetail(this.borderFile); detail.Name = borderFile; if (detail.Outers.Count > 1) { detail.Outers.RemoveRange(1, detail.Outers.Count-1); } // 计算相对坐标原点 var bbox = detail.BoundingBox(); originX = bbox.X; originY = bbox.Y; detail.Offset(-originX, -originY); PathD pathBorder = new PathD(); foreach (var pt in detail.Outers[0].Points) { pathBorder.Add(new Clipper2Lib.PointD(pt.X, pt.Y)); } double dMinFaultLength = 1000; if(!double.TryParse(this.txtMinFaultLength.Text, out dMinFaultLength)) { dMinFaultLength = 0; } // 加载断层数据 RawDetail detailFault = loadLayersDetail(this.faultageFile);// loadDetail(this.faultageFile); double dAreaFault = 0; if (detailFault.Outers?.Count>0) { detailFault.Offset(-originX, -originY); PathsD paths = new PathsD(), solution; foreach (var contour in detailFault.Outers) { // 忽略小断层 if (this.ckbMiniFaultLength.Checked) { //double dLineLength = CaculateLineLength(path); if (contour.Len <= dMinFaultLength) { continue; } } PathD path = new PathD(); bool bOutBorder = true; foreach(var pt in contour.Points) { Clipper2Lib.PointD ptd = new Clipper2Lib.PointD(pt.X, pt.Y); if (Clipper2Lib.Clipper.PointInPolygon(ptd, pathBorder) == PointInPolygonResult.IsInside) { bOutBorder = false; // 一旦有一个点在内部,则线不在边界外部 } path.Add(new Clipper2Lib.PointD(pt.X, pt.Y)); } // 排除边界外断层 if(bOutBorder == false) { paths.Add(path); } } // 断层线外扩成多边形,宽度可调 solution = Clipper.InflatePaths(paths, faultInflate, JoinType.Round, EndType.Round); solution = Clipper.SimplifyPaths(solution, 2.5); dAreaFault = Clipper2Lib.Clipper.Area(solution); // 多边形添加到边界 foreach (var pathChild in solution) { LocalContour contourChild = new LocalContour(); foreach (var pt in pathChild) { contourChild.Points.Add(new PointF((float)pt.x, (float)pt.y)); } detail.Outers.Add(contourChild); } } bbox = detail.BoundingBox(); // 二次部井 if (this.ckbReDeployment.Checked) { // 加载井组数据 RawDetail detailWells = loadWellGroupDetail("井组"); // 相对原点进行坐标偏移 detailWells.Offset(-originX, -originY); // 区域外扩 PathsD paths = new PathsD(), solution; foreach (var contour in detailWells.Outers) { PathD path = new PathD(); bool bOutBorder = true; foreach (var pt in contour.Points) { Clipper2Lib.PointD ptd = new Clipper2Lib.PointD(pt.X, pt.Y); if (Clipper2Lib.Clipper.PointInPolygon(ptd, pathBorder) == PointInPolygonResult.IsInside) { bOutBorder = false; // 一旦有一个点在内部,则线不在边界外部 } path.Add(new Clipper2Lib.PointD(pt.X, pt.Y)); } // 排除边界外断层 if (bOutBorder == false) { if (Math.Abs(path.First().x - path.Last().x) > 1E-4 || Math.Abs(path.First().y - path.Last().y) > 1E-4) { path.Add(new Clipper2Lib.PointD(path.First().x, path.First().y)); } paths.Add(path); } } // 断层线外扩成多边形,宽度可调 solution = Clipper.InflatePaths(paths, this.partSpacing*0.5, JoinType.Miter, EndType.Polygon); solution = Clipper.SimplifyPaths(solution, 2.5); //StringBuilder strbMsg = new StringBuilder(); //foreach(var line in solution) //{ // strbMsg.AppendLine("Pline"); // foreach (var pt in line) // { // strbMsg.AppendLine($"{pt.x},{pt.y}"); // } // strbMsg.AppendLine(); //} //Trace.WriteLine(strbMsg.ToString()); // 统计约束区面积 dAreaFault += Clipper2Lib.Clipper.Area(solution); // 多边形添加到边界 foreach (var pathChild in solution) { LocalContour contourChild = new LocalContour(); foreach (var pt in pathChild) { contourChild.Points.Add(new PointF((float)pt.x, (float)pt.y)); } detail.Outers.Add(contourChild); } } NFP nfp = detail.ToNfp(); nest = new NestingContext(); int src = nest.GetNextSheetSource(); var ns = Background.clone(nfp); Sheet sheet = new Sheet(); sheet.Points = ns.Points; sheet.children = ns.children; nest.Sheets.Add(sheet); sheet.Width = sheet.WidthCalculated; sheet.Height = sheet.HeightCalculated; sheet.source = src; nest.ReorderSheets(); // 边界的面积 double dAreaBorder = Clipper2Lib.Clipper.Area(pathBorder); // 生成双侧井组 DrawerWellGroup wellGroupSide2 = new DrawerWellGroup(); this.groupParaSide2= new WellGroupParameter(); this.groupParaSide2.WellPoint.X = 0; this.groupParaSide2.WellPoint.Y = 0; this.groupParaSide2.WellPoint.Z = 0; this.groupParaSide2.WellPoint.Name = this.txtWellName.Text; wellGroupSide2.Name = this.txtWellName.Text; this.groupParaSide2.BranchDistanceRight = double.Parse(this.txtBranchDistance.Text); this.groupParaSide2.BranchDistanceLeft = this.groupParaSide2.BranchDistanceRight; this.groupParaSide2.BranchAngle = 0.0; this.groupParaSide2.BranchSpace = double.Parse(this.txtBranchSpace.Text); this.groupParaSide2.BranchLength = double.Parse(this.txtBranchLength.Text); this.groupParaSide2.BranchCountRight = int.Parse(txtBranchCount.Text); this.groupParaSide2.BranchCountLeft = this.groupParaSide2.BranchCountRight; wellGroupSide2.Parameter = this.groupParaSide2.Clone(); bool bSuccess = wellGroupSide2.CreateHorizionWells(); // 生成单侧井组 this.groupParaSide1 = this.groupParaSide2.Clone(); this.groupParaSide1.BranchCountLeft = 0; DrawerWellGroup wellGroupSide1 = new DrawerWellGroup(); wellGroupSide1.Parameter = groupParaSide1.Clone(); wellGroupSide1.CreateHorizionWells(); wellBox2 = CreateWellGroupBorder(wellGroupSide2, this.partSpacing); wellBox1 = CreateWellGroupBorder(wellGroupSide1, this.partSpacing); //List shapes = new List(); int nCountSide2 = 0; if (ckbSide2.Checked) { RawDetail detail2 = new RawDetail(); detail2.Outers.Add(wellBox2); detail2.Name = "双侧"; //shapes.Add(detail2); PathD pathSide2 = new PathD(); foreach (var pt in wellBox2.Points) { pathSide2.Add(new Clipper2Lib.PointD(pt.X, pt.Y)); } double dAreaSide2 = Clipper2Lib.Clipper.Area(pathSide2); nCountSide2 = (int)Math.Abs((Math.Abs(dAreaBorder) - Math.Abs(dAreaFault)) / dAreaSide2); for(int i = 0; i < nCountSide2; i++) { nest.ImportFromRawDetail(detail2, 0); } } if (ckbSide1.Checked) { RawDetail detail1 = new RawDetail(); detail1.Outers.Add(wellBox1); detail1.Name = "单侧"; //shapes.Add(detail1); if (ckbSide2.Checked) { int nCountSide1 = (int)(nCountSide2 * 0.35); for (int i = 0; i < nCountSide1; i++) { nest.ImportFromRawDetail(detail1, 1); } } else { PathD pathSide1 = new PathD(); foreach (var pt in wellBox1.Points) { pathSide1.Add(new Clipper2Lib.PointD(pt.X, pt.Y)); } double dAreaSide1 = Clipper2Lib.Clipper.Area(pathSide1); int nCountSide1 = (int)Math.Abs((Math.Abs(dAreaBorder) - Math.Abs(dAreaFault)) / dAreaSide1); for (int i = 0; i < nCountSide1; i++) { nest.ImportFromRawDetail(detail1, 1); } } } // 设置突变率 double dMutation = 0.5; if(double.TryParse(this.txtMutationRate.Text, out dMutation)) { nestConfig.mutationRate = (int)(nest.Polygons.Count * dMutation); } ////loadShapesData(new List() { wellGroupSide1, wellGroupSide2}); ////for(int i = 0; i < shapes.Count; i++) ////{ //// //shapes[i].Offset(-originX, -originY); ////} //int nSrc = 0; //for(int i = 0; i < shapes.Count; i++) //{ // for (int j = 0; j < 20; j++) // { // nest.ImportFromRawDetail(shapes[i], nSrc); // //nSrc++; // } // nSrc++; //} nest.ReorderSheets(); nest.Config = this.nestConfig; run(); } private void run() { if (nest.Polygons.Count == 0 || nest.Sheets.Count == 0) { MessageBox.Show("There are no sheets or parts", Text, MessageBoxButtons.OK, MessageBoxIcon.Error); return; } Background.UseParallel = true; GeneticAlgorithm.StrictAngles = false; RunDeepnest(); } Thread th; public void RunDeepnest() { if (th != null) return; th = new Thread(() => { nest.DisplayProgressAction = displayProgress; nest.StartNest(); //UpdateNestsList(); //Background.DisplayProgressAction = displayProgress; while (true) { if (stop) { //btnPlay.Enabled = true; displayProgress(0.0f); break; } // 根据是否收到信号判断是否阻塞当前线程 ma.WaitOne(); if (stop) { writeUiSafe(""); //btnPlay.Enabled = true; displayProgress(0.0f); break; } Stopwatch sw = new Stopwatch(); sw.Start(); nest.NestIterate(); UpdatePreview(); UpdateNestsList(); displayProgress(1.0f); sw.Stop(); string strInfo = $"利用率: {Math.Round(nest.MaterialUtilization * 100.0f, 2)}% 计算耗时: {sw.ElapsedMilliseconds}ms"; writeUiSafe(strInfo); displayProgress(0.0f); } th = null; }); th.IsBackground = true; th.Start(); } private void updateDeployImage(Bitmap bmp, string info) { if(this.InvokeRequired) { this.Invoke(new Action(() => { updateDeployImage(bmp, info); })); return; } // bmp.MakeTransparent(Color.White); this.pictureBox1.Image = bmp; lblNestInfo.Text = info; } private void updatePlacementsInfo(List placements, double materialUtilization, long elapsedMilliseconds) { if (this.InvokeRequired) { Invoke(new Action(() => { updatePlacementsInfo(placements, materialUtilization, elapsedMilliseconds); })); return; } lsvHistory.BeginUpdate(); lsvHistory.Items.Clear(); foreach (var item in placements) { lsvHistory.Items.Add(new ListViewItem(new string[] { item.fitness == null ? "(null)" : item.fitness.Value.ToString("N5") }) { Tag = item }); } lsvHistory.EndUpdate(); string strInfo = $"利用率: {Math.Round(materialUtilization * 100.0f, 2)}% 计算耗时: {elapsedMilliseconds}ms"; stlInfor.Text = strInfo; } public void UpdateNestsList() { if (nest != null) { lsvHistory.Invoke((Action)(() => { lsvHistory.BeginUpdate(); lsvHistory.Items.Clear(); foreach (var item in nest.Nest.nests) { lsvHistory.Items.Add(new ListViewItem(new string[] { item.fitness == null ? "(null)" : item.fitness.Value.ToString("N5") }) { Tag = item }); } lsvHistory.EndUpdate(); })); } } private bool isDrawing = false; private void UpdatePreview() { if (isDrawing) { return; } if (this.InvokeRequired) { Invoke(new Action(() => { UpdatePreview(); })); } else { isDrawing = true; addSymbols(drawer); // 删除已有井组 if (this.ckbSide2.Checked) { drawer.DeleteLayer(new string[1] { "井组\\双侧" }, true); } if (this.ckbSide1.Checked) { drawer.DeleteLayer(new string[1] { "井组\\单侧" }, true); } //drawer.DeleteLayerElement( "井组" , true); // 部件内缩距离 float fSpace = (float)(partSpacing * 0.5); // 断层外扩距离 float fFaultExpand = fSpace; List box1 = new List(); box1.AddRange(new PointF[5] { new PointF(wellBox1.Points[0].X+fSpace, wellBox1.Points[0].Y+fSpace), new PointF(wellBox1.Points[1].X-fSpace, wellBox1.Points[1].Y+fSpace), new PointF(wellBox1.Points[2].X-fSpace, wellBox1.Points[2].Y-fSpace), new PointF(wellBox1.Points[3].X+fSpace, wellBox1.Points[3].Y-fSpace), new PointF(wellBox1.Points[4].X+fSpace, wellBox1.Points[4].Y+fSpace) }); List box2 = new List(); box2.AddRange(new PointF[] { new PointF(wellBox2.Points[0].X+fSpace, wellBox2.Points[0].Y+fSpace), new PointF(wellBox2.Points[1].X-fSpace, wellBox2.Points[1].Y+fSpace), new PointF(wellBox2.Points[2].X-fSpace, wellBox2.Points[2].Y-fSpace), new PointF(wellBox2.Points[3].X+fSpace, wellBox2.Points[3].Y-fSpace), new PointF(wellBox2.Points[4].X+fSpace, wellBox2.Points[4].Y+fSpace)} ); this.resultFile = this.txtResultFile.Text; string strExt = Path.GetExtension(resultFile).ToUpper(); List> lstWells = new List>(); HashSet removedIndices = DfdParser.ExportPlacements(nest.Polygons, nest.Sheets.ToArray(), this.originX, this.originY, (polygon, wellType) => { // 断层外扩处理 if (wellType == 2) //strName == "断层") { PathsD paths = new PathsD(), solution; PathD path = new PathD(); foreach (var pt in polygon.Points) { path.Add(new Clipper2Lib.PointD(pt.x, pt.y)); } paths.Add(path); // 断层线外扩成多边形,宽度可调 solution = Clipper.InflatePaths(paths, fFaultExpand, JoinType.Round, EndType.Round); solution = Clipper.SimplifyPaths(solution, 2.5); if (solution.Count > 0) { PointF[] pts = solution[0].Select(it => new PointF((float)it.x, (float)it.y)).ToArray(); return pts; } return null; } else if (wellType == 0) //strName.Equals("双侧")) { lstWells.Add(new Tuple(polygon, wellType)); // polygon内缩处理 return box2.ToArray(); } else if (wellType == 1) //strName.Equals("单侧")) { lstWells.Add(new Tuple(polygon, wellType)); return box1.ToArray(); } return null; }); if (lstWells.Count > 0) { string strWellName = this.txtWellName.Text; //DrawerData drawer = new DrawerData(); for (int i = 0; i < lstWells.Count; i++) { if (removedIndices.Contains(i)) { continue; } Tuple well = lstWells[i]; string strElementData = string.Empty; if (well.Item2 == 0) { // 双侧井组 DrawerWellGroup wellGroupSide2 = new DrawerWellGroup(); wellGroupSide2.Parameter = this.groupParaSide2.Clone(); wellGroupSide2.Parameter.BranchAngle = well.Item1.rotation; wellGroupSide2.Name = $"{strWellName}{i+1}"; wellGroupSide2.CreateHorizionWells(); setWellGroupStyle(wellGroupSide2); wellGroupSide2.Offset(this.originX, this.originY); wellGroupSide2.Offset(well.Item1.x, well.Item1.y); DrawerElementProperty element = new DrawerElementProperty(); element.Element = wellGroupSide2; element.ElementType = wellGroupSide2.ElementType; strElementData = DrawerElementHelp.Serialize(element); drawer.AddWellGroup("井组\\双侧", strElementData); } else { // 单侧井组 //wellGroupSide1.Angle = well.Item1.rotation + 90; DrawerWellGroup wellGroupSide1 = new DrawerWellGroup(); wellGroupSide1.Name = $"{strWellName}{i + 1}"; wellGroupSide1.Parameter = this.groupParaSide1.Clone(); wellGroupSide1.Parameter.BranchAngle = well.Item1.rotation; wellGroupSide1.CreateHorizionWells(); setWellGroupStyle(wellGroupSide1); wellGroupSide1.Offset(this.originX, this.originY); wellGroupSide1.Offset(well.Item1.x, well.Item1.y); DrawerElementProperty element = new DrawerElementProperty(); element.Element = wellGroupSide1; element.ElementType = wellGroupSide1.ElementType; strElementData = DrawerElementHelp.Serialize(element); drawer.AddWellGroup("井组\\单侧", strElementData); } } } IntPtr hBmp = drawer.GetBitmapHandle(this.pictureBox1.Width, pictureBox1.Height, 0); Bitmap bmp = Image.FromHbitmap(hBmp); bmp.MakeTransparent(Color.White); this.pictureBox1.Image = bmp; drawer.DeleteHbmp(hBmp); StringBuilder strbStatistic = new StringBuilder(); foreach (var kv in nest.PartsStatistic) { strbStatistic.Append($"{kv.Key}:{kv.Value}个 "); } lblNestInfo.Text = $"覆盖率: {Math.Round(nest.MaterialUtilization * 100.0f, 2)}% {strbStatistic}"; isDrawing = false; } } /// /// 添加进组所需符号 /// /// private void addSymbols(DrawerData drawer) { string strSymbolWell = @"Layer M 0 Pline -0.5,-0.5 -0.5,0.5 0.5,0.5 0.5,-0.5 -0.5,-0.5 "; drawer.AddDataAsSymble(strSymbolWell, "井点", false); strSymbolWell = @"Layer M 0 _Ellipse 0,0 0.5,0.5 0.5 4 "; drawer.AddDataAsSymble(strSymbolWell, "入靶点", false); strSymbolWell = @"Layer M 0 _Ellipse 0,0 0.5,0.5 0.5 4 "; drawer.AddDataAsSymble(strSymbolWell, "出靶点", false); } /// /// 设置进组的显示样式 /// /// 井组 private void setWellGroupStyle(DrawerWellGroup wellGroup) { // 设置井点样式 DrawerPointStyle ptstyleWell = new DrawerPointStyle(); ptstyleWell.AlignHorizion = (int)TextStyleFlags.alignCenterH; ptstyleWell.AlignVertical = (int)TextStyleFlags.alignTop; ptstyleWell.Offset = new PropertyPoint(0, 50); PropertySize txtSize = default(PropertySize); txtSize.Width = 100 * 0.4; txtSize.Height = 100; txtSize.FixScale = true; SizeF sizeSymbol = new SizeF(100f, 100f); ptstyleWell.TextSize = txtSize; ptstyleWell.SymbolSize = sizeSymbol; ptstyleWell.SymbolName = "井点"; wellGroup.WellPointStyle = ptstyleWell; // 设置井支入靶点和出靶点样式 DrawerPointStyle ptStart = ptstyleWell.Clone(); ptStart.Name = "start"; ptStart.SymbolName = "入靶点"; ptStart.SymbolSize = new SizeF((float)(sizeSymbol.Width * 0.5), (float)(sizeSymbol.Height * 0.5)); DrawerPointStyle ptEnd = ptstyleWell.Clone(); ptEnd.Name = "end"; ptEnd.SymbolName = "出靶点"; ptEnd.SymbolSize = new SizeF((float)(sizeSymbol.Width * 0.5), (float)(sizeSymbol.Height * 0.5)); DrawerCurveStyle drawerCurveStyleOffset = new DrawerCurveStyle(); drawerCurveStyleOffset.Name = "offset"; CurveProperty curvePropertyOffset = new CurveProperty(); curvePropertyOffset.Width = 5; curvePropertyOffset.LineColor = Color.Black; drawerCurveStyleOffset.Properties.Add(curvePropertyOffset); DrawerCurveStyle drawerCurveStyleHori = new DrawerCurveStyle(); drawerCurveStyleHori.Name = "horizon"; CurveProperty curvePropertyHori = new CurveProperty(); curvePropertyHori.Width = 5; curvePropertyHori.LineColor = Color.Black; drawerCurveStyleHori.Properties.Add(curvePropertyHori); List lineStyles = new List { drawerCurveStyleOffset, drawerCurveStyleHori }; int nBranchAllCount = wellGroup.WellBranches.Count; for (int i = 0; i < nBranchAllCount; i++) { WellBranch branch = wellGroup.WellBranches[i]; branch.PointStyles = new List { ptStart, ptEnd }; branch.PointStart.Name = $"{wellGroup.Name}-{i + 1}A"; branch.PointEnd.Name = $"{wellGroup.Name}-{i + 1}B"; branch.LineStyles = lineStyles; } } private void lsvHistory_ItemSelectionChanged(object sender, ListViewItemSelectionChangedEventArgs e) { if (lsvHistory.SelectedItems.Count > 0) { int nIndex = lsvHistory.SelectedItems[0].Index; if (caculator.CreatePlacementImage(nIndex, out Bitmap image, out string info)) { updateDeployImage(image, info); } //var shp = lsvHistory.SelectedItems[0].Tag as SheetPlacement; //nest.AssignPlacement(shp); //UpdatePreview(); } } private void writeUiSafe(string infor) { if(this.InvokeRequired) { Invoke(new Action(() => { writeUiSafe(infor); })); } else { stlInfor.Text = infor; if (stop) { this.btnStop.Text = "停止"; } if (this.btnPause.Text == "等待暂停") { this.btnPause.Text = "继续"; this.btnPause.Enabled = true; } } } internal void displayProgress(float progress) { if(this.InvokeRequired) { Invoke(new Action(() => { try { displayProgress(progress); } catch { } })); return; } int nValue = (int)Math.Round(progress * 100f); if ( nValue == 100) { nValue = 0; } toolStripProgressBar1.Value = nValue; toolStripProgressBar1.Control.CreateGraphics().DrawString($"{nValue}", this.Font, Brushes.Black, toolStripProgressBar1.Width/2, 2); // progressVal = progress; } private List loadShapesData(List wellGroups) { List rawDetails = new List(); foreach(DrawerWellGroup group in wellGroups) { LocalContour contour = CreateWellGroupBorder(group, this.partSpacing); RawDetail detail = new RawDetail(); if (group.Parameter.BranchCountLeft > 0 && group.Parameter.BranchCountRight > 0) { detail.Name = "双侧"; } else { detail.Name = "单侧"; } detail.Outers.Add(contour); rawDetails.Add(detail); } return rawDetails; } private static LocalContour CreateWellGroupBorder(DrawerWellGroup wellGroup, double spacing) { RectangleD rect = wellGroup.CaculateDataRange(); float dSpacing = (float)(spacing * 0.5); List shapePoints = new List(); shapePoints.AddRange(new PointF[5] { new PointF((float)rect.Left-dSpacing, (float)rect.Top-dSpacing), new PointF((float)rect.Right+dSpacing, (float)rect.Top-dSpacing), new PointF((float)rect.Right+dSpacing, (float)rect.Bottom+dSpacing), new PointF((float)rect.Left-dSpacing, (float)rect.Bottom+dSpacing), new PointF((float)rect.Left-dSpacing, (float)rect.Top-dSpacing), }); LocalContour contour = new LocalContour() { Points = shapePoints, }; return contour; } /// /// 加载井组的轮廓数据 /// /// /// private RawDetail loadWellGroupDetail(string layers) { RawDetail rawDetail = new RawDetail(); //DrawerData drawerDetail = new DrawerData(); //drawerDetail.OpenFile(mapFile); long[] laPos = this.drawer.SearchElementByType((int)DrawElementType.ELEMENT_WELL_GROUP); foreach(long pos in laPos) { NFP nfpHull = new NFP(); List lstPt= new List(); string strElementData = this.drawer.GetElementByPosition(pos); DrawerElementProperty property = DrawerElementHelp.Deserialize(strElementData); DrawerWellGroup wellGroup = property.Element as DrawerWellGroup; lstPt.Add(new SvgPoint(wellGroup.X, wellGroup.Y)); foreach (WellBranch branch in wellGroup.WellBranches) { lstPt.Add(new SvgPoint(branch.PointStart.X, branch.PointStart.Y)); lstPt.Add(new SvgPoint(branch.PointEnd.X, branch.PointEnd.Y)); } nfpHull.Points = lstPt; NFP hull = Background.getHull(nfpHull); LocalContour contourHull = new LocalContour(); contourHull.Points = new List(hull.Points.Select(it=>new PointF((float)it.x, (float)it.y))); rawDetail.Outers.Add(contourHull); } return rawDetail; } /// /// 加载线数据 /// /// /// private RawDetail loadLayersDetail(string layers) { string[] saFullLayers = Regex.Split(layers, ","); RawDetail rawDetail = new RawDetail(); DrawerData drawerDetail = new DrawerData(); drawerDetail.OpenFile(mapFile); // 遍历每一个图层 foreach (string layer in saFullLayers) { string curveData = string.Empty; int nCount = drawerDetail.LayerGetCurves(layer, ref curveData, false); if (nCount == 0) { continue; } DrawerElementHelp elementHelp = new DrawerElementHelp(); List propertys = elementHelp.DeserializeList(curveData); // 生成每一条线 foreach (DrawerElementProperty eleProperty in propertys) { DrawerPline blockLine = eleProperty.Element as DrawerPline; if (blockLine == null) { continue; } string[] saCoorLine = Regex.Split(blockLine.Coordinate, "\r\n"); if(saCoorLine.Length > 1) { // 生成每一个坐标点 List points = new List(); foreach (string strLine in saCoorLine) { string[] saCoor = strLine.Split(','); if( saCoor.Length > 1 ) { points.Add(new PointF(float.Parse(saCoor[0]), float.Parse(saCoor[1]))); } } if(points.Count > 0) { rawDetail.Outers.Add(new LocalContour() { Points = points }); } } } } drawerDetail.Dispose(); drawerDetail = null; return rawDetail; } /// /// 从文件加载线数据 /// /// /// private RawDetail loadDetail(string dataFile) { // 从文件加载边界 RawDetail detail = new RawDetail(); using (StreamReader sr = new StreamReader(dataFile, Encoding.Default)) { while (!sr.EndOfStream) { string strLine = sr.ReadLine(); if (string.IsNullOrEmpty(strLine)) { continue; } if (strLine.StartsWith("Pline", StringComparison.OrdinalIgnoreCase)) { List points = new List(); while (!sr.EndOfStream) { strLine = sr.ReadLine(); if (string.IsNullOrEmpty(strLine)) { detail.Outers.Add(new LocalContour() { Points = points }); break; ; } string[] saLine = strLine.Split(','); if (saLine.Length > 1) { points.Add(new PointF(float.Parse(saLine[0]), float.Parse(saLine[1]))); } } } } } return detail; } private void Form1_Load(object sender, EventArgs e) { Application.Idle += application_Idle; this.splitContainer2.FixedPanel = FixedPanel.Panel1; } private void application_Idle(object sender, EventArgs e) { CaculateStatus status = this.caculator.Status; switch (status) { case CaculateStatus.None: this.btnPlay.Enabled = true; this.btnPause.Enabled = false; this.btnStop.Enabled = false; this.btnOutput.Enabled = false; this.btnPause.Text = "暂停"; this.btnStop.Text = "停止"; break; case CaculateStatus.Pausing: this.btnPlay.Enabled = false; this.btnPause.Enabled = false; this.btnStop.Enabled = false; this.btnOutput.Enabled = false; this.btnPause.Text = "等待暂停"; this.btnStop.Text = "停止"; break; case CaculateStatus.Paused: this.btnPlay.Enabled = false; this.btnPause.Enabled = true; this.btnStop.Enabled = true; this.btnOutput.Enabled = true; this.btnPause.Text = "继续"; this.btnStop.Text = "停止"; break; case CaculateStatus.Stopping: this.btnPlay.Enabled = false; this.btnPause.Enabled = false; this.btnStop.Enabled = false; this.btnOutput.Enabled = false; this.btnPause.Text = "暂停"; this.btnStop.Text = "等待停止"; break; case CaculateStatus.Stopped: this.btnPlay.Enabled = true; this.btnPause.Enabled = false; this.btnStop.Enabled = false; this.btnOutput.Enabled = true; this.btnPause.Text = "暂停"; this.btnStop.Text = "停止"; break; case CaculateStatus.Working: this.btnPlay.Enabled = false; this.btnPause.Enabled = true; this.btnStop.Enabled = true; this.btnOutput.Enabled = false; this.btnPause.Text = "暂停"; this.btnStop.Text = "停止"; break; default: break; } //(status == CaculateStatus.None || status == CaculateStatus.Stopped) //{ // this.btnPlay.Enabled = true; //} //if (this.btnStop.Text == "等待停止") //{ // this.btnPlay.Enabled = false; //} //else //{ // this.btnPlay.Enabled = this.stop; //} //this.btnOutput.Enabled = (this.stop||this.btnPause.Text == "继续") // && (nest != null && nest.PlacedPartsCount > 0)&& this.btnStop.Text!="等待停止"; //this.btnStop.Enabled = !this.stop; //if(this.stop) //{ // this.btnPause.Enabled = false; //} //txtRotationTimes.Enabled = this.rdbRotationTimes.Checked; //this.txtAngleStart.Enabled = this.rdbRotationTimes.Checked; //this.txtAngleEnd.Enabled = this.rdbRotationTimes.Checked; //txtRotationAngles.Enabled = this.rdbRotationAngles.Checked; } private double CaculateLineLength(PathD path) { if(path.Count<2) return 0; double dTotal = 0; Clipper2Lib.PointD ptLast = path[0]; for(int i=1; i