void SeLct::_fpathmake ( FunnelPath* fpath, GsPolygon& path, float radius, float dang ) { // init path: path.open ( true ); path.size ( 0 ); // check trivial case: if ( fpath->size()==2 ) // only endpoints inserted { path.push() = fpath->get(0); path.push() = fpath->top(); return; } path.push() = fpath->get(0); GsPnt2 lp ( fpath->get(1) ); tangents ( 'p', fpath->get(1).optop(), fpath->get(0), lp, 0, fpath->get(1).dist ); int size = fpath->size(); char code[2]; float ra, rb; GsPnt2 a, b; for ( int i=2; i<size; i++ ) { a=fpath->get(i-1); b=fpath->get(i); ra=fpath->get(i-1).dist; rb=fpath->get(i).dist; code[0]=fpath->get(i-1).optop(); code[1]=fpath->get(i).opside(); tangents ( code[0], code[1], a, b, ra, rb ); GsPnt2& cent = fpath->get(i-1); path.arc ( cent, lp-cent/*v1*/, a-cent/*v2*/, ra, code[0]=='b'? dang:-dang ); lp=b; } path.push() = fpath->top(); }
void panzer::ProjectToEdges<EvalT, Traits>:: evaluateFields(typename Traits::EvalData workset) { const shards::CellTopology & parentCell = *basis->getCellTopology(); const int intDegree = basis->order(); TEUCHOS_ASSERT(intDegree == 1); Intrepid2::DefaultCubatureFactory<double,Kokkos::DynRankView<double,PHX::Device>,Kokkos::DynRankView<double,PHX::Device>> quadFactory; Teuchos::RCP< Intrepid2::Cubature<double,Kokkos::DynRankView<double,PHX::Device>,Kokkos::DynRankView<double,PHX::Device>> > edgeQuad; // Collect the reference edge information. For now, do nothing with the quadPts. const unsigned num_edges = parentCell.getEdgeCount(); std::vector<double> refEdgeWt(num_edges, 0.0); for (unsigned e=0; e<num_edges; e++) { edgeQuad = quadFactory.create(parentCell.getCellTopologyData(1,e), intDegree); const int numQPoints = edgeQuad->getNumPoints(); Kokkos::DynRankView<double,PHX::Device> quadWts("quadWts",numQPoints); Kokkos::DynRankView<double,PHX::Device> quadPts("quadPts",numQPoints,num_dim); edgeQuad->getCubature(quadPts,quadWts); for (int q=0; q<numQPoints; q++) refEdgeWt[e] += quadWts(q); } // Loop over the edges of the workset cells. for (index_t cell = 0; cell < workset.num_cells; ++cell) { for (int p = 0; p < num_pts; ++p) { result(cell,p) = ScalarT(0.0); for (int dim = 0; dim < num_dim; ++dim) result(cell,p) += vector_values(cell,p,dim) * tangents(cell,p,dim); result(cell,p) *= refEdgeWt[p]; } } }
void Mesh::calcTangents() { std::vector<glm::vec3> tangents(mVertices.size()); for (GLuint i = 0; i < mIndices.size(); i += 3) { const auto i0 = mIndices[i]; const auto i1 = mIndices[i + 1]; const auto i2 = mIndices[i + 2]; const auto& edge1 = mVertices[i1].position - mVertices[i0].position; const auto& edge2 = mVertices[i2].position - mVertices[i0].position; const auto& delta1 = mVertices[i1].texCoord - mVertices[i0].texCoord; const auto& delta2 = mVertices[i2].texCoord - mVertices[i0].texCoord; GLfloat dividend = (delta1.x * delta2.y - delta2.x * delta1.y); GLfloat f = dividend == 0.0f ? 0.0f : 1.0f / dividend; const glm::vec3 tangent = { f * (delta2.y * edge1.x - delta1.y * edge2.x), f * (delta2.y * edge1.y - delta1.y * edge2.y), f * (delta2.y * edge1.z - delta1.y * edge2.z) }; tangents[i0] += tangent; tangents[i1] += tangent; tangents[i2] += tangent; } for (GLuint i = 0; i < tangents.size(); ++i) { mVertices[i].normal = glm::normalize(tangents[i]); } }
static bool isgoalopening ( const SeFunnelPt& fa, const SeFunnelPt& fb, GsPnt2 c, float /*radius*/ ) { GsPnt2 a=fa; GsPnt2 b=fb; GsPnt2 p=b; tangents ( fb.side, fa.side, b, a, fb.dist, fa.dist ); tangents ( 'p', fb.side, c, p, 0, fb.dist ); c.x = b.x+(c.x-p.x); c.y = b.y+(c.y-p.y); if ( fb.side=='t' ) { return gs_ccw(a.x,a.y,b.x,b.y,c.x,c.y)>0? true:false; } else { return gs_ccw(b.x,b.y,a.x,a.y,c.x,c.y)>0? true:false; } }
void compute_smooth_vertex_tangents_base_pose(MeshObject& object) { assert(object.get_vertex_tangent_count() == 0); assert(object.get_tex_coords_count() > 0); const size_t vertex_count = object.get_vertex_count(); const size_t triangle_count = object.get_triangle_count(); vector<GVector3> tangents(vertex_count, GVector3(0.0)); for (size_t i = 0; i < triangle_count; ++i) { const Triangle& triangle = object.get_triangle(i); if (!triangle.has_vertex_attributes()) continue; const GVector2 v0_uv = object.get_tex_coords(triangle.m_a0); const GVector2 v1_uv = object.get_tex_coords(triangle.m_a1); const GVector2 v2_uv = object.get_tex_coords(triangle.m_a2); // // Reference: // // Physically Based Rendering, first edition, pp. 128-129 // const GScalar du0 = v0_uv[0] - v2_uv[0]; const GScalar dv0 = v0_uv[1] - v2_uv[1]; const GScalar du1 = v1_uv[0] - v2_uv[0]; const GScalar dv1 = v1_uv[1] - v2_uv[1]; const GScalar det = du0 * dv1 - dv0 * du1; if (det == GScalar(0.0)) continue; const GVector3& v2 = object.get_vertex(triangle.m_v2); const GVector3 dp0 = object.get_vertex(triangle.m_v0) - v2; const GVector3 dp1 = object.get_vertex(triangle.m_v1) - v2; const GVector3 tangent = normalize(dv1 * dp0 - dv0 * dp1); tangents[triangle.m_v0] += tangent; tangents[triangle.m_v1] += tangent; tangents[triangle.m_v2] += tangent; } object.reserve_vertex_tangents(vertex_count); for (size_t i = 0; i < vertex_count; ++i) object.push_vertex_tangent(safe_normalize(tangents[i])); }
static void kdBinCreateTangents(u::vector<kdBinVertex> &vertices, const u::vector<kdBinTriangle> &triangles) { // Computing Tangent Space Basis Vectors for an Arbitrary Mesh (Lengyel’s Method) // Section 7.8 (or in Section 6.8 of the second edition). const size_t vertexCount = vertices.size(); const size_t triangleCount = triangles.size(); u::vector<m::vec3> normals(vertexCount); u::vector<m::vec3> tangents(vertexCount); u::vector<m::vec3> bitangents(vertexCount); m::vec3 normal; m::vec3 tangent; m::vec3 bitangent; for (size_t i = 0; i < triangleCount; i++) { kdBinCalculateTangent(triangles, vertices, i, normal, tangent, bitangent); const size_t x = triangles[i].v[0]; const size_t y = triangles[i].v[1]; const size_t z = triangles[i].v[2]; normals[x] += normal; normals[y] += normal; normals[z] += normal; tangents[x] += tangent; tangents[y] += tangent; tangents[z] += tangent; bitangents[x] += bitangent; bitangents[y] += bitangent; bitangents[z] += bitangent; } for (size_t i = 0; i < vertexCount; i++) { // Gram-Schmidt orthogonalize // http://en.wikipedia.org/wiki/Gram%E2%80%93Schmidt_process vertices[i].normal = normals[i].normalized(); const m::vec3 &n = vertices[i].normal; m::vec3 t = tangents[i]; m::vec3 tangent = (t - n * (n * t)).normalized(); if (!tangent.isNormalized()) { // Couldn't calculate vertex tangent for vertex, so we fill it in along // the x axis. tangent = m::vec3::xAxis; t = tangent; } // bitangents are only stored by handness in the W component (-1.0f or 1.0f). vertices[i].tangent = m::vec4(tangent, (((n ^ t) * bitangents[i]) < 0.0f) ? -1.0f : 1.0f); } }
static bool isopening ( const SeFunnelPt& fa, const SeFunnelPt& fb, const SeFunnelPt& fc, float /*r*/, int& fcase ) { GsPnt2 a = fa; GsPnt2 b = fb; GsPnt2 p = b; GsPnt2 c = fc; char sori; if ( fb.side==fc.side && !fb.apex ) // same as 1st { tangents ( fc.side, fb.side, c, p, fc.dist, fb.dist ); tangents ( fb.side, fa.side, b, a, fb.dist, fa.dist ); fcase = 1; sori = fc.side; } else if ( fb.side==fc.side ) // here fb.apex is 1 { tangents ( fc.side, fb.side, c, p, fc.dist, fb.dist ); tangents ( fa.side, fc.side, b, a, fa.dist, fc.dist ); fcase = 2; sori = fa.side; } else if ( fb.Pnt() ) { tangents ( fc.side, fb.side, c, p, fc.dist, fb.dist ); tangents ( fa.side, fb.side, a, b, fa.dist, fb.dist ); fcase = 3; sori = fa.side; } else // fc.side!=fb.side { tangents ( fc.side, fa.side, c, p, fc.dist, fa.dist ); tangents ( fa.side, fa.side, a, b, fa.dist, fa.dist ); fcase = 4; sori = fa.side; } c.x = b.x+(c.x-p.x); c.y = b.y+(c.y-p.y); if ( sori=='t' ) { return gs_ccw(a.x,a.y,b.x,b.y,c.x,c.y)>0? true:false; } else { return gs_ccw(b.x,b.y,a.x,a.y,c.x,c.y)>0? true:false; } }
void SeLct::_fpathpush ( FunnelPath* fpath, const FunnelPt& fp3, float radius ) { char c3 = fp3.opside(); GsPnt2 p1, p2, p3, q2, q3; if ( fpath->size()==0 ) { fpath->push()=fp3; if ( fpath->autolen ) fpath->len=0; return; } // The following test is rarely needed but examples needing it have been found, even in LCTs. // The r-funnel algorithm remains linear since the overall number of pops is bounded by n. #ifdef PATH_CORRECTION while ( fpath->size()>=2 ) { SeFunnelPt& fp1 = fpath->top(1); SeFunnelPt& fp2 = fpath->top(); p1=fp1; p2=fp2; p3=fp3; q2=p2; char c1 = fp1.opside(); char c2 = fp2.optop(); tangents ( c1, c2, p1, p2, fp1.dist, fp2.dist ); tangents ( c2, c3, q2, p3, fp2.dist, fp3.dist ); q3 = p2 + (p3-q2); double ccw = gs_ccw ( p1.x,p1.y,p2.x,p2.y,q3.x,q3.y ); if ( GS_NEXT(ccw,0,1.0E-9) || (c2=='b' && ccw<=0) || (c2=='t' && ccw>=0) ) { if ( fpath->autolen && fpath->size()>2 ) // discount lenght of the region being popped { SeFunnelPt& fp = fpath->top(2); GsPnt2 p = fp; GsPnt2 p0 = fp1; tangents ( fp.opside(), c1, p, p0, fp.dist, fp1.dist ); fpath->len -= ArcAndTanLen ( p0, p1, fp1, p2, radius ); } fpath->pop(); } else { if ( fpath->autolen ) fpath->len += ArcAndTanLen ( p2, q2, fp2, p3, radius ); fpath->push()=fp3; break; } } #else if ( fpath->size()>=2 ) { SeFunnelPt& fp1 = fpath->top(1); SeFunnelPt& fp2 = fpath->top(); p1=fp1; p2=fp2; p3=fp3; q2=p2; if ( fpath->autolen ) fpath->len += ArcAndTanLen ( p2, q2, fp2, p3, radius ); fpath->push()=fp3; return; } #endif if ( fpath->size()==1 ) { if ( fpath->autolen ) { p3 = fp3; tangents ( 'p', fp3.opside(), fpath->get(0), p3, radius, radius ); fpath->len = dist ( fpath->get(0), p3 ); } fpath->push()=fp3; } }
void MonotonicInterpolate(const vector<Vector>& pts,vector<GeneralizedCubicBezierCurve>& paths,CSpace* space,GeodesicManifold* manifold) { Assert(pts.size() >= 2); paths.resize(pts.size()-1); for(size_t i=0;i<paths.size();i++) { paths[i].x0 = pts[i]; paths[i].x3 = pts[i+1]; paths[i].space = space; paths[i].manifold = manifold; } vector<Vector> tangents(pts.size()),inslopes(pts.size()-1),outslopes(pts.size()-1); if(pts.size() == 2) { paths[0].SetSmoothTangents(NULL,NULL); return; } paths[0].SetSmoothTangents(NULL,&pts[2]); paths[0].Deriv(0,tangents[0]); paths.back().x0 = pts[pts.size()-2]; paths.back().x3 = pts[pts.size()-1]; paths.back().SetSmoothTangents(&pts[pts.size()-3],NULL); paths.back().Deriv(1,tangents.back()); for(size_t i=1;i<pts.size();i++) { if(!manifold) { inslopes[i-1] = pts[i]-pts[i-1]; outslopes[i-1].setRef(inslopes[i-1]); } else { manifold->InterpolateDeriv(pts[i-1],pts[i],0,inslopes[i-1]); manifold->InterpolateDeriv(pts[i],pts[i-1],0,outslopes[i-1]); outslopes[i-1].inplaceNegative(); } if(i+1<pts.size()) { if(!manifold) tangents[i] = (pts[i+1]-pts[i-1])*0.5; else { Vector n,p; manifold->InterpolateDeriv(pts[i],pts[i+1],0,n); manifold->InterpolateDeriv(pts[i],pts[i-1],0,p); tangents[i] = (n-p)*0.5; } } } int n=pts[0].n; for(size_t i=0;i<pts.size();i++) { if(tangents[i].n != n) printf("%d / %d\n",i,tangents.size()); Assert(tangents[i].n == n); } for(size_t i=0;i+1<pts.size();i++) { for(int j=0;j<n;j++) { if(Sign(tangents[i][j]) != Sign(inslopes[i][j])) tangents[i][j] = 0; else { if(tangents[i][j]>0) { if(tangents[i][j] > 3.0*inslopes[i][j]) tangents[i][j] = 3.0*inslopes[i][j]; } else { if(tangents[i][j] < 3.0*inslopes[i][j]) tangents[i][j] = 3.0*inslopes[i][j]; } } if(Sign(tangents[i+1][j]) != Sign(outslopes[i][j])) tangents[i+1][j] = 0; else { if(tangents[i+1][j]>0) { if(tangents[i+1][j] > 3.0*outslopes[i][j]) tangents[i+1][j] = 3.0*outslopes[i][j]; } else { if(tangents[i+1][j] < 3.0*outslopes[i][j]) tangents[i+1][j] = 3.0*outslopes[i][j]; } } } } for(size_t i=0;i+1<pts.size();i++) { paths[i].SetNaturalTangents(tangents[i],tangents[i+1]); } }
void MonotonicAccelInterpolate(const vector<Vector>& pts,vector<GeneralizedCubicBezierCurve>& paths,CSpace* space,GeodesicManifold* manifold) { Assert(pts.size() >= 2); vector<Vector> tangents(pts.size()),inslopes(pts.size()-1),outslopes(pts.size()-1); paths.resize(pts.size()-1); for(size_t i=0;i<paths.size();i++) { paths[i].x0 = pts[i]; paths[i].x3 = pts[i+1]; paths[i].space = space; paths[i].manifold = manifold; } paths[0].x0 = pts[0]; paths[0].x3 = pts[1]; if(pts.size() == 2) { paths[0].SetSmoothTangents(NULL,NULL); return; } paths[0].SetSmoothTangents(NULL,&pts[2]); paths[0].Deriv(0,tangents[0]); paths.back().x0 = pts[pts.size()-2]; paths.back().x3 = pts[pts.size()-1]; paths.back().SetSmoothTangents(&pts[pts.size()-3],NULL); paths.back().Deriv(1,tangents.back()); for(size_t i=1;i<pts.size();i++) { if(!manifold) { inslopes[i-1] = pts[i]-pts[i-1]; outslopes[i-1].setRef(inslopes[i-1]); } else { manifold->InterpolateDeriv(pts[i-1],pts[i],0,inslopes[i-1]); manifold->InterpolateDeriv(pts[i],pts[i-1],0,outslopes[i-1]); outslopes[i-1].inplaceNegative(); } if(i+1<pts.size()) { if(!manifold) tangents[i] = (pts[i+1]-pts[i-1])*0.5; else { Vector n,p; manifold->InterpolateDeriv(pts[i],pts[i+1],0,n); manifold->InterpolateDeriv(pts[i],pts[i-1],0,p); tangents[i] = (n-p)*0.5; } } } int n=pts[0].n; for(size_t i=0;i<pts.size();i++) { if(tangents[i].n != n) printf("%d / %d\n",i,tangents.size()); Assert(tangents[i].n == n); } for(size_t i=0;i+1<pts.size();i++) { if(i == 1) cout<<"Orig tangent 2: "<<tangents[i+1]<<endl; for(int j=0;j<n;j++) { if(j==0) { printf("Segment %d: accel in %g, out %g\n",i,3.0*inslopes[i][j] - tangents[i+1][j]-2*tangents[i][j],2*tangents[i+1][j]+tangents[i][j] - 3.0*outslopes[i][j]); } if(Sign(3.0*inslopes[i][j] - tangents[i+1][j] - 2*tangents[i][j]) != Sign(2*tangents[i+1][j]+tangents[i][j] - 3.0*outslopes[i][j])) { //(3.0*mi - x - 2*t0)*(2*x+t0 - 3.0*mo) = 0 //(- x + 3.0*mi - 2*t0)*(2*x+t0 - 3.0*mo) = // -2x^2 + x*(-t0+3mo+6mi-4t0) + (3mi-2t0)(t0-3mo) = 0 //solve quadratic to set tangents[i+1][j] so one accel becomes //nullified Real a = -2.0; Real b = 6*inslopes[i][j] + 3*outslopes[i][j]-5*tangents[i][j]; Real c = (3*inslopes[i][j]-2*tangents[i][j])*(tangents[i][j]-3*outslopes[i][j]); Real t1,t2; int res=quadratic(a,b,c,t1,t2); if(res == 0) { if(j==0) printf("No solution to quadratic %g %g %g\n",a,b,c); } else { assert(res > 0); if(res == 2) { //pick the closer one to the existing tangent if(Abs(t1 - tangents[i+1][j]) > Abs(t2 - tangents[i+1][j])) t1 = t2; } tangents[i+1][j] = t1; if(j==0) { printf("New accel in %g, out %g\n",3.0*inslopes[i][j] - tangents[i+1][j]-2*tangents[i][j],2*tangents[i+1][j]+tangents[i][j] - 3.0*outslopes[i][j]); } } } } if(i == 1) cout<<"New tangent 2: "<<tangents[i+1]<<endl; } for(size_t i=0;i+1<pts.size();i++) { paths[i].SetNaturalTangents(tangents[i],tangents[i+1]); Vector temp,temp2; paths[i].Accel(0,temp); paths[i].Accel(1,temp2); cout<<"in "<<temp[0]<<" out "<<temp2[0]<<endl; } }
void MonotonicInterpolate(const vector<Vector>& pts,const vector<Real>& times,vector<GeneralizedCubicBezierCurve>& paths,CSpace* space,GeodesicManifold* manifold) { Assert(times.size()==pts.size()); Assert(pts.size() >= 2); paths.resize(pts.size()-1); for(size_t i=0;i<paths.size();i++) { paths[i].x0 = pts[i]; paths[i].x3 = pts[i+1]; paths[i].space = space; paths[i].manifold = manifold; } vector<Real> durations(pts.size()-1); vector<Real> rates(pts.size()-1); for(size_t i=0;i+1<pts.size();i++) { durations[i] = times[i+1]-times[i]; rates[i] = 1.0/durations[i]; } vector<Vector> tangents(pts.size()),inslopes(pts.size()-1),outslopes(pts.size()-1); if(pts.size() == 2) { paths[0].SetSmoothTangents(NULL,NULL); return; } paths[0].SetSmoothTangents(NULL,&pts[2],1.0,durations[1]*rates[0]); paths[0].Deriv(0,tangents[0]); paths.back().x0 = pts[pts.size()-2]; paths.back().x3 = pts[pts.size()-1]; paths.back().SetSmoothTangents(&pts[pts.size()-3],NULL,durations[durations.size()-2]*rates.back(),1.0); paths.back().Deriv(1,tangents.back()); for(size_t i=1;i<pts.size();i++) { if(!manifold) { inslopes[i-1] = pts[i]-pts[i-1]; inslopes[i-1] *= rates[i-1]; outslopes[i-1].setRef(inslopes[i-1]); } else { manifold->InterpolateDeriv(pts[i-1],pts[i],0,inslopes[i-1]); manifold->InterpolateDeriv(pts[i],pts[i-1],0,outslopes[i-1]); outslopes[i-1].inplaceNegative(); inslopes[i-1] *= rates[i-1]; outslopes[i-1] *= rates[i-1]; } /* xi = y(0) * xp = y(-dtp) * xn = y(dtn) * fit a quadratic * y(u) = a u^2 + b u + c * and find y'(0)=b * * c = xi * a dtn^2 + b dtn = xn-xi * a dtp^2 - b dtp = xp-xi * [dtn^2 dtn][a] = [xn-xi] * [dtp^2 -dtp][b] [xp-xi] * -1/(dtn dtp)(dtn + dtp) [ -dtp -dtn ][xn-xi] = [a] * [ -dtp^2 dtn^2][xp-xi] [b] * b = dtp^2/(dtn dtp)(dtn + dtp) (xn-xi) - dtn^2/(dtn dtp)(dtn + dtp)(xp-xi) * = 1/(dtn+dtp) (dtp/dtn (xn-xi) - dtn/dtp (xp-xi)) */ if(i+1<pts.size()) { Vector n,p; Real s1 = durations[i-1]*rates[i]; Real s2 = durations[i]*rates[i-1]; if(!manifold) { n = pts[i+1] - pts[i]; p = pts[i-1] - pts[i]; } else { manifold->InterpolateDeriv(pts[i],pts[i+1],0,n); manifold->InterpolateDeriv(pts[i],pts[i-1],0,p); } tangents[i] = (s2*n-s1*p)/(durations[i-1]+durations[i]); } } int n=pts[0].n; for(size_t i=0;i<pts.size();i++) { if(tangents[i].n != n) printf("%d / %d\n",i,tangents.size()); Assert(tangents[i].n == n); } for(size_t i=0;i+1<pts.size();i++) { for(int j=0;j<n;j++) { if(Sign(tangents[i][j]) != Sign(inslopes[i][j])) tangents[i][j] = 0; else { if(tangents[i][j]>0) { if(tangents[i][j] > 3.0*inslopes[i][j]) tangents[i][j] = 3.0*inslopes[i][j]; } else { if(tangents[i][j] < 3.0*inslopes[i][j]) tangents[i][j] = 3.0*inslopes[i][j]; } } if(Sign(tangents[i+1][j]) != Sign(outslopes[i][j])) tangents[i+1][j] = 0; else { if(tangents[i+1][j]>0) { if(tangents[i+1][j] > 3.0*outslopes[i][j]) tangents[i+1][j] = 3.0*outslopes[i][j]; } else { if(tangents[i+1][j] < 3.0*outslopes[i][j]) tangents[i+1][j] = 3.0*outslopes[i][j]; } } } } for(size_t i=0;i+1<pts.size();i++) { paths[i].SetNaturalTangents(tangents[i]*durations[i],tangents[i+1]*durations[i]); } }
static void BuildCurves(float3* points, int count, bool isClosed, std::vector<BezierCurve>* out) { assert(count > 1); float3 cp[4]; if(count == 2) { cp[0] = points[0]; cp[3] = points[1]; cp[1] = cp[0] + 0.3333f * (cp[3] - cp[0]); cp[2] = cp[0] + 0.6666f * (cp[3] - cp[0]); out->push_back(BezierCurve(cp)); } else { float3 zerov(0.0f,0.0f,0.0f); std::vector<float3> tangents(count,zerov); CalcPointTangents(points,&tangents[0],count,isClosed); for (int i = 1; i < count; i++) { float3 chord = points[i] - points[i - 1]; float segLen = length(chord) * 0.3333f; cp[0] = points[i - 1]; cp[3] = points[i]; float3 tangent1 = tangents[i - 1]; if (dot(chord, tangent1) < 0) tangent1 = -tangent1; cp[1] = cp[0] + (tangent1 * segLen); float3 tangent2 = tangents[i]; if (dot(-chord, tangent2) < 0) tangent2 = -tangent2; cp[2] = cp[3] + (tangent2 * segLen); BezierCurve curve(cp); out->push_back(curve); } // Calculate last curve if is closed if (isClosed) { float3 lastcp1 = cp[1]; float3 lastcp2 = cp[2]; cp[0] = points[count - 1]; cp[3] = points[0]; BezierCurve lastCurve = out->back(); float tanLen = length(cp[3] - cp[0]) * 0.3333f; float3 v = normalize(lastCurve.GetControlPoint(2) - cp[0]); cp[1] = cp[0] - (v * tanLen); BezierCurve firstCurve = out->front(); v = normalize(firstCurve.GetControlPoint(1) - cp[3]); cp[2] = cp[3] - (v * tanLen); BezierCurve curve(cp); out->push_back(curve); } } }
int HCURL_TRI_In_FEM_Test01(const bool verbose) { Teuchos::RCP<std::ostream> outStream; Teuchos::oblackholestream bhs; // outputs nothing if (verbose) outStream = Teuchos::rcp(&std::cout, false); else outStream = Teuchos::rcp(&bhs, false); Teuchos::oblackholestream oldFormatState; oldFormatState.copyfmt(std::cout); typedef typename Kokkos::Impl::is_space<DeviceSpaceType>::host_mirror_space::execution_space HostSpaceType ; // *outStream << "DeviceSpace:: "; DeviceSpaceType::print_configuration(*outStream, false); // *outStream << "HostSpace:: "; HostSpaceType::print_configuration(*outStream, false); *outStream << "===============================================================================\n" << "| |\n" << "| Unit Test HCURL_TRI_In_FEM |\n" << "| |\n" << "| Questions? Contact Pavel Bochev ([email protected]), |\n" << "| Robert Kirby ([email protected]), |\n" << "| Denis Ridzal ([email protected]), |\n" << "| Kara Peterson ([email protected]), |\n" << "| Kyungjoo Kim ([email protected]), |\n" << "| Mauro Perego ([email protected]). |\n" << "| |\n" << "===============================================================================\n"; typedef Kokkos::DynRankView<PointValueType,DeviceSpaceType> DynRankViewPointValueType; typedef Kokkos::DynRankView<OutValueType,DeviceSpaceType> DynRankViewOutValueType; typedef typename ScalarTraits<OutValueType>::scalar_type scalar_type; typedef Kokkos::DynRankView<scalar_type, DeviceSpaceType> DynRankViewScalarValueType; typedef Kokkos::DynRankView<scalar_type, HostSpaceType> DynRankViewHostScalarValueType; #define ConstructWithLabelScalar(obj, ...) obj(#obj, __VA_ARGS__) const scalar_type tol = tolerence(); int errorFlag = 0; constexpr ordinal_type dim =2; typedef Basis_HCURL_TRI_In_FEM<DeviceSpaceType,OutValueType,PointValueType> TriBasisType; typedef Basis_HDIV_TRI_In_FEM<DeviceSpaceType,OutValueType,PointValueType> TriBasisHDivType; constexpr ordinal_type maxOrder = Parameters::MaxOrder ; // constexpr ordinal_type dim = 2; try { *outStream << "\n" << "===============================================================================\n" << "| TEST 1: Testing OPERATOR_VALUE (Kronecker property using getDofCoeffs) |\n" << "===============================================================================\n"; const ordinal_type order = std::min(4, maxOrder); TriBasisType triBasis(order, POINTTYPE_WARPBLEND); const ordinal_type cardinality = triBasis.getCardinality(); DynRankViewScalarValueType ConstructWithLabelScalar(dofCoords_scalar, cardinality, dim); triBasis.getDofCoords(dofCoords_scalar); DynRankViewPointValueType ConstructWithLabelPointView(dofCoords, cardinality , dim); RealSpaceTools<DeviceSpaceType>::clone(dofCoords,dofCoords_scalar); DynRankViewScalarValueType ConstructWithLabelScalar(dofCoeffs, cardinality , dim); triBasis.getDofCoeffs(dofCoeffs); DynRankViewOutValueType ConstructWithLabelOutView(basisAtDofCoords, cardinality , cardinality, dim); triBasis.getValues(basisAtDofCoords, dofCoords, OPERATOR_VALUE); auto h_basisAtDofCoords = Kokkos::create_mirror_view(basisAtDofCoords); Kokkos::deep_copy(h_basisAtDofCoords, basisAtDofCoords); auto h_dofCoeffs = Kokkos::create_mirror_view(dofCoeffs); Kokkos::deep_copy(h_dofCoeffs, dofCoeffs); // test for Kronecker property for (int i=0;i<cardinality;i++) { for (int j=0;j<cardinality;j++) { OutValueType dofValue = 0; for (ordinal_type k=0;k<dim; k++) dofValue += h_basisAtDofCoords(i,j,k)*h_dofCoeffs(j,k); if ( i==j && std::abs( dofValue - 1.0 ) > tol ) { errorFlag++; *outStream << std::setw(70) << "^^^^----FAILURE!" << "\n"; *outStream << " Basis function " << i << " does not have unit value at its node (" << dofValue <<")\n"; } if ( i!=j && std::abs( dofValue ) > tol ) { errorFlag++; *outStream << std::setw(70) << "^^^^----FAILURE!" << "\n"; *outStream << " Basis function " << i << " does not vanish at node " << j << "(" << dofValue <<")\n"; } } } } catch (std::exception err) { *outStream << "UNEXPECTED ERROR !!! ----------------------------------------------------------\n"; *outStream << err.what() << '\n'; *outStream << "-------------------------------------------------------------------------------" << "\n\n"; errorFlag = -1000; }; try { *outStream << "\n" << "=======================================================================================\n" << "| TEST 2: Testing OPERATOR_VALUE (Kronecker property, reconstructing dofs using tags) |\n" << "=======================================================================================\n"; const ordinal_type order = std::min(4, maxOrder); TriBasisType triBasis(order, POINTTYPE_WARPBLEND); const ordinal_type cardinality = triBasis.getCardinality(); DynRankViewScalarValueType ConstructWithLabelScalar(dofCoords_scalar, cardinality , dim); triBasis.getDofCoords(dofCoords_scalar); DynRankViewPointValueType ConstructWithLabelPointView(dofCoords, cardinality , dim); RealSpaceTools<DeviceSpaceType>::clone(dofCoords,dofCoords_scalar); DynRankViewOutValueType ConstructWithLabelOutView(basisAtDofCoords, cardinality , cardinality, dim); triBasis.getValues(basisAtDofCoords, dofCoords, OPERATOR_VALUE); auto h_basisAtDofCoords = Kokkos::create_mirror_view(basisAtDofCoords); Kokkos::deep_copy(h_basisAtDofCoords, basisAtDofCoords); // Dimensions for the output arrays: const ordinal_type numFields = triBasis.getCardinality(); //Normals at each edge DynRankViewHostScalarValueType ConstructWithLabelScalar(tangents, numFields,dim); // normals at each point basis point tangents(0,0) = 1.0; tangents(0,1) = 0.0; tangents(1,0) = -1.0; tangents(1,1) = 1.0; tangents(2,0) = 0.0; tangents(2,1) = -1.0; const auto allTags = triBasis.getAllDofTags(); // test for Kronecker property for (int i=0;i<numFields;i++) { for (int j=0;j<numFields;j++) { OutValueType dofValue = 0; if(allTags(j,0) == dim-1) { //edge auto edgeId = allTags(j,1); for (ordinal_type k=0;k<dim; k++) dofValue += h_basisAtDofCoords(i,j,k)*tangents(edgeId,k); } else { //elem auto elemDofId = allTags(j,2); dofValue = h_basisAtDofCoords(i,j,elemDofId%dim); } if ( i==j && std::abs( dofValue - 1.0 ) > tol ) { errorFlag++; *outStream << std::setw(70) << "^^^^----FAILURE!" << "\n"; *outStream << " Basis function " << i << " does not have unit value at its node (" << dofValue <<")\n"; } if ( i!=j && std::abs( dofValue ) > tol ) { errorFlag++; *outStream << std::setw(70) << "^^^^----FAILURE!" << "\n"; *outStream << " Basis function " << i << " does not vanish at node " << j << "(" << dofValue <<")\n"; } } } } catch (std::exception err) { *outStream << "UNEXPECTED ERROR !!! ----------------------------------------------------------\n"; *outStream << err.what() << '\n'; *outStream << "-------------------------------------------------------------------------------" << "\n\n"; errorFlag = -1000; }; try { *outStream << "\n" << "===============================================================================\n" << "| TEST 3: Testing OPERATOR_VALUE (orthogonality with HDiv) |\n" << "===============================================================================\n"; const ordinal_type order = 1; TriBasisType triBasis(order, POINTTYPE_EQUISPACED); TriBasisHDivType triBasisHDiv(order, POINTTYPE_EQUISPACED); shards::CellTopology tri_3(shards::getCellTopologyData<shards::Triangle<3> >()); const ordinal_type np_lattice = PointTools::getLatticeSize(tri_3, order,0); const ordinal_type cardinality = triBasis.getCardinality(); DynRankViewHostScalarValueType ConstructWithLabelScalar(lattice_host_scalar, np_lattice , dim); PointTools::getLattice(lattice_host_scalar, tri_3, order, 0, POINTTYPE_EQUISPACED); auto lattice_scalar = Kokkos::create_mirror_view(typename DeviceSpaceType::memory_space(), lattice_host_scalar); deep_copy(lattice_scalar, lattice_host_scalar); DynRankViewPointValueType ConstructWithLabelPointView(lattice, np_lattice , dim); RealSpaceTools<DeviceSpaceType>::clone(lattice,lattice_scalar); DynRankViewOutValueType ConstructWithLabelOutView(basisAtLattice, cardinality , np_lattice, dim); triBasis.getValues(basisAtLattice, lattice, OPERATOR_VALUE); DynRankViewOutValueType ConstructWithLabelOutView(basisHDivAtLattice, cardinality , np_lattice, dim); triBasisHDiv.getValues(basisHDivAtLattice, lattice, OPERATOR_VALUE); auto h_basisAtLattice = Kokkos::create_mirror_view(basisAtLattice); Kokkos::deep_copy(h_basisAtLattice, basisAtLattice); auto h_basisHDivAtLattice = Kokkos::create_mirror_view(basisHDivAtLattice); Kokkos::deep_copy(h_basisHDivAtLattice, basisHDivAtLattice); const ordinal_type numFields = triBasis.getCardinality(); for (int i=0;i<numFields;i++) { for (int j=0;j<np_lattice;j++) { if (std::abs( h_basisHDivAtLattice(i,j,1) + h_basisAtLattice(i,j,0) ) > tol ) { errorFlag++; *outStream << std::setw(70) << "^^^^----FAILURE!" << "\n"; // Output the multi-index of the value where the error is: *outStream << " At multi-index { "; *outStream << i << " " << j << " and component 0"; *outStream << "} computed value: " << h_basisAtLattice(i,j,0) << " but correct value: " << -h_basisHDivAtLattice(i,j,1) << "\n"; *outStream << "Difference: " << std::abs( h_basisAtLattice(i,j,0) + h_basisHDivAtLattice(i,j,1) ) << "\n"; } if (std::abs( h_basisHDivAtLattice(i,j,0) - h_basisAtLattice(i,j,1) ) > tol ) { errorFlag++; *outStream << std::setw(70) << "^^^^----FAILURE!" << "\n"; // Output the multi-index of the value where the error is: *outStream << " At multi-index { "; *outStream << i << " " << j << " and component 1"; *outStream << "} computed value: " << h_basisAtLattice(i,j,1) << " but correct value: " << h_basisHDivAtLattice(i,j,0) << "\n"; *outStream << "Difference: " << std::abs( h_basisAtLattice(i,j,1) - h_basisHDivAtLattice(i,j,1) ) << "\n"; } } } } catch (std::exception err) { *outStream << "UNEXPECTED ERROR !!! ----------------------------------------------------------\n"; *outStream << err.what() << '\n'; *outStream << "-------------------------------------------------------------------------------" << "\n\n"; errorFlag = -1000; }; try { *outStream << "\n" << "===============================================================================\n" << "| TEST 4: Testing OPERATOR_VALUE (FIAT Values) |\n" << "===============================================================================\n"; constexpr ordinal_type order = 2; if(order <= maxOrder) { TriBasisType triBasis(order, POINTTYPE_EQUISPACED); shards::CellTopology tri_3(shards::getCellTopologyData<shards::Triangle<3> >()); const ordinal_type np_lattice = PointTools::getLatticeSize(tri_3, order,0); const ordinal_type cardinality = triBasis.getCardinality(); DynRankViewHostScalarValueType ConstructWithLabelScalar(lattice_host_scalar, np_lattice , dim); PointTools::getLattice(lattice_host_scalar, tri_3, order, 0, POINTTYPE_EQUISPACED); auto lattice_scalar = Kokkos::create_mirror_view(typename DeviceSpaceType::memory_space(), lattice_host_scalar); deep_copy(lattice_scalar, lattice_host_scalar); DynRankViewPointValueType ConstructWithLabelPointView(lattice, np_lattice , dim); RealSpaceTools<DeviceSpaceType>::clone(lattice,lattice_scalar); DynRankViewOutValueType ConstructWithLabelOutView(basisAtLattice, cardinality , np_lattice, dim); triBasis.getValues(basisAtLattice, lattice, OPERATOR_VALUE); auto h_basisAtLattice = Kokkos::create_mirror_view(basisAtLattice); Kokkos::deep_copy(h_basisAtLattice, basisAtLattice); const scalar_type fiat_vals[] = { 2.000000000000000e+00, 0.000000000000000e+00, 5.000000000000000e-01, 2.500000000000000e-01, -1.000000000000000e+00, -1.000000000000000e+00, 2.500000000000000e-01, 0.000000000000000e+00, -5.000000000000000e-01, -5.000000000000000e-01, 0.000000000000000e+00, 0.000000000000000e+00, -1.000000000000000e+00, 0.000000000000000e+00, 5.000000000000000e-01, 2.500000000000000e-01, 2.000000000000000e+00, 2.000000000000000e+00, -5.000000000000000e-01, 0.000000000000000e+00, 2.500000000000000e-01, 2.500000000000000e-01, 0.000000000000000e+00, 0.000000000000000e+00, 0.000000000000000e+00, 0.000000000000000e+00, 0.000000000000000e+00, 2.500000000000000e-01, 0.000000000000000e+00, 2.000000000000000e+00, 5.000000000000000e-01, 0.000000000000000e+00, -2.500000000000000e-01, 2.500000000000000e-01, 1.000000000000000e+00, 0.000000000000000e+00, 0.000000000000000e+00, 0.000000000000000e+00, 0.000000000000000e+00, -5.000000000000000e-01, 0.000000000000000e+00, -1.000000000000000e+00, -2.500000000000000e-01, 0.000000000000000e+00, -2.500000000000000e-01, 2.500000000000000e-01, -2.000000000000000e+00, 0.000000000000000e+00, 0.000000000000000e+00, 1.000000000000000e+00, 0.000000000000000e+00, 5.000000000000000e-01, 0.000000000000000e+00, 0.000000000000000e+00, -2.500000000000000e-01, -5.000000000000000e-01, -2.500000000000000e-01, -2.500000000000000e-01, -2.000000000000000e+00, -2.000000000000000e+00, 0.000000000000000e+00, -2.000000000000000e+00, 0.000000000000000e+00, -2.500000000000000e-01, 0.000000000000000e+00, 0.000000000000000e+00, -2.500000000000000e-01, -5.000000000000000e-01, 5.000000000000000e-01, 5.000000000000000e-01, 1.000000000000000e+00, 1.000000000000000e+00, 0.000000000000000e+00, 0.000000000000000e+00, 0.000000000000000e+00, -7.500000000000000e-01, 0.000000000000000e+00, 0.000000000000000e+00, 1.500000000000000e+00, 0.000000000000000e+00, 7.500000000000000e-01, 7.500000000000000e-01, 0.000000000000000e+00, 0.000000000000000e+00, 0.000000000000000e+00, 0.000000000000000e+00, 0.000000000000000e+00, 1.500000000000000e+00, 0.000000000000000e+00, 0.000000000000000e+00, -7.500000000000000e-01, 0.000000000000000e+00, 7.500000000000000e-01, 7.500000000000000e-01, 0.000000000000000e+00, 0.000000000000000e+00 }; ordinal_type cur=0; for (ordinal_type i=0;i<cardinality;i++) { for (ordinal_type j=0;j<np_lattice;j++) { for (ordinal_type k=0;k<dim; k++) { if (std::abs( h_basisAtLattice(i,j,k) - fiat_vals[cur] ) > tol ) { errorFlag++; *outStream << std::setw(70) << "^^^^----FAILURE!" << "\n"; // Output the multi-index of the value where the error is: *outStream << " At multi-index { "; *outStream << i << " " << j << " " << k; *outStream << "} computed value: " << h_basisAtLattice(i,j,k) << " but correct value: " << fiat_vals[cur] << "\n"; *outStream << "Difference: " << std::fabs( h_basisAtLattice(i,j,k) - fiat_vals[cur] ) << "\n"; } cur++; } } } } } catch (std::exception err) { *outStream << "UNEXPECTED ERROR !!! ----------------------------------------------------------\n"; *outStream << err.what() << '\n'; *outStream << "-------------------------------------------------------------------------------" << "\n\n"; errorFlag = -1000; }; try { *outStream << "\n" << "===============================================================================\n" << "| TEST 5: Testing Operator CURL |\n" << "===============================================================================\n"; constexpr ordinal_type order = 2; if(order <= maxOrder) { shards::CellTopology tri_3(shards::getCellTopologyData<shards::Triangle<3> >()); TriBasisType triBasis(order, POINTTYPE_EQUISPACED); const ordinal_type cardinality = triBasis.getCardinality(); const ordinal_type np_lattice = PointTools::getLatticeSize(tri_3, order,0); DynRankViewHostScalarValueType ConstructWithLabelScalar(lattice_host_scalar, np_lattice , dim); PointTools::getLattice(lattice_host_scalar, tri_3, order, 0, POINTTYPE_EQUISPACED); auto lattice_scalar = Kokkos::create_mirror_view(typename DeviceSpaceType::memory_space(), lattice_host_scalar); deep_copy(lattice_scalar, lattice_host_scalar); DynRankViewPointValueType ConstructWithLabelPointView(lattice, np_lattice , dim); RealSpaceTools<DeviceSpaceType>::clone(lattice,lattice_scalar); DynRankViewOutValueType ConstructWithLabelOutView(basisDivAtLattice, cardinality , np_lattice); triBasis.getValues(basisDivAtLattice, lattice, OPERATOR_CURL); auto h_basisDivAtLattice = Kokkos::create_mirror_view(basisDivAtLattice); Kokkos::deep_copy(h_basisDivAtLattice, basisDivAtLattice); const scalar_type fiat_divs[] = { 7.000000000000000e+00, 2.500000000000000e+00, -2.000000000000000e+00, 2.500000000000000e+00, -2.000000000000000e+00, -2.000000000000000e+00, -2.000000000000000e+00, 2.500000000000000e+00, 7.000000000000000e+00, -2.000000000000000e+00, 2.500000000000000e+00, -2.000000000000000e+00, -2.000000000000000e+00, 2.500000000000000e+00, 7.000000000000000e+00, -2.000000000000000e+00, 2.500000000000000e+00, -2.000000000000000e+00, -2.000000000000000e+00, -2.000000000000000e+00, -2.000000000000000e+00, 2.500000000000000e+00, 2.500000000000000e+00, 7.000000000000000e+00, -2.000000000000000e+00, -2.000000000000000e+00, -2.000000000000000e+00, 2.500000000000000e+00, 2.500000000000000e+00, 7.000000000000000e+00, 7.000000000000000e+00, 2.500000000000000e+00, -2.000000000000000e+00, 2.500000000000000e+00, -2.000000000000000e+00, -2.000000000000000e+00, -9.000000000000000e+00, -4.500000000000000e+00, 0.000000000000000e+00, 0.000000000000000e+00, 4.500000000000000e+00, 9.000000000000000e+00, 9.000000000000000e+00, 0.000000000000000e+00, -9.000000000000000e+00, 4.500000000000000e+00, -4.500000000000000e+00, 0.000000000000000e+00 }; ordinal_type cur=0; for (ordinal_type i=0;i<cardinality;i++) { for (ordinal_type j=0;j<np_lattice;j++) { if (std::abs( h_basisDivAtLattice(i,j) - fiat_divs[cur] ) > tol ) { errorFlag++; *outStream << std::setw(70) << "^^^^----FAILURE!" << "\n"; // Output the multi-index of the value where the error is: *outStream << " At multi-index { "; *outStream << i << " " << j; *outStream << "} computed value: " << h_basisDivAtLattice(i,j) << " but correct value: " << fiat_divs[cur] << "\n"; *outStream << "Difference: " << std::fabs( h_basisDivAtLattice(i,j) - fiat_divs[cur] ) << "\n"; } cur++; } } } } catch (std::exception err) { *outStream << "UNEXPECTED ERROR !!! ----------------------------------------------------------\n"; *outStream << err.what() << '\n'; *outStream << "-------------------------------------------------------------------------------" << "\n\n"; errorFlag = -1000; }; if (errorFlag != 0) std::cout << "End Result: TEST FAILED\n"; else std::cout << "End Result: TEST PASSED\n"; // reset format state of std::cout std::cout.copyfmt(oldFormatState); return errorFlag; }
std::vector<glm::vec3> generate_tangents(tinyobj::mesh_t const& model) { // containers for vetex attributes std::vector<glm::vec3> positions(model.positions.size() / 3); std::vector<glm::vec3> normals(model.positions.size() / 3); std::vector<glm::vec2> texcoords(model.positions.size() / 3); std::vector<glm::vec3> tangents(model.positions.size() / 3, glm::vec3{0.0f}); // get vertex positions and texture coordinates from mesh_t for (unsigned i = 0; i < model.positions.size(); i+=3) { positions[i / 3] = glm::vec3{model.positions[i], model.positions[i + 1], model.positions[i + 2]}; normals[i / 3] = glm::vec3{model.normals[i], model.normals[i + 1], model.normals[i + 2]}; } for (unsigned i = 0; i < model.texcoords.size(); i+=2) { texcoords[i / 2] = glm::vec2{model.texcoords[i], model.texcoords[i + 1]}; } // calculate tangent for triangles for (unsigned i = 0; i < model.indices.size() / 3; i++) { // indices of vertices of this triangle, access any attribute of first vert with "attribute[indices[0]]" unsigned indices[3] = {model.indices[i * 3], model.indices[i * 3 + 1], model.indices[i * 3 + 2] }; auto p0 = positions[indices[0]]; auto p1 = positions[indices[1]]; auto p2 = positions[indices[2]]; auto t0 = texcoords[indices[0]]; auto t1 = texcoords[indices[1]]; auto t2 = texcoords[indices[2]]; auto dp1 = p1 - p0; auto dp2 = p2 - p0; auto dt1 = t1 - t0; auto dt2 = t2 - t0; float inv_t = 1 / dt1.x * dt2.y - dt2.x * dt1.y; glm::mat2x2 M = {{dt2.y, -dt1.y}, {-dt2.x, dt1.x}}; glm::mat3x2 N = {{dp1.x, dp2.x}, {dp1.y, dp2.y}, {dp1.z, dp2.z}}; auto tangentsWithBi = inv_t * M * N; glm::vec3 tangent = glm::transpose(tangentsWithBi)[0]; tangent = glm::normalize(tangent); tangents[indices[0]] = tangent; tangents[indices[1]] = tangent; tangents[indices[2]] = tangent; } for (unsigned i = 0; i < tangents.size(); ++i) { // orthogonalization and normalization auto t = tangents[i]; auto n = normals[i]; auto t_prime = t - n * glm::dot(n, t); tangents[i] = glm::normalize(t_prime); } return tangents; }