static int sp_spiral_snappoints (SPItem *item, NRPointF *p, int size) { #if 0 /* fixme: (Lauris) */ SPSpiral *spiral; ArtPoint * p, p1, p2, p3; gdouble affine[6]; spiral = SP_SPIRAL(item); sp_spiral_get_xy (spiral, 0.0, &p1); sp_spiral_get_xy (spiral, spiral->t0, &p2); sp_spiral_get_xy (spiral, 1.0, &p3); sp_item_i2d_affine (item, affine); p = g_new (ArtPoint,1); art_affine_point (p, &p1, affine); points = g_slist_append (points, p); p = g_new (ArtPoint,1); art_affine_point (p, &p2, affine); points = g_slist_append (points, p); p = g_new (ArtPoint,1); art_affine_point (p, &p3, affine); points = g_slist_append (points, p); #else if (((SPItemClass *) parent_class)->snappoints) return ((SPItemClass *) parent_class)->snappoints (item, p, size); #endif return 0; }
Geom::Point SpiralKnotHolderEntityOuter::knot_get() const { SPSpiral const *spiral = SP_SPIRAL(item); return spiral->getXY(1.0); }
static SPRepr * sp_spiral_write (SPObject *object, SPRepr *repr, guint flags) { SPSpiral *spiral; char *d; spiral = SP_SPIRAL (object); if ((flags & SP_OBJECT_WRITE_BUILD) && !repr) { repr = sp_repr_new ("path"); } if (flags & SP_OBJECT_WRITE_EXT) { /* Fixme: we may replace these attributes by * sodipodi:spiral="cx cy exp revo rad arg t0" */ sp_repr_set_attr (repr, "sodipodi:type", "spiral"); sp_repr_set_double_attribute (repr, "sodipodi:cx", spiral->cx); sp_repr_set_double_attribute (repr, "sodipodi:cy", spiral->cy); sp_repr_set_double_attribute (repr, "sodipodi:expansion", spiral->exp); sp_repr_set_double_attribute (repr, "sodipodi:revolution", spiral->revo); sp_repr_set_double_attribute (repr, "sodipodi:radius", spiral->rad); sp_repr_set_double_attribute (repr, "sodipodi:argument", spiral->arg); sp_repr_set_double_attribute (repr, "sodipodi:t0", spiral->t0); } d = sp_svg_write_path (((SPShape *) spiral)->curve->bpath); sp_repr_set_attr (repr, "d", d); g_free (d); if (((SPObjectClass *) (parent_class))->write) ((SPObjectClass *) (parent_class))->write (object, repr, flags | SP_SHAPE_WRITE_PATH); return repr; }
void SpiralKnotHolderEntityInner::knot_click(guint state) { SPSpiral *spiral = SP_SPIRAL(item); if (state & GDK_MOD1_MASK) { spiral->exp = 1; (static_cast<SPObject *>(spiral))->updateRepr(); } else if (state & GDK_SHIFT_MASK) { spiral->t0 = 0; (static_cast<SPObject *>(spiral))->updateRepr(); } }
/* * set attributes via inner (t=t0) knot point: * [default] increase/decrease inner point * [shift] increase/decrease inner and outer arg synchronizely * [control] constrain inner arg to round per PI/4 */ void SpiralKnotHolderEntityInner::knot_set(Geom::Point const &p, Geom::Point const &origin, guint state) { Inkscape::Preferences *prefs = Inkscape::Preferences::get(); int snaps = prefs->getInt("/options/rotationsnapsperpi/value", 12); SPSpiral *spiral = SP_SPIRAL(item); gdouble dx = p[Geom::X] - spiral->cx; gdouble dy = p[Geom::Y] - spiral->cy; gdouble moved_y = p[Geom::Y] - origin[Geom::Y]; if (state & GDK_MOD1_MASK) { // adjust divergence by vertical drag, relative to rad if (spiral->rad > 0) { double exp_delta = 0.1*moved_y/(spiral->rad); // arbitrary multiplier to slow it down spiral->exp += exp_delta; if (spiral->exp < 1e-3) spiral->exp = 1e-3; } } else { // roll/unroll from inside gdouble arg_t0; spiral->getPolar(spiral->t0, NULL, &arg_t0); gdouble arg_tmp = atan2(dy, dx) - arg_t0; gdouble arg_t0_new = arg_tmp - floor((arg_tmp+M_PI)/(2.0*M_PI))*2.0*M_PI + arg_t0; spiral->t0 = (arg_t0_new - spiral->arg) / (2.0*M_PI*spiral->revo); /* round inner arg per PI/snaps, if CTRL is pressed */ if ( ( state & GDK_CONTROL_MASK ) && ( fabs(spiral->revo) > SP_EPSILON_2 ) && ( snaps != 0 ) ) { gdouble arg = 2.0*M_PI*spiral->revo*spiral->t0 + spiral->arg; spiral->t0 = (sp_round(arg, M_PI/snaps) - spiral->arg)/(2.0*M_PI*spiral->revo); } spiral->t0 = CLAMP(spiral->t0, 0.0, 0.999); } (static_cast<SPObject *>(spiral))->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); }
static void sp_spiral_finish(SPSpiralContext *sc) { sc->_message_context->clear(); if (sc->item != NULL) { SPDesktop *desktop = SP_EVENT_CONTEXT(sc)->desktop; SPSpiral *spiral = SP_SPIRAL(sc->item); sp_shape_set_shape(SP_SHAPE(spiral)); SP_OBJECT(spiral)->updateRepr(SP_OBJECT_WRITE_EXT); sp_canvas_end_forced_full_redraws(desktop->canvas); sp_desktop_selection(desktop)->set(sc->item); sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_SPIRAL, _("Create spiral")); sc->item = NULL; } }
static void sp_spiral_set_shape (SPShape *shape) { SPSpiral *spiral; NRPointF darray[SAMPLE_SIZE + 1]; NRPointF hat1, hat2; int i; double tstep, t; double dstep, d; SPCurve *c; spiral = SP_SPIRAL(shape); sp_object_request_modified (SP_OBJECT (spiral), SP_OBJECT_MODIFIED_FLAG); #if 0 if (spiral->rad < SP_EPSILON) return; #endif c = sp_curve_new (); #ifdef SPIRAL_VERBOSE g_print ("ex=%g, revo=%g, rad=%g, arg=%g, t0=%g\n", spiral->cx, spiral->cy, spiral->exp, spiral->revo, spiral->rad, spiral->arg, spiral->t0); #endif tstep = SAMPLE_STEP/spiral->revo; dstep = tstep/(SAMPLE_SIZE - 1.0); if (spiral->t0 - dstep >= 0.0) { for (d = spiral->t0 - dstep, i = 0; i <= 2; d += dstep, i++) sp_spiral_get_xy (spiral, d, &darray[i]); sp_darray_center_tangent (darray, 1, &hat1); hat1.x = - hat1.x; hat1.y = - hat1.y; } else { for (d = spiral->t0, i = 1; i <= 2; d += dstep, i++) sp_spiral_get_xy (spiral, d, &darray[i]); sp_darray_left_tangent (darray, 1, 2, &hat1); } sp_curve_moveto (c, darray[1].x, darray[1].y); for (t = spiral->t0; t < (1.0-tstep); t += tstep) { sp_spiral_fit_and_draw (spiral, c, dstep, darray, &hat1, &hat2, t); hat1.x = - hat2.x; hat1.y = - hat2.y; } if ((1.0 - t) > SP_EPSILON) sp_spiral_fit_and_draw (spiral, c, (1.0 - t)/(SAMPLE_SIZE - 1.0), darray, &hat1, &hat2, t); sp_shape_set_curve_insync ((SPShape *) spiral, c, TRUE); sp_curve_unref (c); }
static void sp_spiral_set (SPObject *object, unsigned int key, const gchar *value) { SPSpiral *spiral; SPShape *shape; gulong unit; spiral = SP_SPIRAL (object); shape = SP_SHAPE (object); /* fixme: we should really collect updates */ switch (key) { case SP_ATTR_SODIPODI_CX: if (!sp_svg_length_read_lff (value, &unit, NULL, &spiral->cx) || (unit == SP_SVG_UNIT_EM) || (unit == SP_SVG_UNIT_EX) || (unit == SP_SVG_UNIT_PERCENT)) { spiral->cx = 0.0; } sp_object_request_update (object, SP_OBJECT_MODIFIED_FLAG); break; case SP_ATTR_SODIPODI_CY: if (!sp_svg_length_read_lff (value, &unit, NULL, &spiral->cy) || (unit == SP_SVG_UNIT_EM) || (unit == SP_SVG_UNIT_EX) || (unit == SP_SVG_UNIT_PERCENT)) { spiral->cy = 0.0; } sp_object_request_update (object, SP_OBJECT_MODIFIED_FLAG); break; case SP_ATTR_SODIPODI_EXPANSION: if (value) { spiral->exp = atof (value); spiral->exp = CLAMP (spiral->exp, 0.0, 1000.0); } else { spiral->exp = 1.0; } sp_object_request_update (object, SP_OBJECT_MODIFIED_FLAG); break; case SP_ATTR_SODIPODI_REVOLUTION: if (value) { spiral->revo = atof (value); spiral->revo = CLAMP (spiral->revo, 0.05, 20.0); } else { spiral->revo = 3.0; } sp_object_request_update (object, SP_OBJECT_MODIFIED_FLAG); break; case SP_ATTR_SODIPODI_RADIUS: if (!sp_svg_length_read_lff (value, &unit, NULL, &spiral->rad) || (unit != SP_SVG_UNIT_EM) || (unit != SP_SVG_UNIT_EX) || (unit != SP_SVG_UNIT_PERCENT)) { spiral->rad = MAX (spiral->rad, 0.001); } sp_object_request_update (object, SP_OBJECT_MODIFIED_FLAG); break; case SP_ATTR_SODIPODI_ARGUMENT: if (value) { spiral->arg = atof (value); } else { spiral->arg = 0.0; } sp_object_request_update (object, SP_OBJECT_MODIFIED_FLAG); break; case SP_ATTR_SODIPODI_T0: if (value) { spiral->t0 = atof (value); spiral->t0 = CLAMP (spiral->t0, -1.0, 0.999); } else { spiral->t0 = 0.0; } sp_object_request_update (object, SP_OBJECT_MODIFIED_FLAG); break; default: if (((SPObjectClass *) parent_class)->set) ((SPObjectClass *) parent_class)->set (object, key, value); break; } }
/* * set attributes via outer (t=1) knot point: * [default] increase/decrease revolution factor * [control] constrain inner arg to round per PI/4 */ void SpiralKnotHolderEntityOuter::knot_set(Geom::Point const &p, Geom::Point const &/*origin*/, guint state) { Inkscape::Preferences *prefs = Inkscape::Preferences::get(); int snaps = prefs->getInt("/options/rotationsnapsperpi/value", 12); SPSpiral *spiral = SP_SPIRAL(item); gdouble dx = p[Geom::X] - spiral->cx; gdouble dy = p[Geom::Y] - spiral->cy; if (state & GDK_SHIFT_MASK) { // rotate without roll/unroll spiral->arg = atan2(dy, dx) - 2.0*M_PI*spiral->revo; if (!(state & GDK_MOD1_MASK)) { // if alt not pressed, change also rad; otherwise it is locked spiral->rad = MAX(hypot(dx, dy), 0.001); } if ( ( state & GDK_CONTROL_MASK ) && snaps ) { spiral->arg = sp_round(spiral->arg, M_PI/snaps); } } else { // roll/unroll // arg of the spiral outer end double arg_1; spiral->getPolar(1, NULL, &arg_1); // its fractional part after the whole turns are subtracted double arg_r = arg_1 - sp_round(arg_1, 2.0*M_PI); // arg of the mouse point relative to spiral center double mouse_angle = atan2(dy, dx); if (mouse_angle < 0) mouse_angle += 2*M_PI; // snap if ctrl if ( ( state & GDK_CONTROL_MASK ) && snaps ) { mouse_angle = sp_round(mouse_angle, M_PI/snaps); } // by how much we want to rotate the outer point double diff = mouse_angle - arg_r; if (diff > M_PI) diff -= 2*M_PI; else if (diff < -M_PI) diff += 2*M_PI; // calculate the new rad; // the value of t corresponding to the angle arg_1 + diff: double t_temp = ((arg_1 + diff) - spiral->arg)/(2*M_PI*spiral->revo); // the rad at that t: double rad_new = 0; if (t_temp > spiral->t0) spiral->getPolar(t_temp, &rad_new, NULL); // change the revo (converting diff from radians to the number of turns) spiral->revo += diff/(2*M_PI); if (spiral->revo < 1e-3) spiral->revo = 1e-3; // if alt not pressed and the values are sane, change the rad if (!(state & GDK_MOD1_MASK) && rad_new > 1e-3 && rad_new/spiral->rad < 2) { // adjust t0 too so that the inner point stays unmoved double r0; spiral->getPolar(spiral->t0, &r0, NULL); spiral->rad = rad_new; spiral->t0 = pow(r0 / spiral->rad, 1.0/spiral->exp); } if (!IS_FINITE(spiral->t0)) spiral->t0 = 0.0; spiral->t0 = CLAMP(spiral->t0, 0.0, 0.999); } (static_cast<SPObject *>(spiral))->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); }
static void sp_spiral_drag(SPSpiralContext *sc, Geom::Point p, guint state) { SPDesktop *desktop = SP_EVENT_CONTEXT(sc)->desktop; Inkscape::Preferences *prefs = Inkscape::Preferences::get(); int const snaps = prefs->getInt("/options/rotationsnapsperpi/value", 12); if (!sc->item) { if (Inkscape::have_viable_layer(desktop, sc->_message_context) == false) { return; } /* Create object */ Inkscape::XML::Document *xml_doc = sp_document_repr_doc(SP_EVENT_CONTEXT_DOCUMENT(sc)); Inkscape::XML::Node *repr = xml_doc->createElement("svg:path"); repr->setAttribute("sodipodi:type", "spiral"); /* Set style */ sp_desktop_apply_style_tool(desktop, repr, "/tools/shapes/spiral", false); sc->item = (SPItem *) desktop->currentLayer()->appendChildRepr(repr); Inkscape::GC::release(repr); sc->item->transform = sp_item_i2doc_affine(SP_ITEM(desktop->currentLayer())).inverse(); sc->item->updateRepr(); sp_canvas_force_full_redraw_after_interruptions(desktop->canvas, 5); } SnapManager &m = desktop->namedview->snap_manager; m.setup(desktop, true, sc->item); Geom::Point pt2g = to_2geom(p); m.freeSnapReturnByRef(Inkscape::SnapPreferences::SNAPPOINT_NODE, pt2g); Geom::Point const p0 = to_2geom(sp_desktop_dt2doc_xy_point(desktop, sc->center)); Geom::Point const p1 = to_2geom(sp_desktop_dt2doc_xy_point(desktop, from_2geom(pt2g))); SPSpiral *spiral = SP_SPIRAL(sc->item); Geom::Point const delta = p1 - p0; gdouble const rad = Geom::L2(delta); gdouble arg = Geom::atan2(delta) - 2.0*M_PI*spiral->revo; if (state & GDK_CONTROL_MASK) { arg = sp_round(arg, M_PI/snaps); } /* Fixme: these parameters should be got from dialog box */ sp_spiral_position_set(spiral, p0[Geom::X], p0[Geom::Y], /*expansion*/ sc->exp, /*revolution*/ sc->revo, rad, arg, /*t0*/ sc->t0); /* status text */ GString *rads = SP_PX_TO_METRIC_STRING(rad, desktop->namedview->getDefaultMetric()); sc->_message_context->setF(Inkscape::IMMEDIATE_MESSAGE, _("<b>Spiral</b>: radius %s, angle %5g°; with <b>Ctrl</b> to snap angle"), rads->str, sp_round((arg + 2.0*M_PI*spiral->revo)*180/M_PI, 0.0001)); g_string_free(rads, FALSE); }