bool IntersectRayToBox( const LVector3& P, const LVector3& A, const LVector3& Pos, LVector3* V, const LVector3& Size, LVector3& isect ) { float Sign[] = { -1, -1, -1, +1, +1, +1 }; // distance to source point; float _dist = -1.0f; bool Intersection = false; // check six faces for ( int i = 0 ; i < 6 ; i++ ) { LVector3 Pt = Sign[i] * V[i % 3] * Size[i % 3] * 0.5f; LVector3 N = Pt.GetNormalized(); Pt = P + Pt; float D = N.Dot( Pt ); LVector3 LocalISect; if ( IntersectRayToPlane( P, A, N, D, LocalISect ) ) { // plane vectors LVector3 V1 = V[( i+1 )%3]; LVector3 V2 = V[( i+2 )%3]; float szX = Size[( i+1 )%3]; float szY = Size[( i+2 )%3]; // project to plane float x = ( LocalISect - Pt ).Dot( V1 ); float y = ( LocalISect - Pt ).Dot( V2 ); // check if the point is inside the rectangle if ( x > -szX / 2 && x < szX / 2 && y > -szY / 2 && y < szY / 2 ) { Intersection = true; // it is, compare its distance to P - to select the closest one float _newDist = ( isect - P ).Length(); if ( _dist < 0.0f || _newDist < _dist ) { isect = LocalISect; _dist = _newDist; } } } } return Intersection; }
// (Re)generate representing geometry (beads and sticks) for the graph/curve clGeom* clGraph::CreateGraphGeometry( float BeadRadius, float TubeRadius, float EdgeArrowSize, bool UseCubes, clMaterial* BeadMaterial, clMaterial* StickMaterial, clMaterial* EdgeArrowMaterial ) { clMesh* Mesh = Env->Resources->CreateMesh(); int VtxMaterialID = Mesh->AddMaterial( BeadMaterial->GetMaterialDesc() ); // 1. points(vertices) are spheres for ( size_t i = 0 ; i < FVertices.size() ; i++ ) { // int VtxGeomID = static_cast<int>(i); clVertexAttribs* VtxVA; LVector3 BoxMin( -BeadRadius, -BeadRadius, -BeadRadius ); LVector3 BoxMax( +BeadRadius, +BeadRadius, +BeadRadius ); // name it for picking LString VtxName = LString( "Vertex " ) + LStr::ToStr( i ); if ( UseCubes ) { FIXME( "hack, resources should also create a VA ? Or it is a geomserv ?" ) // clGeomServ::CreateAxisAlignedBox(BoxMin, BoxMax, false); VtxVA = Env->Resources->CreateBox( BoxMin, BoxMax )->GetCurrentMesh()->GetRigid( 0 ); } else { // it does not work... // VtxVA = Env->Resources->CreateSphere(); VtxVA = Env->Resources->CreateBox( BoxMin, BoxMax )->GetCurrentMesh()->GetRigid( 0 ); } LVector3 VtxPos = FVertices[i]; LMatrix4 VtxTransform = LMatrix4::GetTranslateMatrix( VtxPos ); if ( UseCubes ) { LQuaternion VtxOrientation = FLocalOrientations[i]; // orient the cube at point, if needed VtxTransform = ComposeTransformation( VtxPos, LMatrix4( VtxOrientation.ToMatrix3() ) ); // add rotation from LocalOrientation } Mesh->AddVertexAttribs( VtxName, VtxVA, VtxTransform, -1, VtxMaterialID ); } // 2. render arrows for oriented edges int ArrowMaterialID = -1; if ( FOriented && EdgeArrowMaterial ) { ArrowMaterialID = Mesh->AddMaterial( EdgeArrowMaterial->GetMaterialDesc() ); } // map< pair<int,int> > ProcessedEdges; int EdgeMaterialID = Mesh->AddMaterial( StickMaterial->GetMaterialDesc() ); // 3. render lines from point to point ("tubes"), avoiding duplicate generation for non-oriented edges for ( size_t i = 0; i < FEdge0.size() ; i++ ) { int v1 = FEdge0[i]; int v2 = FEdge1[i]; LVector3 v1pos = FVertices[v1]; LVector3 v2pos = FVertices[v2]; LVector3 Dir = ( v2pos - v1pos ); LVector3 DirN = Dir.GetNormalized(); LVector3 EndPointDir = -Dir.Length() * DirN * ( EdgeArrowSize ); LVector3 Offset = DirN * EdgeArrowSize; clVertexAttribs* EdgeVA = clGeomServ::CreateTube( 10, v1pos + Offset, Dir - Offset, TubeRadius, false ); // name the edge for picking LString EdgeName = LString( "Edge " ) + LStr::ToStr( v1 ) + LString( " " ) + LStr::ToStr( v2 ); LMatrix4 EdgeTransform = LMatrix4::Identity(); Mesh->AddVertexAttribs( EdgeName, EdgeVA, EdgeTransform, -1, EdgeMaterialID ); FIXME( "avoid duplicates, use processed edges list" ) // add arrow, if required if ( FOriented ) { clVertexAttribs* ArrowVA = clGeomServ::CreateTube( 10, v2pos - Offset, -EndPointDir, TubeRadius * 2.0f , true ); LString ArrowName = LString( "Arrow_" ) + EdgeName; LMatrix4 ArrowTransform = LMatrix4::Identity(); Mesh->AddVertexAttribs( ArrowName, ArrowVA, ArrowTransform, -1, ArrowMaterialID ); } } clGeom* Geom = Env->Resources->CreateGeom(); Geom->SetMesh( Mesh ); return Geom; }