public void CalcEquivalentlReactions(ComponentLoad DistributedLoad) { // Разложим load на составляющие в локальной системе для cosa = Math.Cos((DistributedLoad.Direction - AngleD) * Math.PI / 180); sina = Math.Sin((DistributedLoad.Direction - AngleD) * Math.PI / 180); cosL = Math.Cos(Angle); sinL = Math.Sin(Angle); qx = DistributedLoad.Value * cosa; qy = DistributedLoad.Value * sina; // Находим реакции // 1. Если в обоих узлах элемента нет шарниров // 2. Если шарнир в первом узле // 3. Если шарнир во втором узле // 4. Если шарниры в обоих узлах rx1 = qx * Length / 2; rx2 = rx1; if ((!HingeStart) && (!HingeEnd)) { ry1 = qy * Length / 2; ry2 = ry1; //TODO: Разобраться со знаками моментов m1 = qy * (Length * Length) / 12; m2 = -m1; } if ((HingeStart) && (!HingeEnd)) { ry2 = qy * 5 / 8 * Length; ry1 = qy * Length - ry2; m2 = -qy *Math.Pow(Length, 2) / 8; m1 = 0; } if ((!HingeStart) && (HingeEnd)) { ry1 = qy * 5 / 8 * Length; ry2 = qy * Length - ry1; m1 = qy * Math.Pow(Length, 2) / 8; m2 = 0; } if ((HingeStart) && (HingeEnd)) { ry1 = qy * Length / 2; ry2 = ry1; m1 = 0; m2 = 0; } CleanupReactions(); }
public void Load(Stream stream, ObservableCollection <ComponentBasic> DestinationList) { XmlDocument doc = new XmlDocument(); stream.Seek(0, SeekOrigin.Begin); doc.Load(stream); DestinationList.Clear(); for (int i = 0; i < doc.DocumentElement.ChildNodes.Count; i++) { XmlNode n = doc.DocumentElement.ChildNodes[i]; if (n.Name == "x:Nodes") { for (int j = 0; j < n.ChildNodes.Count; j++) { XmlNode node = n.ChildNodes[j]; float x = float.Parse(GetAttrValue(node.Attributes["x:X"], "0")); float y = float.Parse(GetAttrValue(node.Attributes["x:Y"], "0")); bool dx = bool.Parse(GetAttrValue(node.Attributes["x:DX"], "false")); bool dy = bool.Parse(GetAttrValue(node.Attributes["x:DY"], "false")); bool r = bool.Parse(GetAttrValue(node.Attributes["x:Rotation"], "false")); ComponentNode cn = new ComponentNode(new IssoPoint2D() { X = x, Y = y }); if (dx) { cn.DisallowedDisplacements.Add(NodeDisplacement.X); } if (dy) { cn.DisallowedDisplacements.Add(NodeDisplacement.Y); } if (r) { cn.DisallowedDisplacements.Add(NodeDisplacement.Rotation); } DestinationList.Add(cn); } } List <ComponentNode> modelNodes = ModelNodes2(DestinationList); if (n.Name == "x:Beams") { for (int j = 0; j < n.ChildNodes.Count; j++) { XmlNode beam = n.ChildNodes[j]; int sn = int.Parse(GetAttrValue(beam.Attributes["x:StartNode"], "0")); int en = int.Parse(GetAttrValue(beam.Attributes["x:EndNode"], "0")); ComponentLinear cl = new ComponentLinear(modelNodes[sn], modelNodes[en], this); DestinationList.Add(cl); } } if (n.Name == "x:Forces") { for (int j = 0; j < n.ChildNodes.Count; j++) { XmlNode force = n.ChildNodes[j]; int ni = int.Parse(GetAttrValue(force.Attributes["x:Node"], "0")); float d = float.Parse(GetAttrValue(force.Attributes["x:Direction"], "0")); float v = float.Parse(GetAttrValue(force.Attributes["x:Value"], "0")); ComponentLoad cl = new ComponentLoad(ComponentTypes.ctForce, v, modelNodes[ni]); cl.Direction = d; DestinationList.Add(cl); } } List <ComponentLinear> modelBeams = ModelBeams2(DestinationList); if (n.Name == "x:DistributedLoads") { for (int j = 0; j < n.ChildNodes.Count; j++) { XmlNode load = n.ChildNodes[j]; int li = int.Parse(GetAttrValue(load.Attributes["x:Beam"], "0")); float d = float.Parse(GetAttrValue(load.Attributes["x:Direction"], "0")); float v = float.Parse(GetAttrValue(load.Attributes["x:Value"], "0")); ComponentLoad cl = new ComponentLoad(ComponentTypes.ctDistributedLoad, v, modelBeams[li]); cl.Direction = d; DestinationList.Add(cl); } } } }
internal void CalculateStatic() { // Статический расчёт! // 0. Разбиваем модель на элементы: // Незагруженные распределённой нагрузкой стержни берём целиком, // в противном случае - делим стержень на несколько элементов // 1. Создаём список узлов Nodes.Clear(); for (int i = 0; i < CompsList.Count; i++) { if (CompsList[i].CompType == ComponentTypes.ctNode) { Nodes.Add((ComponentNode)CompsList[i]); } } // В соответствии с количеством узлов создаём матрицу жёсткости системы и заполняем её нулями // Для каждого узла - три возможных перемещения // 0 - горизонтальное // 1 - вертикальное // 2 - поворот GlobalMatrix = new double[Nodes.Count * 3, Nodes.Count * 3]; for (int i = 0; i < Nodes.Count; i++) { for (int j = 0; j < Nodes.Count; j++) { GlobalMatrix[i, j] = 0; } } // 2. Создаём балочные элементы и заполняем глобальную матрицу Rods.Clear(); for (int i = 0; i < CompsList.Count; i++) { if (CompsList[i].CompType == ComponentTypes.ctLinear) { ComponentNode n1 = ((ComponentLinear)CompsList[i]).StartNode; ComponentNode n2 = ((ComponentLinear)CompsList[i]).EndNode; int n1i = getNodeIndex(n1); int n2i = getNodeIndex(n2); ElementBeam b = new ElementBeam((ComponentLinear)CompsList[i], this); Rods.Add(b); // Встраиваем матрицу жёсткости элемента в глобальную матрицу жёсткости for (int row = 0; row < 6; row++) { for (int col = 0; col < 6; col++) { int r, c; if (row < 3) { r = n1i * 3 + row; } else { r = n2i * 3 + row - 3; } if (col < 3) { c = n1i * 3 + col; } else { c = n2i * 3 + col - 3; } GlobalMatrix[r, c] += b.ExtMatrix[row, col]; } } } } // 3. Создаём вектор узловых сил. Loads = new double[Nodes.Count * 3]; for (int i = 0; i < Loads.Length; i++) { Loads[i] = 0; } for (int i = 0; i < CompsList.Count; i++) { if (CompsList[i].CompType == ComponentTypes.ctForce) { ComponentLoad load = (ComponentLoad)CompsList[i]; ComponentNode n = load.AppNodes[0]; // Сила приложена к узлу, её нужно разложить на // две составляющие в глобальной системе координат // - горизонтальную и вертикальную // Поскольку в одном узле может быть несколько сил - // складываем их double force = load.Value; double cosa = Math.Cos(load.Direction / 180 * Math.PI); double sina = Math.Sin(load.Direction / 180 * Math.PI); double forceX = force * cosa; double forceY = force * sina; int ind = getNodeIndex(n) * 3; // При этом, если в узле есть связь, запрещающая перемещения по указанному направлению, то // соответствующую часть силы обнуляем if (ind > -1) { // Сила по X if (!n.DisallowedDisplacements.Contains(NodeDisplacement.X)) { Loads[ind] += forceX; } // Сила по Y if (!n.DisallowedDisplacements.Contains(NodeDisplacement.Y)) { Loads[ind + 1] += forceY; } } } if (CompsList[i].CompType == ComponentTypes.ctDistributedLoad) { // Распределённую нагрузку приводим к узловой ComponentLoad load = (ComponentLoad)CompsList[i]; ComponentLinear lc = load.Beam; // Найдём элемент, созданный на основе компонента lc и сообщим ему, // что на нём лежит нагрузка load ElementBeam beam = Rods.Find(b => b.Linear == lc); if (beam != null) { beam.CalcEquivalentlReactions(load); int ind = getNodeIndex(lc.StartNode) * 3; if (ind > -1) { // Сила по X if (!lc.StartNode.DisallowedDisplacements.Contains(NodeDisplacement.X)) { Loads[ind] += beam.Rx1g; } // Сила по Y if (!lc.StartNode.DisallowedDisplacements.Contains(NodeDisplacement.Y)) { Loads[ind + 1] += beam.Ry1g; } // Момент if (!lc.StartNode.DisallowedDisplacements.Contains(NodeDisplacement.Rotation)) { Loads[ind + 2] += beam.M1g; } } ind = getNodeIndex(lc.EndNode) * 3; if (ind > -1) { // Сила по X if (!lc.EndNode.DisallowedDisplacements.Contains(NodeDisplacement.X)) { Loads[ind] += beam.Rx2g; } // Сила по Y if (!lc.EndNode.DisallowedDisplacements.Contains(NodeDisplacement.Y)) { Loads[ind + 1] += beam.Ry2g; } // Момент if (!lc.EndNode.DisallowedDisplacements.Contains(NodeDisplacement.Rotation)) { Loads[ind + 2] += beam.M2g; } } } } } // 4. Применяем ограничения for (int i = 0; i < CompsList.Count; i++) { if (CompsList[i].CompType == ComponentTypes.ctNode) { Block((ComponentNode)CompsList[i]); } } // 5. Получаем перемещения узлов в глобальной системе координат double[,] GlobalInverted = StarMath.inverse(GlobalMatrix); Displacements = StarMath.multiply(GlobalInverted, Loads); // "Подчистим" перемещения от сверхмалых значений CleanupDisplacements(); // Определим значения реакций в узлах - они же внутренние усилия for (int i = 0; i < Rods.Count; i++) { Rods[i].CalculateForces(); } }