示例#1
0
文件: Target.cpp 项目: Team694/frc
/**
* @brief Find the largest particles that meet a criteria 
* @param binaryImage Image to inspect
* @param hitReport structure containing arry of hits - first hit is largest 
* @param rect area to search
* @param numParticles Number of particles in array
* @return 0 = error
*/
int GetLargestParticles(Image* binaryImage, ImageHits *hitReport, Rect rect,
		int numberHitsRequested)
{	
	//char funcName[]="GetLargestParticles";
	HitList *hitsInArea = new HitList();  // list to contain all particles within area sorted by size
	int i;
	
	/* determine number of particles in thresholded image */	
	int numParticles = -1;
	int success = frcCountParticles(binaryImage, &numParticles);
	if ( !success )	{ return success; }	
	//DPRINTF(LOG_DEBUG, "particles requested = %i ; particles found in image = %i", numberHitsRequested, numParticles);	
	
	/* if no particles found we can quit here */
	if (numParticles <= 0)  {  return 1; 	}  // successful, but zero particles found

	/* get areas of each particle and insert into list */
	double particleArea;
	int count = 0;
	for (i = 0; i < numParticles; ++i) {		
		success = imaqMeasureParticle(binaryImage, i, 0, IMAQ_MT_AREA, &particleArea);
		if ( !success )	{ return success; }	
		//DPRINTF (LOG_INFO, "size of particle %i = %g", i, particleArea);
		// see if is in the right area and large enough to be considered a possible target
		
		//TODO: Call InArea & delete TempInArea when new WPILib is released
		//if (InArea(binaryImage, i, rect)) {
		//if ( InArea(binaryImage, i, rect) && (particleArea >= FRC_MINIMUM_PIXELS_FOR_TARGET) ) {
		if ( TempInArea(binaryImage, i, rect) && (particleArea >= FRC_MINIMUM_PIXELS_FOR_TARGET) ) {
			hitsInArea->AddNode(i,particleArea);
			count++;
		}
	}
	// see what's in the list 
	hitsInArea->debugDump();
	
	// fill in return structure - number of hits
	if (numParticles < numberHitsRequested) {
		hitReport->numberOfHits = numParticles;		
	} else {
		hitReport->numberOfHits = numberHitsRequested;		
	}
	
	// fill in return structure - indices & areas of largest hits
	HitNode *hitPtr = hitsInArea->head;	
	for (i = 0; i < hitReport->numberOfHits; ++i) {	
		if (hitPtr == NULL) {
			break;
		}
		hitReport->indices[i] = hitPtr->nodeIndex;
		hitReport->areas[i] = hitPtr->nodeArea;
		//DPRINTF (LOG_INFO, "put index %i in hitReport %i", hitPtr->nodeIndex, hitReport->indices[i]);
		hitPtr = hitPtr->next;
	}	
	// dispose of HitList 
	delete hitsInArea;		
	return 1;  // success
}
示例#2
0
文件: brep.cpp 项目: cciechad/brlcad
int
brep_edge_check(int reason,
		const SubsurfaceBBNode* sbv,
		const ON_BrepFace* face,
		const ON_Surface* surf,
		const ON_Ray& r,
		HitList& hits)
{
    // if the intersection was not found for any reason, we need to
    // check and see if we are close to any topological edges; we may
    // have hit a crack...

    // the proper way to do this is to only look at edges
    // interesecting with the subsurface bounding box... but for
    // now, we'll look at the edges associated with the face for the bounding box...

    // XXX - optimize this

    set<ON_BrepEdge*> edges;
    ON_3dPoint pt;
    for (int i = 0; i < face->LoopCount(); i++) {
	ON_BrepLoop* loop = face->Loop(i);
	for (int j = 0; j < loop->TrimCount(); j++) {
	    ON_BrepTrim* trim = loop->Trim(j);
	    ON_BrepEdge* edge = trim->Edge();
	    pair<set<ON_BrepEdge*>::iterator, bool> res = edges.insert(edge);
	    //	    if (res.second) {
	    // only check if its the first time we've seen this
	    // edge
	    const ON_Curve* curve = edge->EdgeCurveOf();
	    Sample s;
	    if (curve->CloseTo(ON_3dPoint(hits.back().point), BREP_EDGE_MISS_TOLERANCE, s)) {
		TRACE1("CLOSE TO EDGE");
		hits.back().closeToEdge = true;
		return BREP_INTERSECT_FOUND;
	    }
	}
    }
    return BREP_INTERSECT_TRIMMED;
}
示例#3
0
void check_mates(const HitList& hits1_in_ref,
		 const HitList& hits2_in_ref,
		 vector<pair<size_t, size_t> >& happy_mates,
		 vector<size_t>& map1_singletons,
		 vector<size_t>& map2_singletons)
{
  std::set<size_t> marked;
  // TODO: if this shows up on the profile, replace it with a linear
  // time algorithm.  This one is 2*n*lg(n).
  HitList::const_iterator last_good = hits2_in_ref.begin();
  
  for (size_t i = 0; i < hits1_in_ref.size(); ++i)
    {
      pair<HitList::const_iterator, HitList::const_iterator> range_pair;
      range_pair = equal_range(last_good, hits2_in_ref.end(),
			       hits1_in_ref[i], hit_insert_id_lt);
      bool found_hit = false;
      if (range_pair.first != range_pair.second)
	last_good = range_pair.first;
      for (HitList::const_iterator f = range_pair.first;
	   f != range_pair.second;
	   ++f)
	{
	  if (possible_cotranscript(hits1_in_ref[i], *f))
	    {
	      happy_mates.push_back(make_pair(i,f - hits2_in_ref.begin()));
	      marked.insert(f - hits2_in_ref.begin());
	      found_hit = true;
	    }
	}
      if (!found_hit)
	map1_singletons.push_back(i);
    }
  
  for (size_t i = 0; i < hits2_in_ref.size(); ++i)
    {
      if (marked.find(i) == marked.end())
	{
	  map2_singletons.push_back(i);
	}
    }	
}
示例#4
0
/**
 * Compute the intersection between the line segment and the capped cylinder.
 *
 * Site from is ALWAYS fluid
 * Site to is ALWAYS solid
 *
 * Therefore we expect exactly one intersection. Due to floating point errors,
 * we can't guarantee this. So, we search for intersections with some
 * tolerance (macro TOL) and pick the closest to fluid site (as given by the
 * parametic line coordinate t. We use a priority_queue to keep the hits in
 * order.
 */
