// Add a face to the partial boundingbox result. static void ON_Brep_GetTightFaceBoundingBox_Helper( const ON_BrepFace& face, ON_BoundingBox& bbox, const ON_Xform* xform, const ON_Xform* xform_inverse ) { ON_BoundingBox loose_box; // This should ideally test for planarity inside the OuterLoop() pbox only, // but no such function exists in the SDK as far as I can tell. if( face.IsPlanar() ) return; // Get loose boundingbox of face. if( face.GetBoundingBox(loose_box, false) ) { if( xform_inverse ) loose_box.Transform(*xform_inverse); if( bbox.Includes(loose_box, false) ) return; } const TL_Brep* tlbrep = TL_Brep::Promote(face.Brep()); if( tlbrep ) { ON_Brep_GetTightIsoCurveBoundingBox_Helper( *tlbrep, face, bbox, xform, 0); ON_Brep_GetTightIsoCurveBoundingBox_Helper( *tlbrep, face, bbox, xform, 1); } }
bool brep_pt_trimmed(pt2d_t pt, const ON_BrepFace& face) { bool retVal = false; TRACE1("brep_pt_trimmed: " << PT2(pt)); // for each loop const ON_Surface* surf = face.SurfaceOf(); double umin, umax; ON_2dPoint from, to; from.x = pt[0]; from.y = to.y = pt[1]; surf->GetDomain(0, &umin, &umax); to.x = umax + 1; ON_Line ray(from,to); int intersections = 0; for (int i = 0; i < face.LoopCount(); i++) { ON_BrepLoop* loop = face.Loop(i); // for each trim for (int j = 0; j < loop->m_ti.Count(); j++) { ON_BrepTrim& trim = face.Brep()->m_T[loop->m_ti[j]]; const ON_Curve* trimCurve = trim.TrimCurveOf(); // intersections += brep_count_intersections(ray, trimCurve); //ray.IntersectCurve(trimCurve, intersections, 0.0001); intersections += trimCurve->NumIntersectionsWith(ray); } } // If we base trimming on the number of intersections with, rhino generated curves won't raytrace. // In fact, we need to ignore trimming for the time being, just return false. // To do: figure out what this code does, and fix it for rhino generated geometries. djg 4/16/08 // the point is trimmed if the # of intersections is even and non-zero retVal= (intersections > 0 && (intersections % 2) == 0); return retVal; }
RH_C_FUNCTION const ON_Surface* ON_BrepFace_SurfaceOf( const ON_Brep* pConstBrep, int faceIndex ) { const ON_Surface* rc = NULL; if( pConstBrep ) { ON_BrepFace* pFace = pConstBrep->Face(faceIndex); if( pFace ) rc = pFace->SurfaceOf(); } return rc; }
RH_C_FUNCTION const ON_Mesh* ON_BrepFace_Mesh( const ON_Brep* pConstBrep, int faceIndex, int meshtype ) { const ON_Mesh* rc = NULL; if( pConstBrep ) { ON_BrepFace* pFace = pConstBrep->Face(faceIndex); if( pFace ) { rc = pFace->Mesh( ON::MeshType(meshtype) ); } } return rc; }
RH_C_FUNCTION ON_Surface* ON_Brep_DuplicateFaceSurface( const ON_Brep* pConstBrep, int faceIndex ) { ON_Surface* rc = NULL; if( pConstBrep ) { ON_BrepFace* pFace = pConstBrep->Face(faceIndex); if( pFace ) { const ON_Surface* pSurf = pFace->SurfaceOf(); if( pSurf ) rc = pSurf->DuplicateSurface(); } } return rc; }
// XXX - most of this function is broken :-( except for the bezier span caching // need to fix it! - could provide real performance benefits... void brep_preprocess_trims(const ON_BrepFace& face, SurfaceTree* tree) { list<BBNode*> leaves; tree->getLeaves(leaves); for (list<BBNode*>::iterator i = leaves.begin(); i != leaves.end(); i++) { SubsurfaceBBNode* bb = dynamic_cast<SubsurfaceBBNode*>(*i); // XXX - TODO: check to see if this portion of the surface // needs to be checked for trims pt2d_t test[] = {{bb->m_u.Min(),bb->m_v.Min()}, {bb->m_u.Max(),bb->m_v.Min()}, {bb->m_u.Max(),bb->m_v.Max()}, {bb->m_u.Min(),bb->m_v.Max()}}; // check to see if the bbox encloses a trim ON_3dPoint uvmin(bb->m_u.Min(),bb->m_v.Min(),0); ON_3dPoint uvmax(bb->m_u.Max(),bb->m_v.Max(),0); ON_BoundingBox bbox(uvmin,uvmax); bool internalTrim = false; for (int i = 0; i < face.Brep()->m_L.Count(); i++) { ON_BrepLoop& loop = face.Brep()->m_L[i]; // for each trim for (int j = 0; j < loop.m_ti.Count(); j++) { ON_BrepTrim& trim = face.Brep()->m_T[loop.m_ti[j]]; if (bbox.Intersection(trim.m_pbox)) internalTrim = true; // tell the NURBS curves to cache their Bezier spans // (used in trimming routines, and not thread safe) const ON_Curve* c = trim.TrimCurveOf(); if (c->ClassId()->IsDerivedFrom(&ON_NurbsCurve::m_ON_NurbsCurve_class_id)) { ON_NurbsCurve::Cast(c)->CacheBezierSpans(); } } } bb->m_checkTrim = true; // XXX - ack, hardcode for now // for this node to be completely trimmed, all four corners // must be trimmed and the depth of the tree needs to be > 0, // since 0 means there is just a single leaf - and since // "internal" outer loops will be make a single node seem // trimmed, we must account for it. bb->m_trimmed = false; // XXX - ack, hardcode for now } }
// Add the isocurves of a BrepFace to the partial boundingbox result. static void ON_Brep_GetTightIsoCurveBoundingBox_Helper( const TL_Brep& tlbrep, const ON_BrepFace& face, ON_BoundingBox& bbox, const ON_Xform* xform, int dir ) { ON_Interval domain = face.Domain(1 - dir); int degree = face.Degree(1 - dir); int spancount = face.SpanCount(1 - dir); int spansamples = degree * (degree + 1) - 1; if( spansamples < 2 ) spansamples = 2; // pbox delineates the extremes of the face interior. // We can use it to trivially reject spans and isocurves. ON_BrepLoop* pOuterLoop = face.OuterLoop(); if( NULL==pOuterLoop ) return; const ON_BoundingBox& pbox = pOuterLoop->m_pbox; double t0 = ((dir == 0) ? pbox.Min().y : pbox.Min().x); double t1 = ((dir == 0) ? pbox.Max().y : pbox.Max().x); // Get the surface span vector. ON_SimpleArray<double> spanvector(spancount + 1); spanvector.SetCount(spancount + 1); face.GetSpanVector(1 - dir, spanvector.Array()); // Generate a list of all the sampling parameters. ON_SimpleArray<double> samples(spancount * spansamples); for( int s = 0; s < spancount; s++) { double s0 = spanvector[s]; double s1 = spanvector[s+1]; // Reject span if it does not intersect the pbox. if( s1 < t0 ) { continue; } if( s0 > t1 ) { continue; } ON_Interval span(s0, s1); for( int i = 1; i < spansamples; i++ ) { double t = span.ParameterAt((double)i / (double)(spansamples - 1)); // Reject iso if it does not intersect the pbox. if( t < t0 ) continue; if( t > t1 ) break; samples.Append(t); } } //Iterate over samples int sample_count = samples.Count(); ON_BoundingBox loose_box; ON_SimpleArray<ON_Interval> intervals; ON_NurbsCurve isosubcrv; for( int i = 0; i<sample_count; i++) { // Retrieve iso-curve. ON_Curve* isocrv = face.IsoCurve(dir, samples[i]); while( NULL!=isocrv ) { // Transform isocurve if necessary, this is better than transforming downstream boundingboxes. if( xform ) isocrv->Transform(*xform); // Compute loose box. if( !isocrv->GetBoundingBox(loose_box, false)) break; // Determine whether the loose box is already contained within the partial result. if( bbox.Includes(loose_box, false) ) break; // Solve trimming domains for the iso-curve. intervals.SetCount(0); if( !tlbrep.GetIsoIntervals(face, dir, samples[i], intervals)) break; // Iterate over trimmed iso-curves. int interval_count = intervals.Count(); for( int k=0; k<interval_count; k++ ) { //this to mask a bug in Rhino4. GetNurbForm does not destroy the Curve Tree. It does now. isosubcrv.DestroyCurveTree(); isocrv->GetNurbForm(isosubcrv, 0.0, &intervals[k]); ON_Brep_GetTightCurveBoundingBox_Helper(isosubcrv, bbox, NULL, NULL); } break; } if( isocrv ) { delete isocrv; isocrv = NULL; } } }
void ON_GL( const ON_BrepFace& face, GLUnurbsObj* nobj // created with gluNewNurbsRenderer ) ) { bool bSkipTrims = false; const ON_Mesh* mesh; mesh = face.Mesh(ON::render_mesh); if ( mesh ) { // use saved render mesh ON_GL(*mesh); } else { // use (slow and buggy) glu trimmed NURBS rendering double knot_scale[2][2] = {{0.0,1.0},{0.0,1.0}}; const ON_Brep* brep = face.Brep(); if ( !brep ) return; // untrimmed surface { ON_NurbsSurface tmp_nurbssrf; const ON_Surface* srf = brep->m_S[face.m_si]; const ON_NurbsSurface* nurbs_srf = ON_NurbsSurface::Cast(srf); if ( !nurbs_srf ) { // attempt to get NURBS form of this surface if ( srf->GetNurbForm( tmp_nurbssrf ) ) nurbs_srf = &tmp_nurbssrf; } if ( !nurbs_srf ) return; gluBeginSurface( nobj ); ON_GL( *nurbs_srf, nobj, (nurbs_srf->IsRational()) ? GL_MAP2_VERTEX_4 : GL_MAP2_VERTEX_3, true, knot_scale[0], knot_scale[1] ); } if ( bSkipTrims || brep->FaceIsSurface( face.m_face_index ) ) { gluEndSurface( nobj ); return; // face is trivially trimmed } int fli, li, lti, ti; // any knot scaling applied to the surface must also be applied to // the parameter space trimming geometry double xform[4][4] = {{knot_scale[0][1], 0.0, 0.0, -knot_scale[0][0]*knot_scale[0][1] }, {0.0, knot_scale[1][1], 0.0, -knot_scale[1][0]*knot_scale[1][1] }, {0.0, 0.0, 1.0, 0.0}, {0.0, 0.0, 0.0, 1.0}}; // Add face's 2d trimming loop(s) const int face_loop_count = face.m_li.Count(); for ( fli = 0; fli < face_loop_count; fli++ ) { gluBeginTrim( nobj ); li = face.m_li[fli]; const ON_BrepLoop& loop = brep->m_L[li]; const int loop_trim_count = loop.m_ti.Count(); for ( lti = 0; lti < loop_trim_count; lti++ ) { ti = loop.m_ti[lti]; const ON_BrepTrim& trim = brep->m_T[ti]; ON_GL( trim, nobj, GLU_MAP1_TRIM_2, xform ); } gluEndTrim( nobj ); } gluEndSurface( nobj ); } }
static bool SealSeam(int closed_dir, ON_BrepFace& F) { if (closed_dir) closed_dir = 1; int seam_dir = 1-closed_dir; ON_Brep* pBrep = F.Brep(); if (!pBrep) return false; const ON_Surface* pSrf = F.SurfaceOf(); if (!pSrf || !pSrf->IsClosed(closed_dir)) return false; ON_Surface::ISO isoA = ON_Surface::not_iso;//same dir as isocurve ON_Surface::ISO isoB = ON_Surface::not_iso;//opposite dir as isocurve if (closed_dir){ isoA = ON_Surface::S_iso; isoB = ON_Surface::N_iso; } else { isoA = ON_Surface::E_iso; isoB = ON_Surface::W_iso; } /* TODO: Handle cases where there is more than one trim on a seam side or seam edges do not fully overlap. */ //Look for a single pair of trims that match across parameter space. int A_id = -1; int B_id = -1; int li; for (li=0; li<F.m_li.Count(); li++){ const ON_BrepLoop* L = F.Loop(li); if (!L || L->m_type != ON_BrepLoop::outer) continue; int lti; for (lti = 0; lti<L->m_ti.Count(); lti++ ){ ON_BrepTrim* T = L->Trim(lti); if (!T) continue; if (T->m_iso == isoA) { if (A_id >= 0) return false; A_id = T->m_trim_index; } else if (T->m_iso == isoB) { if (B_id >= 0) return false; B_id = T->m_trim_index; } } } if (A_id < 0 || B_id < 0) return true;//no seam to join ON_BrepTrim& TA = pBrep->m_T[A_id]; ON_BrepTrim& TB = pBrep->m_T[B_id]; ON_BrepEdge* pEA = TA.Edge(); ON_BrepEdge* pEB = TB.Edge(); if (!pEA || !pEB) return false; ON_Interval a,b; int i; for (i=0; i<2; i++){ a[i] = TA.PointAt(TA.Domain()[i])[seam_dir]; b[i] = TB.PointAt(TB.Domain()[i])[seam_dir]; } a.MakeIncreasing(); b.MakeIncreasing(); if (a[0] >= b[1] || b[0] >= a[1]) return true; //nothing to be joined; double pspace_tol = 1.0e-8; if (a.Length() < 10.0*pspace_tol) return false; if (fabs(a[0] - b[0]) > pspace_tol || fabs(a[1] - b[1]) > pspace_tol) return false; //fix vertices so join will work. RebuildVertexToTrimEnd(TA, 0); RebuildVertexToTrimEnd(TA, 1); RebuildVertexToTrimEnd(TB, 0); RebuildVertexToTrimEnd(TB, 1); double join_tol = 1.0e-6; if (!pBrep->JoinEdges(*pEA, *pEB, join_tol)) return false; TA.m_type = ON_BrepTrim::seam; TB.m_type = ON_BrepTrim::seam; return true; }