diff options
| author | Maximilian Albert <maximilian.albert@gmail.com> | 2007-08-06 07:37:24 +0000 |
|---|---|---|
| committer | cilix42 <cilix42@users.sourceforge.net> | 2007-08-06 07:37:24 +0000 |
| commit | de43f9fc6fc4f6f8e716924c7c6f1242d4b036a3 (patch) | |
| tree | 8b0b862bd0b0eea74d9e1cdc04c7b833df75c54c /src/vanishing-point.cpp | |
| parent | Workaround for some segfaults: Store perspectives globally instead of in each... (diff) | |
| download | inkscape-de43f9fc6fc4f6f8e716924c7c6f1242d4b036a3.tar.gz inkscape-de43f9fc6fc4f6f8e716924c7c6f1242d4b036a3.zip | |
First stage of draggable vanishing points (no snapping/unsnapping yet)
(bzr r3391)
Diffstat (limited to 'src/vanishing-point.cpp')
| -rw-r--r-- | src/vanishing-point.cpp | 339 |
1 files changed, 339 insertions, 0 deletions
diff --git a/src/vanishing-point.cpp b/src/vanishing-point.cpp index 5f40936cf..edf769c17 100644 --- a/src/vanishing-point.cpp +++ b/src/vanishing-point.cpp @@ -12,9 +12,31 @@ */ #include "vanishing-point.h" +#include "desktop-handles.h" +#include "box3d.h" namespace Box3D { +#define VP_KNOT_COLOR_NORMAL 0xffffff00 +#define VP_KNOT_COLOR_SELECTED 0x0000ff00 + +#define VP_LINE_COLOR_FILL 0x0000ff7f +#define VP_LINE_COLOR_STROKE_X 0xff00007f +#define VP_LINE_COLOR_STROKE_Y 0x0000ff7f +#define VP_LINE_COLOR_STROKE_Z 0xffff007f + +// screen pixels between knots when they snap: +#define SNAP_DIST 5 + +// absolute distance between gradient points for them to become a single dragger when the drag is created: +#define MERGE_DIST 0.1 + +// knot shapes corresponding to GrPointType enum +SPKnotShapeType vp_knot_shapes [] = { + SP_KNOT_SHAPE_SQUARE, // VP_FINITE + SP_KNOT_SHAPE_CIRCLE //VP_INFINITE +}; + // FIXME: We should always require to have both the point (for finite VPs) // and the direction (for infinite VPs) set. Otherwise toggling // shows very unexpected behaviour. @@ -45,6 +67,8 @@ VanishingPoint::VanishingPoint(VanishingPoint const &rhs) : NR::Point (rhs) this->v_dir = rhs.v_dir; } +VanishingPoint::~VanishingPoint () {} + bool VanishingPoint::operator== (VanishingPoint const &other) { // Should we compare the parent perspectives, too? Probably not. @@ -98,6 +122,321 @@ void VanishingPoint::draw(Box3D::Axis const axis) } } +static void +vp_drag_sel_changed(Inkscape::Selection *selection, gpointer data) +{ + VPDrag *drag = (VPDrag *) data; + drag->updateDraggers (); + //drag->updateLines (); +} + +static void +vp_drag_sel_modified (Inkscape::Selection *selection, guint flags, gpointer data) +{ + VPDrag *drag = (VPDrag *) data; + /*** + if (drag->local_change) { + drag->local_change = false; + } else { + drag->updateDraggers (); + } + ***/ + //drag->updateLines (); +} + +static void +vp_knot_moved_handler (SPKnot *knot, NR::Point const *ppointer, guint state, gpointer data) +{ + g_warning ("Please implement vp_knot_moved_handler.\n"); + VPDragger *dragger = (VPDragger *) data; + //VPDrag *drag = dragger->parent; + + NR::Point p = *ppointer; + + dragger->point = p; + + dragger->reshapeBoxes (p, Box3D::XYZ); + //dragger->parent->updateLines (); + + //drag->local_change = false; +} + +static void +vp_knot_grabbed_handler (SPKnot *knot, unsigned int state, gpointer data) +{ + VPDragger *dragger = (VPDragger *) data; + + //sp_canvas_force_full_redraw_after_interruptions(dragger->parent->desktop->canvas, 5); +} + +static void +vp_knot_ungrabbed_handler (SPKnot *knot, guint state, gpointer data) +{ + g_warning ("Please fully implement vp_knot_ungrabbed_handler.\n"); + + VPDragger *dragger = (VPDragger *) data; + //VPDrag *drag = dragger->parent; + + //sp_canvas_end_forced_full_redraws(dragger->parent->desktop->canvas); + + dragger->point_original = dragger->point = knot->pos; + + /*** + VanishingPoint *vp; + for (GSList *i = dragger->vps; i != NULL; i = i->next) { + vp = (VanishingPoint *) i->data; + vp->set_pos (knot->pos); + } + ***/ + + dragger->parent->updateDraggers (); + dragger->updateBoxReprs (); + + // TODO: Update box's paths and svg representation + + // TODO: Undo machinery!! +} + +VPDragger::VPDragger(VPDrag *parent, NR::Point p, VanishingPoint *vp) +{ + if (vp == NULL) { + g_print ("VP used to create the VPDragger is NULL. This can happen when shift-dragging knots.\n"); + g_print ("How to correctly handle this? Should we just ignore it, as we currently do?\n"); + //g_assert (vp != NULL); + } + this->vps = NULL; + + this->parent = parent; + + this->point = p; + this->point_original = p; + + // create the knot + this->knot = sp_knot_new (parent->desktop, NULL); + this->knot->setMode(SP_KNOT_MODE_XOR); + this->knot->setFill(VP_KNOT_COLOR_NORMAL, VP_KNOT_COLOR_NORMAL, VP_KNOT_COLOR_NORMAL); + this->knot->setStroke(0x000000ff, 0x000000ff, 0x000000ff); + sp_knot_update_ctrl(this->knot); + + // move knot to the given point + sp_knot_set_position (this->knot, &this->point, SP_KNOT_STATE_NORMAL); + sp_knot_show (this->knot); + + // connect knot's signals + g_signal_connect (G_OBJECT (this->knot), "moved", G_CALLBACK (vp_knot_moved_handler), this); + /*** + g_signal_connect (G_OBJECT (this->knot), "clicked", G_CALLBACK (vp_knot_clicked_handler), this); + ***/ + g_signal_connect (G_OBJECT (this->knot), "grabbed", G_CALLBACK (vp_knot_grabbed_handler), this); + g_signal_connect (G_OBJECT (this->knot), "ungrabbed", G_CALLBACK (vp_knot_ungrabbed_handler), this); + /*** + g_signal_connect (G_OBJECT (this->knot), "doubleclicked", G_CALLBACK (vp_knot_doubleclicked_handler), this); + ***/ + + // add the initial VP (which may be NULL!) + this->addVP (vp); + //updateKnotShape(); +} + +VPDragger::~VPDragger() +{ + // unselect if it was selected + //this->parent->setDeselected(this); + + // disconnect signals + g_signal_handlers_disconnect_by_func(G_OBJECT(this->knot), (gpointer) G_CALLBACK (vp_knot_moved_handler), this); + /*** + g_signal_handlers_disconnect_by_func(G_OBJECT(this->knot), (gpointer) G_CALLBACK (vp_knot_clicked_handler), this); + ***/ + g_signal_handlers_disconnect_by_func(G_OBJECT(this->knot), (gpointer) G_CALLBACK (vp_knot_grabbed_handler), this); + g_signal_handlers_disconnect_by_func(G_OBJECT(this->knot), (gpointer) G_CALLBACK (vp_knot_ungrabbed_handler), this); + /*** + g_signal_handlers_disconnect_by_func(G_OBJECT(this->knot), (gpointer) G_CALLBACK (vp_knot_doubleclicked_handler), this); + ***/ + + /* unref should call destroy */ + g_object_unref (G_OBJECT (this->knot)); + + g_slist_free (this->vps); + this->vps = NULL; +} + +/** + * Adds a vanishing point to the dragger (also updates the position) + */ +void +VPDragger::addVP (VanishingPoint *vp) +{ + if (vp == NULL) { + g_print ("No VP present in addVP. We return without adding a new VP to the list.\n"); + return; + } + vp->set_pos (this->point); + this->vps = g_slist_prepend (this->vps, vp); + + //this->updateTip(); +} + +void +VPDragger::removeVP (VanishingPoint *vp) +{ + if (vp == NULL) { + g_print ("NULL vanishing point will not be removed.\n"); + return; + } + g_assert (this->vps != NULL); + this->vps = g_slist_remove (this->vps, vp); + + //this->updateTip(); +} + +void +VPDragger::reshapeBoxes (NR::Point const &p, Box3D::Axis axes) +{ + Perspective3D *persp; + for (GSList const* i = this->vps; i != NULL; i = i->next) { + VanishingPoint *vp = (VanishingPoint *) i->data; + // TODO: We can extract the VP directly from the box's perspective. Is that vanishing point identical to 'vp'? + // Or is there duplicated information? If so, remove it and simplify the whole construction! + vp->set_pos(p); + persp = get_persp_of_VP (vp); + Box3D::Axis axis = persp->get_axis_of_VP (vp); + get_persp_of_VP (vp)->reshape_boxes (axis); // FIXME: we should only update the direction of the VP + } +} + +void +VPDragger::updateBoxReprs () +{ + for (GSList *i = this->vps; i != NULL; i = i->next) { + Box3D::get_persp_of_VP ((VanishingPoint *) i->data)->update_box_reprs (); + } +} + +VPDrag::VPDrag (SPDesktop *desktop) +{ + this->desktop = desktop; + this->draggers = NULL; + this->selection = sp_desktop_selection(desktop); + + this->sel_changed_connection = this->selection->connectChanged( + sigc::bind ( + sigc::ptr_fun(&vp_drag_sel_changed), + (gpointer)this ) + + ); + this->sel_modified_connection = this->selection->connectModified( + sigc::bind( + sigc::ptr_fun(&vp_drag_sel_modified), + (gpointer)this ) + ); + + this->updateDraggers (); + //this->updateLines (); +} + +VPDrag::~VPDrag() +{ + this->sel_changed_connection.disconnect(); + this->sel_modified_connection.disconnect(); + + for (GList *l = this->draggers; l != NULL; l = l->next) { + delete ((VPDragger *) l->data); + } + g_list_free (this->draggers); + this->draggers = NULL; +} + +/** + * Select the dragger that has the given VP. + */ +VPDragger * +VPDrag::getDraggerFor (VanishingPoint const &vp) +{ + for (GList const* i = this->draggers; i != NULL; i = i->next) { + VPDragger *dragger = (VPDragger *) i->data; + for (GSList const* j = dragger->vps; j != NULL; j = j->next) { + VanishingPoint *vp2 = (VanishingPoint *) j->data; + g_assert (vp2 != NULL); + + // TODO: Should we compare the pointers or the VPs themselves!?!?!?! + //if ((*vp2) == vp) { + if (vp2 == &vp) { + return (dragger); + } + } + } + return NULL; +} + +/** + * Regenerates the draggers list from the current selection; is called when selection is changed or modified + */ +void +VPDrag::updateDraggers () +{ + /*** + while (selected) { + selected = g_list_remove(selected, selected->data); + } + ***/ + // delete old draggers + for (GList const* i = this->draggers; i != NULL; i = i->next) { + delete ((VPDragger *) i->data); + } + g_list_free (this->draggers); + this->draggers = NULL; + + g_return_if_fail (this->selection != NULL); + + for (GSList const* i = this->selection->itemList(); i != NULL; i = i->next) { + SPItem *item = SP_ITEM(i->data); + //SPStyle *style = SP_OBJECT_STYLE (item); + + if (!SP_IS_3DBOX (item)) continue; + SP3DBox *box = SP_3DBOX (item); + + // FIXME: Get the VPs from the selection!!!! + //addDragger (Box3D::Perspective3D::current_perspective->get_vanishing_point(Box3D::X)); + //addDragger (Box3D::Perspective3D::current_perspective->get_vanishing_point(Box3D::Y)); + //addDragger (Box3D::Perspective3D::current_perspective->get_vanishing_point(Box3D::Z)); + + //Box3D::Perspective3D *persp = box->perspective; + Box3D::Perspective3D *persp = Box3D::get_persp_of_box (box); + addDragger (persp->get_vanishing_point(Box3D::X)); + addDragger (persp->get_vanishing_point(Box3D::Y)); + addDragger (persp->get_vanishing_point(Box3D::Z)); + } +} + +/** + * If there already exists a dragger within MERGE_DIST of p, add the VP to it; + * otherwise create new dragger and add it to draggers list + */ +void +VPDrag::addDragger (VanishingPoint *vp) +{ + if (vp == NULL) { + g_print ("Warning: The VP in addDragger is already NULL. Aborting.\n)"); + g_assert (vp != NULL); + } + NR::Point p = vp->get_pos(); + + for (GList *i = this->draggers; i != NULL; i = i->next) { + VPDragger *dragger = (VPDragger *) i->data; + if (NR::L2 (dragger->point - p) < MERGE_DIST) { + // distance is small, merge this draggable into dragger, no need to create new dragger + dragger->addVP (vp); + //dragger->updateKnotShape(); + return; + } + } + + VPDragger *new_dragger = new VPDragger(this, p, vp); + // fixme: draggers should be added AFTER the last one: this way tabbing through them will be from begin to end. + this->draggers = g_list_append (this->draggers, new_dragger); +} + } // namespace Box3D /* |
