int CIRCLE_WIDGET::stroke_cb(CGESTUREptr& g, DrawState*&) { err_adv(debug_all, "CIRCLE_WIDGET::stroke_cb()"); // Activity occurred to extend the deadline for fading away: reset_timeout(); // sanity check assert(g); if( !g->is_line() ) return 1; _preview.update_length(); if (PIXEL_list(_preview).dist(g->start()) < PIXEL_DIST_THRESH || g->start().dist(_center) < PIXEL_DIST_THRESH ) { if ( _circle ) { Bcurve *border = Bcurve::lookup(_circle->bfaces().get_boundary().edges()); if ( border != 0 ) { Wplane plane = border->plane(); _radius = _center.dist(Wpt(plane, Wline(XYpt(g->end())))); } } else { Wplane P = get_draw_plane(g->end()); if (!P.is_valid()) return 1; _radius = _center.dist(Wpt(P, Wline(XYpt(g->end())))); } make_preview(); } return 1; }
//! Find a plane associated with the Bcurve; return a //! parallel plane that contains the given point p. //! To be used for translating the curve in the plane. inline Wplane find_xlate_plane(Bcurve* c, CWpt& p) { Wplane P = find_plane(c); if (P.is_valid()) return Wplane(p, P.normal()); return Wplane(); }
bool CIRCLE_WIDGET::create_literal(GESTUREptr gest) { PIXEL hit_start, hit_end; Bpoint* b1 = Bpoint::hit_point(gest->start(), 8, hit_start); Bpoint* b2 = Bpoint::hit_point(gest->end(), 8, hit_end); // Find a plane to project the stroke into, but only // accept planes that are sufficiently parallel to the // film plane. Wplane P = get_plane(b1, b2); if (!P.is_valid()) { b1 = b2 = 0; // Ignoring the endpoints, try for a plane from the FLOOR // or AxisWidget: P = get_draw_plane(gest->pts()); if (!P.is_valid()) { return false; } } // Project pixel trail to the plane, and if the gesture // is "closed", make the Wpt_list form a closed loop. //DrawPen::project_to_plane(gest, P, _literal_shape); _literal_shape.clear(); gest->pts().project_to_plane(P, _literal_shape); if (gest->is_closed()) { // If closed, remove the final few points to prevent jagginess for (int i = _literal_shape.num()-1;i>=0;i--) if (PIXEL(_literal_shape[0]).dist(PIXEL(_literal_shape[i])) < 15) _literal_shape.remove(i); else break; // add the first point as the last point _literal_shape += _literal_shape[0]; _literal_shape.update_length(); } return true; }
bool PAPER_DOLL::init(CBcurve_list& contour) { if (contour.empty()) { err_adv(debug, "PAPER_DOLL::init: empty contour"); return false; } LMESHptr skel_mesh = contour.mesh(); if (!skel_mesh) { err_adv(debug, "PAPER_DOLL::init: curves don't share a mesh"); return false; } if (!contour.is_each_straight()) { err_adv(debug, "PAPER_DOLL::init: curves not straight"); return false; } if (!contour.forms_closed_chain()) { err_adv(debug, "PAPER_DOLL::init: curves don't form a closed chain"); return false; } if (!contour.is_planar()) { err_adv(debug, "PAPER_DOLL::init: curves not planar"); return false; } Wpt_list pts = contour.get_chain().get_verts().pts(); if (!(pts.size() == 4 || pts.size() == 5)) { err_adv(debug, "PAPER_DOLL::init: can't do %d-gon", pts.size()); return false; } Wplane P; if (!pts.get_plane(P)) { err_adv(debug, "PAPER_DOLL::init: can't get plane from contour"); return false; } assert(P.is_valid()); Wpt o = pts.average(); Wvec n = P.normal(); // make plane normal point toward camera if (VIEW::eye_vec(o) * n > 0) n = -n; // reverse order of points if needed so they go CCW // around plane normal: err_adv(debug, "contour winding number: %f", pts.winding_number(o, n)); if (pts.winding_number(o, n) > 1) { std::reverse(pts.begin(), pts.end()); } // create the primitive MULTI_CMDptr cmd = make_shared<MULTI_CMD>(); Primitive* p = Primitive::init(skel_mesh, pts, P.normal(), cmd); if (!p) { err_adv(debug, "PAPER_DOLL::init: Primitive::init() failed"); return false; } // hide the curves // take over drawing the primitive (?) // or just augment // activate delete_all(contour); get_instance()->init(p); err_adv(debug, "PAPER_DOLL::init: curves okay"); return true; }
//! Returns true if the gesture is valid for beginning a circle_widget //! session. bool CIRCLE_WIDGET::init(CGESTUREptr& gest) { static bool debug = Config::get_var_bool("DEBUG_CIRCLE_WIDGET_INIT",false) || debug_all; err_adv(debug, "CIRCLE_WIDGET::init"); // Get the ellipse description: PIXEL center; // the center VEXEL axis; // the long axis (unit length) double r1, r2; // the long and short radii, respectively bool suggest_active; if (!gest->is_ellipse(center, axis, r1, r2)) { if (!gest->is_almost_ellipse(center, axis, r1, r2)) { return 0; } else { suggest_active = true; } } else { suggest_active = false; } Wplane plane = get_draw_plane(center); if (!plane.is_valid()) { // didn't work out this time return false; } /////////////////////////////////////////////////////// // // y1 // // x0 c ------> x1 // axis // y0 // // Project the extreme points of the ellipse to the // plane and check that after projection they are // reasonably equidistant from the center. // // I.e., the ellipse should reasonably match the // foreshortened circle as it would actually appear in // the given plane. /////////////////////////////////////////////////////// VEXEL perp = axis.perpend(); Wpt x0 = Wpt(plane, Wline(XYpt(center - axis*r1))); Wpt x1 = Wpt(plane, Wline(XYpt(center + axis*r1))); Wpt y0 = Wpt(plane, Wline(XYpt(center - perp*r2))); Wpt y1 = Wpt(plane, Wline(XYpt(center + perp*r2))); Wpt c = Wpt(plane, Wline(XYpt(center))); // The two diameters -- we'll check their ratio double dx = x0.dist(x1); double dy = y0.dist(y1); // XXX - Use environment variable for testing phase: // XXX - don't make static (see below): double MIN_RATIO = Config::get_var_dbl("EPC_RATIO", 0.85,true); // Be more lenient when the plane is more foreshortened: // // XXX - not sure what the right policy is, but for a // completely edge-on plane there's certainly no sense in // doing a real projection... the following drops the // min_ratio lower for more foreshortened planes: double cos_theta = VIEW::eye_vec(c) * plane.normal(); double scale = sqrt(fabs(cos_theta)); // XXX - just trying this out MIN_RATIO *= scale; // XXX - this is why it can't be static double ratio = min(dx,dy)/max(dx,dy); err_adv(debug, "CIRCLE_WIDGET::init: projected ratio: %f, min: %f", ratio, MIN_RATIO); if (ratio < MIN_RATIO) return false; CIRCLE_WIDGETptr me = get_instance(); static const int DISK_RES = Config::get_var_int("DISK_RES", 4,true); me->_plane = plane; me->_radius = dx/2; me->_disk_res = DISK_RES; me->_center = c; me->_init_stamp = VIEW::stamp(); if( me->_suggest_active = suggest_active ) { me->create_literal(gest); } //PIXEL gest_center = gest->center(); me->make_preview(); return go(); }