void PatternKnotHolderEntityAngle::knot_set(Geom::Point const &p, Geom::Point const &/*origin*/, guint state) { Inkscape::Preferences *prefs = Inkscape::Preferences::get(); int const snaps = prefs->getInt("/options/rotationsnapsperpi/value", 12); SPPattern *pat = SP_PATTERN(SP_STYLE_FILL_SERVER(SP_OBJECT(item)->style)); // get the angle from pattern 0,0 to the cursor pos Geom::Point delta = p - sp_pattern_extract_trans(pat); gdouble theta = atan2(delta); if ( state & GDK_CONTROL_MASK ) { theta = sp_round(theta, M_PI/snaps); } // get the scale from the current transform so we can keep it. Geom::Point scl = sp_pattern_extract_scale(pat); Geom::Affine rot = Geom::Affine(Geom::Scale(scl)) * Geom::Affine(Geom::Rotate(theta)); Geom::Point const t = sp_pattern_extract_trans(pat); rot[4] = t[Geom::X]; rot[5] = t[Geom::Y]; item->adjust_pattern(rot, true); item->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); }
/* * 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); }
void ArcKnotHolderEntityEnd::knot_set(Geom::Point const &p, Geom::Point const &/*origin*/, guint state) { int snaps = Inkscape::Preferences::get()->getInt("/options/rotationsnapsperpi/value", 12); SPGenericEllipse *arc = SP_GENERICELLIPSE(item); arc->setClosed(sp_genericellipse_side(arc, p) == -1); Geom::Point delta = p - Geom::Point(arc->cx.computed, arc->cy.computed); Geom::Scale sc(arc->rx.computed, arc->ry.computed); arc->end = atan2(delta * sc.inverse()); if ((state & GDK_CONTROL_MASK) && snaps) { arc->end = sp_round(arc->end, M_PI/snaps); } arc->normalize(); arc->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); }
/* * 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); }