/// <summary> /// Interpolate source values to target /// </summary> public void Interpolate(double[] sourceValues, double[] targetValues) { // Loop over all target elements/nodes for (int i = 0; i < _interpData.Length; i++) { InterPData interPData = _interpData[i]; double value = 0; double weight = 0; int[] indices = interPData.Indices; double[] weights = interPData.Weights; // For angular-type data, find reference value double refValue = 0; if (_circularType != CircularValueTypes.Normal) { for (int j = 0; j < indices.Length; j++) { double sourceValue = sourceValues[indices[j]]; if (sourceValue != _deleteValue) { // First one found is good, break out. refValue = sourceValue; break; } } } // Loop over all source elements connected to target for (int j = 0; j < indices.Length; j++) { double sourceValue = sourceValues[indices[j]]; if (sourceValue != _deleteValue) { // For angular type values, correct to match reference value CircularValueHandler.ToReference(_circularType, ref sourceValue, refValue); value += sourceValue * weights[j]; weight += weights[j]; } } if (weight == 0) // all element values were delete values { targetValues[i] = _deleteValue; } else { value /= weight; // For angular type values, correct to match angular span. CircularValueHandler.ToCircular(_circularType, ref value); targetValues[i] = value; } } }
/// <summary> /// Interpolate values from source (element values) to target points. /// </summary> public void InterpolateToTarget(double[] sourceElementValues, double[] target) { // Firstly, interpolate to node values _nodeInterpolator.Interpolate(sourceElementValues, _nodeValues); for (int i = 0; i < _targets.Count; i++) { InterPData interPData = _targets[i]; if (interPData.Element1Index < 0) { // target not included in source target[i] = _deleteValue; continue; } // Do interpolation inside (element-element-node) triangle, // disregarding any delete values. double sourceElementValue = sourceElementValues[interPData.Element1Index]; if (sourceElementValue != _deleteValue) { double value = sourceElementValue * interPData.Element1Weight; double weight = interPData.Element1Weight; { double otherElmentValue = sourceElementValues[interPData.Element2Index]; if (otherElmentValue != _deleteValue) { CircularValueHandler.ToReference(_circularType, ref otherElmentValue, sourceElementValue); value += otherElmentValue * interPData.Element2Weight; weight += interPData.Element2Weight; } } { double nodeValue = _nodeValues[interPData.NodeIndex]; if (nodeValue != _deleteValue) { CircularValueHandler.ToReference(_circularType, ref nodeValue, sourceElementValue); value += nodeValue * interPData.NodeWeight; weight += interPData.NodeWeight; } } value /= weight; CircularValueHandler.ToCircular(_circularType, ref value); target[i] = value; } else { target[i] = _deleteValue; } } }
/// <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); }