private double radius; // 外接円半径 #endregion Fields #region Constructors /// <summary> /// DelaunayElement2Dクラスの新規インスタンスを初期化し,各頂点情報(座標,ID)をセットする. /// </summary> /// <param name="a"></param> /// <param name="b"></param> /// <param name="c"></param> public DelaunayElement2D(Node a, Node b, Node c) { Elementcode = ElementCode.Tria03; Nodes = new List<Node>() { a, b, c }; Edges = new List<Edge>() { new Edge(a.ID, b.ID), new Edge(b.ID, c.ID), new Edge(c.ID, a.ID) }; center = new Node(-256, false, 0.0, 0.0); radius = 0; SetSideLength(); Area = CalcArea(); SetCircumscribedCircle(); DeleteFlag = false; }
/// <summary> /// コピーコンストラクタ /// </summary> /// <param name="source">コピーされるobject</param> public DelaunayElement2D(DelaunayElement2D source) { Elementcode = source.Elementcode; Nodes = new List<Node>() { source.Nodes[0], source.Nodes[1], source.Nodes[2] }; Edges = new List<Edge>() { source.Edges[0], source.Edges[1], source.Edges[2] }; Area = source.Area; center = new Node(source.center); radius = source.radius; DeleteFlag = source.DeleteFlag; }
/// <summary> /// (要素が四面体の場合のみ)与えられた点の座標が外接球の内部に含まれるかどうか判定する. /// </summary> /// <param name="p">点</param> /// <returns>判定結果</returns> public bool IsInside(Node p) { if (Nodes.Count == 4) { double distance_sq = ((p.X - center.X) * (p.X - center.X) + (p.Y - center.Y) * (p.Y - center.Y) + (p.Z - center.Z) * (p.Z - center.Z)); if (distance_sq < radius * radius) { return true; } else { return false; } } else { return false; } }
public Element3D(Node a, Node b, Node c, Node d) { Nodes = new List<Node>() { a, b, c, d }; Edges = new List<Edge>(); Surfaces = new List<Surface3D>() { new Surface3D(a.ID, b.ID, c.ID), new Surface3D(a.ID, d.ID, b.ID), new Surface3D(b.ID, d.ID, c.ID), new Surface3D(a.ID, c.ID, d.ID) }; center = new Node(0, false, 0.0, 0.0, 0.0); SetCircumscribedSphere(); DeleteFlag = false; }
/// <summary> /// コピーコンストラクタ /// </summary> /// <param name="source"></param> public Element3D(Element3D source) { elementcode = source.elementcode; material = source.material; Nodes = new List<Node>(); for (int i = 0; i < source.Nodes.Count; ++i) { Nodes.Add(new Node(source.Nodes[i])); } Edges = new List<Edge>(); for (int i = 0; i < source.Edges.Count; ++i) { Edges.Add(new Edge(source.Edges[i])); } Surfaces = new List<Surface3D>(); for (int i = 0; i < source.Surfaces.Count; ++i) { Surfaces.Add(new Surface3D(source.Surfaces[i])); } center = new Node(source.center); radius = source.radius; DeleteFlag = source.DeleteFlag; }
/// <summary> /// 追加ノードに対して,そのノードを外接球内部に含むような要素をすべて探索し,該当領域のメッシュ・サーフェスを抽出する. /// </summary> /// <param name="adding_node">追加ノード</param> /// <param name="rediv_surface">再分割要素を囲むサーフェスを返す</param> private void SearchRedivisionMesh(Node adding_node, out List<Surface3D> rediv_surface) { rediv_surface = new List<Surface3D>(); for (int j = 0; j < delaunay_elements.Count; j++) { if (delaunay_elements[j].IsInside(adding_node)) //ノードを外接球内部に含むような要素であれば { for (int k = 0; k < 4; k++) { var find_surface = delaunay_elements[j].GetSurface(k); if (rediv_surface.Exists(ls => ls == find_surface)) { rediv_surface.RemoveAll(ls => ls == find_surface); //サーフェスの重複は必ず2回なので重複が検知された場合除去 } else { rediv_surface.Add(find_surface); //重複のない場合は取り合えず追加 } } delaunay_elements[j].DeleteFlag = true; //削除用フラグのセット } } }
/// <summary> /// 与えられている全てのノード座標を読み取り,これらすべてを囲むようなブラケット三角形要素を生成し,elemに追加する.また,最大値最小値をセットする. /// </summary> private void SetBracketTriangle() { var min_x = givennode_min_x = given_node.Min(ls => ls.X); var max_x = givennode_max_x = given_node.Max(ls => ls.X); var min_y = givennode_min_y = given_node.Min(ls => ls.Y); var max_y = givennode_max_y = given_node.Max(ls => ls.Y); var min_z = givennode_min_z = given_node.Min(ls => ls.Z); var max_z = givennode_max_z = given_node.Max(ls => ls.Z); var cubecenter = new Node(0, false, (min_x + max_x) / 2, (min_y + max_y) / 2, (min_z + max_z) / 2); var cubulength = Math.Max(Math.Max((max_x - min_x), (max_y - min_y)), (max_z - min_z)); //与えられた全てのノードを内部に含み,各辺が座標軸に平行な最小の立方体の辺の長さ // cubelength = a とおく.一辺aの立方体の外接円の半径rはr=\sqrt{3}/2*a // 半径rの球の外接正四面体の一辺の長さLはL=3\sqrt{2}a // 球の中心から正四面体の頂点までの距離は3r = 3*\sqrt{3}/2*a <= 3a // 球の中心から正四面体の面までの距離はr = \sqrt{3}/2*a <= a bracket_node.Add(new Node(-4, false, cubecenter.X, cubecenter.Y + 2.5 * cubulength, cubecenter.Z - cubulength)); //上から見て底面上 bracket_node.Add(new Node(-3, false, cubecenter.X - 2.2 * cubulength, cubecenter.Y - 1.3 * cubulength, cubecenter.Z - cubulength)); //上から見て底面左下 bracket_node.Add(new Node(-2, false, cubecenter.X + 2.2 * cubulength, cubecenter.Y - 1.3 * cubulength, cubecenter.Z - cubulength)); //上から見て底面右下 bracket_node.Add(new Node(-1, false, cubecenter.X, cubecenter.Y, cubecenter.Z + 3 * cubulength)); //真上 delaunay_elements.Add(new Element3D(bracket_node[0], bracket_node[1], bracket_node[2], bracket_node[3])); }
/// <summary> /// 再分割領域を分割しメッシュを追加する. /// </summary> /// <param name="adding_node"></param> /// <param name="rediv_surface"></param> private void Redivision(Node adding_node, List<Surface3D> rediv_surface) { for (int i = 0; i < rediv_surface.Count; i++) { double[,] coordi = new double[3, 3]; for (int j = 0; j < 3; j++) { if (rediv_surface[i].GetNodeID(j) < 0) //ノードインデックス負数(ブラケット節点)の場合 { coordi[j, 0] = bracket_node[4 + rediv_surface[i].GetNodeID(j)].X; coordi[j, 1] = bracket_node[4 + rediv_surface[i].GetNodeID(j)].Y; coordi[j, 2] = bracket_node[4 + rediv_surface[i].GetNodeID(j)].Z; } else { coordi[j, 0] = given_node[rediv_surface[i].GetNodeID(j)].X; coordi[j, 1] = given_node[rediv_surface[i].GetNodeID(j)].Y; coordi[j, 2] = given_node[rediv_surface[i].GetNodeID(j)].Z; } } delaunay_elements.Add(new Element3D(new Node(rediv_surface[i].GetNodeID(0), false, coordi[0, 0], coordi[0, 1], coordi[0, 2]), new Node(rediv_surface[i].GetNodeID(1), false, coordi[1, 0], coordi[1, 1], coordi[1, 2]), new Node(rediv_surface[i].GetNodeID(2), false, coordi[2, 0], coordi[2, 1], coordi[2, 2]), adding_node ) ); } }
/// <summary> /// 追加ノードに対して,そのノードを外接円内部に含むような要素をすべて探索し,該当領域のメッシュ・エッジ・ノードを抽出する. /// </summary> /// <param name="add_node">追加ノード</param> /// <param name="rediv_edge">再分割要素を囲むエッジを返す</param> private void SearchRedivisionMesh(Node add_node, out List<Edge> rediv_edge) { rediv_edge = new List<Edge>(); for (int i = 0; i < delaunay_elements.Count; i++) { if (delaunay_elements[i].IsInside(add_node)) //ノードを外接円内部に含むような要素の探索 { for (int j = 0; j < 3; j++) { var find_edge = delaunay_elements[i].GetEdge(j); if (rediv_edge.Exists(ls => ls == find_edge)) { rediv_edge.RemoveAll(ls => ls == find_edge); //エッジの重複は必ず2回なので重複が検地された場合除去 } else { rediv_edge.Add(find_edge); //重複のない場合は追加 } } delaunay_elements[i].DeleteFlag = true; //削除用フラグのセット } } }
/// <summary> /// 再分割領域を分割しメッシュを追加する. /// </summary> /// <param name="adding_node">追加ノード</param> /// <param name="rediv_edge">再分割領域を囲むエッジ</param> private void Redivision(Node adding_node, List<Edge> rediv_edge) { for (int j = 0; j < rediv_edge.Count; j++) { double start_coordi_x = 0; double start_coordi_y = 0; double end_coordi_x = 0; double end_coordi_y = 0; bool start_onboundary = false; bool end_onboundary = false; if (rediv_edge[j].StartNodeId < 0) //ノードインデックス負数(ブラケット節点)の場合 { // start_coordi_x = bracket_node[bracket_node.Count + rediv_edge[j].StartNodeId].X; start_coordi_y = bracket_node[bracket_node.Count + rediv_edge[j].StartNodeId].Y; start_onboundary = bracket_node[bracket_node.Count + rediv_edge[j].StartNodeId].OnBoundary; } else { start_coordi_x = given_node[rediv_edge[j].StartNodeId].X; start_coordi_y = given_node[rediv_edge[j].StartNodeId].Y; start_onboundary = given_node[rediv_edge[j].StartNodeId].OnBoundary; } if (rediv_edge[j].EndNodeId < 0) //ノードインデックス負数(ブラケット節点)の場合 { end_coordi_x = bracket_node[bracket_node.Count + rediv_edge[j].EndNodeId].X; end_coordi_y = bracket_node[bracket_node.Count + rediv_edge[j].EndNodeId].Y; end_onboundary = bracket_node[bracket_node.Count + rediv_edge[j].EndNodeId].OnBoundary; } else { end_coordi_x = given_node[rediv_edge[j].EndNodeId].X; end_coordi_y = given_node[rediv_edge[j].EndNodeId].Y; end_onboundary = given_node[rediv_edge[j].EndNodeId].OnBoundary; } delaunay_elements.Add(new DelaunayElement2D(adding_node, new Node(rediv_edge[j].StartNodeId, start_onboundary, start_coordi_x, start_coordi_y), new Node(rediv_edge[j].EndNodeId, end_onboundary, end_coordi_x, end_coordi_y) ) ); } }
/// <summary> /// コピーコンストラクタ /// </summary> /// <param name="source"></param> public Node(Node source) { Dimension = source.Dimension; ID = source.ID; OnBoundary = source.OnBoundary; ConnectedNodeID = new List<int>(); for (int i = 0; i < source.ConnectedNodeID.Count; ++i) { ConnectedNodeID.Add(source.ConnectedNodeID[i]); } coordinates = new double[Dimension]; rest = new bool[Dimension]; point_force = new double[Dimension]; point_force_exist = new bool[Dimension]; for (int i = 0; i < Dimension; ++i) { coordinates[i] = source.coordinates[i]; rest[i] = source.rest[i]; point_force[i] = source.point_force[i]; point_force_exist[i] = source.point_force_exist[i]; } }
public bool PositiveSide(Node p) { return true; }