///////////////////////////////////// // add_limits() ///////////////////////////////////// void UVMapping::add_limit(Bface *f) { int k; assert(f); UVdata* uvdata = UVdata::lookup(f); assert(uvdata); assert(uvdata->mapping()==0); for (k=1; k<=3; k++) { if ( uvdata->uv(k)[0] < _min_u ) _min_u = uvdata->uv(k)[0]; if ( uvdata->uv(k)[0] > _max_u ) _max_u = uvdata->uv(k)[0]; if ( uvdata->uv(k)[1] < _min_v ) _min_v = uvdata->uv(k)[1]; if ( uvdata->uv(k)[1] > _max_v ) _max_v = uvdata->uv(k)[1]; } }
///////////////////////////////////// // compute_limits() ///////////////////////////////////// void UVMapping::compute_limits(Bface *f) { int k; assert(f); //There oughta be uv here UVdata* uvdata = UVdata::lookup(f); assert(uvdata); //And it should not be mapped yet assert(uvdata->mapping()==0); //Init uv limits _min_u = uvdata->uv(1)[0]; _max_u = uvdata->uv(1)[0]; _min_v = uvdata->uv(1)[1]; _max_v = uvdata->uv(1)[1]; //Clear the mesh bits CBface_list& faces = f->mesh()->faces(); for (k=0; k< faces.num(); k++) faces[k]->clear_bit(1); //Walk from seed face and fill out uv min/max recurse(f,&UVMapping::add_limit); //Sanity check assert( _min_u < _max_u ); assert( _min_v < _max_v ); _span_u = _max_u - _min_u; _span_v = _max_v - _min_v; _du = _span_u/(double)MAPPING_SIZE; _dv = _span_v/(double)MAPPING_SIZE; err_mesg(ERR_LEV_INFO, "UVMapping::compute_limits() - u_min=%f u_max=%f v_min=%f v_max=%f u_span=%f v_span=%f", _min_u, _max_u, _min_v, _max_v, _span_u, _span_v); }
///////////////////////////////////// // add_face() ///////////////////////////////////// void UVMapping::add_face(Bface *f) { int k, u, v; int umax=0, vmax=0; int umin=MAPPING_SIZE-1, vmin=MAPPING_SIZE-1; int entry_count = 0; int bin_count = 0; assert(f); UVdata* uvdata = UVdata::lookup(f); assert(uvdata); assert(uvdata->mapping()==0); //Sanity check for (k=1; k<=3; k++) { assert( uvdata->uv(k)[0] <= _max_u ); assert( uvdata->uv(k)[1] <= _max_v ); assert( uvdata->uv(k)[0] >= _min_u ); assert( uvdata->uv(k)[1] >= _min_v ); } //Find the square set of u,v bins holding face for (k=1; k<=3; k++) { u = int(floor( (uvdata->uv(k)[0] - _min_u) / _du )); if (u==MAPPING_SIZE) u--; v = int(floor( (uvdata->uv(k)[1] - _min_v ) /_dv )); if (v==MAPPING_SIZE) v--; if (u<umin) umin=u; if (u>umax) umax=u; if (v<vmin) vmin=v; if (v>vmax) vmax=v; } //So escape rounding error that would //exclude bins that we genuinely intersect //we puff out the set of bins by 1 on each side if (umin>0) umin--; if (vmin>0) vmin--; if (umax<MAPPING_SIZE-1) umax++; if (vmax<MAPPING_SIZE-1) vmax++; //Sanity checks assert(umin>=0); assert(vmin>=0); assert(umax<MAPPING_SIZE); assert(vmax<MAPPING_SIZE); assert(umax>=umin); assert(vmax>=vmin); UVpt_list box; UVpt_list tri; bool isect; for (v=vmin; v<=vmax; v++) { for (u=umin; u<=umax; u++) { isect = false; box.clear(); tri.clear(); box += UVpt( _min_u + u *_du , _min_v + v * _dv ); box += UVpt( _min_u + (u+1) *_du , _min_v + v * _dv ); box += UVpt( _min_u + (u+1) *_du , _min_v + (v+1) * _dv ); box += UVpt( _min_u + u *_du , _min_v + (v+1) * _dv ); tri += uvdata->uv1(); tri += uvdata->uv2(); tri += uvdata->uv3(); //isect if box holds tri or vice versa if (box.contains(tri)) isect = true; else if (tri.contains(box)) isect = true; //or if any edges intersect else { for (k=0; k<3; k++) { if (!isect) { if (intersect(box[0],box[1],tri[k],tri[(k+1)%3])) isect=true; else if (intersect(box[1],box[2],tri[k],tri[(k+1)%3])) isect=true; else if (intersect(box[2],box[3],tri[k],tri[(k+1)%3])) isect=true; else if (intersect(box[3],box[0],tri[k],tri[(k+1)%3])) isect=true; } } } if (isect) { entry_count++; _mapping[u+MAPPING_SIZE*v]->add(f); if ( _mapping[u+MAPPING_SIZE*v]->num() == 1 ) bin_count++; } } } //By definition , a face imust fall somewhere //within the mapping's bin assert(entry_count>0); uvdata->set_mapping(this); //Increment mapped face count _face_cnt++; //Increment map face entry count _entry_cnt += entry_count; //Increment unique bin usage count _bin_cnt += bin_count; }
///////////////////////////////////// // recurse() ///////////////////////////////////// void UVMapping::recurse(Bface *seed_f, rec_fun_t fun ) { int k; // bool done = false; Bface* f; ARRAY<Bface*> faces; assert(seed_f); faces.push(seed_f); while (faces.num()>0) { //Remove oldest face from end of queue f = faces.pop(); //Skip if already seen if (!f->is_set(1)) { f->set_bit(1); //If we get here, then this face *should* have uvdata //and *should* be unmapped UVdata* uvdata = UVdata::lookup(f); assert(uvdata); assert(uvdata->mapping()==0); //Do the action (add to map, or update limits, etc.) (this->*fun)(f); for (k=1; k<=3; k++) { Bedge *nxt_e = f->e(k); assert(nxt_e); Bface *nxt_f = nxt_e->other_face(f); if (nxt_f) { UVdata *nxt_uvdata = UVdata::lookup(nxt_f); if (nxt_uvdata) { UVpt uva = uvdata->uv(k); UVpt uvb = uvdata->uv((k==3)?(1):(k+1)); int nxt_k = ( (nxt_f->e1()==nxt_e)?(1): ((nxt_f->e2()==nxt_e)?(2): ((nxt_f->e3()==nxt_e)?(3):(0)))); assert(nxt_k); UVpt nxt_uva = nxt_uvdata->uv(nxt_k); UVpt nxt_uvb = nxt_uvdata->uv((nxt_k==3)?(1):(nxt_k+1)); //If neighboring face has uv, and the they match //we recurse into this next face if ((uva==nxt_uvb)&&(uvb==nxt_uva)) { //Add to front of queue faces.push(nxt_f); } else { //Nothing } } } } } } }
///////////////////////////////////// // recurse_wrapping() ///////////////////////////////////// void UVMapping::recurse_wrapping(Bface *seed_f) { int k; Bface *f; ARRAY<Bface*> faces; assert(seed_f); faces.push(seed_f); while (faces.num()>0) { //Remove face from end of queue f = faces.pop(); //Skip if already seen if (!f->is_set(1)) { f->set_bit(1); //If we get here, then this face *should* have uvdata //and *should* be allready be mapped to us! UVdata* uvdata = UVdata::lookup(f); assert(uvdata); assert(uvdata->mapping()==this); for (k=1; k<=3; k++) { Bedge *nxt_e = f->e(k); assert(nxt_e); Bface *nxt_f = nxt_e->other_face(f); if (nxt_f) { UVdata *nxt_uvdata = UVdata::lookup(nxt_f); if (nxt_uvdata) { UVpt uva = uvdata->uv(k); UVpt uvb = uvdata->uv((k==3)?(1):(k+1)); int nxt_k = ( (nxt_f->e1()==nxt_e)?(1): ((nxt_f->e2()==nxt_e)?(2): ((nxt_f->e3()==nxt_e)?(3):(0)))); assert(nxt_k); UVpt nxt_uva = nxt_uvdata->uv(nxt_k); UVpt nxt_uvb = nxt_uvdata->uv((nxt_k==3)?(1):(nxt_k+1)); //If neighboring face has uv, and the they match //we recurse into this next face if ((uva==nxt_uvb)&&(uvb==nxt_uva)) { //Stick face on start of queue faces.push(nxt_f); } //But if not, let's see if the other face is //part of this mapping. If it is, then we found //a seam. Find the direction (u or v) and if //its consistent with the _min_u/_max_u (or v) //Then set the wrap flag for u or v appropriately //or just turn all wrapping off if something's amiss else { //Here's a seam! if (nxt_uvdata->mapping() == this) { //We support 2 kinds of wrapping: //-Wrap on a line of constant u (wrap at _min_u,_max_u) //-Wrap on a line of constant v (wrap at _min_v,_max_v) //If neither is seen, or if the discontinuity isn't //at the extrema, we found something anomolous, abort! //Note - There can be holes at the seam without problems. if ((uva[0]==uvb[0])&&(nxt_uva[0]==nxt_uvb[0])) { //This looks like wrapping on a line of const. u //Let's make sure the discontinuity is at the extrema if ( (uva[0]==_min_u && nxt_uva[0]==_max_u) || (uva[0]==_max_u && nxt_uva[0]==_min_u)) { //It's all good if (!_wrap_u) { err_mesg(ERR_LEV_SPAM, "UVMapping::recurse_wrapping() - Found a valid wrapping seam in u."); _wrap_u = true; } } else { //We aren't at the extrema, so set the bad flag //to avoid further checking _wrap_bad = true; _wrap_u = false; _wrap_v = false; err_mesg(ERR_LEV_WARN, "UVMapping::recurse_wrapping() - Found an INVALID wrapping seam in u: (%f,%f) since u extrema are: (%f,%f)", uva[0], nxt_uva[0], _min_u, _max_u); err_mesg(ERR_LEV_WARN, "UVMapping::recurse_wrapping() - Aborting all wrapping."); } } else if ((uva[1]==uvb[1])&&(nxt_uva[1]==nxt_uvb[1])) { //This looks like wrapping on a line of const. v //Let's make sure the discontinuity is at the extrema if ( (uva[1]==_min_v && nxt_uva[1]==_max_v) || (uva[1]==_max_v && nxt_uva[1]==_min_v)) { //It's all good if (!_wrap_v) { err_mesg(ERR_LEV_INFO, "UVMapping::recurse_wrapping() - Found a valid wrapping seam in v."); _wrap_v = true; } } else { //We aren't at the extrema, so set the bad flag //to avoid further checking _wrap_bad = true; _wrap_u = false; _wrap_v = false; err_mesg(ERR_LEV_WARN, "UVMapping::recurse_wrapping() - Found an INVALID wrapping seam in v: (%f,%f) since v extrema are: (%f,%f)", uva[1], nxt_uva[1], _min_v, _max_v); err_mesg(ERR_LEV_WARN, "UVMapping::recurse_wrapping() - Aborting all wrapping."); } } else { //One or both edges failed to show constant u or v //Abort any further wrapping... _wrap_bad = true; _wrap_u = false; _wrap_v = false; err_mesg(ERR_LEV_WARN, "UVMapping::recurse_wrapping() - Found an INVALID wrapping. The seam wasn't constant in u or v."); err_mesg(ERR_LEV_WARN, "UVMapping::recurse_wrapping() - Edge #1 (%f,%f)-(%f,%f) Edge #2 (%f,%f)-(%f,%f)", uva[0], uva[1], uvb[0], uvb[1], nxt_uvb[0], nxt_uvb[1], nxt_uva[0], nxt_uva[1]); err_mesg(ERR_LEV_WARN, "UVMapping::recurse_wrapping() - Aborting all wrapping."); } } } } } } } } }