/* * Given a site with known fluidness, examine the links to not-yet-visited * neighbouring sites. If the neighbours have unknown fluidness, set that. * * Since we wish to examine each link only once, this will set link properties * from neighbour => site as well as site => neighbour * */ void CylinderGenerator::ClassifySite(Site& site) { for (LaterNeighbourIterator neighIt = site.begin(); neighIt != site.end(); ++neighIt) { Site& neigh = *neighIt; unsigned int iNeigh = neighIt.GetNeighbourIndex(); int nHits; if (!neigh.IsFluidKnown) { neigh.IsFluidKnown = true; neigh.IsFluid = IsInsideCylinder(this->Cylinder, neigh.Position); if (neigh.IsFluid) neigh.CreateLinksVector(); } // Four cases: fluid-fluid, solid-solid, fluid-solid and solid-fluid. // Will handle the last two together. if (site.IsFluid == neigh.IsFluid) { if (site.IsFluid) { // Fluid-fluid, must set CUT_NONE for both site.Links[iNeigh].Type = geometry::CUT_NONE; neigh.Links[Neighbours::inverses[iNeigh]].Type = geometry::CUT_NONE; } else { // solid-solid, nothing to do. } } else { // They differ, figure out which is fluid and which is solid. Site* fluid; Site* solid; // Index of the solid site from the fluid site. int iSolid; if (site.IsFluid) { fluid = &site; solid = &neigh; iSolid = iNeigh; } else { fluid = &neigh; solid = &site; iSolid = Neighbours::inverses[iNeigh]; } // This uses special knowledge about the fact that we're working // on a cylinder. Since the first point is always fluid, and the // second always solid, we must get exactly one hit. Hit hit = ComputeIntersection(this->Cylinder, this->Iolets, *fluid, *solid); LinkData& link = fluid->Links[iSolid]; // This is set in any solid case float distanceInVoxels = (hit.pt - fluid->Position).GetMagnitude(); // The distance is in voxels but must be output as a fraction of // the lattice vector. Scale it. link.Distance = distanceInVoxels / Neighbours::norms[iSolid]; if (hit.cellId < 0) { // -1 => we hit a wall link.Type = geometry::CUT_WALL; } else { // We hit an inlet or outlet Iolet* iolet = this->Iolets[hit.cellId]; if (iolet->IsInlet) { link.Type = geometry::CUT_INLET; } else { link.Type = geometry::CUT_OUTLET; } // Set the Id link.IoletId = iolet->Id; } // If this link intersected the wall, store the normal of the cell we hit and the distance to it. if (link.Type == geometry::CUT_WALL) { this->ComputeCylinderNormalAtAPoint(link.WallNormalAtWallCut, hit.pt, this->Cylinder->Axis); link.DistanceInVoxels = distanceInVoxels; } } } // If there's enough information available, an approximation of the wall normal will be computed for this fluid site. this->ComputeAveragedNormal(site); }
/* * Given a site with known fluidness, examine the links to not-yet-visited * neighbouring sites. If the neighbours have unknown fluidness, set that. * * Since we wish to examine each link only once, this will set link properties * from neighbour => site as well as site => neighbour * */ void PolyDataGenerator::ClassifySite(Site& site) { if (!site.IsFluidKnown){ throw GenerationErrorMessage("The start site is not known cannot continue"); } for (LaterNeighbourIterator neighIt = site.begin(); neighIt != site.end(); ++neighIt) { Site& neigh = *neighIt; unsigned int iNeigh = neighIt.GetNeighbourIndex(); int nHits = Intersect(site,neigh); // Four cases: fluid-fluid, solid-solid, fluid-solid and solid-fluid. // Will handle the last two together. if (site.IsFluid == neigh.IsFluid) { if (site.IsFluid) { // Fluid-fluid, must set CUT_NONE for both site.Links[iNeigh].Type = geometry::CUT_NONE; neigh.Links[Neighbours::inverses[iNeigh]].Type = geometry::CUT_NONE; } else { // solid-solid, nothing to do. } } else { // They differ, figure out which is fluid and which is solid. Site* fluid; Site* solid; // Index of the solid site from the fluid site. int iSolid; // Index of the point in this->hitPoints we're considering as the // hit of interest (i.e. the one closest to the fluid site). int iHit; Vector hitPoint; PointCGAL hitPointCGAL; SegmentCGAL hitsegmentCGAL; int hitCellId; double distancetol = 0.01; std::vector<int> CloseIoletIDS; if (nHits == -1){//unclassified intersection need to be carefull. if (site.IsFluid) { fluid = &site; solid = &neigh; iSolid = iNeigh; int n=0; iHit = n; // here we iterate over all intersections until we // find a wall or the rest are futher away than the tol. for (std::vector<Object_Primitive_and_distance>::iterator distit = IntersectionCGAL.begin(); distit != IntersectionCGAL.end(); ++distit){ if (distit->second > IntersectionCGAL[0].second+distancetol){ iHit = n; break; } int tempioletId = distit->first.second->id() - 2; //shifting back from unsigned if (tempioletId < 0){ break;//hit a wall no need to continue. }//what if we hit both an inlet and outlet. Can that ever happen? ++n; } } else { fluid = &neigh; solid = &site; iSolid = Neighbours::inverses[iNeigh]; int n = IntersectionCGAL.size()-1; iHit = n; for (std::vector<Object_Primitive_and_distance>::reverse_iterator distit = IntersectionCGAL.rbegin(); distit != IntersectionCGAL.rend(); ++distit){ if (distit->second < IntersectionCGAL.back().second - distancetol){ iHit = n; break;//ignoring the following intersections, they are to far away. } int tempioletId = distit->first.second->id() - 2; //shifting back from unsigned if (tempioletId < 0){ break;//hit a wall no need to continue. }//what if we hit both an inlet and outlet. Can that ever happen? --n; } } } else{//normal intersection just take the closest point. if (site.IsFluid) { fluid = &site; solid = &neigh; iSolid = iNeigh; iHit = 0; } else { fluid = &neigh; solid = &site; iSolid = Neighbours::inverses[iNeigh]; iHit = nHits - 1; } } Object_Primitive_and_distance hitpoint_triangle_dist = IntersectionCGAL[iHit]; if (CGAL::assign(hitPointCGAL, hitpoint_triangle_dist.first.first)){ //we do an explicite cast to double here. //The cast to double is only needed if we use an exact_construction kernel. //Otherwise this is already a double but keeping this in makes it //posible to change the kernel for testing. hitPoint = Vector(CGAL::to_double(hitPointCGAL.x()),CGAL::to_double(hitPointCGAL.y()), CGAL::to_double(hitPointCGAL.z())); } else if (CGAL::assign(hitsegmentCGAL, hitpoint_triangle_dist.first.first)){ hitPointCGAL = CGAL::midpoint(hitsegmentCGAL.vertex(0),hitsegmentCGAL.vertex(1)); hitPoint = Vector(CGAL::to_double(hitPointCGAL.x()),CGAL::to_double(hitPointCGAL.y()), CGAL::to_double(hitPointCGAL.z())); } else{ throw GenerationErrorMessage("This type of intersection should not happen"); } LinkData& link = fluid->Links[iSolid]; // This is set in any solid case float distanceInVoxels = (hitPoint - fluid->Position).GetMagnitude(); // The distance is in voxels but must be output as a fraction of // the lattice vector. Scale it. link.Distance = distanceInVoxels / Neighbours::norms[iSolid]; int ioletId = hitpoint_triangle_dist.first.second->id() - 2; //shifting back from unsigned. if (ioletId < 0) { // -1 => we hit a wall link.Type = geometry::CUT_WALL; } else { // We hit an inlet or outlet Iolet* iolet = this->Iolets[ioletId]; if (iolet->IsInlet) { link.Type = geometry::CUT_INLET; } else { link.Type = geometry::CUT_OUTLET; } // Set the Id link.IoletId = iolet->Id; } // If this link intersected the wall, store the normal of the cell we hit and the distance to it. if (link.Type == geometry::CUT_WALL) { VectorCGAL CGALNorm = CGAL::cross_product(hitpoint_triangle_dist.first.second->halfedge()->next()->vertex()->point() - hitpoint_triangle_dist.first.second->halfedge()->vertex()->point(), hitpoint_triangle_dist.first.second->halfedge()->next()->next()->vertex()->point() - hitpoint_triangle_dist.first.second->halfedge()->next()->vertex()->point()); CGALNorm = CGALNorm/CGAL::sqrt(CGALNorm.squared_length()); link.WallNormalAtWallCut = Vector(CGALNorm.x(), CGALNorm.y(),CGALNorm.z()); link.DistanceInVoxels = distanceInVoxels; } } } // If there's enough information available, an approximation of the wall normal will be computed for this fluid site. this->ComputeAveragedNormal(site); }