Hit ComputeIntersection(CylinderData* cyl, std::vector<Iolet*>& iolets,
		Site& from, Site& to) {
	HitList hitList = HitList();
	/*
	 * The equation of the line segment is:
	 * x(t) = a + t (b - a)		t E (0, 1)
	 */
	Vector& n = cyl->Axis;
	double& r = cyl->Radius;
	Vector& c = cyl->Centre;
	double& h = cyl->Length;

	{
		/*
		 * The equation determining intersection with an INFINITE cylinder of
		 * radius r is:
		 * [(b-a)^2 - ((b-a).n)^2] t^2 + [2 a.(b - a) - 2 (a.n)((b-a).n)] t + [a^2 - (a.n)^2 - r^2] = 0
		 * So first compute the coefficients and then the discriminant of the eqn
		 */
		Vector a = from.Position - c;
		Vector b = to.Position - c;
		Vector b_a = b - a;

		double b_aDOTn = Vector::Dot(b_a, n);
		double aDOTn = Vector::Dot(a, n);

		double A = (b_a.GetMagnitudeSquared() - b_aDOTn * b_aDOTn);
		double B = 2. * (Vector::Dot(a, b_a) - aDOTn * b_aDOTn);
		double C = a.GetMagnitudeSquared() - aDOTn * aDOTn - r * r;

		double discriminant = B * B - 4 * A * C;

		if (discriminant < 0.) {
			// No real solutions.
		} else if (discriminant == 0) {
			// Exactly one solution, i.e. line segment just brushes the cylinder.
			// This means the line must be outside the cylinder everywhere else,
			// so we will count this as no intersection.
		} else {
			// Two real solutions. So we have two intersections between the
			// infinite line and infinite cylinder.
			// If t outside (0,1), then the intersection isn't on the line segment
			// we care about.
			std::vector<double> ts(2);
			ts[0] = (-B + std::sqrt(discriminant)) / (2 * A);
			ts[1] = (-B - std::sqrt(discriminant)) / (2 * A);
			for (std::vector<double>::iterator tIt = ts.begin();
					tIt != ts.end(); ++tIt) {
				double t = *tIt;
				if (t > 0. && t < 1. + TOL) {
					// Hit in part of line we care about.
					// Now check if it's on the finite cylinder. This requires that
					// x.n E (-h/2, h/2)
					double xDOTn = aDOTn + t * b_aDOTn;
					if (xDOTn >= -0.5 * h - TOL && xDOTn <= 0.5 * h + TOL) {
						// Real cylinder hit!
						Hit hit;
						hit.t = t;
						hit.pt = from.Position + b_a * t;
						hit.cellId = -1;
						hitList.push(hit);
					}
				}
			}
		}
	}
	/*
	 * Now we want to look for intersections with the capping planes.
	 */
	Vector& a = from.Position;
	Vector& b = to.Position;
	Vector b_a = b - a;
	for (std::vector<Iolet*>::iterator iIt = iolets.begin();
			iIt != iolets.end(); ++iIt) {
		Iolet* iolet = *iIt;
		/*
		 * Plane equation is x.p = q.p (p = plane normal, q = point on plane)
		 * Line is x = a + t(b-a)
		 */
		Vector& q = iolet->Centre;
		Vector& p = iolet->Normal;

		double t = Vector::Dot(q - a, p) / Vector::Dot(b_a, p);
		if (t > 0. && t < 1. + TOL) {
			// Intersection within the line segment. Now check within cap.
			Vector x = a + b_a * t;
			Vector x_c = x - c;
			double x_cDOTn = Vector::Dot(x_c, n);
			Vector radial = x_c - n * x_cDOTn;
			if (radial.GetMagnitudeSquared() < (r + TOL) * (r + TOL)) {
				// Within the cap
				Hit hit;
				hit.t = t;
				hit.pt = x;
				hit.cellId = iIt - iolets.begin();
				hitList.push(hit);
			}
		}
	}
	// We know there SHOULD be exactly one intersection. Take the closest.
	if (hitList.size() == 0)
		throw InconsistentFluidnessError(from, to, hitList.size());

	// Ensure that the hit lies on the link
	Hit ans = hitList.top();
	if (ans.t > 1.) {
		ans.t = 1.;
		ans.pt = b;
	}
	return ans;
}
示例#5
0
void best_insert_mappings(uint64_t refid,
						  ReadTable& it,
						  /*const string& name,*/
						  HitList& hits1_in_ref,
						  HitList& hits2_in_ref,
						  BestInsertAlignmentTable& best_status_for_inserts,
						  bool prefer_shorter_pairs)
{	
	
	long chucked_for_shorter_pair = 0;
	std::set<size_t> marked;
	HitList::iterator last_good = hits2_in_ref.begin();
	
	for (size_t i = 0; i < hits1_in_ref.size(); ++i)
	{
		BowtieHit& h1 = hits1_in_ref[i];
		pair<HitList::iterator, HitList::iterator> range_pair;
		range_pair = equal_range(last_good, hits2_in_ref.end(),
								 h1, hit_insert_id_lt);
		bool found_hit = false;
		if (range_pair.first != range_pair.second)
			last_good = range_pair.first;
		
		uint32_t obs_order = it.observation_order(h1.insert_id());
		
		for (HitList::iterator f = range_pair.first;
			 f != range_pair.second;
			 ++f)
		{
			BowtieHit& h2 = *f;
			
			if (h1.insert_id() == h2.insert_id())
			{
				// max mate inner distance (genomic)
				int min_mate_inner_dist = inner_dist_mean - inner_dist_std_dev;
				if (max_mate_inner_dist == -1)
				{
					max_mate_inner_dist = inner_dist_mean + inner_dist_std_dev;
				}
				
				InsertAlignmentGrade s(h1, h2, min_mate_inner_dist, max_mate_inner_dist);
				
				pair<InsertAlignmentGrade, vector<InsertAlignment> >& insert_best
					= best_status_for_inserts[obs_order];
				InsertAlignmentGrade& current = insert_best.first;
				// Is the new status better than the current best one?
				if (current < s)
				{
					insert_best.second.clear();
					current = s;
					insert_best.second.push_back(InsertAlignment(refid, &h1, &h2));
				}
				else if (!(s < current))
				{
					if (prefer_shorter_pairs && current.num_mapped == 2)
					{
						pair<int, int> dc = pair_distances(*(insert_best.second[0].left_alignment), *(insert_best.second[0].right_alignment));
						pair<int, int> ds = pair_distances(h1,h2);
						if (ds.second < dc.second)
						{
							chucked_for_shorter_pair += insert_best.second.size();
							insert_best.second.clear();
							current = s;
							insert_best.second.push_back(InsertAlignment(refid, &h1, &h2));
						}
					}
					else
					{
						insert_best.second.push_back(InsertAlignment(refid, &h1, &h2));
					}
				}
				
				marked.insert(f - hits2_in_ref.begin());
				found_hit = true;
			}
			
		}
		if (!found_hit)
		{
			pair<InsertAlignmentGrade, vector<InsertAlignment> >& insert_best
			= best_status_for_inserts[obs_order];
			InsertAlignmentGrade& current = insert_best.first;	
			
			InsertAlignmentGrade s(h1);
			
			if (current < s)
			{	
				insert_best.second.clear();
				current = s;
				insert_best.second.push_back(InsertAlignment(refid, &h1, NULL));
			}
			else if (! (s < current))
			{
				insert_best.second.push_back(InsertAlignment(refid, &h1, NULL));
			}
			
		}
	}
	
	for (size_t i = 0; i < hits2_in_ref.size(); ++i)
	{
		BowtieHit& h2 = hits2_in_ref[i];
		uint32_t obs_order = it.observation_order(h2.insert_id());
		pair<InsertAlignmentGrade, vector<InsertAlignment> >& insert_best
			= best_status_for_inserts[obs_order];
		InsertAlignmentGrade& current = insert_best.first;	
		
		InsertAlignmentGrade s(h2);
		// Did we include h2 as part of a pairing already, or is this first time
		// we've seen it?  If so, it's a singleton.
		if (marked.find(i) == marked.end())
		{
			if (current < s)
			{
				insert_best.second.clear();
				current = s;
				insert_best.second.push_back(InsertAlignment(refid, NULL, &h2));
			}
			else if (! (s < current))
			{
				insert_best.second.push_back(InsertAlignment(refid, NULL, &h2));
			}
		}
	}	
	fprintf(stderr, "Chucked %ld pairs for shorter pairing of same mates\n", chucked_for_shorter_pair);
}
示例#6
0
文件: brep.cpp 项目: cciechad/brlcad
/**
 *  			R T _ B R E P _ S H O T
 *
 *  Intersect a ray with a brep.
 *  If an intersection occurs, a struct seg will be acquired
 *  and filled in.
 *
 *  Returns -
 *  	0	MISS
 *	>0	HIT
 */
