1 /*=========================================================================
2  *
3  *  Copyright Insight Software Consortium
4  *
5  *  Licensed under the Apache License, Version 2.0 (the "License");
6  *  you may not use this file except in compliance with the License.
7  *  You may obtain a copy of the License at
8  *
9  *         http://www.apache.org/licenses/LICENSE-2.0.txt
10  *
11  *  Unless required by applicable law or agreed to in writing, software
12  *  distributed under the License is distributed on an "AS IS" BASIS,
13  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  *  See the License for the specific language governing permissions and
15  *  limitations under the License.
16  *
17  *=========================================================================*/
18 
19 #include "itkFEMElement2DC0LinearLine.h"
20 
21 namespace itk
22 {
23 namespace fem
24 {
25 void
26 Element2DC0LinearLine
GetIntegrationPointAndWeight(unsigned int i,VectorType & pt,Float & w,unsigned int order) const27 ::GetIntegrationPointAndWeight(unsigned int i, VectorType & pt, Float & w, unsigned int order) const
28 {
29 
30   // default integration order
31   if( ( order == 0 ) || (order >= Element::gaussMaxOrder) )
32     {
33     order = DefaultIntegrationOrder;
34     }
35 
36   pt.set_size(1);
37 
38   pt[0] = gaussPoint[order][i];
39   w = gaussWeight[order][i];
40 }
41 
42 unsigned int
43 Element2DC0LinearLine
GetNumberOfIntegrationPoints(unsigned int order) const44 ::GetNumberOfIntegrationPoints(unsigned int order) const
45 {
46   // default integration order
47   if( ( order == 0 ) || (order >= Element::gaussMaxOrder) )
48     {
49     order = DefaultIntegrationOrder;
50     }
51 
52   return order;
53 }
54 
55 Element2DC0LinearLine::VectorType
56 Element2DC0LinearLine
ShapeFunctions(const VectorType & pt) const57 ::ShapeFunctions(const VectorType & pt) const
58 {
59   /* Linear Line element has two shape functions  */
60   VectorType shapeF(2);
61 
62   shapeF[0] = 0.5 - pt[0] / 2.0;
63   shapeF[1] = 0.5 + pt[0] / 2.0;
64 
65   return shapeF;
66 }
67 
68 void
69 Element2DC0LinearLine
ShapeFunctionDerivatives(const VectorType &,MatrixType & shapeD) const70 ::ShapeFunctionDerivatives(const VectorType &, MatrixType & shapeD) const
71 {
72   shapeD.set_size(1, 2);
73 
74   shapeD[0][0] = -0.5;
75   shapeD[0][1] =  0.5;
76 }
77 
78 void
79 Element2DC0LinearLine
Jacobian(const VectorType &,MatrixType & J,const MatrixType *) const80 ::Jacobian(const VectorType &, MatrixType & J, const MatrixType *) const
81 {
82   // Since the line element defines only one global coordinate
83   // and lives in 2D space, we need to provide a custom Jacobian.
84   J.set_size(1, 1);
85 
86   // Get the length of the element
87   // Note: This simple implementation is only valid for linear line elements.
88   //       For higher order elements we must integrate to obtain the exact
89   //       element length
90   Float l = ( this->m_node[1]->GetCoordinates() - this->m_node[0]->GetCoordinates() ).magnitude();
91   J[0][0] = l / 2;
92 }
93 
94 bool
95 Element2DC0LinearLine
GetLocalFromGlobalCoordinates(const VectorType & globalPt,VectorType & pcoords) const96 ::GetLocalFromGlobalCoordinates(const VectorType & globalPt, VectorType & pcoords) const
97 {
98   VectorType closestPoint(3);
99 
100   pcoords[1] = 0.0;
101   pcoords[2] = 0.0;
102 
103   // get the length of the element
104   const Float l = ( this->m_node[1]->GetCoordinates() - this->m_node[0]->GetCoordinates() ).magnitude();
105 
106   // tolerance is based on the length of the element
107   const Float tol = l * l * 1e-8;
108 
109   const VectorType a1 = this->m_node[0]->GetCoordinates();
110   const VectorType a2 = this->m_node[1]->GetCoordinates();
111 
112   // DistanceToLine sets pcoords[0] to a value t, 0 <= t <= 1
113   const Float dist2 = this->DistanceToLine(globalPt, a1, a2, pcoords[0], closestPoint);
114 
115   // if the distance specified is more than the tolerance
116   if( ( dist2 <= tol ) && ( pcoords[0] >= 0.0 ) && ( pcoords[0] <= 1.0 ) )
117     {
118     return true;
119     }
120   return false;
121 }
122 
123 // ----------------------------------------------------------------------------
124 // Compute distance to finite line. Returns parametric coordinate t
125 // and point location on line.
DistanceToLine(const VectorType & x,const VectorType & p1,const VectorType & p2,Float & t,VectorType & closestPoint) const126 itk::fem::Element::Float Element2DC0LinearLine::DistanceToLine(
127   const VectorType & x, const VectorType & p1, const VectorType & p2, Float & t,
128   VectorType & closestPoint) const
129 {
130   Float      denom, num;
131   VectorType p21(3);
132   VectorType closest;
133   Float      tolerance;
134 
135   //
136   //   Determine appropriate vectors
137   //
138   p21[0] = p2[0] - p1[0];
139   p21[1] = p2[1] - p1[1];
140   p21[2] = p2[2] - p1[2];
141 
142   //
143   //   Get parametric location
144   //
145   num = p21[0] * (x[0] - p1[0]) + p21[1] * (x[1] - p1[1]) + p21[2] * (x[2] - p1[2]);
146   denom = p21[0] * p21[0] + p21[1] * p21[1] + p21[2] * p21[2];
147 
148   // trying to avoid an expensive fabs
149   tolerance = 1e-5 * num;
150   if( tolerance < 0.0 )
151     {
152     tolerance = -tolerance;
153     }
154   if( -tolerance < denom && denom < tolerance )  // numerically bad!
155     {
156     closest = p1; // arbitrary, point is (numerically) far away
157     }
158   //
159   // If parametric coordinate is within 0<=p<=1, then the point is closest to
160   // the line.  Otherwise, it's closest to a point at the end of the line.
161   //
162   else if( denom <= 0.0 || (t = num / denom) < 0.0 )
163     {
164     closest = p1;
165     }
166   else if( t > 1.0 )
167     {
168     closest = p2;
169     }
170   else
171     {
172     closest = p21;
173     p21[0] = p1[0] + t * p21[0];
174     p21[1] = p1[1] + t * p21[1];
175     p21[2] = p1[2] + t * p21[2];
176     }
177 
178   closestPoint[0] = closest[0];
179   closestPoint[1] = closest[1];
180   closestPoint[2] = closest[2];
181   Float dist = (x[0] - closestPoint[0]) * (x[0] - closestPoint[0])
182     + (x[1] - closestPoint[1]) * (x[1] - closestPoint[1]) + (x[2] - closestPoint[2]) * (x[2] - closestPoint[2]);
183   return dist;
184 }
185 
PopulateEdgeIds()186 void Element2DC0LinearLine::PopulateEdgeIds()
187 {
188   this->m_EdgeIds.resize(0);
189 
190   std::vector<int> edgePtIds;
191   edgePtIds.resize(2);
192 
193   // edge 0
194   edgePtIds[0] = 0;
195   edgePtIds[1] = 1;
196   this->m_EdgeIds.push_back(edgePtIds);
197 }
198 
PrintSelf(std::ostream & os,Indent indent) const199 void Element2DC0LinearLine::PrintSelf(std::ostream& os, Indent indent) const
200 {
201   Superclass::PrintSelf(os, indent);
202 }
203 
204 } // end namespace fem
205 } // end namespace itk
206