Geom::PathVector LPEGears::doEffect_path (Geom::PathVector const &path_in) { Geom::PathVector path_out; Geom::Path gearpath = path_in[0]; Geom::Path::iterator it(gearpath.begin()); if ( it == gearpath.end() ) return path_out; Gear * gear = new Gear(teeth, 200.0, phi * M_PI / 180); Geom::Point gear_centre = (*it).finalPoint(); gear->centre(gear_centre); gear->angle(atan2((*it).initialPoint() - gear_centre)); ++it; if ( it == gearpath.end() ) return path_out; gear->pitch_radius(Geom::distance(gear_centre, (*it).finalPoint())); path_out.push_back( gear->path()); for (++it; it != gearpath.end() ; ++it) { // iterate through Geom::Curve in path_in Gear* gearnew = new Gear(gear->spawn( (*it).finalPoint() )); path_out.push_back( gearnew->path() ); delete gear; gear = gearnew; } delete gear; return path_out; }
static void sp_svg_write_path(Inkscape::SVG::PathString & str, Geom::Path const & p) { str.moveTo( p.initialPoint()[0], p.initialPoint()[1] ); for(Geom::Path::const_iterator cit = p.begin(); cit != p.end_open(); ++cit) { sp_svg_write_curve(str, &(*cit)); } if (p.closed()) { str.closePath(); } }
/* rectangular cutter. ctr "center" of rectangle (might not actually be in the center with respect to leading/trailing edges pos vector from center to leading edge neg vector from center to trailing edge width vector to side edge */ Geom::PathVector PrintMetafile::rect_cutter(Geom::Point ctr, Geom::Point pos, Geom::Point neg, Geom::Point width) { std::vector<Geom::Path> outres; Geom::Path cutter; cutter.start(ctr + pos - width); cutter.appendNew<Geom::LineSegment>(ctr + pos + width); cutter.appendNew<Geom::LineSegment>(ctr + neg + width); cutter.appendNew<Geom::LineSegment>(ctr + neg - width); cutter.close(); outres.push_back(cutter); return outres; }
void LPESimplify::drawHandleLine(Geom::Point p,Geom::Point p2) { Geom::Path path; path.start( p ); double diameter = radius_helper_nodes; if(helper_size > 0 && Geom::distance(p,p2) > (diameter * 0.35)) { Geom::Ray ray2(p, p2); p2 = p2 - Geom::Point::polar(ray2.angle(),(diameter * 0.35)); } path.appendNew<Geom::LineSegment>( p2 ); hp.push_back(path); }
static void _circle(Geom::Point center, double radius, std::vector<Geom::Path> &path_out) { using namespace Geom; Geom::Path pb; D2<SBasis> B; Linear bo = Linear(0, 2 * M_PI); B[0] = cos(bo,4); B[1] = sin(bo,4); B = B * radius + center; pb.append(SBasisCurve(B)); path_out.push_back(pb); }
/** Feeds path-creating calls to the cairo context translating them from the Path, with the given transform and shift */ static void feed_path_to_cairo (cairo_t *ct, Geom::Path const &path, Geom::Affine trans, Geom::OptRect area, bool optimize_stroke, double stroke_width) { if (!area) return; if (path.empty()) return; // Transform all coordinates to coords within "area" Geom::Point shift = area->min(); Geom::Rect view = *area; view.expandBy (stroke_width); view = view * (Geom::Affine)Geom::Translate(-shift); // Pass transformation to feed_curve, so that we don't need to create a whole new path. Geom::Affine transshift(trans * Geom::Translate(-shift)); Geom::Point initial = path.initialPoint() * transshift; cairo_move_to(ct, initial[0], initial[1] ); for(Geom::Path::const_iterator cit = path.begin(); cit != path.end_open(); ++cit) { feed_curve_to_cairo(ct, *cit, transshift, view, optimize_stroke); } if (path.closed()) { if (!optimize_stroke) { cairo_close_path(ct); } else { cairo_line_to(ct, initial[0], initial[1]); /* We cannot use cairo_close_path(ct) here because some parts of the path may have been clipped and not drawn (maybe the before last segment was outside view area), which would result in closing the "subpath" after the last interruption, not the entire path. However, according to cairo documentation: The behavior of cairo_close_path() is distinct from simply calling cairo_line_to() with the equivalent coordinate in the case of stroking. When a closed sub-path is stroked, there are no caps on the ends of the sub-path. Instead, there is a line join connecting the final and initial segments of the sub-path. The correct fix will be possible when cairo introduces methods for moving without ending/starting subpaths, which we will use for skipping invisible segments; then we will be able to use cairo_close_path here. This issue also affects ps/eps/pdf export, see bug 168129 */ } } }
Geom::Path Layout::baseline() const { iterator pos = this->begin(); Geom::Point left_pt = this->characterAnchorPoint(pos); pos.thisEndOfLine(); Geom::Point right_pt = this->characterAnchorPoint(pos); if (this->_blockProgression() == LEFT_TO_RIGHT || this->_blockProgression() == RIGHT_TO_LEFT) { left_pt = Geom::Point(left_pt[Geom::Y], left_pt[Geom::X]); right_pt = Geom::Point(right_pt[Geom::Y], right_pt[Geom::X]); } Geom::Path baseline; baseline.start(left_pt); baseline.appendNew<Geom::LineSegment>(right_pt); return baseline; }
/** Feeds path-creating calls to the cairo context translating them from the Path */ static void feed_path_to_cairo (cairo_t *ct, Geom::Path const &path) { if (path.empty()) return; cairo_move_to(ct, path.initialPoint()[0], path.initialPoint()[1] ); for(Geom::Path::const_iterator cit = path.begin(); cit != path.end_open(); ++cit) { feed_curve_to_cairo(ct, *cit, Geom::identity(), Geom::Rect(), false); // optimize_stroke is false, so the view rect is not used } if (path.closed()) { cairo_close_path(ct); } }
void offset_curve_old(Geom::Path& res, Geom::Curve const* current, double width) { double const tolerance = 0.0025; size_t levels = 8; if (current->isDegenerate()) return; // don't do anything // TODO: we can handle SVGEllipticalArc here as well, do that! if (Geom::BezierCurve const *b = dynamic_cast<Geom::BezierCurve const*>(current)) { size_t order = b->order(); switch (order) { case 1: res.append(offset_line_old(static_cast<Geom::LineSegment const&>(*current), width)); break; case 2: { Geom::QuadraticBezier const& q = static_cast<Geom::QuadraticBezier const&>(*current); offset_quadratic_old(res, q, width, tolerance, levels); break; } case 3: { Geom::CubicBezier const& cb = static_cast<Geom::CubicBezier const&>(*current); offset_cubic_old(res, cb, width, tolerance, levels); break; } default: { Geom::Path sbasis_path = Geom::cubicbezierpath_from_sbasis(current->toSBasis(), tolerance); for (size_t i = 0; i < sbasis_path.size(); ++i) offset_curve_old(res, &sbasis_path[i], width); break; } } } else { Geom::Path sbasis_path = Geom::cubicbezierpath_from_sbasis(current->toSBasis(), 0.1); for (size_t i = 0; i < sbasis_path.size(); ++i) offset_curve_old(res, &sbasis_path[i], width); } }
void offset_cubic_old(Geom::Path& p, Geom::CubicBezier const& bez, double width, double tol, size_t levels) { using Geom::X; using Geom::Y; Geom::Point start_pos = bez.initialPoint(); Geom::Point end_pos = bez.finalPoint(); Geom::Point start_normal = Geom::rot90(bez.unitTangentAt(0)); Geom::Point end_normal = -Geom::rot90(Geom::unitTangentAt(Geom::reverse(bez.toSBasis()), 0.)); // offset the start and end control points out by the width Geom::Point start_new = start_pos + start_normal*width; Geom::Point end_new = end_pos + end_normal*width; // -------- double start_rad, end_rad; double start_len, end_len; // tangent lengths get_cubic_data_old(bez, 0, start_len, start_rad); get_cubic_data_old(bez, 1, end_len, end_rad); double start_off = 1, end_off = 1; // correction of the lengths of the tangent to the offset if (!Geom::are_near(start_rad, 0)) start_off += width / start_rad; if (!Geom::are_near(end_rad, 0)) end_off += width / end_rad; start_off *= start_len; end_off *= end_len; // -------- Geom::Point mid1_new = start_normal.ccw()*start_off; mid1_new = Geom::Point(start_new[X] + mid1_new[X]/3., start_new[Y] + mid1_new[Y]/3.); Geom::Point mid2_new = end_normal.ccw()*end_off; mid2_new = Geom::Point(end_new[X] - mid2_new[X]/3., end_new[Y] - mid2_new[Y]/3.); // create the estimate curve Geom::CubicBezier c = Geom::CubicBezier(start_new, mid1_new, mid2_new, end_new); // reached maximum recursive depth // don't bother with any more correction if (levels == 0) { p.append(c); return; } // check the tolerance for our estimate to be a parallel curve Geom::Point chk = c.pointAt(.5); Geom::Point req = bez.pointAt(.5) + Geom::rot90(bez.unitTangentAt(.5))*width; // required accuracy Geom::Point const diff = req - chk; double const err = Geom::dot(diff, diff); if (err < tol) { if (Geom::are_near(start_new, p.finalPoint())) { p.setFinal(start_new); // if it isn't near, we throw } // we're good, curve is accurate enough try { p.append(c);} catch (...) { } return; } else { // split the curve in two std::pair<Geom::CubicBezier, Geom::CubicBezier> s = bez.subdivide(.5); offset_cubic_old(p, s.first, width, tol, levels - 1); offset_cubic_old(p, s.second, width, tol, levels - 1); } }
Geom::Path half_outline_old(Geom::Path const& input, double width, double miter, Inkscape::LineJoinType join = Inkscape::JOIN_BEVEL) { Geom::Path res; if (input.size() == 0) return res; Geom::Point tang1 = input[0].unitTangentAt(0); Geom::Point start = input.initialPoint() + tang1 * width; Geom::Path temp; Geom::Point tang[2]; res.setStitching(true); temp.setStitching(true); res.start(start); // Do two curves at a time for efficiency, since the join function needs to know the outgoing curve as well const size_t k = (input.back_closed().isDegenerate() && input.closed()) ?input.size_default()-1:input.size_default(); for (size_t u = 0; u < k; u += 2) { temp.clear(); offset_curve_old(temp, &input[u], width); // on the first run through, there isn't a join if (u == 0) { res.append(temp); } else { tangents_old(tang, input[u-1], input[u]); outline_join(res, temp, tang[0], tang[1], width, miter, join); } // odd number of paths if (u < k - 1) { temp.clear(); offset_curve_old(temp, &input[u+1], width); tangents_old(tang, input[u], input[u+1]); outline_join(res, temp, tang[0], tang[1], width, miter, join); } } if (input.closed()) { Geom::Curve const &c1 = res.back(); Geom::Curve const &c2 = res.front(); temp.clear(); temp.append(c1); Geom::Path temp2; temp2.append(c2); tangents_old(tang, input.back(), input.front()); outline_join(temp, temp2, tang[0], tang[1], width, miter, join); res.erase(res.begin()); res.erase_last(); // res.append(temp); res.close(); } return res; }
virtual void draw(cairo_t *cr, std::ostringstream *notify, int width, int height, bool save, std::ostringstream *timer_stream) { D2<SBasis2d> sb2; for(unsigned dim = 0; dim < 2; dim++) { sb2[dim].us = 2; sb2[dim].vs = 2; const int depth = sb2[dim].us*sb2[dim].vs; sb2[dim].resize(depth, Linear2d(0)); } Geom::Point dir(1,-2); if(hand.pts.empty()) { for(unsigned vi = 0; vi < sb2[0].vs; vi++) for(unsigned ui = 0; ui < sb2[0].us; ui++) for(unsigned iv = 0; iv < 2; iv++) for(unsigned iu = 0; iu < 2; iu++) hand.pts.push_back(Geom::Point((2*(iu+ui)/(2.*ui+1)+1)*width/4., (2*(iv+vi)/(2.*vi+1)+1)*width/4.)); } for(int dim = 0; dim < 2; dim++) { Geom::Point dir(0,0); dir[dim] = 1; for(unsigned vi = 0; vi < sb2[dim].vs; vi++) for(unsigned ui = 0; ui < sb2[dim].us; ui++) for(unsigned iv = 0; iv < 2; iv++) for(unsigned iu = 0; iu < 2; iu++) { unsigned corner = iu + 2*iv; unsigned i = ui + vi*sb2[dim].us; Geom::Point base((2*(iu+ui)/(2.*ui+1)+1)*width/4., (2*(iv+vi)/(2.*vi+1)+1)*width/4.); if(vi == 0 && ui == 0) { base = Geom::Point(width/4., width/4.); } double dl = dot((hand.pts[corner+4*i] - base), dir)/dot(dir,dir); sb2[dim][i][corner] = dl/(width/2)*pow(4.0,(double)ui+vi); } } cairo_d2_sb2d(cr, sb2, dir*0.1, width); cairo_set_source_rgba (cr, 0., 0., 0, 0.5); cairo_stroke(cr); for(unsigned vi = 0; vi < v_subs; vi++) { double tv = vi * inv_v_subs; for(unsigned ui = 0; ui < u_subs; ui++) { double tu = ui * inv_u_subs; Geom::Path pb; D2<SBasis> B; D2<SBasis> tB; B[0] = Linear(tu-fudge, tu+fudge + inv_u_subs ); B[1] = Linear(tv-fudge, tv-fudge); tB = compose_each(sb2, B); tB = tB*(width/2) + Geom::Point(width/4, width/4); pb.append(tB); B[0] = Linear(tu+fudge + inv_u_subs , tu+fudge + inv_u_subs); B[1] = Linear(tv-fudge, tv+fudge + inv_v_subs); tB = compose_each(sb2, B); tB = tB*(width/2) + Geom::Point(width/4, width/4); pb.append(tB); B[0] = Linear(tu+fudge + inv_u_subs, tu-fudge); B[1] = Linear(tv+fudge + inv_v_subs, tv+fudge + inv_v_subs); tB = compose_each(sb2, B); tB = tB*(width/2) + Geom::Point(width/4, width/4); pb.append(tB); B[0] = Linear(tu-fudge, tu-fudge); B[1] = Linear(tv+fudge + inv_v_subs, tv-fudge); tB = compose_each(sb2, B); tB = tB*(width/2) + Geom::Point(width/4, width/4); pb.append(tB); cairo_path(cr, pb); //std::cout << pb.peek().end() - pb.peek().begin() << std::endl; cairo_set_source_rgba (cr, tu, tv, 0, 1); cairo_fill(cr); } } //*notify << "bo = " << sb2.index(0,0); Toy::draw(cr, notify, width, height, save,timer_stream); }
Geom::Path Gear::path() { Geom::Path pb; // angle covered by a full tooth and fillet double tooth_rotation = 2.0 * tooth_thickness_angle(); // angle covered by an involute double involute_advance = involute_intersect_angle(outer_radius()) - involute_intersect_angle(root_radius()); // angle covered by the tooth tip double tip_advance = tooth_thickness_angle() - (2 * (involute_intersect_angle(outer_radius()) - involute_intersect_angle(pitch_radius()))); // angle covered by the toothe root double root_advance = (tooth_rotation - tip_advance) - (2.0 * involute_advance); // begin drawing the involute at t if the root circle is larger than the base circle double involute_t = involute_swath_angle(root_radius())/involute_swath_angle(outer_radius()); //rewind angle to start drawing from the leading edge of the tooth double first_tooth_angle = _angle - ((0.5 * tip_advance) + involute_advance); Geom::Point prev; for (int i=0; i < _number_of_teeth; i++) { double cursor = first_tooth_angle + (i * tooth_rotation); D2<SBasis> leading_I = compose(_involute(cursor, cursor + involute_swath_angle(outer_radius())), Linear(involute_t,1)); if(i != 0) makeContinuous(leading_I, prev); pb.append(SBasisCurve(leading_I)); cursor += involute_advance; prev = leading_I.at1(); D2<SBasis> tip = _arc(cursor, cursor+tip_advance, outer_radius()); makeContinuous(tip, prev); pb.append(SBasisCurve(tip)); cursor += tip_advance; prev = tip.at1(); cursor += involute_advance; D2<SBasis> trailing_I = compose(_involute(cursor, cursor - involute_swath_angle(outer_radius())), Linear(1,involute_t)); makeContinuous(trailing_I, prev); pb.append(SBasisCurve(trailing_I)); prev = trailing_I.at1(); if (base_radius() > root_radius()) { Geom::Point leading_start = trailing_I.at1(); Geom::Point leading_end = (root_radius() * unit_vector(leading_start - _centre)) + _centre; prev = leading_end; pb.appendNew<LineSegment>(leading_end); } D2<SBasis> root = _arc(cursor, cursor+root_advance, root_radius()); makeContinuous(root, prev); pb.append(SBasisCurve(root)); //cursor += root_advance; prev = root.at1(); if (base_radius() > root_radius()) { Geom::Point trailing_start = root.at1(); Geom::Point trailing_end = (base_radius() * unit_vector(trailing_start - _centre)) + _centre; pb.appendNew<LineSegment>(trailing_end); prev = trailing_end; } } return pb; }
void Inkscape::ObjectSnapper::_snapPathsConstrained(IntermSnapResults &isr, SnapCandidatePoint const &p, SnapConstraint const &c, Geom::Point const &p_proj_on_constraint) const { _collectPaths(p_proj_on_constraint, p.getSourceType(), p.getSourceNum() <= 0); // Now we can finally do the real snapping, using the paths collected above SPDesktop const *dt = _snapmanager->getDesktop(); g_assert(dt != NULL); Geom::Point direction_vector = c.getDirection(); if (!is_zero(direction_vector)) { direction_vector = Geom::unit_vector(direction_vector); } // The intersection point of the constraint line with any path, must lie within two points on the // SnapConstraint: p_min_on_cl and p_max_on_cl. The distance between those points is twice the snapping tolerance Geom::Point const p_min_on_cl = dt->dt2doc(p_proj_on_constraint - getSnapperTolerance() * direction_vector); Geom::Point const p_max_on_cl = dt->dt2doc(p_proj_on_constraint + getSnapperTolerance() * direction_vector); Geom::Coord tolerance = getSnapperTolerance(); // PS: Because the paths we're about to snap to are all expressed relative to document coordinate system, we will have // to convert the snapper coordinates from the desktop coordinates to document coordinates std::vector<Geom::Path> constraint_path; if (c.isCircular()) { Geom::Circle constraint_circle(dt->dt2doc(c.getPoint()), c.getRadius()); constraint_circle.getPath(constraint_path); } else { Geom::Path constraint_line; constraint_line.start(p_min_on_cl); constraint_line.appendNew<Geom::LineSegment>(p_max_on_cl); constraint_path.push_back(constraint_line); } // Length of constraint_path will always be one bool strict_snapping = _snapmanager->snapprefs.getStrictSnapping(); // Find all intersections of the constrained path with the snap target candidates std::vector<Geom::Point> intersections; for (std::vector<SnapCandidatePath >::const_iterator k = _paths_to_snap_to->begin(); k != _paths_to_snap_to->end(); ++k) { if (k->path_vector && _allowSourceToSnapToTarget(p.getSourceType(), (*k).target_type, strict_snapping)) { // Do the intersection math Geom::CrossingSet cs = Geom::crossings(constraint_path, *(k->path_vector)); // Store the results as intersection points unsigned int index = 0; for (Geom::CrossingSet::const_iterator i = cs.begin(); i != cs.end(); ++i) { if (index >= constraint_path.size()) { break; } // Reconstruct and store the points of intersection for (Geom::Crossings::const_iterator m = (*i).begin(); m != (*i).end(); ++m) { intersections.push_back(constraint_path[index].pointAt((*m).ta)); } index++; } //Geom::crossings will not consider the closing segment apparently, so we'll handle that separately here //TODO: This should have been fixed in rev. #9859, which makes this workaround obsolete for(Geom::PathVector::iterator it_pv = k->path_vector->begin(); it_pv != k->path_vector->end(); ++it_pv) { if (it_pv->closed()) { // Get the closing linesegment and convert it to a path Geom::Path cls; cls.close(false); cls.append(it_pv->back_closed()); // Intersect that closing path with the constrained path Geom::Crossings cs = Geom::crossings(constraint_path.front(), cls); // Reconstruct and store the points of intersection index = 0; // assuming the constraint path vector has only one path for (Geom::Crossings::const_iterator m = cs.begin(); m != cs.end(); ++m) { intersections.push_back(constraint_path[index].pointAt((*m).ta)); } } } // Convert the collected points of intersection to snapped points for (std::vector<Geom::Point>::iterator p_inters = intersections.begin(); p_inters != intersections.end(); ++p_inters) { // Convert to desktop coordinates (*p_inters) = dt->doc2dt(*p_inters); // Construct a snapped point Geom::Coord dist = Geom::L2(p.getPoint() - *p_inters); SnappedPoint s = SnappedPoint(*p_inters, p.getSourceType(), p.getSourceNum(), k->target_type, dist, getSnapperTolerance(), getSnapperAlwaysSnap(), true, k->target_bbox);; // Store the snapped point if (dist <= tolerance) { // If the intersection is within snapping range, then we might snap to it isr.points.push_back(s); } } } } }
int main(int argc, char **argv) { char const *const filename = (argc >= 2 ? argv[1] : "toy.svgd"); FILE* f = fopen(filename, "r"); if (!f) { perror(filename); return 1; } display_path = read_svgd(f); Geom::Rect r = display_path.bbox(); display_path = display_path*Geom::translate(-r.min()); Geom::scale sc(r.max() - r.min()); display_path = display_path*(sc.inverse()*Geom::scale(500,500)); gtk_init (&argc, &argv); gdk_rgb_init(); GtkWidget* window = gtk_window_new(GTK_WINDOW_TOPLEVEL); gtk_window_set_title(GTK_WINDOW(window), "text toy"); gtk_window_set_policy(GTK_WINDOW(window), TRUE, TRUE, TRUE); gtk_signal_connect(GTK_OBJECT(window), "delete_event", GTK_SIGNAL_FUNC(delete_event_cb), NULL); gtk_widget_push_visual(gdk_rgb_get_visual()); gtk_widget_push_colormap(gdk_rgb_get_cmap()); canvas = gtk_drawing_area_new(); gtk_signal_connect(GTK_OBJECT (canvas), "expose_event", GTK_SIGNAL_FUNC(expose_event), 0); gtk_widget_add_events(canvas, (GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_KEY_PRESS_MASK | GDK_POINTER_MOTION_MASK)); gtk_signal_connect(GTK_OBJECT (canvas), "button_press_event", GTK_SIGNAL_FUNC(mouse_event), 0); gtk_signal_connect(GTK_OBJECT (canvas), "button_release_event", GTK_SIGNAL_FUNC(mouse_release_event), 0); gtk_signal_connect(GTK_OBJECT (canvas), "motion_notify_event", GTK_SIGNAL_FUNC(mouse_motion_event), 0); gtk_signal_connect(GTK_OBJECT(canvas), "key_press_event", GTK_SIGNAL_FUNC(key_release_event), 0); gtk_widget_pop_colormap(); gtk_widget_pop_visual(); GtkWidget *vb = gtk_vbox_new(0, 0); gtk_container_add(GTK_CONTAINER(window), vb); gtk_box_pack_start(GTK_BOX(vb), canvas, TRUE, TRUE, 0); gtk_window_set_default_size(GTK_WINDOW(window), 600, 600); gtk_widget_show_all(window); dash_gc = gdk_gc_new(canvas->window); gint8 dash_list[] = {4, 4}; gdk_gc_set_dashes(dash_gc, 0, dash_list, 2); GdkColor colour; colour.red = 0xffff; colour.green = 0xffff; colour.blue = 0xffff; plain_gc = gdk_gc_new(canvas->window); //gdk_gc_set_rgb_fg_color(dash_gc, &colour); gdk_rgb_find_color(gtk_widget_get_colormap(canvas), &colour); gdk_window_set_background(canvas->window, &colour); gdk_gc_set_line_attributes(dash_gc, 1, GDK_LINE_ON_OFF_DASH, GDK_CAP_BUTT,GDK_JOIN_MITER); /* Make sure the canvas can receive key press events. */ GTK_WIDGET_SET_FLAGS(canvas, GTK_CAN_FOCUS); assert(GTK_WIDGET_CAN_FOCUS(canvas)); gtk_widget_grab_focus(canvas); assert(gtk_widget_is_focus(canvas)); gtk_main(); return 0; }
static gboolean expose_event(GtkWidget *widget, GdkEventExpose *event, gpointer data) { int width = 256; int height = 256; std::ostringstream notify; gdk_drawable_get_size(widget->window, &width, &height); for(int i = 0; i < display_path.handles.size(); i++) { draw_handle(widget->window, display_path.handles[i]); } draw_path(widget->window, display_path); //draw_elip(widget->window, handles); Geom::Point dir(1,1); /* vector<Geom::Path::Location> pts = find_vector_extreme_points(display_path, dir); for(int i = 0; i < pts.size(); i++) { draw_circ(widget->window, display_path.point_at(pts[i])); }*/ double dist = INFINITY; Geom::Path::Location pl = display_path.nearest_location(old_mouse_point, dist); { Geom::Point pos, tgt, acc; display_path.point_tangent_acc_at (pl, pos, tgt, acc); draw_circ(widget->window, pos); double kurvature = dot(acc, rot90(tgt))/pow(Geom::L2(tgt),3); if(fabs(kurvature) > 0.001) draw_ray(widget->window, pos, (1./kurvature)*Geom::unit_vector(rot90(tgt))); else // just normal draw_ray(widget->window, pos, rot90(tgt)); } Geom::Path pth = display_path.subpath(display_path.begin(), display_path.end()); pth = pth*Geom::translate(Geom::Point(30, 30)); draw_path(widget->window, pth); Bezier a, b; const int curve_seg = 3; Geom::Path::Elem ai(*display_path.indexed_elem(curve_seg)), bi(*pth.indexed_elem(curve_seg)); for(int i = 0; i < 4; i++) { a.p[i] = ai[i]; b.p[i] = bi[i]; } std::vector<std::pair <double, double> > ts = Geom::FindIntersections(a, b); for(int i = 0; i < ts.size(); i++) { Geom::Path::Location pl(display_path.indexed_elem(curve_seg), ts[i].first); draw_handle(widget->window, display_path.point_at(pl)); Geom::Path::Location p2(pth.indexed_elem(curve_seg), ts[i].second); draw_circ(widget->window, display_path.point_at(p2)); } /* vector<Geom::Path::Location> pts = find_inflection_points(display_path); for(int i = 0; i < pts.size(); i++) { Geom::Point pos, tgt, acc; display_path.point_tangent_acc_at (pts[i], pos, tgt, acc); //tgt *= 0.1; //acc *= 0.1; draw_handle(widget->window, display_path.point_at(pts[i])); draw_circ(widget->window, pos); //draw_ray(widget->window, pos+tgt, acc); } */ notify << "path length: " << arc_length_integrating(display_path, 1e3) << "\n"; { notify << std::ends; PangoLayout *layout = gtk_widget_create_pango_layout(widget, notify.str().c_str()); PangoRectangle logical_extent; pango_layout_get_pixel_extents(layout, NULL, &logical_extent); gdk_draw_layout(widget->window, widget->style->fg_gc[GTK_STATE_NORMAL], 0, height-logical_extent.height, layout); } return TRUE; }
std::vector<Geom::Path> LPEVonKoch::doEffect_path (std::vector<Geom::Path> const & path_in) { using namespace Geom; std::vector<Geom::Path> generating_path = generator.get_pathvector(); if (generating_path.size()==0) { return path_in; } //Collect transform matrices. Matrix m0; Geom::Path refpath = ref_path.get_pathvector().front(); Point A = refpath.pointAt(0); Point B = refpath.pointAt(refpath.size()); Point u = B-A; m0 = Matrix(u[X], u[Y],-u[Y], u[X], A[X], A[Y]); //FIXME: a path is used as ref instead of 2 points to work around path/point param incompatibility bug. //Point u = refB-refA; //m0 = Matrix(u[X], u[Y],-u[Y], u[X], refA[X], refA[Y]); m0 = m0.inverse(); std::vector<Matrix> transforms; for (unsigned i=0; i<generating_path.size(); i++){ Matrix m; if(generating_path[i].size()==1){ Point p = generating_path[i].pointAt(0); Point u = generating_path[i].pointAt(1)-p; m = Matrix(u[X], u[Y],-u[Y], u[X], p[X], p[Y]); m = m0*m; transforms.push_back(m); }else if(generating_path[i].size()>=2){ Point p = generating_path[i].pointAt(1); Point u = generating_path[i].pointAt(2)-p; Point v = p-generating_path[i].pointAt(0); if (similar_only.get_value()){ int sign = (u[X]*v[Y]-u[Y]*v[X]>=0?1:-1); v[X] = -u[Y]*sign; v[Y] = u[X]*sign; } m = Matrix(u[X], u[Y],v[X], v[Y], p[X], p[Y]); m = m0*m; transforms.push_back(m); } } if (transforms.size()==0){ return path_in; } //Do nothing if the output is too complex... int path_in_complexity = 0; for (unsigned k = 0; k < path_in.size(); k++){ path_in_complexity+=path_in[k].size(); } double complexity = pow(transforms.size(),nbgenerations)*path_in_complexity; if (drawall.get_value()){ int k = transforms.size(); if(k>1){ complexity = (pow(k,nbgenerations+1)-1)/(k-1)*path_in_complexity; }else{ complexity = nbgenerations*k*path_in_complexity; } }else{ complexity = pow(transforms.size(),nbgenerations)*path_in_complexity; } if (complexity > double(maxComplexity)){ g_warning("VonKoch lpe's output too complex. Effect bypassed."); return path_in; } //Generate path: std::vector<Geom::Path> pathi = path_in; std::vector<Geom::Path> path_out = path_in; for (unsigned i = 0; i<nbgenerations; i++){ if (drawall.get_value()){ path_out = path_in; complexity = path_in_complexity; }else{ path_out = std::vector<Geom::Path>(); complexity = 0; } for (unsigned j = 0; j<transforms.size(); j++){ for (unsigned k = 0; k<pathi.size() && complexity < maxComplexity; k++){ path_out.push_back(pathi[k]*transforms[j]); complexity+=pathi[k].size(); } } pathi = path_out; } return path_out; }