/// <summary> /// Find elements either contained, containing or intersecting polygon. /// <para> /// If no elements are found, an empty list is returned. /// </para> /// </summary> public IList <MeshElement> FindElements(Polygon polygon) { if (_elementSearchTree == null) { SetupElementSearch(); } Envelope targetEnvelope = polygon.EnvelopeInternal; IList <MeshElement> potentialElmts = _elementSearchTree.Query(targetEnvelope); List <MeshElement> result = new List <MeshElement>(); // Loop over all potential elements for (int i = 0; i < potentialElmts.Count; i++) { MeshElement element = potentialElmts[i]; // Fast-lane check: When there is no overlap even by the envelopes if (!targetEnvelope.Intersects(element.EnvelopeInternal())) { continue; } // More detailed check for actual overlap Polygon elementPolygon = element.ToPolygon(); if (elementPolygon.Intersects(polygon)) { result.Add(element); } } return(result); }
/// <summary> /// Find element containing (x,y) coordinate. Returns null if no element found. /// <para> /// If (x,y) is exacly on the boundary between two elements, one of them will be returned. /// If (x,y) is matching exacly a node coordinate, one of the elements including the node will be returned. /// </para> /// </summary> public MeshElement FindElement(double x, double y) { // Find potential elements for (x,y) point Envelope targetEnvelope = new Envelope(x, x, y, y); #if NTS173 IList potentialSourceElmts = _elementSearchTree.Query(targetEnvelope); #else IList <MeshElement> potentialSourceElmts = _elementSearchTree.Query(targetEnvelope); #endif // Loop over all potential elements for (int i = 0; i < potentialSourceElmts.Count; i++) { #if NTS173 MeshElement element = (MeshElement)potentialSourceElmts[i]; #else MeshElement element = potentialSourceElmts[i]; #endif // Check if element includes the (x,y) point if (element.Includes(x, y)) { return(element); } } return(null); }
public void BuildNodeElements() { if (Nodes[0].Elements != null) { return; } // Build up element list in nodes for (int i = 0; i < Nodes.Count; i++) { Nodes[i].Elements = new List <MeshElement>(); } for (int ielmt = 0; ielmt < Elements.Count; ielmt++) { MeshElement element = Elements[ielmt]; List <MeshNode> nodeInElmt = element.Nodes; int numNodesInElmt = nodeInElmt.Count; for (int j = 0; j < numNodesInElmt; j++) { MeshNode meshNode = nodeInElmt[j]; meshNode.Elements.Add(element); } } }
/// <summary> /// Set a target being all elements of the <paramref name="targetMesh"/> /// </summary> public void SetTarget(MeshData targetMesh) { SetTargetSize(targetMesh.Elements.Count); for (int i = 0; i < targetMesh.Elements.Count; i++) { MeshElement targetElement = targetMesh.Elements[i]; AddTarget(targetElement.XCenter, targetElement.YCenter); } }
/// <summary> /// Create mesh from arrays. /// </summary> public static MeshData CreateMesh(string projection, int[] nodeIds, double[] x, double[] y, double[] z, int[] code, int[] elementIds, int[] elementTypes, int[][] connectivity, MeshUnit zUnit = MeshUnit.Meter) { MeshData meshData = new MeshData(); meshData.Projection = projection; meshData.ZUnit = zUnit; meshData.Nodes = new List <MeshNode>(nodeIds.Length); meshData.Elements = new List <MeshElement>(elementIds.Length); for (int i = 0; i < nodeIds.Length; i++) { var node = new MeshNode() { Index = i, Id = nodeIds[i], X = x[i], Y = y[i], Z = z[i], Code = code[i], Elements = new List <MeshElement>(), }; meshData.Nodes.Add(node); } for (int ielmt = 0; ielmt < elementIds.Length; ielmt++) { var element = new MeshElement() { Index = ielmt, Id = elementIds[ielmt], ElementType = elementTypes[ielmt], Nodes = new List <MeshNode>(connectivity[ielmt].Length), }; double xc = 0; double yc = 0; double zc = 0; for (int j = 0; j < connectivity[ielmt].Length; j++) { MeshNode meshNode = meshData.Nodes[connectivity[ielmt][j] - 1]; element.Nodes.Add(meshNode); meshNode.Elements.Add(element); xc += meshNode.X; yc += meshNode.Y; zc += meshNode.Z; } element.XCenter = xc / connectivity[ielmt].Length; element.YCenter = yc / connectivity[ielmt].Length; element.ZCenter = zc / connectivity[ielmt].Length; meshData.Elements.Add(element); } return(meshData); }
/// <summary> /// Create mesh from arrays. /// <para> /// Note that the <paramref name="connectivity"/> array is using zero-based indices /// (as compared to the <see cref="MeshFile.ElementTable"/>, which is using one-based indices) /// </para> /// </summary> public MeshDataBase(string projection, int[] nodeIds, double[] x, double[] y, double[] z, int[] code, int[] elementIds, int[] elementTypes, int[][] connectivity, MeshUnit zUnit = MeshUnit.Meter) { Projection = projection; ZUnit = zUnit; Nodes = new List <MeshNode>(nodeIds.Length); Elements = new List <MeshElement>(elementIds.Length); for (int i = 0; i < nodeIds.Length; i++) { var node = new MeshNode() { Index = i, Id = nodeIds[i], X = x[i], Y = y[i], Z = z[i], Code = code[i], }; Nodes.Add(node); } for (int ielmt = 0; ielmt < elementIds.Length; ielmt++) { int[] nodeInElmt = connectivity[ielmt]; int numNodesInElmt = nodeInElmt.Length; var element = new MeshElement() { Index = ielmt, Id = elementIds[ielmt], ElementType = elementTypes[ielmt], Nodes = new List <MeshNode>(numNodesInElmt), }; double xc = 0; double yc = 0; double zc = 0; for (int j = 0; j < numNodesInElmt; j++) { int nodeIndex = nodeInElmt[j]; MeshNode meshNode = Nodes[nodeIndex]; element.Nodes.Add(meshNode); xc += meshNode.X; yc += meshNode.Y; zc += meshNode.Z; } double inumNodesInElmt = 1.0 / numNodesInElmt; element.XCenter = xc * inumNodesInElmt; // / numNodesInElmt; element.YCenter = yc * inumNodesInElmt; // / numNodesInElmt; element.ZCenter = zc * inumNodesInElmt; // / numNodesInElmt; Elements.Add(element); } }
/// <summary> /// Returns true if mesh element is a quadrilateral element /// </summary> public static bool IsQuadrilateral(this MeshElement element) { // TODO: Should probably check on type? int nodesCount = element.Nodes.Count; if (nodesCount == 4 || nodesCount == 8) { return(true); } return(false); }
/// <summary> /// Get the other element of a <see cref="MeshFace"/>, when /// looking from <paramref name="element"/>. /// <para> /// For boundary faces, null is returned. /// </para> /// </summary> public static MeshElement OtherElement(this MeshFace face, MeshElement element) { if (ReferenceEquals(face.LeftElement, element)) { return(face.RightElement); } if (ReferenceEquals(face.RightElement, element)) { return(face.LeftElement); } throw new Exception("element is not part of face"); }
/// <summary> /// Setup for element-search /// </summary> public void SetupElementSearch() { _elementSearchTree = new SearchTreeType(); for (int i = 0; i < _mesh.Elements.Count; i++) { MeshElement element = _mesh.Elements[i]; Envelope extent = element.EnvelopeInternal(); _elementSearchTree.Insert(extent, element); } // When using STRtree, call this method here //_elementSearchTree.Build(); }
/// <summary> /// Convert a <see cref="MeshData"/> class into a <see cref="MeshFile"/> class. /// </summary> public static MeshFile ToMeshFile(this MeshData meshData) { int numberOfNodes = meshData.Nodes.Count; int[] nodeId = new int[numberOfNodes]; double[] x = new double[numberOfNodes]; double[] y = new double[numberOfNodes]; double[] z = new double[numberOfNodes]; int[] code = new int[numberOfNodes]; for (int i = 0; i < numberOfNodes; i++) { MeshNode node = meshData.Nodes[i]; nodeId[i] = node.Id; x[i] = node.X; y[i] = node.Y; z[i] = node.Z; code[i] = node.Code; } int numberOfElements = meshData.Elements.Count; int[] elmtId = new int[numberOfElements]; int[][] elmtTable = new int[numberOfElements][]; for (int i = 0; i < numberOfElements; i++) { MeshElement elmt = meshData.Elements[i]; elmtId[i] = elmt.Id; int[] elmtNodes = new int[elmt.Nodes.Count]; elmtTable[i] = elmtNodes; for (int j = 0; j < elmt.Nodes.Count; j++) { elmtNodes[j] = elmt.Nodes[j].Index + 1; } } MeshFileBuilder builder = new MeshFileBuilder(); builder.SetProjection(meshData.Projection); builder.SetZUnit(meshData.ZUnit); builder.SetNodeIds(nodeId); builder.SetNodes(x, y, z, code); builder.SetElementIds(elmtId); builder.SetElements(elmtTable); MeshFile meshFile = builder.CreateMesh(); return(meshFile); }
private static void CreateAddElementFaces(CMeshData meshData, List <CMeshFace>[] facesFromNode, int ielmt, bool checkAllFaces) { MeshElement elmt = meshData.Elements[ielmt]; List <MeshNode> elmtNodes = elmt.Nodes; for (int j = 0; j < elmtNodes.Count; j++) { MeshNode fromNode = elmtNodes[j]; MeshNode toNode = elmtNodes[(j + 1) % elmtNodes.Count]; if (checkAllFaces || fromNode.Code > 0 && toNode.Code > 0) { MeshData.AddFace(elmt, fromNode, toNode, facesFromNode); } } }
/// <summary> /// Create an envelop around from a mesh element. /// </summary> public static Envelope EnvelopeInternal(this MeshElement element) { List <MeshNode> elementNodes = element.Nodes; double minx = elementNodes[0].X; double miny = elementNodes[0].Y; double maxx = elementNodes[0].X; double maxy = elementNodes[0].Y; for (int i = 1; i < elementNodes.Count; i++) { minx = minx < elementNodes[i].X ? minx : elementNodes[i].X; maxx = maxx > elementNodes[i].X ? maxx : elementNodes[i].X; miny = miny < elementNodes[i].Y ? miny : elementNodes[i].Y; maxy = maxy > elementNodes[i].Y ? maxy : elementNodes[i].Y; } return(new Envelope(minx, maxx, miny, maxy)); }
/// <summary> /// Returns true if coordinate (x,y) is inside element /// </summary> public static bool Includes(this MeshElement element, double x, double y, double tolerance) { bool isQuad = element.IsQuadrilateral(); List <MeshNode> elementNodes = element.Nodes; if (!isQuad) { return (LeftDistance(x, y, elementNodes[0], elementNodes[1]) >= -tolerance && LeftDistance(x, y, elementNodes[1], elementNodes[2]) >= -tolerance && LeftDistance(x, y, elementNodes[2], elementNodes[0]) >= -tolerance); } return (LeftDistance(x, y, elementNodes[0], elementNodes[1]) >= -tolerance && LeftDistance(x, y, elementNodes[1], elementNodes[2]) >= -tolerance && LeftDistance(x, y, elementNodes[2], elementNodes[3]) >= -tolerance && LeftDistance(x, y, elementNodes[3], elementNodes[0]) >= -tolerance); }
/// <summary> /// Create a polygon from a mesh element. /// </summary> public static Polygon ToPolygon(this MeshElement element, GeometryFactory geomFactory) { List <CoordinateZ> coordinates = new List <CoordinateZ>(element.Nodes.Count); MeshNode node; for (int i = 0; i < element.Nodes.Count; i++) { node = element.Nodes[i]; coordinates.Add(new CoordinateZ(node.X, node.Y, node.Z)); } // Add the first node again, to close the polygon node = element.Nodes[0]; coordinates.Add(new CoordinateZ(node.X, node.Y, node.Z)); Polygon elementPolygon = geomFactory.CreatePolygon(coordinates.ToArray()); return(elementPolygon); }
/// <summary> /// Create and add a face. /// <para> /// A face is only "added once", i.e. when two elements share the face, it is found twice, /// once defined as "toNode"-"fromNode" and once as "fromNode"-"toNode". The second time, /// the existing face is being reused, and the element is added as the <see cref="CMeshFace.RightElement"/> /// </para> /// <para> /// The <see cref="CMeshFace"/> is added to the global list of faces, and also to tne nodes list of faces. /// </para> /// </summary> private void AddFace(MeshElement element, MeshNode fromNode, MeshNode toNode) { List <CMeshFace> fromNodeFaces = fromNode.Faces; List <CMeshFace> toNodeFaces = toNode.Faces; // Try find "reverse face" going from to-node to from-node. // The FindIndex with delegate is 10+ times slower than the tight loop below. //int reverseFaceIndex = toNodeFaces.FindIndex(mf => mf.ToNode == fromNode); int reverseToNodeFaceIndex = -1; // Look in all faces starting from toNode for (int i = 0; i < toNodeFaces.Count; i++) { // Check if the face goes to fromNode if (toNodeFaces[i].ToNode == fromNode) { reverseToNodeFaceIndex = i; break; } } if (reverseToNodeFaceIndex >= 0) { // Found reverse face, reuse it and add the element as the RightElement CMeshFace reverseFace = toNodeFaces[reverseToNodeFaceIndex]; reverseFace.RightElement = element; } else { // Found new face, set element as LeftElement and add it to both from-node and to-node CMeshFace meshFace = new CMeshFace(fromNode, toNode) { LeftElement = element, }; Faces.Add(meshFace); fromNodeFaces.Add(meshFace); // Adding to toNodeFaces is not required for the algorithm to work, // however, it is required in order to get NodesFaces lists right toNodeFaces.Add(meshFace); } }
/// <summary> /// Setup for element-search /// </summary> public void SetupElementSearch() { #if NTS173 _elementSearchTree = new STRtree(); #else _elementSearchTree = new STRtree <MeshElement>(); #endif for (int i = 0; i < _mesh.Elements.Count; i++) { MeshElement element = _mesh.Elements[i]; double x = element.Nodes[0].X; double y = element.Nodes[0].Y; Envelope extent = new Envelope(x, x, y, y); for (int j = 1; j < element.Nodes.Count; j++) { extent.ExpandToInclude(element.Nodes[j].X, element.Nodes[j].Y); } _elementSearchTree.Insert(extent, element); } }
/// <summary> /// Set a target being all elements of the <paramref name="targetMesh"/> /// </summary> public void SetTarget(MeshData targetMesh, MeshValueType targetType) { if (targetType == MeshValueType.Elements) { SetTargetSize(targetMesh.NumberOfElements); for (int i = 0; i < targetMesh.NumberOfElements; i++) { MeshElement targetMeshElement = targetMesh.Elements[i]; AddTarget(targetMeshElement.XCenter, targetMeshElement.YCenter); } } else { SetTargetSize(targetMesh.NumberOfNodes); for (int i = 0; i < targetMesh.NumberOfNodes; i++) { MeshNode targetMeshNode = targetMesh.Nodes[i]; AddTarget(targetMeshNode.X, targetMeshNode.Y); } } }
/// <summary> /// Find element containing (x,y) coordinate. Returns null if no element found. /// <para> /// If (x,y) is exactly on the boundary between two elements, one of them will be returned. /// If (x,y) is matching exacly a node coordinate, one of the elements including the node will be returned. /// </para> /// </summary> public MeshElement FindElement(double x, double y) { // Find potential elements for (x,y) point Envelope targetEnvelope = new Envelope(x, x, y, y); IList <MeshElement> potentialSourceElmts = _elementSearchTree.Query(targetEnvelope); // Loop over all potential elements for (int i = 0; i < potentialSourceElmts.Count; i++) { MeshElement element = potentialSourceElmts[i]; // Check if element includes the (x,y) point if (element.Includes(x, y)) { return(element); } } if (Tolerance <= 0) { return(null); } // Try again, now with tolerance for (int i = 0; i < potentialSourceElmts.Count; i++) { MeshElement element = potentialSourceElmts[i]; // Check if element includes the (x,y) point if (element.Includes(x, y, Tolerance)) { return(element); } } return(null); }
/// <summary> /// Determines whether the specified mesh geometry is equal to the current mesh's geometry. /// The order of the nodes and elements in the mesh must equal. /// <para> /// This only checks the geometry, i.e. node coordinates, node boundary codes and element connectivity. /// The Id's in the mesh may differ. /// </para> /// </summary> /// <param name="other"></param> /// <param name="tolerance"></param> public bool EqualsGeometry(MeshData other, double tolerance = 1e-3) { if (this.Nodes.Count != other.Nodes.Count || this.Elements.Count != other.Elements.Count) { return(false); } for (int i = 0; i < this.Nodes.Count; i++) { MeshNode nt = this.Nodes[i]; MeshNode no = other.Nodes[i]; if (Math.Abs(nt.X - no.X) > tolerance || Math.Abs(nt.Y - no.Y) > tolerance || nt.Code != no.Code) { return(false); } } for (int i = 0; i < this.Elements.Count; i++) { MeshElement et = this.Elements[i]; MeshElement eo = other.Elements[i]; if (et.Nodes.Count != eo.Nodes.Count) { return(false); } for (int j = 0; j < et.Nodes.Count; j++) { if (et.Nodes[j].Index != eo.Nodes[j].Index) { return(false); } } } return(true); }
/// <summary> /// Convert a <see cref="MeshData"/> class into a <see cref="SMeshData"/> class. /// </summary> public static SMeshData ToSMesh(this MeshData meshData) { int numberOfNodes = meshData.Nodes.Count; int[] nodeId = new int[numberOfNodes]; double[] x = new double[numberOfNodes]; double[] y = new double[numberOfNodes]; double[] z = new double[numberOfNodes]; int[] code = new int[numberOfNodes]; for (int i = 0; i < numberOfNodes; i++) { MeshNode node = meshData.Nodes[i]; nodeId[i] = node.Id; x[i] = node.X; y[i] = node.Y; z[i] = node.Z; code[i] = node.Code; } int numberOfElements = meshData.Elements.Count; int[] elmtId = new int[numberOfElements]; int[][] elmtTable = new int[numberOfElements][]; for (int i = 0; i < numberOfElements; i++) { MeshElement elmt = meshData.Elements[i]; elmtId[i] = elmt.Id; int[] elmtNodes = new int[elmt.Nodes.Count]; elmtTable[i] = elmtNodes; for (int j = 0; j < elmt.Nodes.Count; j++) { elmtNodes[j] = elmt.Nodes[j].Index; } } return(new SMeshData(meshData.Projection, nodeId, x, y, z, code, elmtId, null, elmtTable, meshData.ZUnit)); }
/// <summary> /// Create and add a face. /// <para> /// A face is only "added once", i.e. when two elements share the face, it is found twice, /// once defined as "toNode"-"fromNode" and once as "fromNode"-"toNode". The second time, /// the existing face is being reused, and the element is added as the <see cref="MeshFace.RightElement"/> /// </para> /// <para> /// The <see cref="MeshFace"/> is added to the global list of faces, and also to tne nodes list of faces. /// </para> /// </summary> private void AddFace(MeshElement element, MeshNode fromNode, MeshNode toNode) { List <MeshFace> fromNodeFaces = fromNode.Faces; List <MeshFace> toNodeFaces = toNode.Faces; if (fromNodeFaces.FindIndex(mf => mf.ToNode == toNode) >= 0) { throw new Exception(string.Format("Invalid mesh: Double face, from node {0} to node {1}. " + "Hint: Probably too many nodes was merged into one of the two face nodes." + "Try decrease node merge tolerance value", fromNode.Index + 1, toNode.Index + 1)); } // Try find "reverse face" going from from-node to to-node. int reverseFaceIndex = toNodeFaces.FindIndex(mf => mf.ToNode == fromNode); if (reverseFaceIndex >= 0) { // Found reverse face, reuse it and add the elment as the RightElement MeshFace reverseFace = toNodeFaces[reverseFaceIndex]; reverseFace.RightElement = element; } else { // Found new face, set element as LeftElement and add it to both from-node and to-node MeshFace meshFace = new MeshFace() { FromNode = fromNode, ToNode = toNode, LeftElement = element, }; Faces.Add(meshFace); fromNodeFaces.Add(meshFace); toNodeFaces.Add(meshFace); } }
/// <summary> /// Create and add a face - special version for <see cref="MeshBoundaryExtensions.GetBoundaryFaces(MeshData)"/> /// <para> /// A face is only "added once", i.e. when two elements share the face, it is found twice, /// once defined as "toNode"-"fromNode" and once as "fromNode"-"toNode". The second time, /// the existing face is being reused, and the element is added as the <see cref="CMeshFace.RightElement"/> /// </para> /// <para> /// The <see cref="CMeshFace"/> is added to the global list of faces, and also to tne nodes list of faces. /// </para> /// </summary> internal static void AddFace(MeshElement element, MeshNode fromNode, MeshNode toNode, List <CMeshFace>[] nodeFaces) { List <CMeshFace> fromNodeFaces = nodeFaces[fromNode.Index]; List <CMeshFace> toNodeFaces = nodeFaces[toNode.Index]; // Try find "reverse face" going from from-node to to-node. // The FindIndex with delegate is 10+ times slower than the tight loop below. //int reverseFaceIndex = toNodeFaces.FindIndex(mf => mf.ToNode == fromNode); int reverseFaceIndex = -1; for (int i = 0; i < toNodeFaces.Count; i++) { if (toNodeFaces[i].ToNode == fromNode) { reverseFaceIndex = i; break; } } if (reverseFaceIndex >= 0) { // Found reverse face, reuse it and add the element as the RightElement CMeshFace reverseFace = toNodeFaces[reverseFaceIndex]; reverseFace.RightElement = element; } else { // Found new face, set element as LeftElement and add it to both from-node and to-node CMeshFace meshFace = new CMeshFace(fromNode, toNode) { LeftElement = element, }; fromNodeFaces.Add(meshFace); } }
/// <summary> /// Find elements either contained, containing or intersecting the polygon. /// <para> /// This method can be used if only some elements of the mesh is to be included /// in the weight calculations. /// </para> /// <para> /// If polygon is totally contained within one mesh element, then 1 element is returned. /// If polygon partially falls outside of the grid, only elements within grid are returned. /// </para> /// <param name="polygon">Polygon or multi-polygon</param> /// <param name="elements">List of elements</param> /// </summary> public List <ElementWeight> CalculateWeights(Geometry polygon, IList <MeshElement> elements) { Envelope targetEnvelope = polygon.EnvelopeInternal; //// It should be faster to use than the polygon directly? //PreparedPolygon prepolygon = new PreparedPolygon(polygon); List <ElementWeight> result = new List <ElementWeight>(); // Total intersecting area double totalArea = 0; // Loop over all potential elements for (int i = 0; i < elements.Count; i++) { MeshElement element = elements[i]; // Fast-lane check: When there is no overlap even by the envelopes if (!targetEnvelope.Intersects(element.EnvelopeInternal())) { continue; } Polygon elementPolygon = element.ToPolygon(); Geometry intersection = elementPolygon.Intersection(polygon); if (!intersection.IsEmpty) { // Target polygon and element polygon has an overlap. // If target polygon fully contains the element polygon, this is the element area // If element polygon fully contains the target polygon, this is the polygon area double intersectingArea = intersection.Area; totalArea += intersectingArea; if (WeightType == WeightType.Fraction) { result.Add(new ElementWeight(element, intersectingArea / elementPolygon.Area)); } else { result.Add(new ElementWeight(element, intersectingArea)); } } } IntersectionArea = totalArea; if (result.Count == 0 || totalArea == 0) { return(null); } // When Weight-based calculations, weight with the total intersecting area if (WeightType == WeightType.Weight) { for (int i = 0; i < result.Count; i++) { ElementWeight elmtWeight = result[i]; elmtWeight.Weight /= totalArea; result[i] = elmtWeight; } } return(result); }
/// <summary> /// Add a target, by specifying its (x,y) coordinate. /// </summary> public void AddTarget(double x, double y) { if (_mesh == null) { AddSTarget(x, y); return; } // Find element that includes the (x,y) coordinate MeshElement element = _searcher.FindElement(x, y); // Setup interpolation from node values if (NodeValueInterpolation) { InterpNodeData interp; // Check if element has been found, i.e. includes the (x,y) point if (element != null) { var nodes = element.Nodes; if (nodes.Count == 3) { var weights = InterpTriangle.InterpolationWeights(x, y, nodes); interp = new InterpNodeData(element.Index, weights.w1, weights.w2, weights.w3); } else if (nodes.Count == 4) { var weights = InterpQuadrangle.InterpolationWeights(x, y, nodes); interp = new InterpNodeData(element.Index, weights.dx, weights.dy); } else { interp = InterpNodeData.Undefined(); } } else { interp = InterpNodeData.Undefined(); } if (_targetsNode == null) { _targetsNode = new List <InterpNodeData>(); } _targetsNode.Add(interp); } // Setup interpolation from element+node values if (ElmtNodeValueInterpolation) { InterpElmtNode.Weights weights; // Check if element has been found, i.e. includes the (x,y) point if (element != null) { weights = InterpElmtNode.InterpolationWeights(x, y, element); } else { weights = InterpElmtNode.Undefined(); } if (_targetsElmtNode == null) { _targetsElmtNode = new List <InterpElmtNode.Weights>(); } _targetsElmtNode.Add(weights); } }
/// <summary> /// Create a polygon from a mesh element /// </summary> public static Polygon ToPolygon(this MeshElement element) { return(element.ToPolygon(GeomFactory)); }
/// <summary> /// Add a target, by specifying its (x,y) coordinate. /// </summary> public void AddTarget(double x, double y) { if (_targets == null) { _targets = new List <InterPData>(); } if (_searcher == null) { _searcher = new MeshSearcher(_mesh); _searcher.SetupElementSearch(); } InterPData interpData = new InterPData(); // Setting "out-of-bounds" index interpData.Element1Index = -1; // Find element that includes the (x,y) coordinate MeshElement element = _searcher.FindElement(x, y); // Check if element has been found, i.e. includes the (x,y) point if (element != null) { bool found = false; interpData.Element1Index = element.Index; // Check which face the point belongs to, and which "side" of the face bool isQuad = element.IsQuadrilateral(); int numFaces = isQuad ? 4 : 3; for (int j = 0; j < numFaces; j++) { MeshFace elementFace = element.Faces[j]; // From the element (x,y), looking towards the face, // figure out wich node is right and which is left. MeshNode rightNode, leftNode; if (elementFace.LeftElement == element) { rightNode = elementFace.FromNode; leftNode = elementFace.ToNode; } else { rightNode = elementFace.ToNode; leftNode = elementFace.FromNode; } // Find also the element on the other side of the face double otherElementX, otherElementY; MeshElement otherElement = elementFace.OtherElement(element); if (otherElement != null) { otherElementX = otherElement.XCenter; otherElementY = otherElement.YCenter; interpData.Element2Index = otherElement.Index; } else { // No other element - boundary face, use center of face. otherElementX = 0.5 * (rightNode.X + leftNode.X); otherElementY = 0.5 * (rightNode.Y + leftNode.Y); // Use "itself" as element-2 interpData.Element2Index = element.Index; } // Check if point is on the right side of the line between element and other-element if (MeshExtensions.IsPointInsideLines(x, y, element.XCenter, element.YCenter, rightNode.X, rightNode.Y, otherElementX, otherElementY)) { (double w1, double w2, double w3) = MeshExtensions.InterpolationWeights(x, y, element.XCenter, element.YCenter, rightNode.X, rightNode.Y, otherElementX, otherElementY); interpData.NodeIndex = rightNode.Index; interpData.Element1Weight = w1; interpData.NodeWeight = w2; interpData.Element2Weight = w3; found = true; break; } // Check if point is on the left side of the line between element and other-element if (MeshExtensions.IsPointInsideLines(x, y, element.XCenter, element.YCenter, otherElementX, otherElementY, leftNode.X, leftNode.Y)) { (double w1, double w2, double w3) = MeshExtensions.InterpolationWeights(x, y, element.XCenter, element.YCenter, otherElementX, otherElementY, leftNode.X, leftNode.Y); interpData.NodeIndex = leftNode.Index; interpData.Element1Weight = w1; interpData.Element2Weight = w2; interpData.NodeWeight = w3; found = true; break; } } if (!found) // Should never happen, but just in case { interpData.Element1Weight = 1; interpData.Element2Weight = 0; interpData.NodeWeight = 0; interpData.Element2Index = element.Index; interpData.NodeIndex = element.Nodes[0].Index; } } _targets.Add(interpData); }
/// <summary> /// Build derived mesh data, especially the <see cref="MeshFace"/> lists. /// </summary> public void BuildDerivedData() { Faces = new List <MeshFace>(); // Preallocate list of face on all nodes - used in next loop for (int i = 0; i < Nodes.Count; i++) { Nodes[i].Faces = new List <MeshFace>(); } // Create all faces. for (int ielmt = 0; ielmt < Elements.Count; ielmt++) { MeshElement element = Elements[ielmt]; element.Faces = new List <MeshFace>(); List <MeshNode> elmtNodes = element.Nodes; for (int j = 0; j < elmtNodes.Count; j++) { MeshNode fromNode = elmtNodes[j]; MeshNode toNode = elmtNodes[(j + 1) % elmtNodes.Count]; AddFace(element, fromNode, toNode); } } // Figure out boundary code for (int i = 0; i < Faces.Count; i++) { MeshFace face = Faces[i]; // If the RightElement exists, this face is an internal face if (face.RightElement != null) { continue; } // RightElement does not exist, so it is a boundary face. int fromCode = face.FromNode.Code; int toCode = face.ToNode.Code; // True if "invalid" boundary face, then set it as internal face. bool internalFace = false; if (fromCode == 0) { internalFace = true; throw new Exception(string.Format("Invalid mesh: Boundary face, from node {0} to node {1} is missing a boundary code on node {0}. " + "Hint: Modify boundary code for node {0}", face.FromNode.Index + 1, face.ToNode.Index + 1)); } if (toCode == 0) { internalFace = true; throw new Exception(string.Format("Invalid mesh: Boundary face, from node {0} to node {1} is missing a boundary code on node {1}. " + "Hint: Modify boundary code for node {1}", face.FromNode.Index + 1, face.ToNode.Index + 1)); } int faceCode; // Find face code: // 1) In case any of the nodes is a land node (code value 1) then the // boundary face is a land face, given boundary code value 1. // 2) For boundary faces (if both fromNode and toNode have code values larger than 1), // the face code is the boundary code value of toNode. if (fromCode == 1 || toCode == 1) { faceCode = 1; } else { faceCode = toCode; } if (!internalFace) { face.Code = faceCode; } } // Add face to the elements list of faces for (int i = 0; i < Faces.Count; i++) { MeshFace face = Faces[i]; face.LeftElement.Faces.Add(face); face.RightElement?.Faces.Add(face); } }
public ElementWeight(MeshElement element, double weight) { ElementIndex = element.Index; Weight = weight; }
/// <summary> /// Calculate interpolation weights for interpolating a value at the provided <paramref name="node"/> /// from the surrounding element center values. /// </summary> /// <param name="node">Node to setup interpolation for</param> public Interpolator.InterPData SetupNodeInterpolation(MeshNode node) { Interpolator.InterPData interpData = new Interpolator.InterPData() { Indices = new int[node.Elements.Count], Weights = new double[node.Elements.Count], }; double Ixx = 0; double Iyy = 0; double Ixy = 0; double Rx = 0; double Ry = 0; double omegaTot = 0; for (int i = 0; i < node.Elements.Count; i++) { MeshElement element = node.Elements[i]; double dx = element.XCenter - node.X; double dy = element.YCenter - node.Y; Ixx += dx * dx; Iyy += dy * dy; Ixy += dx * dy; Rx += dx; Ry += dy; interpData.Indices[i] = element.Index; } double lambda = Ixx * Iyy - Ixy * Ixy; if (lambda > 1e-10 * (Ixx * Iyy)) { // Standard case - Pseudo Laplacian for (int i = 0; i < node.Elements.Count; i++) { MeshElement element = node.Elements[i]; double dx = element.XCenter - node.X; double dy = element.YCenter - node.Y; double lambda_x = (Ixy * Ry - Iyy * Rx) / lambda; double lambda_y = (Ixy * Rx - Ixx * Ry) / lambda; double omega = 1.0 + lambda_x * dx + lambda_y * dy; if (!_allowExtrapolation) { if (omega < 0) { omega = 0; } else if (omega > 2) { omega = 2; } } interpData.Weights[i] = omega; omegaTot += omega; } } if (omegaTot <= 0) { // We did not succeed using pseudo laplace procedure, // use inverse distance instead omegaTot = 0; for (int i = 0; i < node.Elements.Count; i++) { MeshElement element = node.Elements[i]; double dx = element.XCenter - node.X; double dy = element.YCenter - node.Y; // Inverse distance weighted interpolation weight double omega = 1 / Math.Sqrt(dx * dx + dy * dy); interpData.Weights[i] = omega; omegaTot += omega; } } // Scale to 1 if (omegaTot != 0) { for (int i = 0; i < interpData.Weights.Length; i++) { interpData.Weights[i] /= omegaTot; } } else { for (int i = 0; i < interpData.Weights.Length; i++) { interpData.Weights[i] = 0; } } //double sum = 0; //for (int i = 0; i < interpData.Weights.Length; i++) //{ // sum += interpData.Weights[i]; //} //if (Math.Abs(sum - 1) > 1e-12) // Console.Out.WriteLine("Duh!!!: "+node.Index); return(interpData); }
/// <summary> /// Build up the list of <see cref="Faces"/> /// </summary> /// <param name="elmtFaces">Also build up <see cref="MeshElement.Faces"/></param> public List <string> BuildFaces(bool elmtFaces = false) { List <string> errors = new List <string>(); int numberOfNodes = NumberOfNodes; int numberOfElements = NumberOfElements; bool hasElementFaces = Elements[0].Faces != null; //System.Diagnostics.Stopwatch timer = MeshExtensions.StartTimer(); if (Faces == null) { // Build up face lists // The exact number of faces is: NumberOfElements+NumberOfNodes + numberOfSubMeshes - numberOfHoles Faces = new List <CMeshFace>((int)((numberOfElements + numberOfNodes) * 1.01)); // Preallocate list of face on all nodes - used in next loop for (int i = 0; i < Nodes.Count; i++) { Nodes[i].Faces = new List <CMeshFace>(); } //timer.ReportAndRestart("Prealloc nodeface"); //watch.Start(); // Create all faces. for (int ielmt = 0; ielmt < Elements.Count; ielmt++) { MeshElement element = Elements[ielmt]; List <MeshNode> elmtNodes = element.Nodes; if (elmtFaces) { element.Faces = new List <CMeshFace>(elmtNodes.Count); } for (int j = 0; j < elmtNodes.Count; j++) { MeshNode fromNode = elmtNodes[j]; MeshNode toNode = elmtNodes[(j + 1) % elmtNodes.Count]; AddFace(element, fromNode, toNode); } } //timer.ReportAndRestart("Create faces "+Faces.Count); // Figure out boundary code for (int i = 0; i < Faces.Count; i++) { CMeshFace face = Faces[i]; face.SetBoundaryCode(errors); } //timer.ReportAndRestart("Set Boundary Code"); } if (elmtFaces && !hasElementFaces) { // If not already created, create the lists if (Elements[0].Faces == null) { for (int ielmt = 0; ielmt < numberOfElements; ielmt++) { Elements[ielmt].Faces = new List <CMeshFace>(); } } // Add face to the elements list of faces for (int i = 0; i < Faces.Count; i++) { CMeshFace face = Faces[i]; face.LeftElement.Faces.Add(face); if (face.RightElement != null) { face.RightElement.Faces.Add(face); } } } //timer.ReportAndRestart("Create element faces"); return(errors); }