int
rt_brep_shot(struct soltab *stp, register struct xray *rp, struct application *ap, struct seg *seghead)
{
    //TRACE1("rt_brep_shot origin:" << ON_PRINT3(rp->r_pt) << " dir:" << ON_PRINT3(rp->r_dir));
    TRACE("^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^");
    vect_t invdir;
    struct brep_specific* bs = (struct brep_specific*)stp->st_specific;

    // check the hierarchy to see if we have a hit at a leaf node
    BBNode::IsectList inters;
    ON_Ray r = toXRay(rp);
    bs->bvh->intersectsHierarchy(r, &inters);

    if (inters.size() == 0) return 0; // MISS
    TRACE1("bboxes: " << inters.size());

    // find all the hits (XXX very inefficient right now!)
    HitList all_hits; // record all hits
    MissList misses; // XXX - get rid of this stuff (for debugging)
    int s = 0;
    for (BBNode::IsectList::iterator i = inters.begin(); i != inters.end(); i++) {
	const SubsurfaceBBNode* sbv = dynamic_cast<SubsurfaceBBNode*>((*i).m_node);
	const ON_BrepFace* f = sbv->m_face;
	const ON_Surface* surf = f->SurfaceOf();
	brep_hit* hit;
	pt2d_t uv = {sbv->m_u.Mid(),sbv->m_v.Mid()};
	TRACE1("surface: " << s);
	int status = brep_intersect(sbv, f, surf, uv, r, all_hits);
	if (status == BREP_INTERSECT_FOUND) {
	    TRACE("INTERSECTION: " << PT(all_hits.back().point) << all_hits.back().trimmed << ", " << all_hits.back().closeToEdge << ", " << all_hits.back().oob);
	} else {
	    TRACE1("dammit");
	    misses.push_back(ip_t(all_hits.size()-1,status));
	}
	s++;
    }


    HitList hits = all_hits;

    // sort the hits
    hits.sort();

    int num = 0;
    for (HitList::iterator i = hits.begin(); i != hits.end(); ++i) {
	TRACE("hit " << num << ": " << PT(i->point) << " [" << VDOT(i->normal,rp->r_dir) << "] " << i->trimmed << ", " << i->closeToEdge << ", " << i->oob);
	++num;
    }


    TRACE("---");
    num = 0;
    for (HitList::iterator i = hits.begin(); i != hits.end(); ++i) {
	if ((i->trimmed && !i->closeToEdge) || i->oob || NEAR_ZERO(VDOT(i->normal,rp->r_dir),RT_DOT_TOL)) {
	    // remove what we were removing earlier
	    if (i->oob) {
		TRACE("\toob u: " << i->uv[0] << ", " << IVAL(i->sbv->m_u));
		TRACE("\toob v: " << i->uv[1] << ", " << IVAL(i->sbv->m_v));
	    }
	    i = hits.erase(i);

	    if (i != hits.begin())
		--i;

	    continue;
	}
	TRACE("hit " << num << ": " << PT(i->point) << " [" << VDOT(i->normal,rp->r_dir) << "]");
	++num;
    }

    {
	// we should have "valid" points now, remove duplicates or grazes
	HitList::iterator last = hits.begin();
	HitList::iterator i = hits.begin();
	++i;
	while (i != hits.end()) {
	    if ((*i) == (*last)) {
		double lastDot = VDOT(last->normal,rp->r_dir);
		double iDot = VDOT(i->normal,rp->r_dir);

		if (sign(lastDot) != sign(iDot)) {
		    // delete them both
		    i = hits.erase(last);
		    i = hits.erase(i);
		    last = i;

		    if (i != hits.end())
			++i;
		} else {
		    // just delete the second
		    i = hits.erase(i);
		}
	    } else {
		last = i;
		++i;
	    }
	}
    }

    // remove "duplicate" points
    //     HitList::iterator new_end = unique(hits.begin(), hits.end());
    //     hits.erase(new_end, hits.end());

    if (hits.size() > 1 && (hits.size() % 2) != 0) {
	cerr << "WTF???" << endl;
#if PLOTTING
	pcount++;
	if (pcount > -1) {
	    point_t ray;
	    point_t vscaled;
	    VSCALE(vscaled,rp->r_dir,100);
	    VADD2(ray,rp->r_pt,vscaled);
	    COLOR_PLOT(200,200,200);
	    LINE_PLOT(rp->r_pt,ray);
	}
#endif

	num = 0;
	int lastSign = 0;
	MissList::iterator m = misses.begin();
	for (HitList::iterator i = all_hits.begin(); i != all_hits.end(); ++i) {
	    double dot = VDOT(i->normal,rp->r_dir);

#if PLOTTING
	    if (pcount > -1) {
		// set the color of point and normal
		if (i->trimmed && i->closeToEdge) {
		    COLOR_PLOT(0,0,255); // blue is trimmed but close to edge
		} else if (i->trimmed) {
		    COLOR_PLOT(255,255,0); // yellow trimmed
		} else if (i->oob) {
		    COLOR_PLOT(255,0,0); // red is oob
		} else if (NEAR_ZERO(VDOT(i->normal,rp->r_dir),RT_DOT_TOL)) {
		    COLOR_PLOT(0,255,255); // purple is grazing
		} else {
		    COLOR_PLOT(0,255,0); // green is regular surface
		}

		// draw normal
		point_t v;
		VADD2(v,i->point,i->normal);
		LINE_PLOT(i->point,v);

		// draw intersection
		PT_PLOT(i->point);

		// draw bounding box
		BB_PLOT(i->sbv->m_node.m_min,i->sbv->m_node.m_max);
		fflush(plot_file());
	    }
#endif

	    // 	    if ((num == 0 && dot > 0) || sign(dot) == lastSign) {
	    // remove hits with "bad" normals
	    // 		i = hits.erase(i);
	    // 		--i;
	    // 		TRACE("removed a hit!");
	    // 		continue;
	    // 	    } else {
	    // 		lastSign = sign(dot);
	    // 	    }

	    TRACE("hit " << num << ": " << ON_PRINT3(i->point) << " [" << dot << "]");
	    while ((m != misses.end()) && (m->first == num)) {
		TRACE("miss " << num << ": " << BREP_INTERSECT_GET_REASON(m->second));
		++m;
	    }
	    num++;
	}
	while (m != misses.end()) {
	    TRACE("miss " << BREP_INTERSECT_GET_REASON(m->second));
	    ++m;
	}
    }

    bool hit = false;
    if (hits.size() > 0) {
	if (hits.size() % 2 == 0) {
	    // take each pair as a segment
	    for (HitList::iterator i = hits.begin(); i != hits.end(); ++i) {
		brep_hit& in = *i;
		i++;
		brep_hit& out = *i;

		register struct seg* segp;
		RT_GET_SEG(segp, ap->a_resource);
		segp->seg_stp = stp;

		VMOVE(segp->seg_in.hit_point, in.point);
		VMOVE(segp->seg_in.hit_normal, in.normal);
		segp->seg_in.hit_dist = DIST_PT_PT(rp->r_pt,in.point);
		segp->seg_in.hit_surfno = in.face.m_face_index;
		VSET(segp->seg_in.hit_vpriv,in.uv[0],in.uv[1],0.0);

		VMOVE(segp->seg_out.hit_point, out.point);
		VMOVE(segp->seg_out.hit_normal, out.normal);
		segp->seg_out.hit_dist = DIST_PT_PT(rp->r_pt,out.point);
		segp->seg_out.hit_surfno = out.face.m_face_index;
		VSET(segp->seg_out.hit_vpriv,out.uv[0],out.uv[1],0.0);

		BU_LIST_INSERT( &(seghead->l), &(segp->l) );
	    }
	    hit = true;
	}
	else {
	    TRACE2("screen xy: " << ap->a_x << "," << ap->a_y);
	}
    }

    return (hit) ? hits.size() : 0; // MISS
}
示例#7
0
文件: brep.cpp 项目: cciechad/brlcad
int
brep_intersect(const SubsurfaceBBNode* sbv, const ON_BrepFace* face, const ON_Surface* surf, pt2d_t uv, ON_Ray& ray, HitList& hits)
{
    int found = BREP_INTERSECT_ROOT_ITERATION_LIMIT;
    fastf_t Dlast = MAX_FASTF;
    int diverge_iter = 0;
    pt2d_t Rcurr;
    pt2d_t new_uv;
    ON_3dPoint pt;
    ON_3dVector su;
    ON_3dVector sv;
    plane_ray pr;
    brep_get_plane_ray(ray, pr);
    for (int i = 0; i < BREP_MAX_ITERATIONS; i++) {
	brep_r(surf,pr,uv,pt,su,sv,Rcurr);
	//fastf_t d = v2mag(Rcurr);
	fastf_t d = DIST_PT_PT(pt,ray.m_origin);
	//if (d < BREP_INTERSECTION_ROOT_EPSILON) {
	if (NEAR_ZERO(d-Dlast,BREP_INTERSECTION_ROOT_EPSILON)) {
	    TRACE1("R:"<<ON_PRINT2(Rcurr));
	    found = BREP_INTERSECT_FOUND; break;
	} else if (d > Dlast) {
	    found = BREP_INTERSECT_ROOT_DIVERGED; //break;
	    diverge_iter++;
	    if (diverge_iter > 10)
		break;
	    //return brep_edge_check(found, sbv, face, surf, ray, hits);
	}
	brep_newton_iterate(surf, pr, Rcurr, su, sv, uv, new_uv);
	move(uv, new_uv);
	Dlast = d;
    }
    if (found > 0) {
	fastf_t l,h;

	ON_3dPoint _pt;
	ON_3dVector _norm;
	surf->EvNormal(uv[0],uv[1],_pt,_norm);
	if (face->m_bRev) _norm.Reverse();
	hits.push_back(brep_hit(*face,(const fastf_t*)ray.m_origin,(const fastf_t*)_pt,(const fastf_t*)_norm, uv));
	hits.back().sbv = sbv;

 	if (!sbv->m_u.Includes(uv[0]) || !sbv->m_v.Includes(uv[1])) {
	    // 	    if (!sbv->m_u.Includes(uv[0]-BREP_SAME_POINT_TOLERANCE) ||
	    // 		!sbv->m_v.Includes(uv[1]-BREP_SAME_POINT_TOLERANCE)) {
	    hits.back().oob = true;
	    return BREP_INTERSECT_OOB;
	}


	if (sbv->doTrimming() && brep_pt_trimmed(uv, *face)) {
	    hits.back().trimmed = true;
	    TRACE1("Should be TRIMMED!");
	    // if the point was trimmed, see if it is close to the edge before removing it
	    return brep_edge_check(BREP_INTERSECT_TRIMMED, sbv, face, surf, ray, hits);
	    //return BREP_INTERSECT_TRIMMED;
	}
    }

    return found;
}