Patch* Bedge::patch() const { Bface* f = frontfacing_face(); f = f ? f : _f1 ? _f1 : _f2; return f ? f->patch() : 0; }
///////////////////////////////////// // clip_to_patch() ///////////////////////////////////// void HatchingGroupFixed::clip_to_patch( CNDCpt_list &pts, NDCpt_list &cpts, const ARRAY<double>&prl, ARRAY<double>&cprl ) { int k, started = 0; Bface *f; Wpt foo; for (k=0; k<pts.num(); k++) { f = find_face_vis(pts[k], foo); if ((f) && (f->patch() == _patch)) { started = 1; cpts += pts[k]; cprl += prl[k]; } else { if (started) { k=pts.num(); } } } }
///////////////////////////////////// // store_visibility() ///////////////////////////////////// bool HatchingGroupFixed::store_visibility(HatchingLevelBase *hlb) { assert(!_complete); HatchingLevelBase::size_type k; NDCZpt_list::size_type j; NDCZpt_list pts, hull; //One side for (k=0; k<hlb->size(); k++) for (j=0; j<(*hlb)[k]->get_pts().size(); j++) pts.push_back(NDCZpt( _patch->xform() * ((*hlb)[k]->get_pts()[j]) )); compute_convex_hull(pts,hull); if (hull.size() == 0) { err_mesg(ERR_LEV_WARN, "HatchingGroupFixed:store_visibility() - Error!! There were %d convex hull verts found from %d hatch verts.", hull.size(), pts.size()); return false; } else { err_mesg(ERR_LEV_INFO, "HatchingGroupFixed:store_visibility() - There were %d convex hull verts found from %d hatch verts.", hull.size(), pts.size()); } Bface *f = nullptr; XYpt center = NDCpt(hull.average()); BMESHray r(center); VIEW::peek()->intersect(r); f = r.face(); if (!f) { err_mesg(ERR_LEV_WARN, "HatchingGroupFixed:store_visibility() - Seed face intersect failed (hull center)!"); } if (!(_patch == f->patch())) { err_mesg(ERR_LEV_WARN, "HatchingGroupFixed:store_visibility() - Seed face intersected wrong patch (hull center)!!"); return false; } CBface_list & faces = f->mesh()->faces(); for (k=0; k < faces.size(); k++) faces[k]->clear_bit(1); int ctr = 0; ctr = recurse_visibility(f,hull); err_mesg(ERR_LEV_INFO, "HatchingGroupFixed:store_visibility() - There were %d faces in the visible region (from %d).", ctr, faces.size()); _group->patch()->changed(); if (ctr>0) return true; else return false; }
int XformPen::tap_cb(CGESTUREptr& tap, DrawState*& s) { assert(tap); if (tap->is_double_tap()) { // should never happen given order of arcs in XformPen constructor cerr << "XformPen::tap_cb: error: gesture is double tap" << endl; return 0; } // tap on cursor? BMESHray ray(tap->center()); _view->intersect(ray); Cursor3D* c = Cursor3D::upcast(ray.geom()); if (c) { err_adv(debug, "XformPen::tap_cb: hit axis"); c->handle_gesture(tap); return 0; } // tap on mesh? _mesh = 0; Bface* f = cur_face(); if (!f) { err_adv(debug, "XformPen::tap_cb: missed face"); return cancel_cb(tap, s); } BMESH* m = f->mesh(); if (!m) { err_adv(debug, "XformPen::tap_cb: hit face, no mesh"); return cancel_cb(tap, s); } GEOMptr g = bmesh_to_geom(m); if (!g) { err_adv(debug, "XformPen::tap_cb: hit mesh, no geom"); return cancel_cb(tap, s); } // skip floor: if (FLOOR::isa(g)) { err_adv(debug, "XformPen::tap_cb: hit floor, skipping..."); return cancel_cb(tap, s); } // tap on ordinary mesh (not floor): _mesh = m; assert(_mesh); BMESH::set_focus(_mesh, f->patch()); FLOOR::show(); FLOOR::realign(_mesh,0); // 0 = no undo command Cursor3D::attach(g); return 0; }
///////////////////////////////////// // clip_to_patch() ///////////////////////////////////// void HatchingGroupFixed::clip_to_patch( CNDCpt_list &pts, NDCpt_list &cpts, const vector<double>&prl, vector<double>&cprl ) { NDCpt_list::size_type k; bool started = false; Bface *f; Wpt foo; for (k=0; k<pts.size(); k++) { f = find_face_vis(pts[k], foo); if (f && f->patch() == _patch) { started = true; cpts.push_back(pts[k]); cprl.push_back(prl[k]); } else { if (started) { k=pts.size(); } } } }
///////////////////////////////////// // add() ///////////////////////////////////// bool HatchingGroupFixed::add( CNDCpt_list &pl, const vector<double>&prl, int curve_type ) { size_t 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.size() != prl.size()) { 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; vector<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; vector<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.size(); k++) { f = HatchingGroupBase::find_face_vis(NDCpt(ndcpts[k]),wloc); if ((f) && (f->patch() == _patch) && (f->front_facing())) { wlProjList.push_back(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.size()<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.size()* (double)wlProjList.length())/(double)wlClipList.length()); size_t num = max(guess,5); double step = 1.0/((double)(num-1)); for (k=0 ; k<num ; k++) wlScaledList.push_back(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 size_t num = max(wlClipList.size(), 5UL); double step = 1.0/((double)(num-1)); for (k=0 ; k<num ; k++) wlScaledList.push_back(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.size();k++) ndczlScaledList.push_back(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; } vector<HatchingFixedVertex> verts; Wpt_list pts; vector<Wvec> norms; err_mesg_cond(debug, ERR_LEV_SPAM, "HatchingGroupFixed::add() - Final sampling."); for (k=0; k<ndczlScaledList.size(); 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.push_back(HatchingFixedVertex(f->index(), bc)); f->bc2norm_blend(bc,norm); pts.push_back(wloc); norms.push_back(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.size()>1) { //XXX - Okay, using the gesture pressure, but no offsets. //Need to go back and add offset generation... BaseStrokeOffsetLISTptr ol = make_shared<BaseStrokeOffsetLIST>(); ol->set_replicate(0); ol->set_hangover(1); ol->set_pix_len(pix_len); ol->push_back(BaseStrokeOffset(0.0, 0.0, finalprl[0], BaseStrokeOffset::OFFSET_TYPE_BEGIN)); for (k=1; k<finalprl.size(); k++) ol->push_back(BaseStrokeOffset((double)k / (double)(finalprl.size()-1), 0.0, finalprl[k], BaseStrokeOffset::OFFSET_TYPE_MIDDLE)); ol->push_back(BaseStrokeOffset(1.0, 0.0, finalprl[finalprl.size()-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; }
bool TriStrip::build( Bface* start, // build a new strip starting here. Bface_list& stack // used to build nearby parallel strips ) { // a set flag means this face is already in a TriStrip assert(!start->flag()); // start fresh reset(); // repeat 1st vertex if needed if (!start->orient_strip()) start->orient_strip(start->v1()); // get the starting vert. i.e., the strip will // continue onto the next face across the edge // opposite this vertex. Bvert *a = start->orient_strip(), *b, *c; // squash and stretch start = backup_strip(start,a); if (!start) { // should never happen, but can happen // if there are inconsistently oriented faces err_msg("TriStrip::build: error: backup_strip() failed"); err_msg("*** check mesh for inconsistently oriented faces ***"); return 0; } // claim it claim_face(start); // record direction of strip on 1st face: start->orient_strip(a); // faces alternate CCW / CW if (_orientation) { c = start->next_vert_ccw(a); b = start->next_vert_ccw(c); } else { b = start->next_vert_ccw(a); c = start->next_vert_ccw(b); } add(a,start); add(b,start); add(c,start); Bface* opp; if ((opp = start->opposite_face(b)) && is_cleared(opp) && opp->patch() == start->patch()) { opp->orient_strip(_orientation ? a : c); stack.push_back(opp); } int i=_orientation; Bface* cur = start; while ((cur = cur->next_strip_face()) && !is_claimed(cur)) { claim_face(cur); i++; a = b; b = c; c = cur->other_vertex(a,b); cur->orient_strip(a); if ((opp = cur->opposite_face(b)) && is_cleared(opp) && opp->patch() == start->patch()) { opp->orient_strip(i % 2 ? a : c); stack.push_back(opp); } add(c,cur); } return 1; }