public void UnboundLine(MyLine tempLine) { int currentModel = this.parent.GetCurrentModelIndex(); MyFiniteElementModel model = this.parent.currentFullModel.FiniteElementModels[currentModel]; List <MyNode> nodes = new List <MyNode>(); if (tempLine is MyStraightLine) { nodes = model.Nodes.FindAll(node => Mathematics.pointOnLine(node.X, node.Y, (MyStraightLine)tempLine) && model.INOUT[node.Id] != 0); } else { double precision = (model.baseType == MyFiniteElementModel.GridType.Delauney || model.type == MyFiniteElementModel.GridType.FrontalMethod) ? 0.01 : -1; nodes = model.Nodes.FindAll(node => Mathematics.pointFitsArc(node, (MyArc)tempLine, precision) && model.INOUT[node.Id] != 0); } foreach (MyNode node in nodes) { UnboundNode(node); } // сохраняем закрепления в массив NFIX renewNfixNB(currentModel); this.parent.DrawFEBounds(Color.Brown); this.txtLine.Text = ""; this.txtLine.Select(); }
public void BoundLine(MyLine tempLine) { int currentModel = this.parent.GetCurrentModelIndex(); MyFiniteElementModel model = this.parent.currentFullModel.FiniteElementModels[currentModel]; this.errorNoLine.Visible = false; tempLine.BoundType = GetBoundType(); List <MyNode> nodes = new List <MyNode>(); if (tempLine is MyStraightLine) { nodes = model.Nodes.FindAll(node => Mathematics.pointOnLine(node.X, node.Y, (MyStraightLine)tempLine) && model.INOUT[node.Id] != 0); } else { MyArc a = tempLine as MyArc; double r = Mathematics.FindDist(a.CenterPoint, a.StartPoint); double precision = NewMethod(model); nodes = model.Nodes.FindAll(node => Mathematics.pointFitsArc(node, (MyArc)tempLine, precision) && model.INOUT[node.Id] != 0); } foreach (MyNode node in nodes) { BoundNode(node, tempLine.BoundType); } // сохраняем закрепления в массив NFIX renewNfixNB(currentModel); this.parent.DrawFEBounds(Color.Brown); this.txtLine.Text = ""; this.txtLine.Select(); }
private void button1_Click(object sender, EventArgs e) { if (textBox1.Text == string.Empty) { return; } this.parent.precision = this.parent.DefinePrecision(); this.parent.showForces.Checked = true; int number; int currentModel = this.parent.GetCurrentModelIndex(); MyFiniteElementModel model = this.parent.currentFullModel.FiniteElementModels[currentModel]; MyLine lineToForces; bool error = false; if (!int.TryParse(this.textBox1.Text, out number)) { error = true; } lineToForces = parent.currentFullModel.geometryModel.Lines.Find(l => l.Id == number); if (lineToForces == null) { error = true; } if (error) { return; } UnboundLine(lineToForces); parent.ReDrawAll(); }
private void okButton_Click(object sender, EventArgs e) { List <string> lineNumbers = new List <string>(this.notMoveLines.Text.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries).ToList <string>()); List <MyLine> fixedLines = new List <MyLine>(); if (gridName.Text == string.Empty) { MessageBox.Show("Имя сетки не может быть пустым!"); return; } foreach (string str in lineNumbers) { int idx; if (!int.TryParse(str, out idx)) { MessageBox.Show("Неверно заданы линии!"); return; } MyLine line = parent.currentFullModel.geometryModel.Lines.Find(l => l.Id == idx); if (line == null) { MessageBox.Show("Не найдена линия с номером " + idx.ToString()); return; } fixedLines.Add(line); } parent.precision = parent.DefinePrecision(); if (parent.currentFullModel.geometryModel.Areas.Count != 0) { errorMessage1.Visible = false; errorBadGridName.Visible = false; // создаем новый объект "конечно-элементная модель" и добавляем его в список конечно-элементных моделей. foreach (MyFiniteElementModel model in parent.currentFullModel.FiniteElementModels) // проверяем, нет ли модели с таким именем { if (model.ModelName == gridName.Text) { errorBadGridName.Visible = true; return; } } // создаем для новой КЭ модели id int id = parent.currentFullModel.IdCandidate; currentModel = (MyFiniteElementModel)Util.getObjectCopy(currentModel); currentModel.ModelName = gridName.Text; currentModel.Id = id; currentModel.type = MyFiniteElementModel.GridType.Ruppert; currentModel.restoreArraysForOldMethods(parent.currentFullModel.geometryModel); parent.clearSelection(); parent.ReDrawAll(); this.Hide(); Optimize(fixedLines); } else { errorMessage1.Visible = true; } }
public void DrawFE(MyFiniteElementModel model, Color color, bool showFEnumbers = true, bool showFEnodeNumbers = true, bool showMaterials = false) { DrawElements(model.FiniteElements.ToArray(), color, showFEnumbers, showMaterials); if (showFEnodeNumbers) { Gl.glColor3dv(colorArray(Color.Green)); model.Nodes.ForEach(n => DrawString(n.Id.ToString(), (float)n.X, (float)n.Y)); FlushText(Color.Green); } }
public Regularization(ProjectForm parent) { InitializeComponent(); this.parent = parent; currentModel = parent.currentFullModel.FiniteElementModels[this.parent.GetCurrentModelIndex()]; currentModelIndex = parent.currentFullModel.FiniteElementModels.Count; gridName.Text = "Сетка №" + (currentModelIndex + 1).ToString(); TopMost = true; }
public Delauney(ProjectForm parent) { InitializeComponent(); this.parent = parent; currentModel = parent.currentFullModel.FiniteElementModels.Find(m => m.ModelName == parent.currentFullModel.currentGridName); gridName.Text = "Сетка №" + (parent.currentFullModel.IdCandidate).ToString(); ddlTriangulationMethod.SelectedIndex = ddlGenerationMethod.SelectedIndex = 0; if (parent.currentFullModel.FiniteElementModels.Count == 0) { ddlGenerationMethod.Items.RemoveAt(4); } settingsForm = new DelauneySettings(parent); settingsForm.FormClosing += new FormClosingEventHandler(settingsForm_FormClosing); }
private void fillObjectsFromArrays(MyFiniteElementModel model, List <double> CORDD, List <int> NOP, int MAXNP, int NEL, int zonesCount) { model.FiniteElements.Clear(); model.Nodes.Clear(); for (int i = 1; i <= MAXNP; i++) // MAXNP - число узлов { model.Nodes.Add(new MyNode(CORDD[2 * (i - 1) + 1], CORDD[2 * (i - 1) + 2], i)); } model.IMAT.Clear(); for (int i = 0; i <= NEL; i++) { model.IMAT.Add(0); } int numOfFe = 0; List <MyNode> tempNodes = new List <MyNode>(); int elemsPerZone = NEL / zonesCount; for (int temp = 1; temp <= NEL; temp++) { double X1 = CORDD[2 * (NOP[3 * (temp - 1) + 1] - 1) + 1]; double Y1 = CORDD[2 * (NOP[3 * (temp - 1) + 1] - 1) + 2]; double X2 = CORDD[2 * (NOP[3 * (temp - 1) + 2] - 1) + 1]; double Y2 = CORDD[2 * (NOP[3 * (temp - 1) + 2] - 1) + 2]; double X3 = CORDD[2 * (NOP[3 * (temp - 1) + 3] - 1) + 1]; double Y3 = CORDD[2 * (NOP[3 * (temp - 1) + 3] - 1) + 2]; tempNodes.AddRange(model.Nodes.FindAll(node => Math.Abs(node.X - X1) <= 0.001 && Math.Abs(node.Y - Y1) <= 0.001 || Math.Abs(node.X - X2) <= 0.001 && Math.Abs(node.Y - Y2) <= 0.001 || Math.Abs(node.X - X3) <= 0.001 && Math.Abs(node.Y - Y3) <= 0.001)); model.FiniteElements.Add(new MyFiniteElement(++numOfFe, 0, tempNodes, (temp - 1) / elemsPerZone)); tempNodes.Clear(); } // сохраняем число КЭ model.NE = NEL; // сохраняем NP model.NP = MAXNP; // сохраняем массив CORD model.CORD = new List <double>(CORDD); // сохраняем массив NOP model.NOP = new List <int>(NOP); }
public RuppertForm(ProjectForm parent) { InitializeComponent(); this.parent = parent; if (this.parent.currentFullModel.FiniteElementModels.Count == 0) { MessageBox.Show("Нельзя экспортировать модель в систему Рапперта, пока она не разбита на КЭ!"); Close(); } currentModel = parent.currentFullModel.FiniteElementModels[parent.GetCurrentModelIndex()]; currentModelIndex = parent.currentFullModel.FiniteElementModels.Count; gridName.Text = "Рапперт_Сетка №" + (currentModelIndex + 1).ToString(); TopMost = true; }
public int[] Get_Star(int IND, MyFiniteElementModel model) { //C Содержит подпрограмму GET_STAR //C ============================================================= //C формирование массива КЭ, сост-щих звезду оптимизируемого КЭ //C Вызывается из REGULARIZATION, вызываемых модулей нет //C ============================================================= //C входные параметры: //C IND - номер рассматриваемого узла //C NOPT - массив номеров узлов, сост-щих элементы //C NUMOFELT - число элементов //C выходные параметры: //C ITSTAR - массив номеров узлов, сост-щих элементы звезды //C NSTAREL - число элементов звезды //C ============================================================= //C =============== начало кода GET_STAR ========================= //C ============================================================= int NODELS, JGT; int NSTAREL = 0; List <int> nodePoints = model.NOP; NODELS = 3; JGT = 1; List <int> Indexes = new List <int>(); int index = -1; while ((index = nodePoints.IndexOf(IND, index + 1)) != -1) { Indexes.Add(index - 1); } int[] ITSTAR = new int[Indexes.Count * 3 + 1]; foreach (int elemIndex in Indexes) { int elemNumber = (elemIndex / NODELS); ITSTAR[NODELS * (JGT - 1) + 1] = nodePoints[NODELS * (elemNumber) + 1]; ITSTAR[NODELS * (JGT - 1) + 2] = nodePoints[NODELS * (elemNumber) + 2]; ITSTAR[NODELS * (JGT - 1) + 3] = nodePoints[NODELS * (elemNumber) + 3]; JGT++; } //* запоминаем число элементов звезды return(ITSTAR); }
private void renewNfixNB(int modelIndex) { parent.showBounds.Checked = true; MyFiniteElementModel currentModel = parent.currentFullModel.FiniteElementModels[modelIndex]; currentModel.NBC.Clear(); currentModel.NFIX.Clear(); currentModel.NBC.Add(0); currentModel.NFIX.Add(0); List <MyNode> boundedNodes = currentModel.Nodes.FindAll(n => n.BoundType != 0); foreach (MyNode node in boundedNodes) { currentModel.NFIX.Add(node.BoundType); currentModel.NBC.Add(node.Id); } currentModel.NB = boundedNodes.Count; }
private void okButton_Click(object sender, EventArgs e) { List <string> lineStrings = new List <string>(this.notMoveLines.Text.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries).ToList <string>()); List <MyLine> fixedLines = new List <MyLine>(); if (gridName.Text == string.Empty) { MessageBox.Show("Имя сетки не может быть пустым!"); return; } foreach (string str in lineStrings) { int idx; if (!int.TryParse(str, out idx)) { MessageBox.Show("Неверно заданы линии!"); return; } MyLine line = parent.currentFullModel.geometryModel.Lines.Find(l => l.Id == idx); if (line == null) { MessageBox.Show("Не найдена линия с номером " + idx.ToString()); return; } fixedLines.Add(line); } parent.precision = parent.DefinePrecision(); if (parent.currentFullModel.geometryModel.Areas.Count != 0) { errorMessage1.Visible = false; errorBadGridName.Visible = false; // создаем новый объект "конечно-элементная модель" и добавляем его в список конечно-элементных моделей. foreach (MyFiniteElementModel model in parent.currentFullModel.FiniteElementModels) // проверяем, нет ли модели с таким именем { if (model.ModelName == gridName.Text) { errorBadGridName.Visible = true; return; } } // создаем для новой КЭ модели id int id = parent.currentFullModel.IdCandidate; currentModel = (MyFiniteElementModel)Util.getObjectCopy(currentModel); currentModel.ModelName = gridName.Text; currentModel.Id = id; currentModel.restoreArraysForOldMethods(parent.currentFullModel.geometryModel); List <MyNode> dontMove = new List <MyNode>(); for (int i = 1; i < currentModel.INOUT.Count; i++) { if (currentModel.INOUT[i] == 0) { continue; } MyNode node = currentModel.Nodes.Find(n => n.Id == i); if (node != null) { dontMove.Add(node); } } foreach (MyLine line in fixedLines) { if (line is MyStraightLine) { dontMove.AddRange(findNodesAtStraightLine(line as MyStraightLine)); } else { dontMove.AddRange(findNodesAtArc(line as MyArc)); } } Regularize(dontMove); parent.clearSelection(); parent.ModelCreated(currentModel); Close(); } else { errorMessage1.Visible = true; } }
private static double NewMethod(MyFiniteElementModel model) { return((model.baseType == MyFiniteElementModel.GridType.Delauney || model.type == MyFiniteElementModel.GridType.FrontalMethod) ? 0.01 : -1); }
private void btnOk_Click(object sender, EventArgs e) { string modelName = gridName.Text; int elemId = 0; errorBadGridName.Visible = false; if (gridName.Text == string.Empty) { MessageBox.Show("Имя сетки не может быть пустым!"); return; } if (parent.currentFullModel.FiniteElementModels.Find(m => m.ModelName == modelName) != null) { errorBadGridName.Visible = true; return; } if (ddlGenerationMethod.SelectedIndex == -1) { MessageBox.Show("Не задан метод генерации точек!"); return; } this.Hide(); parent.StartProgress("Построение сетки"); List <MyFrontSegment> segments = new List <MyFrontSegment>(); nodesCount = 0; MyFiniteElementModel newModel = new MyFiniteElementModel(parent.currentFullModel.IdCandidate, gridName.Text, MyFiniteElementModel.GridType.Normal); // если выбрана триангуляция на основе существующих узлов if (ddlGenerationMethod.SelectedIndex == 4) { List <MyFiniteElement> elems = GetTriangulation(currentModel.Nodes); newModel.Nodes.AddRange(currentModel.Nodes); newModel.Nodes.ForEach(n => n.finiteElements.Clear()); foreach (MyFiniteElement elem in elems) { double cx = elem.Nodes.Sum(s => s.X) / 3; double cy = elem.Nodes.Sum(s => s.Y) / 3; foreach (MyArea area in parent.currentFullModel.geometryModel.Areas) { //if (Mathematics.ContainsPoint(area.Nodes, cx, cy)) if (PointFits(area, new List <MyNode>(), new MyPoint(cx, cy), double.MinValue)) { elem.Id = ++elemId; elem.areaId = area.Id; elem.LinkNodes(); newModel.FiniteElements.Add(elem); break; } } } } // любая другая триангуляция else { foreach (MyArea area in parent.currentFullModel.geometryModel.Areas) { List <MyNode> result = new List <MyNode>(); for (int j = 0; j < 4; j++) { int neighbor = parent.currentFullModel.geometryModel.joinTable[area.Id - 1, j] - 1; if (neighbor != -1) { if (neighbor < area.Id - 1) { List <MyLine> lines = area.Lines.FindAll(l => l.Areas.Contains(area.Id) && l.Areas.Contains(neighbor + 1)); foreach (MyLine line in lines) { if (line is MyStraightLine) { result.AddRange(findNodesAtStraightLine(segments[neighbor].Nodes, line as MyStraightLine)); } else { result.AddRange(findNodesAtArc(segments[neighbor].Nodes, line as MyArc)); } } } } } result = result.Distinct().ToList(); double h = (double)nudMinDistance.Value; foreach (MyPoint p in area.Nodes) { if (result.Find(n => Mathematics.sameNode(n, p)) == null) { result.Add(new MyNode(p.X, p.Y, ++nodesCount)); } } GeneratePoints(area, result); MyFrontSegment seg = new MyFrontSegment(area); seg.Nodes = result; segments.Add(seg); AddNodesFromCommonLine(seg, segments); } elemId = 0; if (ddlGenerationMethod.SelectedIndex == 1) { GenerateNodesInDensitySectors(segments); } foreach (MyFrontSegment seg in segments) { foreach (MyNode node in seg.Nodes) { if (!newModel.Nodes.Contains(node)) { newModel.Nodes.Add(node); } } } if (ddlGenerationMethod.SelectedIndex == 1) { foreach (MyFiniteElement elem in GetTriangulation(newModel.Nodes)) { double cx = elem.Nodes.Sum(s => s.X) / 3; double cy = elem.Nodes.Sum(s => s.Y) / 3; foreach (MyArea area in parent.currentFullModel.geometryModel.Areas) { //if (Mathematics.ContainsPoint(area.Nodes, cx, cy)) if (PointFits(area, new List <MyNode>(), new MyPoint(cx, cy), 0.001)) { elem.Id = ++elemId; elem.LinkNodes(); newModel.FiniteElements.Add(elem); break; } } } } else { foreach (MyFrontSegment seg in segments) { foreach (MyFiniteElement elem in GetTriangulation(seg.Nodes, seg.CorrespondingArea.Id)) { double cx = elem.Nodes.Sum(s => s.X) / 3; double cy = elem.Nodes.Sum(s => s.Y) / 3; MyArea area = parent.currentFullModel.geometryModel.Areas[segments.IndexOf(seg)]; //if (PointFits(Mathematics.ContainsPoint(area.Nodes, cx, cy)) if (PointFits(area, new List <MyNode>(), new MyPoint(cx, cy), 0.001)) { elem.Id = ++elemId; elem.LinkNodes(); seg.finiteElems.Add(elem); } } newModel.FiniteElements.AddRange(seg.finiteElems); } } } newModel.baseType = newModel.type = MyFiniteElementModel.GridType.Delauney; parent.currentFullModel.densityPoints.Clear(); parent.EndProgress(); parent.ModelCreated(newModel); Close(); // создаем для новой КЭ модели id }
public void DrawForces(MyFiniteElementModel model, double scale, Color color, bool showValues = true) { MyNode[] forcedNodes = model.Nodes.FindAll(n => n.ForceX != 0.0 || n.ForceY != 0.0).ToArray(); int nodesCount = forcedNodes.Length; if (nodesCount == 0) { return; } int count = 6 * nodesCount; float[] pts = new float[count * 2]; Gl.glColor3dv(colorArray(color)); for (int i = 0; i < nodesCount; i++) { MyNode node = forcedNodes[i]; // силу будем рисовать, как линию со стрелочкой на конце. Если сила > 0, то она идет вверх или вправо ( зависит от нагрузки - по X или по Y) // плюс, надо еще масштабировать длину стрелки // координаты начальной и конечной точки в пикселях float forceLengthX = (float)node.ForceX; float forceLengthY = (float)node.ForceY; float x1 = (float)node.X; float y1 = (float)node.Y; float x2 = x1 + forceLengthX * (float)scale; // масштабируем длину стрелки float y2 = y1 + forceLengthY * (float)scale; // масштабируем длину стрелки pts[(i * 12)] = x1; pts[(i * 12) + 1] = y1; pts[(i * 12) + 2] = x2; pts[(i * 12) + 3] = y2; // вычисляем угол нагрузки float alfa = (float)Math.Atan2(y2 - y1, x2 - x1); // длина стрелочки float aSize = (float)Math.Pow(((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1)), 0.5) / 10.0f; float px1 = x2; float py1 = y2; float px2 = (float)(x2 - aSize * Math.Cos(alfa + 15.0 * (Math.PI / 180.0))); float py2 = (float)(y2 - aSize * Math.Sin(alfa + 15.0 * (Math.PI / 180.0))); float px3 = (float)(x2 - aSize * Math.Cos(alfa - 15.0 * (Math.PI / 180.0))); float py3 = (float)(y2 - aSize * Math.Sin(alfa - 15.0 * (Math.PI / 180.0))); pts[(i * 12) + 4] = px1; pts[(i * 12) + 5] = py1; pts[(i * 12) + 6] = px2; pts[(i * 12) + 7] = py2; pts[(i * 12) + 8] = px1; pts[(i * 12) + 9] = py1; pts[(i * 12) + 10] = px3; pts[(i * 12) + 11] = py3; if (showValues) { float f = (float)Math.Pow((Math.Pow(node.ForceX, 2) + Math.Pow(node.ForceY, 2)), 0.5); double fRound = Mathematics.floor(f, Mathematics.accuracy_medium); DrawString(fRound.ToString(), x2, y2, true); } } int list; list = Gl.glGenLists(1); Gl.glNewList(list, Gl.GL_COMPILE); Gl.glColor3dv(colorArray(color)); Gl.glLineWidth(1.0f); Gl.glEndList(); drawBuffer.Add(new DrawingOperation(Gl.GL_LINES, pts, list)); if (showValues) { FlushText(color); } }
private void btnStatistics_Click(object sender, EventArgs e) { MyFiniteElementModel currentModel = parent.currentFullModel.FiniteElementModels.Find(m => m.ModelName == parent.currentFullModel.currentGridName); StringBuilder stats = new StringBuilder(); stats.AppendLine("Статистика по сетке: " + currentModel.ModelName + "."); stats.AppendLine(); stats.AppendLine("Заданные параметры:"); stats.AppendLine("Минимально допустимый угол: " + MinAllowAngle); stats.AppendLine("Максимально допустимый угол: " + MaxAllowAngle); stats.AppendLine("Минимально допустимая площадь: " + MinAllowSquare); stats.AppendLine(); stats.AppendLine("Всего конечных элементов: " + currentModel.Nodes.Count); int badMinAngle = 0, badMaxAngle = 0, badSquare = 0, badAngles = 0; double minAngle = double.MaxValue, maxAngle = double.MinValue, minSquare = double.MaxValue, maxSquare = double.MinValue;; int minAngleElem = 0, maxAngleElem = 0, minSquareElem = 0, maxSquareElem = 0; foreach (MyFiniteElement elem in currentModel.FiniteElements) { double[] angles = Mathematics.getFEangles(elem); double max = angles.Max(); double min = angles.Min(); if (max > MaxAllowAngle || min < MinAllowAngle) { badAngles++; if (max > MaxAllowAngle) { badMaxAngle++; } else { badMinAngle++; } } if (max > maxAngle) { maxAngle = max; maxAngleElem = elem.Id; } if (min < minAngle) { minAngle = min; minAngleElem = elem.Id; } double sqr = Mathematics.GeronLaw(elem.Nodes); if (sqr < MinAllowSquare) { badSquare++; if (sqr < minSquare) { minSquare = sqr; minSquareElem = elem.Id; } } if (sqr > maxSquare) { maxSquare = sqr; maxSquareElem = elem.Id; } } int elemCount = currentModel.FiniteElements.Count; string percentBadAngles = String.Format(" ({0:##0.##}% от общего числа).", (1.0 * badAngles / elemCount) * 100); string percentBadMinAngles = String.Format(" ({0:##0.##}% от общего числа).", (1.0 * badMinAngle / elemCount) * 100); string percentBadMaxAngles = String.Format(" ({0:##0.##}% от общего числа).", (1.0 * badMaxAngle / elemCount) * 100); string percentBadSquare = String.Format(" ({0:##0.##}% от общего числа).", (1.0 * badSquare / elemCount) * 100); stats.AppendLine("Из них содержат недопустимых углов: " + badAngles + percentBadAngles); stats.AppendLine("Элементов с углом меньше допустимого: " + badMinAngle + percentBadMinAngles); stats.AppendLine("Элементов с углом больше допустимого: " + badMaxAngle + percentBadMaxAngles); stats.AppendLine("Минимальный угол: " + minAngle.ToString("##0.##") + ", в элементе: " + minAngleElem + "."); stats.AppendLine("Максимальный угол: " + maxAngle.ToString("##0.##") + ", в элементе: " + maxAngleElem + "."); stats.AppendLine(); stats.AppendLine("Элементов с площадью меньше допустимой: " + badSquare + percentBadSquare); stats.AppendLine("Минимальная площадь: " + minSquare.ToString("##0.00") + ", у элемента: " + minSquareElem); stats.AppendLine("Максимальная площадь: " + maxSquare.ToString("##0.00") + ", у элемента: " + maxSquareElem); GridAnalysisStatistics statForm = new GridAnalysisStatistics(); statForm.StatText = stats.ToString(); statForm.ShowDialog(); }
public int Griddm(int NRC, int boundaryPointsCount, int zonesCount, int NMAT, int NCN, MyFiniteElementModel newModel) { // Эти массивы используются при обходе зон для извлечения координат узлов, образующих каждую из зон double[] areaNodesX = new double[10]; double[] areaNodesY = new double[10]; // функции формы для квадратичного четырехугольника double[] formFunctions = new double[9]; // номера узлов, определяющих зону int[] definingNodesNumbers = new int[9]; // ? int[] LB = new int[4]; double[] CORD = new double[4]; double[] CORD1 = new double[4]; // номера узлов зоны int[,] nodeNumbers = new int[53, 53]; // видимо, номера элементов int[] NE = new int[601]; double[] xElem = new double[601]; double[] yElem = new double[601]; int[] NR = new int[5]; // координаты X и Y узлов зоны double[,] xCord = new double[53, 53]; double[,] yCord = new double[53, 53]; // трехмерный массив номеров узлов, находящихся на границе. По индексам: 1 - зона, 2 - сторона, 3 - номер узла int[, ,] boundaryNodesNumbers = new int[101, 5, 53]; // Матрица данных о соединениях зон. Строка i = номер зоны, столбец j = номер стороны, элемент на пересечении - граничащая с зоной i зона по стороне j int[,] joinTable = new int[101, 5]; // ооох. int[,] ICOMP = { { 0, 0, 0, 0, 0 }, { 0, -1, 1, 1, -1 }, { 0, 1, -1, -1, 1 }, { 0, 1, -1, -1, 1 }, { 0, -1, 1, 1, -1 } }; double[] GLOB = { 0.0, 0.0, -1.0, 3.0, 0.0, -5.0, -1.0, 0.0, 3.0, 0.0 }; List <double> CORDD = new List <double>(); List <int> NOP = new List <int>(); //List<int> INOUT = new List<int>(); int NUMOFELEM; int NBW = 0; int NB = 0; int NEL = 0; int TR; double DETA, DSI, ETA, SI, DIAG1, DIAG2; int KN1, KN2, KS1, KS2, neighborArea, JL, JK, K, L, NELBW; int neighborAreaSide = 0; int J1 = 0; int J2 = 0; int J3 = 0; /*формируем массив joinTable*/ for (int i = 1; i <= 100; i++) { for (int j = 1; j <= 4; j++) { joinTable[i, j] = this.parent.currentFullModel.geometryModel.joinTable[i - 1, j - 1]; } } /*формируем массив areaDefiningNodes*/ int p = 1; foreach (MyArea area in this.parent.currentFullModel.geometryModel.Areas) { for (int i = 1; i <= 8; i++) { newModel.areaDefiningNodes[i, p] = area.Nodes[i - 1].Id; } p++; } /*формируем массив XP и YP. Массивы глобальных координат точек, образующих зоны */ List <MyPoint> nodes = new List <MyPoint>(); foreach (MyArea area in this.parent.currentFullModel.geometryModel.Areas) { for (int i = 1; i <= 8; i++) { if (nodes.IndexOf(area.Nodes[i - 1]) == -1) { nodes.Add(area.Nodes[i - 1]); } } } newModel.XP.Add(0); newModel.YP.Add(0); for (int i = 1; i <= nodes.Count; i++) { newModel.XP.Add(nodes[i - 1].X); newModel.YP.Add(nodes[i - 1].Y); } // подсчет количества элементов. NUMOFELEM = NRC * NRC * zonesCount - NRC * (zonesCount - 1); for (int i = 0; i <= NUMOFELEM; i++) { newModel.INOUT.Add(1); } int MAXNP = 1; int nodeRowsCount, nodeColsCount; for (int i = 0; i <= NUMOFELEM * NCN * 2; i++) { CORDD.Add(0.0); NOP.Add(0); } for (int zoneNumber = 1; zoneNumber <= zonesCount; zoneNumber++) { Application.DoEvents(); // рассматриваемая зона - zoneNumber // количество рядов и строк в будущей сетке nodeRowsCount = NRC; nodeColsCount = NRC; // выбираем точки, образующие текущую зону for (int i = 1; i <= 8; i++) { definingNodesNumbers[i] = newModel.areaDefiningNodes[i, zoneNumber]; } // генерация сетки КЭ // записываем координаты граничных узлов зоны в массивы areaNodes for (int i = 1; i <= 8; i++) { int nodeNumber = definingNodesNumbers[i]; areaNodesX[i] = newModel.XP[nodeNumber]; areaNodesY[i] = newModel.YP[nodeNumber]; } areaNodesX[9] = areaNodesX[1]; areaNodesY[9] = areaNodesY[1]; // вычисления шага сетки TR = nodeRowsCount - 1; // по сути nrc-1 // буквы D в названии переменных обозначают шаг (по аналогии с dx и т.п.), т.е. DETA - это величина, на которую изменяется ETA DETA = 2.0 / TR; // видимо, этот коэффициент определяет расстояние между узлами на сторонах зоны // Зона состоит из 8 узлов и за исходное расстояние принимается расстояние между двумя соседними узлами (не путать с узлами сетки!) // При умножении этого расстояния на коэффициенты DETA и DSI, получим реальный шаг распределения узлов. // например, для NRC = 5 получим DETA = DSI = 2.0/4 = 1/2, тоесть необходимо расставить узлы сетки // на стороне зоны с шагом 0.5 от исходного расстояния между узлами зоны TR = nodeColsCount - 1; // то же DSI = 2.0 / TR; for (int i = 1; i <= nodeRowsCount; i++) { // Дальше используются хитрые коэффициенты ETA и SI. Смысл в следующем: разбивая четырехугольник на 4 части, примем координаты пересечения // его центральных линий за (0; 0), координаты его граничных узлов за (-1, -1), (1, -1), (1, 1), (-1, 1). // Тогда Координаты каждого из узлов будут отличаться друг от друга на величину {±DSI, ±DETA} и получится равномерная сетка в пределах четырехгранника. // Суть дальнейших махинаций - в преобразовании координат каждого узла из системы координат нашего четырехугольника // к глобальным координатам TR = i - 1; ETA = 1.0 - TR * DETA; // координата y текущего узла в системе координат четырехугольника for (int j = 1; j <= nodeColsCount; j++) { TR = j - 1; SI = -1.0 + TR * DSI;// координата x текущего узла в системе координат четырехугольника // Функции формы квадратичного четырехугольника. Будут использоватсья для получения угловых координат элементов // Комментарии по поводу того, откуда это все берется, заняли бы больше, чем сама подпрограмма. // Жаждущие знаний могут обратиться к циклу статей http://www.exponenta.ru/soft/mathemat/pinega/a1/a1.asp formFunctions[1] = -0.25 * (1.0 - SI) * (1.0 - ETA) * (SI + ETA + 1.0); formFunctions[2] = 0.50 * (1.0 - SI * SI) * (1.0 - ETA); formFunctions[3] = 0.25 * (1.0 + SI) * (1.0 - ETA) * (SI - ETA - 1.0); formFunctions[4] = 0.50 * (1.0 + SI) * (1.0 - ETA * ETA); formFunctions[5] = 0.25 * (1.0 + SI) * (1.0 + ETA) * (SI + ETA - 1.0); formFunctions[6] = 0.50 * (1.0 - SI * SI) * (1.0 + ETA); formFunctions[7] = .25 * (1.0 - SI) * (1.0 + ETA) * (ETA - SI - 1.0); formFunctions[8] = 0.50 * (1.0 - SI) * (1.0 - ETA * ETA); // обнуление начальных координат определяемого узла xCord[i, j] = 0.0; yCord[i, j] = 0.0; // вычисляются координаты узлов сетки // в формировании координаты нового узла участвуют все восемь // базовых (образующих зону) узлов, координаты каждого из которых // умножаются на коэффицент, соответсвующий номеру узла в зоне // по сути - афинное преобразование координат. for (int k = 1; k <= 8; k++) { xCord[i, j] = xCord[i, j] + areaNodesX[k] * formFunctions[k]; yCord[i, j] = yCord[i, j] + areaNodesY[k] * formFunctions[k]; } Application.DoEvents(); } } KN1 = 1; KS1 = 1; KN2 = nodeRowsCount; KS2 = nodeColsCount; for (int i = 1; i <= 4; i++) { // перебор связей текущей зоны с другими neighborArea = joinTable[zoneNumber, i]; // На каждом этапе нас интересуют только те зоны, граничащие с данной, которые уже разбиты на КЭ // Отсюда условие: если со стороны i зона не граничит с другими зонами (neighborArea = 0) // или номер смежной зоны больше чем рассматриваемой, переходим к следующей стороне if (neighborArea == 0 || neighborArea > zoneNumber) { continue; } else { for (int j = 1; j <= 4; j++) { // запоминаем номер стороны соседней зоны, по которой она граничит с нашей if (joinTable[neighborArea, j] == zoneNumber) { neighborAreaSide = j; } } K = nodeColsCount; if (i == 2 || i == 4) { K = nodeRowsCount; } JL = 1; // I - номер смежной стороны рассм зоны, // neighborAreaSide - номер смежной стороны текущей зоны JK = ICOMP[i, neighborAreaSide]; if (JK == -1) { JL = K; } for (int j = 1; j <= K; j++) { switch (i) { case 1: nodeNumbers[nodeRowsCount, j] = boundaryNodesNumbers[neighborArea, neighborAreaSide, JL]; // узлы на стыке двух зон - внутренние if (j != 1 && j != nodeColsCount) { newModel.INOUT[nodeNumbers[nodeRowsCount, j]] = 0; } KN2 = nodeRowsCount - 1; break; case 2: nodeNumbers[j, nodeColsCount] = boundaryNodesNumbers[neighborArea, neighborAreaSide, JL]; // узлы на стыке двух зон - внутренние if (j != 1 && j != nodeRowsCount) { newModel.INOUT[nodeNumbers[j, nodeColsCount]] = 0; } KS2 = nodeColsCount - 1; break; case 3: nodeNumbers[1, j] = boundaryNodesNumbers[neighborArea, neighborAreaSide, JL]; // узлы на стыке двух зон - внутренние if (j != 1 && j != nodeColsCount) { newModel.INOUT[nodeNumbers[1, j]] = 0; } KN1 = 2; break; case 4: nodeNumbers[j, 1] = boundaryNodesNumbers[neighborArea, neighborAreaSide, JL]; // узлы на стыке двух зон - внутренние if (j != 1 && j != nodeRowsCount) { newModel.INOUT[nodeNumbers[j, 1]] = 0; } KS1 = 2; break; } JL = JL + JK; } } } if (KN1 > KN2) { } else if (KS1 > KS2) { } else { for (int i = KN1; i <= KN2; i++) { int j; for (j = KS1; j <= KS2; j++) { NB = NB + 1; nodeNumbers[i, j] = NB; } } for (int i = 1; i <= nodeColsCount; i++) { boundaryNodesNumbers[zoneNumber, 1, i] = nodeNumbers[nodeRowsCount, i]; boundaryNodesNumbers[zoneNumber, 3, i] = nodeNumbers[1, i]; } for (int i = 1; i <= nodeRowsCount; i++) { boundaryNodesNumbers[zoneNumber, 2, i] = nodeNumbers[i, nodeColsCount]; boundaryNodesNumbers[zoneNumber, 4, i] = nodeNumbers[i, 1]; } } /* < Определение внешних и внутренних узлов * формируется массив INOUT: если узел внутренний, то соответсвующий * элемент INOUT равен 0, если внешний - 1. * все неграничные узлы внутренние; * если сторона зоны смежна с другой зоной, узлы на этой стороне, * кроме угловых, тоже внутренние. * узлы не на границе зоны - внутренние */ try { for (int INODE = 2; INODE <= nodeRowsCount - 1; INODE++) { for (int JNODE = 2; JNODE <= nodeColsCount - 1; JNODE++) { newModel.INOUT[nodeNumbers[INODE, JNODE]] = 0; } } } catch { return(-1); } // > Определение внешних и внутренних узлов // > завершена генерация сетки конечных элементов // < определение конечных элементов (группировка узлов) K = 1; for (int i = 1; i <= nodeRowsCount; i++) { for (int j = 1; j <= nodeColsCount; j++) { xElem[K] = xCord[i, j]; yElem[K] = yCord[i, j]; //ZE[K] = ZC[i,j]; NE[K] = nodeNumbers[i, j]; if (NE[K] > MAXNP) { MAXNP = NE[K]; } CORDD[(2 * (NE[K] - 1) + 1)] = xElem[K]; CORDD[(2 * (NE[K] - 1) + 2)] = yElem[K]; CORD[1] = xElem[K]; CORD[2] = yElem[K]; K = K + 1; } } L = nodeRowsCount - 1; for (int i = 1; i <= L; i++) { for (int j = 2; j <= nodeColsCount; j++) { DIAG1 = Math.Pow((Math.Pow((xCord[i, j] - xCord[i + 1, j - 1]), 2) + Math.Pow((yCord[i, j] - yCord[i + 1, j - 1]), 2)), 0.5); DIAG2 = Math.Pow((Math.Pow((xCord[i + 1, j] - xCord[i, j - 1]), 2) + Math.Pow((yCord[i + 1, j] - yCord[i, j - 1]), 2)), 0.5); //DIAG1 = Math.Pow((Math.Pow((xCord[i, j] - xCord[i + 1, j - 1]), 2) + Math.Pow((yCord[i, j] - yCord[i + 1, j - 1]), 2) + Math.Pow((ZC[i, j] - ZC[i + 1, j - 1]), 2)), 0.5); //DIAG2 = Math.Pow((Math.Pow((xCord[i + 1, j] - xCord[i, j - 1]), 2) + Math.Pow((yCord[i + 1, j] - yCord[i, j - 1]), 2) + Math.Pow((ZC[i + 1, j] - ZC[i, j - 1]), 2)), 0.5); NR[1] = nodeColsCount * i + j - 1; NR[2] = nodeColsCount * i + j; NR[3] = nodeColsCount * (i - 1) + j; NR[4] = nodeColsCount * (i - 1) + j - 1; for (int ij = 1; ij <= 2; ij++) { NEL = NEL + 1; if ((DIAG1 / DIAG2) > 1.01) { J1 = NR[ij]; J2 = NR[ij + 1]; J3 = NR[4]; } else if ((DIAG1 / DIAG2) < 1.01) { J1 = NR[1]; J2 = NR[ij + 1]; J3 = NR[ij + 2]; } else if ((i + j) % 2 == 1) { J1 = NR[ij]; J2 = NR[ij + 1]; J3 = NR[4]; } LB[1] = Math.Abs(NE[J1] - NE[J2]) + 1; LB[2] = Math.Abs(NE[J2] - NE[J3]) + 1; LB[3] = Math.Abs(NE[J1] - NE[J3]) + 1; for (int ik = 1; ik <= 3; ik++) { if (LB[ik] <= NBW) { } else { NBW = LB[ik]; NELBW = NEL; } } NOP[(NCN * (NEL - 1) + 1)] = NE[J1]; NOP[(NCN * (NEL - 1) + 2)] = NE[J2]; NOP[(NCN * (NEL - 1) + 3)] = NE[J3]; // > завершено определение конечных элементов (группировка узлов) } } } } fillObjectsFromArrays(newModel, CORDD, NOP, MAXNP, NEL, zonesCount); return(0); }
private void okButton_Click(object sender, EventArgs e) { this.parent.precision = this.parent.DefinePrecision(); if (this.parent.currentFullModel.geometryModel.Areas.Count != 0) { this.errorMessage1.Visible = false; this.errorBadGridName.Visible = false; if (gridName.Text == string.Empty) { MessageBox.Show("Имя сетки не может быть пустым!"); return; } List <MyPoint> nodes = new List <MyPoint>(); foreach (MyArea area in this.parent.currentFullModel.geometryModel.Areas) { for (int i = 0; i < 8; i++) { if (nodes.IndexOf(area.Nodes[i]) == -1) { nodes.Add(area.Nodes[i]); } } } // создаем новый объект "конечно-элементная модель" и добавляем его в список конечно-элементных моделей. foreach (MyFiniteElementModel model in this.parent.currentFullModel.FiniteElementModels) // проверяем, нет ли модели с таким именем { if (model.ModelName == this.gridName.Text) { this.errorBadGridName.Visible = true; return; } } // создаем для новой КЭ модели id int id = this.parent.currentFullModel.IdCandidate; MyFiniteElementModel newModel = new MyFiniteElementModel(id, this.gridName.Text, Convert.ToInt32(this.NRC.Text), MyFiniteElementModel.GridType.Normal); newModel.baseType = newModel.type; this.parent.currentFullModel.geometryModel.boundaryPointsCount = nodes.Count; int NRC = Convert.ToInt32(this.NRC.Text); if (NRC < 3 || NRC > 15) { MessageBox.Show("Нельзя задать такое NRC!"); return; } parent.StartProgress("Формируется сетка"); this.Hide(); int result = Griddm(NRC, this.parent.currentFullModel.geometryModel.boundaryPointsCount, this.parent.currentFullModel.geometryModel.Areas.Count, 1, 3, newModel); // последний парамер - номер рассматриваемой модели, расчитаный по числу моделей в списке if (result == -1) { MessageBox.Show("Невозможно построить сетку КЭ, зоны были заданы непоследовательно!"); return; } parent.EndProgress(); parent.clearSelection(); parent.ModelCreated(newModel); this.Close(); } else { this.errorMessage1.Visible = true; } }
private void constructionArea_MouseMove(object sender, MouseEventArgs e) { mouseAboveArea = true; MyPoint clickPoint = visualizer.getClickPoint(e.X, e.Y); if (mouseXcord.Equal(clickPoint.X) && mouseYcord.Equal(clickPoint.Y)) { return; } mouseXcord = clickPoint.X; mouseYcord = clickPoint.Y; if (e.Button == MouseButtons.Left) { // кусочек, который отвечает за перетаскивание области построения if (!this.mouseAboveEditedPoint && !this.mouseAboveEditedNode && this.currentFullModel.geometryModel.editedPoint == null) { this.mouseMoved = true; visualizer.MoveBy((e.X - mouseX), (e.Y - mouseY), showGrid.Checked); mouseX = e.X; mouseY = e.Y; } // кусочек, который отвечает за перетаскивание точки в режиме редактирования точки if (this.editPointsControl != null && this.editPointsControl.IsHandleCreated && this.mouseAboveEditedPoint) { if (this.currentFullModel.geometryModel.editedPoint != null) { if (currentFullModel.geometryModel.editedPoint.IsCenterOfArc) { MessageBox.Show("Изменение центра дуги невозможно!"); this.mouseAboveEditedPoint = false; } else { MyPoint ePoint = currentFullModel.geometryModel.editedPoint; if (currentFullModel.geometryModel.editedPoint.IsStartOfArc || currentFullModel.geometryModel.editedPoint.IsEndOfArc) { MyArc[] incidentArcs = currentFullModel.geometryModel.Arcs.Where(a => a.StartPoint == currentFullModel.geometryModel.editedPoint || a.EndPoint == currentFullModel.geometryModel.editedPoint).ToArray(); if (incidentArcs.Length > 0) { MyPoint commonCenter; commonCenter = incidentArcs[0].CenterPoint; double R = Mathematics.FindDist(currentFullModel.geometryModel.editedPoint, commonCenter); double x; double y; double angle = Math.Atan2(clickPoint.Y - commonCenter.Y, clickPoint.X - commonCenter.X); x = commonCenter.X + R * Math.Cos(angle); y = commonCenter.Y + R * Math.Sin(angle); bool PointFits = true; foreach (MyArc arc in incidentArcs) { MyArc testArc; if (arc.EndPoint == currentFullModel.geometryModel.editedPoint) { testArc = new MyArc(0, arc.Clockwise, arc.StartPoint, new MyPoint(x, y, MyPoint.PointType.IsGeometryPoint), arc.CenterPoint); } else { testArc = new MyArc(0, arc.Clockwise, new MyPoint(x, y, MyPoint.PointType.IsGeometryPoint), arc.EndPoint, arc.CenterPoint); } if (!TestArc(testArc)) { PointFits = false; break; } } if (PointFits) { currentFullModel.geometryModel.editedPoint.X = x; currentFullModel.geometryModel.editedPoint.Y = y; } } else { currentFullModel.geometryModel.editedPoint.X = clickPoint.Y; currentFullModel.geometryModel.editedPoint.Y = clickPoint.Y; } } else { currentFullModel.geometryModel.editedPoint.X = clickPoint.X; currentFullModel.geometryModel.editedPoint.Y = clickPoint.Y; } if (currentFullModel.geometryModel.editedPoint.NodeReference != null) // точка может и не иметь ссылки на узел - если это центральная точка дуги, например { currentFullModel.geometryModel.editedPoint.NodeReference.X = this.currentFullModel.geometryModel.editedPoint.X; currentFullModel.geometryModel.editedPoint.NodeReference.Y = this.currentFullModel.geometryModel.editedPoint.Y; } // отображаем id, x и y точки this.editPointsControl.number.Text = this.currentFullModel.geometryModel.editedPoint.Id.ToString(); this.editPointsControl.x.Text = Mathematics.floor(this.currentFullModel.geometryModel.editedPoint.X, Mathematics.accuracy_medium).ToString(); this.editPointsControl.y.Text = Mathematics.floor(this.currentFullModel.geometryModel.editedPoint.Y, Mathematics.accuracy_medium).ToString(); ReDrawAll(true); } } } // кусочек, который отвечает за перетаскивание узла зоны в режиме редактирования узлов зоны if (this.editNodesControl != null && this.editNodesControl.IsHandleCreated && this.mouseAboveEditedNode) { if (this.currentFullModel.geometryModel.editedNode != null) { this.currentFullModel.geometryModel.editedNode.X = clickPoint.X; this.currentFullModel.geometryModel.editedNode.Y = clickPoint.Y; if (currentFullModel.geometryModel.editedNode.PointReference != null) // точка может и не иметь ссылки на узел - если это центральная точка дуги, например { if (!(currentFullModel.geometryModel.editedNode.PointReference.IsCenterOfArc || currentFullModel.geometryModel.editedNode.PointReference.IsStartOfArc || currentFullModel.geometryModel.editedNode.PointReference.IsEndOfArc)) { currentFullModel.geometryModel.editedNode.PointReference.X = this.currentFullModel.geometryModel.editedNode.X; currentFullModel.geometryModel.editedNode.PointReference.Y = this.currentFullModel.geometryModel.editedNode.Y; } } // отображаем id, x и y точки this.editNodesControl.number.Text = this.currentFullModel.geometryModel.editedNode.Id.ToString(); this.editNodesControl.x.Text = Mathematics.floor(this.currentFullModel.geometryModel.editedNode.X, Mathematics.accuracy_medium).ToString(); this.editNodesControl.y.Text = Mathematics.floor(this.currentFullModel.geometryModel.editedNode.Y, Mathematics.accuracy_medium).ToString(); ReDrawAll(true); } } } else { // подсвечиваем точки и линии MyPoint nearestPoint; if ((nearestPoint = currentFullModel.geometryModel.Points.Find(p => Math.Abs(clickPoint.X - p.X) < (double)visualizer.pointLocality && Math.Abs(clickPoint.Y - p.Y) < (double)visualizer.pointLocality)) != null) { hoveredPoint = nearestPoint; mouseXcord = nearestPoint.X; mouseYcord = nearestPoint.Y; ReDrawAll(true); } else { if (hoveredPoint != null) { hoveredPoint = null; ReDrawAll(true); } } if (creatingCircle) // если мы в режиме рисования окружности { if (this.currentFullModel.geometryModel.centerOfCircle != null) { double x1, y1; if (hoveredPoint == null) { x1 = clickPoint.X; y1 = clickPoint.Y; } else { x1 = hoveredPoint.X; y1 = hoveredPoint.Y; } double radius = Mathematics.FindDist(x1, y1, currentFullModel.geometryModel.centerOfCircle.X, currentFullModel.geometryModel.centerOfCircle.Y); if (this.addCirclesControl != null) { this.addCirclesControl.radius.Text = Mathematics.floor(radius, Mathematics.accuracy_medium).ToString(); } currentFullModel.geometryModel.tempCircle = new MyCircle(this.currentFullModel.geometryModel.NumOfCircles + 1, this.currentFullModel.geometryModel.centerOfCircle, radius); ReDrawAll(true); } } if (activeControl is GridAnalysis) { MyFiniteElementModel model = currentFullModel.FiniteElementModels.Find(m => m.ModelName == currentFullModel.currentGridName); MyFiniteElement elem = model.FiniteElements.Find(el => Mathematics.ContainsPoint(el.Nodes.ToArray(), clickPoint)); if (elem != null) { elemInfoTooltip.ToolTipTitle = "Элемент №" + elem.Id.ToString(); StringBuilder tooltipText = new StringBuilder(); tooltipText.AppendLine("Площадь: " + Mathematics.floor(Mathematics.GeronLaw(elem.Nodes), 0.01)); double[] angles = Mathematics.getFEangles(elem); for (int i = 0; i < 3; i++) { tooltipText.AppendLine("Угол " + (i + 1).ToString() + ": " + angles[i].ToString("###.##")); } elemInfoTooltip.Show(tooltipText.ToString(), constructionArea, new Point(e.X, e.Y)); } else { elemInfoTooltip.Hide(constructionArea); } } } this.textBox1.Text = Mathematics.floor(mouseXcord, Mathematics.accuracy_medium).ToString(); this.textBox2.Text = Mathematics.floor(mouseYcord, Mathematics.accuracy_medium).ToString(); }
// чтение вариантов сетки из файла (Рапперт) public void ReadRuppertVariants(string file) { string[] lines = File.ReadAllLines(file, Encoding.Default); int NRC = Convert.ToInt32(lines[0]); int countOfZones = Convert.ToInt32(lines[1]); int CountOfBasePoints = Convert.ToInt32(lines[2]); int j = 3; // создаем для новой сетки id MyFiniteElementModel model = new MyFiniteElementModel(currentModel.Id, currentModel.ModelName, MyFiniteElementModel.GridType.Ruppert); int cur = parent.GetCurrentModelIndex(); model.INOUT = parent.currentFullModel.FiniteElementModels[cur].INOUT; model.NP = Convert.ToInt32(lines[j++]); // число узлов в варианте сетки model.CORD.Add(0.0); for (int n = 1; n <= model.NP; n++) { int Number = Convert.ToInt32(lines[j++]); double X = Convert.ToDouble(lines[j++].Replace(".", ",")); double Y = Convert.ToDouble(lines[j++].Replace(".", ",")); //int SeNum = Convert.ToInt32(slines[j++]); //int ZoneNum = Convert.ToInt32(slines[j++]); //string s = slines[j++]; //s = slines[j++]; j += 9; model.Nodes.Add(new MyNode(X, Y, Number)); model.CORD.Add(X); model.CORD.Add(Y); } model.NE = Convert.ToInt32(lines[j++]); // число КЭ в варианте сетки for (int e = 1; e <= model.NE; e++) { int Number = Convert.ToInt32(lines[j++]); int Node1 = Convert.ToInt32(lines[j++]); int Node2 = Convert.ToInt32(lines[j++]); int Node3 = Convert.ToInt32(lines[j++]); int Material = Convert.ToInt32(lines[j++]); List <MyNode> nodes = new List <MyNode>(); nodes = model.Nodes.FindAll(n => n.Id == Node1 || n.Id == Node2 || n.Id == Node3); MyFiniteElement elem = new MyFiniteElement(Number, Material, nodes); elem.DefineArea(parent.currentFullModel.geometryModel.Areas); model.FiniteElements.Add(elem); nodes.Clear(); } model.NOP.Add(0); for (int i = 0; i < model.NE; i++) { int n1 = model.FiniteElements[i].Nodes[0].Id; int n2 = model.FiniteElements[i].Nodes[1].Id; int n3 = model.FiniteElements[i].Nodes[2].Id; model.NOP.Add(n1); model.NOP.Add(n2); model.NOP.Add(n3); } File.Delete(Path.GetDirectoryName(this.parent.FullProjectFileName) + "\\grid.Ralg"); parent.ModelCreated(model); }
private void btnOk_Click(object sender, EventArgs e) { if (txtLine.Text == string.Empty && txtNode.Text == string.Empty) { return; } this.parent.precision = this.parent.DefinePrecision(); this.parent.showBounds.Checked = true; int number; int currentModel = this.parent.GetCurrentModelIndex(); MyFiniteElementModel model = this.parent.currentFullModel.FiniteElementModels[currentModel]; if (rbnOnLine.Checked) { MyLine lineToBound; bool error = false; if (!int.TryParse(this.txtLine.Text, out number)) { error = true; } lineToBound = parent.currentFullModel.geometryModel.Lines.Find(l => l.Id == number); if (lineToBound == null) { error = true; } if (error) { errorNoLine.Visible = true; return; } UnboundLine(lineToBound); } else { MyNode nodeToBound; bool error = false; if (!int.TryParse(this.txtNode.Text, out number)) { error = true; } nodeToBound = model.Nodes.Find(n => n.Id == number); if (nodeToBound == null) { error = true; } if (error) { lblNoNode.Visible = true; return; } UnboundNode(nodeToBound); renewNfixNB(currentModel); this.parent.DrawFEBounds(Color.Brown); this.txtNode.Text = ""; this.txtNode.Select(); } parent.ReDrawAll(); }
public void Regularization(int NRC, int zonesCount, MyFiniteElementModel model, int[] notMove) { //C =================================================================== //C REGULARIZATION - процедура оптимизации конечных элементов по углам //C вызывается из GRIDDM, //C вызывает модули FINDNODD, GET_STAR, FIND_MIN_ANG //C =================================================================== //C входные параметры: //C NRC - параметр разбиения //C zonesCount - число зон //C NOPR - массив номеров узлов, сост-щих элементы //C nodeRowsCount - число строк узлов в зоне ( равно NRC) //C nodeColsCount - число столбцов узлов в зоне ( равно NRC) //C CORDDR - массив координат узлов //C INOUTR - массив признаков узлов (узел граничный или внутренний) //C NP - число узлов //C NUMOFEL - число элементов //C выходные параметры отсутствуют //C ================================================================= //C ================ начало кода REGULARIZATION ====================== int[] EX = { 0, 1, 0, -1, 0 }; int[] EY = { 0, 0, 1, -0, -1 }; double[] CDNT = new double[7]; int[] ISTAR = new int[101]; List <double> CORD = model.CORD; List <double> CORDDR_NO_OPT = new List <double>(); List <int> NOTMOVE = new List <int>(); int NOUTPNT, //IND, NSTEL, L, K, INDSTAR, JNDSTAR, KTIMES, MAXTIMES; double MINANG, NEWMINANG, NEWMINSIDE, STEP, COORX, COORY, MAXDELTA, CURDELTA, MANG, MODMANG, NEWMODMANG; double CURMINANG = 0; double CURMINSIDE = 0; double MINSIDE = 0; int i; // NOTMOVE - массив для хранения номеров узлов, которые лежат на границе материалов // J - колличество элементов в массиве NOTMOVE //double X1,Y1; int MAXL = 3; int NP = model.NP; KTIMES = 0; MAXTIMES = 100; NOUTPNT = (3 * NRC - 4) * zonesCount + NRC - (zonesCount - 1) * NRC; for (i = 0; i <= 2 * NP; i++) { CORDDR_NO_OPT.Add(0.0); } for (i = 1; i <= NP; i++) { CORDDR_NO_OPT[2 * (i - 1) + 1] = CORD[2 * (i - 1) + 1]; CORDDR_NO_OPT[2 * (i - 1) + 2] = CORD[2 * (i - 1) + 2]; } List <int> nullIndexes = new List <int>(); int index = -1; while ((index = model.INOUT.IndexOf(0, index + 1)) != -1) { if (notMove[index] == 0) { nullIndexes.Add(index); } } // Ищем соседние узлы для всех изменяемых узлов Dictionary <int, int[]> stars = new Dictionary <int, int[]>(); foreach (int IND in nullIndexes) { stars.Add(IND, Get_Star(IND, model)); } // -- число прогонов процедуры оптимизации do { KTIMES = KTIMES + 1; MANG = 1.0472; MODMANG = 1.0472; NEWMODMANG = 1.0472; MAXDELTA = 0.0; // -- цикл по узлам foreach (int IND in nullIndexes) { // если текущий узел не принадлежит границе области и не относится к узлам, // которые лежат на границе материалов //IF ((INOUTR(IND).EQ.0).AND.(NTM(IND,NOTMOVE,J).EQ.0)) THEN //* -- принадлежит ли узел границе области //C ============================================================== //C -- определяем звезду, соотв-ю данному узлу //C ================================================================= ISTAR = stars[IND]; NSTEL = ISTAR.Count() / 3; // -- найти более хорошее положение узла // вычисление мин. угла при исходных коор-тах // перебор эл-тов звезды MINANG = 1.0472; for (INDSTAR = 1; INDSTAR <= NSTEL; INDSTAR++) { // перебор узлов текущего эл-та for (JNDSTAR = 1; JNDSTAR <= 3; JNDSTAR++) { // опр-ние коор-т узлов тек. эл-та для вычисл. мин. угла CDNT[2 * (JNDSTAR - 1) + 1] = CORD[2 * (ISTAR[3 * (INDSTAR - 1) + JNDSTAR] - 1) + 1]; CDNT[2 * (JNDSTAR - 1) + 2] = CORD[2 * (ISTAR[3 * (INDSTAR - 1) + JNDSTAR] - 1) + 2]; } // ============================================================== // Определение мин. угла в эл-те // ================================================================= Find_Min_Ang(CDNT); CURMINANG = GLOBAL_MINANG; CURMINSIDE = GLOBAL_MINSIDE; // определение минимального угла звезды if (MINANG > CURMINANG) { MINANG = CURMINANG; MINSIDE = CURMINSIDE; } } // осуществляем оптимизацию положения узла STEP = MINSIDE / 3.0; for (L = 1; L <= MAXL; L++) { STEP = STEP / 2.0; for (K = 1; K <= 4; K++) { COORX = CORD[2 * (IND - 1) + 1] + STEP * EX[K]; COORY = CORD[2 * (IND - 1) + 2] + STEP * EY[K]; // вычисление минимального звезды угла при новом положении узла NEWMINANG = 1.0472; for (INDSTAR = 1; INDSTAR <= NSTEL; INDSTAR++) { // перебор узлов текущего эл-та for (JNDSTAR = 1; JNDSTAR <= 3; JNDSTAR++) { // опр-ние коор-т узлов тек. эл-та для вычисл. мин. угла // если это оптимизируемый узел, принять новые координаты if (ISTAR[3 * (INDSTAR - 1) + JNDSTAR] == IND) { CDNT[2 * (JNDSTAR - 1) + 1] = COORX; CDNT[2 * (JNDSTAR - 1) + 2] = COORY; } else { CDNT[2 * (JNDSTAR - 1) + 1] = CORD[2 * (ISTAR[3 * (INDSTAR - 1) + JNDSTAR] - 1) + 1]; CDNT[2 * (JNDSTAR - 1) + 2] = CORD[2 * (ISTAR[3 * (INDSTAR - 1) + JNDSTAR] - 1) + 2]; } } // ============================================================== // вычисление мин. угла и стороны тек. эл-та звезды // ================================================================= Find_Min_Ang(CDNT); CURMINANG = GLOBAL_MINANG; CURMINSIDE = GLOBAL_MINSIDE; //* определение минимального угла звезды if (NEWMINANG > CURMINANG) { NEWMINANG = CURMINANG; NEWMINSIDE = CURMINSIDE; } } // Определение минимального угла из всех // нужно лишь для проверки if (MINANG <= MANG) { MANG = MINANG; } // выяснить, лучше ли нов. коор. узла, т.е. увеличился ли мин. угол if (NEWMINANG > MINANG) { CURDELTA = NEWMINANG - MINANG; if (CURDELTA > MAXDELTA) { MAXDELTA = CURDELTA; } //* Определение минимального измененного угла из всех //* нужно лишь для проверки if (MODMANG >= MINANG) { MODMANG = MINANG; } if (NEWMODMANG >= NEWMINANG) { NEWMODMANG = NEWMINANG; } CORD[2 * (IND - 1) + 1] = COORX; CORD[2 * (IND - 1) + 2] = COORY; MINANG = NEWMINANG; continue; } } Application.DoEvents(); } } } while (MAXDELTA > (0.001) && KTIMES < MAXTIMES); }
private void okButton_Click(object sender, EventArgs e) { List <string> lineStrings = new List <string>(this.notMoveLines.Text.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries).ToList <string>()); List <MyLine> fixedLines = new List <MyLine>(); foreach (string str in lineStrings) { int idx; if (!int.TryParse(str, out idx)) { MessageBox.Show("Неверно заданы линии!"); return; } MyLine line = (MyLine)parent.currentFullModel.geometryModel.StraightLines.Find(l => l.Id == idx) ?? (MyLine)parent.currentFullModel.geometryModel.Arcs.Find(a => a.Id == idx); if (line == null) { MessageBox.Show("Не найдена линия с номером " + idx.ToString()); return; } fixedLines.Add(line); } parent.precision = parent.DefinePrecision(); if (parent.currentFullModel.geometryModel.Areas.Count != 0) { errorMessage1.Visible = false; errorBadGridName.Visible = false; // создаем новый объект "конечно-элементная модель" и добавляем его в список конечно-элементных моделей. foreach (MyFiniteElementModel model in parent.currentFullModel.FiniteElementModels) // проверяем, нет ли модели с таким именем { if (model.ModelName == gridName.Text) { errorBadGridName.Visible = true; return; } } this.Hide(); parent.StartProgress("Выполняется оптимизация"); // создаем для новой КЭ модели id int id = parent.currentFullModel.IdCandidate; currentModel = (MyFiniteElementModel)Util.getObjectCopy(currentModel); currentModel.ModelName = gridName.Text; currentModel.Id = id; currentModel.restoreArraysForOldMethods(parent.currentFullModel.geometryModel); int[] notMove = new int[currentModel.INOUT.Count]; notMove.Initialize(); if (notMoveLines.TextLength != 0) { foreach (MyLine fixedLine in fixedLines) { List <MyNode> tempNodes = new List <MyNode>(); if (fixedLine is MyStraightLine) { findNodesAtStraightLine(tempNodes, (MyStraightLine)fixedLine); foreach (MyNode node in tempNodes) { node.Type = NodeType.Fixed; notMove[node.Id] = 1; } } else { findNodesAtArc(tempNodes, (MyArc)fixedLine); foreach (MyNode node in tempNodes) { node.Type = NodeType.Fixed; notMove[node.Id] = 1; //currentModel.INOUT[node.Id] = 1; } } } } Regularization(currentModel.NRC, parent.currentFullModel.geometryModel.Areas.Count, currentModel, notMove); currentModel.FiniteElements.Clear(); currentModel.Nodes.Clear(); for (int i = 1; i <= currentModel.NP; i++) // MAXNP - число узлов { currentModel.Nodes.Add(new MyNode(currentModel.CORD[2 * (i - 1) + 1], currentModel.CORD[2 * (i - 1) + 2], i)); } for (int temp = 1; temp <= currentModel.NE; temp++) { int numOfFE = currentModel.FiniteElements.Count; int numOfNodes = currentModel.Nodes.Count; List <MyNode> tempNodes = new List <MyNode>(); double X1 = currentModel.CORD[2 * (currentModel.NOP[3 * (temp - 1) + 1] - 1) + 1]; double Y1 = currentModel.CORD[2 * (currentModel.NOP[3 * (temp - 1) + 1] - 1) + 2]; double X2 = currentModel.CORD[2 * (currentModel.NOP[3 * (temp - 1) + 2] - 1) + 1]; double Y2 = currentModel.CORD[2 * (currentModel.NOP[3 * (temp - 1) + 2] - 1) + 2]; double X3 = currentModel.CORD[2 * (currentModel.NOP[3 * (temp - 1) + 3] - 1) + 1]; double Y3 = currentModel.CORD[2 * (currentModel.NOP[3 * (temp - 1) + 3] - 1) + 2]; foreach (MyNode node in currentModel.Nodes) { if (Math.Abs(node.X - X1) <= 0.001 && Math.Abs(node.Y - Y1) <= 0.001) { tempNodes.Add(node); } if (Math.Abs(node.X - X2) <= 0.001 && Math.Abs(node.Y - Y2) <= 0.001) { tempNodes.Add(node); } if (Math.Abs(node.X - X3) <= 0.001 && Math.Abs(node.Y - Y3) <= 0.001) { tempNodes.Add(node); } } MyFiniteElement elem = new MyFiniteElement(numOfFE + 1, 0, tempNodes); elem.DefineArea(parent.currentFullModel.geometryModel.Areas); currentModel.FiniteElements.Add(elem); tempNodes.Clear(); } parent.EndProgress(); parent.ModelCreated(currentModel); Close(); } else { errorMessage1.Visible = true; } }
public static void restoreArraysForOldMethods(this MyFiniteElementModel model, MyGeometryModel geomModel) { // Восстанавливаем закрепленные узлы List <MyNode> boundedNodes = model.Nodes.FindAll(n => n.BoundType != 0); // Восстанавливаем закрепленные узлы model.NBC.Clear(); model.NB = boundedNodes.Count; model.NBC = boundedNodes.ConvertAll(n => n.Id); model.NBC.Insert(0, 0); // Типы закреплений model.NFIX.Clear(); model.NFIX = boundedNodes.ConvertAll(n => n.BoundType); model.NFIX.Insert(0, 0); // Нагрузки model.R.Clear(); model.Nodes.ConvertAll(n => new double[] { n.ForceX, n.ForceY }).ForEach(pair => model.R.AddRange(pair)); model.R.Insert(0, 0.0); // Сами узлы model.NP = model.Nodes.Count; model.Nodes.Sort((n, m) => n.Id.CompareTo(m.Id)); model.CORD.Clear(); model.Nodes.ConvertAll(n => new double[] { n.X, n.Y }).ForEach(pair => model.CORD.AddRange(pair)); model.CORD.Insert(0, 0.0); // Конечные элементы model.NE = model.FiniteElements.Count; model.NOP.Clear(); model.NOP.Insert(0, 0); if (model.IMAT.Count == 0) { model.IMAT = new List <int>(); } for (int i = 0; i <= model.NE; i++) { model.IMAT.Add(0); } foreach (MyFiniteElement elem in model.FiniteElements) { List <MyNode> nodes = new List <MyNode>(elem.Nodes); // сортировка узлов КЭ против часовой стрелке // double[] angle = new double[3]; for (int i = 1; i < 3; i++) { angle[i] = Math.Atan2(nodes[i].Y - nodes[0].Y, nodes[i].X - nodes[0].X); if (angle[i] < 0) { angle[i] += Math.PI * 2; } } model.NOP.Add(nodes[0].Id); if (angle[1] > angle[2]) { if (angle[1] - angle[2] < Math.PI) { model.NOP.Add(nodes[2].Id); model.NOP.Add(nodes[1].Id); } else { model.NOP.Add(nodes[1].Id); model.NOP.Add(nodes[2].Id); } } else { if (angle[2] - angle[1] < Math.PI) { model.NOP.Add(nodes[2].Id); model.NOP.Add(nodes[1].Id); } else { model.NOP.Add(nodes[2].Id); model.NOP.Add(nodes[1].Id); } } } // восстанавливаем принадлежность к зонам foreach (MyFiniteElement elem in model.FiniteElements) { elem.DefineArea(geomModel.Areas); } model.INOUT.Clear(); model.INOUT.Add(1); foreach (MyNode node in model.Nodes) { int nodeCount = model.INOUT.Count; foreach (MyFiniteElement elem in node.finiteElements) { MyArea inspectArea = geomModel.Areas.Find(area => area.Id == elem.areaId + 1); double precision = (model.baseType == MyFiniteElementModel.GridType.Delauney || model.type == MyFiniteElementModel.GridType.FrontalMethod) ? 0.01 : -1; if (inspectArea.StraightLines.Find(line => Mathematics.pointOnLine(node, line) && line.Areas.Count == 1) != null) { model.INOUT.Add(1); } else if (inspectArea.Arcs.Find(arc => Mathematics.pointFitsArc(node, arc, precision) && arc.Areas.Count == 1) != null) { model.INOUT.Add(1); } if (model.INOUT.Count != nodeCount) { break; } } if (nodeCount == model.INOUT.Count) { model.INOUT.Add(0); } } }