inline Wpt center (Wpt_list& pts, ARRAY<int>& N) { Wpt ret = Wpt(0); for (int i = 0; i < N.num(); i++) { ret += pts[N[i]]; } return ret / N.num(); }
///////////////////////////////////// // get_visibility() ///////////////////////////////////// void HatchingGroupFixed::get_visibility(TAGformat &d) { err_mesg(ERR_LEV_SPAM, "HatchingGroupFixed::get_visibility()"); BMESH *m = _patch->mesh(); if (LMESH::isa(m)) m = ((LMESH*)m)->cur_mesh(); int k, ctr=0; ARRAY<int> indices; CBface_list& faces = m->faces(); *d >> indices; for (k=0; k<indices.num(); k++) { HatchingSimplexDataFixed *hsdf = HatchingSimplexDataFixed::find(faces[indices[k]]); if (!hsdf) { hsdf = new HatchingSimplexDataFixed(faces[indices[k]]); ctr++; } hsdf->add(this); } err_mesg(ERR_LEV_SPAM, "HatchingGroupFixed::get_visibility() - Flagged %d tris and added %d new simplex data.", indices.num(), ctr); }
void UVdata::split(CEdgeStrip& strip) { ARRAY<Bvert_list> chains; strip.get_chains(chains); for (int i=0; i<chains.num(); i++) split_chain(chains[i]); }
inline Wpt_list get_pts(Bface_list& flist, ARRAY<Wvec>& blist) { assert(flist.num() == blist.num()); Wpt_list pts; for (int i = 0; i < flist.num(); i++) { Wpt pt; flist[i]->bc2pos(blist[i], pt); pts += pt; } return pts; }
inline int pick (ARRAY<QuadtreeNode*>& l) { int ret = -1; double total_w = 0.0; for (int i = 0; i < l.num(); i++) { total_w += l[i]->get_weight(); } double r = dorand() * total_w; total_w = 0.0; for (int i = 0; i < l.num(); i++) { total_w += l[i]->get_weight(); if (total_w >= r) { ret = i; break; } } return ret; }
int make_chain(ARRAY<NDCZpt*>& V, int (*cmp)(const void*, const void*)) { int i, j, s = 1; NDCZpt *tmp; V.sort(cmp); for (i=2; i<V.num(); i++) { for (j=s; j>=1 ; j--) if ((det(NDCvec(*(V[i]) - *(V[j])), NDCvec(*(V[j-1]) - *(V[j]))) > 0)) break; s = j+1; tmp = V[s]; V[s] = V[i]; V[i] = tmp; } return s; }
void visit(OctreeNode* node, double regularity, Bface_list& flist, ARRAY<Wvec>& blist) { if (node->get_leaf()) { if (node->get_disp()) { // subdivision ARRAY<QuadtreeNode*> fs; Bface_list temp; for (int i = 0; i < node->intersects().num(); i++) { Bface* f = node->intersects()[i]; temp += f; fs += new QuadtreeNode(f->v1()->loc(), f->v2()->loc(), f->v3()->loc()); fs.last()->build_quadtree(node, regularity); fs.last()->set_terms(); } // assign weights assign_weights(fs, regularity, node->center()); // pick a triangle int t = pick(fs); // moved below; want to ensure flist and blist stay in sync: // flist += temp[t]; //set node face Bface_list ftemp; ftemp += temp[t]; node->set_face(ftemp); // pick a point int p = pick(fs[t]->terms()); if (p != -1) { Wvec bc; temp[t]->project_barycentric(fs[t]->terms()[p]->urand_pick(), bc); blist += bc; flist += temp[t]; // moved from above node->set_point(bc); } for (int i = 0; i < fs.num(); i++) delete fs[i]; fs.clear(); } } else { for (int i = 0; i < 8; i++) visit(node->get_children()[i], regularity, flist, blist); } }
inline void show_polys(BMESH* m) { // for debugging: show polyline edges of a mesh if (!m) return; // Construct filter that accepts unreached polyline edges UnreachedSimplexFilter unreached; PolylineEdgeFilter poly; EdgeStrip strip(m->edges(), unreached + poly); ARRAY<Bvert_list> chains; strip.get_chains(chains); for (int i=0; i<chains.num(); i++) WORLD::show_polyline(chains[i].pts(), 3, Color::blue_pencil_d, 0.5); }
void assign_weights(ARRAY<QuadtreeNode*>& fs, double regularity, CWpt& pt) { double weight, d; QuadtreeNode* leaf; for (int i = 0; i < fs.num(); i++) { weight = 0.0; for (int j = 0; j < fs[i]->terms().num(); j++) { leaf = fs[i]->terms()[j]; d = pt.dist(leaf->centroid()); leaf->set_weight(distr_func(regularity, d) * leaf->area()); weight += leaf->get_weight(); } fs[i]->set_weight(weight); } }
void SkinCurveMap::set_pts(CBsimplex_list& simps, ARRAY<Wvec>& bcs) { assert(simps.num() == bcs.num()); _simps = simps; _bcs = bcs; static bool debug = Config::get_var_bool("DEBUG_SKIN_CURVE_SETUV",false,true); if (debug) { cerr << "-- In SkinCurveMap::set_ptss() got hte following simp/bc pair list" << endl; int i; for (i = 0; i < _simps.num(); i++) { cerr << i << " " << _simps[i] << "; " << _bcs[i] << endl; } cerr << "-- End list" << endl; } // Notify dependents they're out of date and sign up to be // recomputed invalidate(); }
void ProxySurface::trim_proxy_surface() { assert(_proxy_mesh); int n = 0; //number of faces outside the bounding box //get all the quads Bface_list faces = _proxy_mesh->faces(); //clear out all the markings for(int i=0; i < faces.num(); ++i) { if(faces[i]) ProxyData::set_mark(faces[i],this, false); //else // cerr << "FACE is NULL" << endl; } //mark all the faces that do not overap bounding box for(int i=0; i < faces.num(); ++i) { if(faces[i]){ bool t1 = (is_inside_bounding_box(faces[i]->e1())) ? true : false; bool t2 = (is_inside_bounding_box(faces[i]->e2())) ? true : false; bool t3 = (is_inside_bounding_box(faces[i]->e3())) ? true : false; // If all the edges are outside, then mark the face if(!t1 && !t2 && !t3){ //cerr << "we can delete this face" << endl; ProxyData::set_mark(faces[i], this, true); n++; } }else { //cerr << "FACE is NULL" << endl; } } if(n < 1) return; //for all verts check to see if all the faces that it is attached to has a marked Bvert_list verts = _proxy_mesh->verts(); for(int i=0; i < verts.num(); ++i) { ARRAY<Bface*> ret; verts[i]->get_quad_faces(ret); // Make sure that all adjasent faces need to be deleted bool do_it=true; for(int k=0; k < ret.num(); ++k) { if(ret[k]){ assert(ret[k]->is_quad()); if(!ProxyData::get_mark(ret[k], this) || !ProxyData::get_mark(ret[k]->quad_partner(), this)) { // cerr << "vert degree " << verts[i]->p_degree() << endl; do_it = false; break; } } } if(do_it){ UVpt remove_uv; UVdata::get_uv(verts[i], remove_uv); remove_vert_grid(remove_uv); _proxy_mesh->remove_vertex(verts[i]); _proxy_mesh->changed(); } } //clean up faces Bface_list faces2 = _proxy_mesh->faces(); for(int i=0; i < faces2.num(); ++i) { if(!(faces2[i]->is_quad()) || !(faces2[i]->quad_partner())){ _proxy_mesh->remove_face(faces2[i]); _proxy_mesh->changed(); } } //debug_grid(); }
void remove_nodes(Bface_list& flist, ARRAY<Wvec>& blist, double min_dist, ARRAY<OctreeNode*>& t) { // if (flist.num() != blist.num()) { // return; // } assert(flist.num() == blist.num()); Wpt_list pts = get_pts(flist, blist); ARRAY< ARRAY<int> > N; ARRAY<bool> to_remove; for (int i = 0; i < pts.num(); i++) { N += ARRAY<int>(); to_remove += false; } for (int i = 0; i < pts.num(); i++) { for (int j = 0; j < t[i]->neibors().num(); j++) { int index = t[i]->neibors()[j]->get_term_index(); if (index < pts.num()) { if (pts[i].dist(pts[index]) < min_dist) { N[i] += index; N[index] += i; } } else { //cerr << "Sps Warning, index > pts.num()" << endl; } } } priority_queue< Priority, vector<Priority> > queue; ARRAY<int> versions; for (int i = 0; i < pts.num(); i++) { if (!to_remove[i] && !N[i].empty()) { Priority p; p._priority = center(pts, N[i]).dist(pts[i]); p._index = i; p._version = 0; queue.push(p); } versions += 0; } while (!queue.empty()) { Priority p = queue.top(); queue.pop(); int r = p._index; if (p._version == versions[r]) { to_remove[r] = true; for (int i = 0; i < N[r].num(); i++) { N[N[r][i]] -= r; versions[N[r][i]]++; if (!N[N[r][i]].empty()) { Priority q; q._priority = center(pts, N[N[r][i]]).dist(pts[N[r][i]]); q._index = N[r][i]; q._version = versions[N[r][i]]; queue.push(q); } } } } versions.clear(); Bface_list ftemp(flist); ARRAY<Wvec> btemp(blist); flist.clear(); blist.clear(); for (int i = 0; i < ftemp.num(); i++) if (!to_remove[i]) { flist += ftemp[i]; blist += btemp[i]; } }
///////////////////////////////////// // add() ///////////////////////////////////// bool HatchingGroupFixed::add( CNDCpt_list &pl, const ARRAY<double>&prl, int curve_type ) { int k; double a,b; Bface *f; // It happens: if (pl.empty()) { err_mesg(ERR_LEV_ERROR, "HatchingGroupFixed:add() - Error: point list is empty!"); return false; } if (prl.empty()) { err_mesg(ERR_LEV_ERROR, "HatchingGroupFixed:add() - Error: pressure list is empty!"); return false; } if (pl.num() != prl.num()) { err_mesg(ERR_LEV_ERROR, "HatchingGroupFixed:add() - gesture pixel list and pressure list are not same length."); return false; } err_mesg_cond(debug, ERR_LEV_SPAM, "HatchingGroupFixed:add() - smoothing gesture."); //Smooth the input gesture NDCpt_list smoothpts; ARRAY<double> smoothprl; if (!smooth_gesture(pl, smoothpts, prl, smoothprl, _params.anim_style())) return false; err_mesg_cond(debug, ERR_LEV_SPAM, "HatchingGroupFixed:add() - clipping gesture to model."); NDCpt_list ndcpts; ARRAY<double> finalprl; clip_to_patch(smoothpts,ndcpts,smoothprl,finalprl); ndcpts.update_length(); err_mesg_cond(debug, ERR_LEV_SPAM, "HatchingGroupFixed::add() - Checking gesture silliness."); if (HatchingGroupBase::is_gesture_silly(ndcpts,_params.anim_style())) { err_mesg(ERR_LEV_WARN, "HatchingGroupFixed::add() - Punting silly gesture..."); return false; } //Even if the user wants to project to create the //hatch, we continue with plane cutting to //generate a curve we can use to estimate //the mesh spacing so that the final projected //hatch is sampled evenly on the level of the mesh //spacing //Get the cutting line err_mesg_cond(debug, ERR_LEV_SPAM, "HatchingGroupFixed:add() - fitting line."); if (!fit_line(ndcpts,a,b)) return false; //Slide to midpoint if desired if (Config::get_var_bool("HATCHING_GROUP_SLIDE_FIT",false,true)) b = ndcpts.interpolate(0.5)[1] - (a*ndcpts.interpolate(0.5)[0]); err_mesg_cond(debug, ERR_LEV_SPAM, "HatchingGroupFixed:add() - computing plane."); //Find the cutting plane Wplane wpPlane; f = compute_cutting_plane(_patch, a, b, ndcpts, wpPlane); if (!f) return false; else { if (!f->front_facing()) { err_mesg(ERR_LEV_WARN, "HatchingGroupFixed::add() - Nearest pt. on fit line hit backfacing surface."); return false; } } err_mesg_cond(debug, ERR_LEV_SPAM, "HatchingGroupFixed:add() - slicing mesh."); //Intersect the mesh to get a 3D curve Wpt_list wlList; slice_mesh_with_plane(f,wpPlane,wlList); err_mesg_cond(debug, ERR_LEV_SPAM, "HatchingGroupFixed:add() - cliping curve to gesture."); //Clip end of 3D curve to match gesture Wpt_list wlClipList; clip_curve_to_stroke(_patch, ndcpts, wlList, wlClipList); wlClipList.update_length(); Wpt_list wlScaledList; if (curve_type == HatchingGroup::CURVE_MODE_PROJECT) { err_mesg_cond(debug, ERR_LEV_SPAM, "HatchingGroupFixed::add() - Projecting to surface."); //Okay, the user wants to get literal, projected //points, so lets do it. We're careful to //toss points that hit the no/wrong mesh Wpt_list wlProjList; Wpt wloc; for (k=0; k<ndcpts.num(); k++) { f = HatchingGroupBase::find_face_vis(NDCpt(ndcpts[k]),wloc); if ((f) && (f->patch() == _patch) && (f->front_facing())) { wlProjList += wloc; } else { if (!f) err_mesg(ERR_LEV_WARN, "HatchingGroupFixed::add() - Missed while projecting: No hit on a mesh!"); else if (!(f->patch() == _patch)) err_mesg(ERR_LEV_WARN, "HatchingGroupFixed::add() - Missed while projecting: Hit wrong patch."); else if (!f->front_facing()) err_mesg(ERR_LEV_WARN, "HatchingGroupFixed::add() - Missed while projecting: Hit backfacing tri."); else err_mesg(ERR_LEV_WARN, "HatchingGroupFixed::add() - Missed while projecting: WHAT?!?!?!?!"); } } if (wlProjList.num()<2) { err_mesg(ERR_LEV_WARN, "HatchingGroupFixed:add() - Nothing left after projection failures. Punting..."); return false; } wlProjList.update_length(); err_mesg_cond(debug, ERR_LEV_SPAM, "HatchingGroupFixed::add() - Resampling curve."); //Resample to even spacing in world space. Sample //at a world distance similar to wlClipList, which //will be on the order of the mesh resolution //unless the gesture fits into one triangle, //in which case we ensure a minimum sampling int guess = (int)ceil(((double)wlClipList.num()* (double)wlProjList.length())/(double)wlClipList.length()); int num = max(guess,5); double step = 1.0/((double)(num-1)); for (k=0 ; k<num ; k++) wlScaledList += wlProjList.interpolate((double)k*step); } else //CURVE_MODE_PLANE { assert(curve_type == HatchingGroup::CURVE_MODE_PLANE); err_mesg_cond(debug, ERR_LEV_SPAM, "HatchingGroupFixed::add() - Resampling curve."); //Resample to even spacing in world space. This curve will //be sampled on the order of the mesh spacing but we'll //not allow the num of samples to drop too low in case //the gesture's on the scale of one triangle int num = max(wlClipList.num(),5); double step = 1.0/((double)(num-1)); for (k=0 ; k<num ; k++) wlScaledList += wlClipList.interpolate((double)k*step); } // Convert back to 2D err_mesg_cond(debug, ERR_LEV_SPAM, "HatchingGroupFixed:add() - converting to 2D."); NDCZpt_list ndczlScaledList; for (k=0;k<wlScaledList.num();k++) ndczlScaledList += NDCZpt(_patch->xform()*wlScaledList[k]); ndczlScaledList.update_length(); // Calculate pixel length of hatch double pix_len = ndczlScaledList.length() * VIEW::peek()->ndc2pix_scale(); if (pix_len < 8.0) { err_mesg(ERR_LEV_WARN, "HatchingGroupFixed::add() - Stroke only %f pixels. Probably an accident. Punting...", pix_len); return false; } ARRAY<HatchingFixedVertex> verts; Wpt_list pts; ARRAY<Wvec> norms; err_mesg_cond(debug, ERR_LEV_SPAM, "HatchingGroupFixed::add() - Final sampling."); for (k=0; k<ndczlScaledList.num(); k++) { Wpt wloc; f = HatchingGroupBase::find_face_vis(NDCpt(ndczlScaledList[k]),wloc); if ((f) && (f->patch() == _patch) && (f->front_facing())) { Wvec bc; Wvec norm; //f->project_barycentric(wloc,bc); f->project_barycentric_ndc(NDCpt(ndczlScaledList[k]),bc); Wvec bc_old = bc; Bsimplex::clamp_barycentric(bc); double dL = fabs(bc.length() - bc_old.length()); if (bc != bc_old) { err_mesg(ERR_LEV_INFO, "HatchingGroupFixed::add() - Baycentric clamp modified result: (%f,%f,%f) --> (%f,%f,%f) Length Change: %f", bc_old[0], bc_old[1], bc_old[2], bc[0], bc[1], bc[2], dL); } if (dL < 1e-3) { verts += HatchingFixedVertex(f->index(),bc); f->bc2norm_blend(bc,norm); pts += wloc; norms += norm; } else { err_mesg(ERR_LEV_WARN, "HatchingGroupFixed::add() - Change too large due to error in projection. Dumping point..."); } } else { if (!f) err_mesg(ERR_LEV_WARN, "HatchingGroupFixed::add() - Missed in final lookup: No hit on a mesh!"); else if (!(f->patch() == _patch)) err_mesg(ERR_LEV_WARN, "HatchingGroupFixed::add() - Missed in final lookup: Hit wrong patch."); else if (!(f->front_facing())) err_mesg(ERR_LEV_WARN, "HatchingGroupFixed::add() - Missed in final lookup: Hit backfracing tri."); else err_mesg(ERR_LEV_WARN, "HatchingGroupFixed::add() - Missed in final lookup: WHAT?!?!?!?!"); } } if (pts.num()>1) { //XXX - Okay, using the gesture pressure, but no offsets. //Need to go back and add offset generation... BaseStrokeOffsetLISTptr ol = new BaseStrokeOffsetLIST; ol->set_replicate(0); ol->set_hangover(1); ol->set_pix_len(pix_len); ol->add(BaseStrokeOffset( 0.0, 0.0, finalprl[0], BaseStrokeOffset::OFFSET_TYPE_BEGIN)); for (k=1; k< finalprl.num(); k++) ol->add(BaseStrokeOffset( (double)k/(double)(finalprl.num()-1), 0.0, finalprl[k], BaseStrokeOffset::OFFSET_TYPE_MIDDLE)); ol->add(BaseStrokeOffset( 1.0, 0.0, finalprl[finalprl.num()-1], BaseStrokeOffset::OFFSET_TYPE_END)); if (base_level(num_base_levels()-1)->pix_size() > 0) { assert(_params.anim_style() != HatchingGroup::STYLE_MODE_NEAT); add_base_level(); // Make sure we can see it whil we're editing! base_level(num_base_levels()-1)->set_desired_frac(1.0); } base_level(num_base_levels()-1)->add_hatch( new HatchingHatchFixed( base_level(num_base_levels()-1),_patch->mesh()->pix_size(),verts,pts,norms,ol) ); return true; } else { err_mesg(ERR_LEV_WARN, "HatchingGroupFixed:add() - All lookups are bad. Punting..."); return false; } return true; }
///////////////////////////////////// // put_visibility() ///////////////////////////////////// void HatchingGroupFixed::put_visibility(TAGformat &d) const { err_mesg(ERR_LEV_SPAM, "HatchingGroupFixed::put_visibility()"); BMESH *m = _patch->mesh(); if (LMESH::isa(m)) m = ((LMESH*)m)->cur_mesh(); int k; ARRAY<int> indices; CBface_list& faces = m->faces(); for (k=0; k< faces.num(); k++) { HatchingSimplexDataFixed *hsdf = HatchingSimplexDataFixed::find(faces[k]); if (hsdf) { if(hsdf->hack_exists(this)) indices += faces[k]->index(); } } err_mesg(ERR_LEV_SPAM, "HatchingGroupFixed::put_visibility() - Stored %d tri indices.", indices.num()); d.id(); *d << indices; d.end_id(); }
///////////////////////////////////// // 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."); } } } } } } } } }
void LMESH::fit(ARRAY<Lvert*>& verts, bool do_gauss_seidel) { static bool debug = Config::get_var_bool("DEBUG_LMESH_FIT",false); static bool move_along_normal = Config::get_var_bool("FITTING_MOVE_ALONG_NORMAL",false); if (verts.empty()) return; // calculate the bounding box of the vertices BBOX box; int i; for (i=0; i<verts.num(); i++) box.update(verts[i]->loc()); double max_err = box.dim().length() * 1e-5; int n = verts.num(); // get original control point locations ARRAY<Wpt> C(n); // original control points ARRAY<Wpt> L(n); // current limit points for (i=0; i<n; i++) { C += verts[i]->loc(); L += Wpt::Origin(); } if(debug) { cerr << "LMESH::fit- fitting " << n << " vertices"<<endl; cerr << "Max_err = " << max_err <<endl; } // do 50 iterations... double prev_err = 0; ARRAY<double> errors; for (int k=0; k<50; k++) { errors.clear(); double err = 0; if (do_gauss_seidel) { // Gauss-Seidel iteration: use updated values from the // current iteration as they are computed... for (int j=0; j<n; j++) { // don't need that L[] array... Wpt limit; verts[j]->limit_loc(limit); Wvec delt = C[j] - limit; errors+=delt.length(); err += delt.length(); if(move_along_normal) delt = delt*verts[j]->norm()*verts[j]->norm(); verts[j]->offset_loc(delt); } } else { // compute the new offsets from the offsets computed in the // previous iteration int j; for (j=0; j<n; j++) verts[j]->limit_loc(L[j]); for (j=0; j<n; j++) { Wvec delt = C[j] - L[j]; err += delt.length(); errors+=delt.length(); if(move_along_normal) delt = delt*verts[j]->norm()*verts[j]->norm(); verts[j]->offset_loc(delt); } } // compute the average error: err /= n; double avg,std_d,max,min; if (debug) { if (prev_err != 0) { err_msg("Iter %d: avg error: %f, reduction: %f", k, err, err/prev_err); statistics(errors,true,&avg,&std_d,&max,&min); } else { err_msg("Iter %d: avg error: %f", k, err); statistics(errors,true,&avg,&std_d,&max,&min); } } else statistics(errors,false,&avg,&std_d,&max,&min); prev_err = err; if (max < max_err) { if(debug) cerr << "Terminating at " << k <<" th iterations"<<endl; return; } } }