Exemplo n.º 1
0
/*
 * 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);
}
Exemplo n.º 2
0
/*
 * 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);
}