From: Maximilian Albert Date: Sat, 26 Dec 2009 00:32:25 +0000 (+0100) Subject: Major simplification of 3D box code. X-Git-Url: https://git.tokkee.org/?a=commitdiff_plain;h=e711b02fbbe0b7d07102ebdd63b05027d6f8af47;p=inkscape.git Major simplification of 3D box code. --- diff --git a/src/box3d.cpp b/src/box3d.cpp index 460465637..aa2dc55e3 100644 --- a/src/box3d.cpp +++ b/src/box3d.cpp @@ -244,16 +244,10 @@ box3d_ref_changed(SPObject *old_ref, SPObject *ref, SPBox3D *box) if (old_ref) { sp_signal_disconnect_by_data(old_ref, box); persp3d_remove_box (SP_PERSP3D(old_ref), box); - /* Note: This sometimes leads to attempts to remove boxes twice from the list of selected/transformed - boxes in a perspectives, but this should be uncritical. */ - persp3d_remove_box_transform (SP_PERSP3D(old_ref), box); } if ( SP_IS_PERSP3D(ref) && ref != box ) // FIXME: Comparisons sane? { persp3d_add_box (SP_PERSP3D(ref), box); - /* Note: This sometimes leads to attempts to add boxes twice to the list of selected/transformed - boxes in a perspectives, but this should be uncritical. */ - persp3d_add_box_transform (SP_PERSP3D(ref), box); } } @@ -349,37 +343,8 @@ box3d_set_transform(SPItem *item, Geom::Matrix const &xform) { SPBox3D *box = SP_BOX3D(item); - /* check whether we need to unlink any boxes from their perspectives */ - Persp3D *persp = box3d_get_perspective(box); - Persp3D *transf_persp; - - if (sp_desktop_document(inkscape_active_desktop()) == SP_OBJECT_DOCUMENT(item) && - !persp3d_has_all_boxes_in_selection (persp)) { - std::list selboxes = sp_desktop_selection(inkscape_active_desktop())->box3DList(); - - /* create a new perspective as a copy of the current one and link the selected boxes to it */ - transf_persp = persp3d_create_xml_element (SP_OBJECT_DOCUMENT(persp), persp->perspective_impl); - - for (std::list::iterator b = selboxes.begin(); b != selboxes.end(); ++b) { - box3d_switch_perspectives(*b, persp, transf_persp); - } - } else { - transf_persp = persp; - } - - /* only transform the perspective once, even if it has several selected boxes */ - if(!persp3d_was_transformed (transf_persp)) { - /* concatenate the affine transformation with the perspective mapping; this - function also triggers repr updates of boxes and the perspective itself */ - persp3d_apply_affine_transformation(transf_persp, xform); - } - - box3d_mark_transformed(box); - - if (persp3d_all_transformed(transf_persp)) { - /* all boxes were transformed; make perspective sensitive for further transformations */ - persp3d_unset_transforms(transf_persp); - } + // We don't apply the transform to the box directly but instead to its perspective (which is + // done in sp_selection_apply_affine). Here we only adjust strokes, patterns, etc. Geom::Matrix ret(Geom::Matrix(xform).without_translation()); gdouble const sw = hypot(ret[0], ret[1]); @@ -1323,31 +1288,6 @@ box3d_check_for_swapped_coords(SPBox3D *box) { box3d_exchange_coords(box); } -void -box3d_add_to_selection(SPBox3D *box) { - Persp3D *persp = box3d_get_perspective(box); - g_return_if_fail(persp); - persp3d_add_box_transform(persp, box); -} - -void -box3d_remove_from_selection(SPBox3D *box) { - Persp3D *persp = box3d_get_perspective(box); - if (!persp) { - /* this can happen if a box is deleted through undo and the persp_ref is already detached; - should we rebuild the boxes of each perspective in this case or is it safe to leave it alone? */ - return; - } - persp3d_remove_box_transform(persp, box); -} - -void -box3d_mark_transformed(SPBox3D *box) { - Persp3D *persp = box3d_get_perspective(box); - g_return_if_fail(persp); - persp3d_set_box_transformed(persp, box, true); -} - static void box3d_extract_boxes_rec(SPObject *obj, std::list &boxes) { if (SP_IS_BOX3D(obj)) { @@ -1388,9 +1328,6 @@ box3d_switch_perspectives(SPBox3D *box, Persp3D *old_persp, Persp3D *new_persp, persp3d_remove_box (old_persp, box); persp3d_add_box (new_persp, box); - persp3d_remove_box_transform (old_persp, box); - persp3d_add_box_transform (new_persp, box); - gchar *href = g_strdup_printf("#%s", SP_OBJECT_REPR(new_persp)->attribute("id")); SP_OBJECT_REPR(box)->setAttribute("inkscape:perspectiveID", href); g_free(href); diff --git a/src/box3d.h b/src/box3d.h index b6d962a3c..9f2e1d78e 100644 --- a/src/box3d.h +++ b/src/box3d.h @@ -70,10 +70,6 @@ int box3d_VP_lies_in_PL_sector (SPBox3D const *box, Proj::Axis vpdir, int id1, i void box3d_relabel_corners(SPBox3D *box); void box3d_check_for_swapped_coords(SPBox3D *box); -void box3d_add_to_selection(SPBox3D *box); -void box3d_remove_from_selection(SPBox3D *box); -void box3d_mark_transformed(SPBox3D *box); - std::list box3d_extract_boxes(SPObject *obj); Persp3D *box3d_get_perspective(SPBox3D const *box); diff --git a/src/persp3d.cpp b/src/persp3d.cpp index 3f1e8851f..6a697ec9b 100644 --- a/src/persp3d.cpp +++ b/src/persp3d.cpp @@ -34,6 +34,9 @@ static Inkscape::XML::Node *persp3d_write(SPObject *object, Inkscape::XML::Docum static void persp3d_on_repr_attr_changed (Inkscape::XML::Node * repr, const gchar *key, const gchar *oldval, const gchar *newval, bool is_interactive, void * data); +static void persp3d_update_with_point (Persp3DImpl *persp_impl, Proj::Axis const axis, Proj::Pt2 const &new_image); +static gchar * persp3d_pt_to_str (Persp3DImpl *persp_impl, Proj::Axis const axis); + static SPObjectClass *persp3d_parent_class; static int global_counter = 0; @@ -42,18 +45,11 @@ static int global_counter = 0; Persp3DImpl::Persp3DImpl() { tmat = Proj::TransfMat3x4 (); - - boxes_transformed = new std::map; - boxes_transformed->clear(); document = NULL; my_counter = global_counter++; } -Persp3DImpl::~Persp3DImpl() { - delete boxes_transformed; -} - /** * Registers Persp3d class and returns its type. */ @@ -438,83 +434,6 @@ persp3d_has_box (Persp3D *persp, SPBox3D *box) { return false; } -void -persp3d_add_box_transform (Persp3D *persp, SPBox3D *box) { - Persp3DImpl *persp_impl = persp->perspective_impl; - - std::map::iterator i = persp_impl->boxes_transformed->find(box); - if (i != persp_impl->boxes_transformed->end() && (*i).second == true) { - g_print ("Warning! In %s (%d): trying to add transform status for box %d twice when it's already listed as true.\n", SP_OBJECT_REPR(persp_impl)->attribute("id"), persp_impl->my_counter, box->my_counter); - return; - } - - (*persp_impl->boxes_transformed)[box] = false; -} - -void -persp3d_remove_box_transform (Persp3D *persp, SPBox3D *box) { - persp->perspective_impl->boxes_transformed->erase(box); -} - -void -persp3d_set_box_transformed (Persp3D *persp, SPBox3D *box, bool transformed) { - Persp3DImpl *persp_impl = persp->perspective_impl; - - if (persp_impl->boxes_transformed->find(box) == persp_impl->boxes_transformed->end()) { - g_print ("Warning! In %s (%d): trying to set transform status for box %d, but it is not listed in the perspective!! Aborting.\n", - SP_OBJECT_REPR(persp)->attribute("id"), persp_impl->my_counter, - box->my_counter); - return; - } - - (*persp_impl->boxes_transformed)[box] = transformed; -} - -bool -persp3d_was_transformed (Persp3D *persp) { - Persp3DImpl *persp_impl = persp->perspective_impl; - - if (persp_impl->boxes_transformed->size() == 1) { - /* either the transform has not been applied to the single box associated to this perspective yet - or the transform was already reset; in both cases we need to return false because upcoming - transforms need to be applied */ - (*persp_impl->boxes_transformed->begin()).second = false; // make sure the box is marked as untransformed (in case more boxes are added later) - return false; - } - - for (std::map::iterator i = persp_impl->boxes_transformed->begin(); - i != persp_impl->boxes_transformed->end(); ++i) { - if ((*i).second == true) { - // at least one of the boxes in the perspective has already been transformed; - return true; - } - } - return false; // all boxes in the perspective are still untransformed; a pending transformation should be applied -} - -bool -persp3d_all_transformed(Persp3D *persp) { - Persp3DImpl *persp_impl = persp->perspective_impl; - - for (std::map::iterator i = persp_impl->boxes_transformed->begin(); - i != persp_impl->boxes_transformed->end(); ++i) { - if ((*i).second == false) { - return false; - } - } - return true; -} - -void -persp3d_unset_transforms(Persp3D *persp) { - Persp3DImpl *persp_impl = persp->perspective_impl; - - for (std::map::iterator i = persp_impl->boxes_transformed->begin(); - i != persp_impl->boxes_transformed->end(); ++i) { - (*i).second = false; - } -} - void persp3d_update_box_displays (Persp3D *persp) { Persp3DImpl *persp_impl = persp->perspective_impl; @@ -607,10 +526,10 @@ persp3d_on_repr_attr_changed ( Inkscape::XML::Node * /*repr*/, /* checks whether all boxes linked to this perspective are currently selected */ bool -persp3d_has_all_boxes_in_selection (Persp3D *persp) { +persp3d_has_all_boxes_in_selection (Persp3D *persp, Inkscape::Selection *selection) { Persp3DImpl *persp_impl = persp->perspective_impl; - std::list selboxes = sp_desktop_selection(inkscape_active_desktop())->box3DList(); + std::list selboxes = selection->box3DList(); for (std::vector::iterator i = persp_impl->boxes.begin(); i != persp_impl->boxes.end(); ++i) { if (std::find(selboxes.begin(), selboxes.end(), *i) == selboxes.end()) { @@ -621,59 +540,6 @@ persp3d_has_all_boxes_in_selection (Persp3D *persp) { return true; } -/** - * For each perspective having a box in \a selection, determine all its unselected boxes. - */ -// TODO: Check where we can use pass-by-reference (or so) instead of recreating all the lists afresh. -std::map > -persp3d_unselected_boxes(Inkscape::Selection *selection) { - std::list plist = selection->perspList(); - std::map > punsel; - - std::list::iterator i; - std::vector::iterator j; - // for all perspectives in the list ... - for (i = plist.begin(); i != plist.end(); ++i) { - Persp3D *persp = *i; - Persp3DImpl *persp_impl = persp->perspective_impl; - // ... and each box associated to it ... - for (j = persp_impl->boxes.begin(); j != persp_impl->boxes.end(); ++j) { - SPBox3D *box = *j; - // ... check whether it is unselected, and if so add it to the list - if (persp_impl->boxes_transformed->find(box) == persp_impl->boxes_transformed->end()) { - punsel[persp].push_back(box); - } - } - } - return punsel; -} - -/** - * Split all perspectives with a box in \a selection by moving their unselected boxes to newly - * created perspectives. - */ -void -persp3d_split_perspectives_according_to_selection(Inkscape::Selection *selection) { - std::map > punsel = persp3d_unselected_boxes(selection); - - std::map >::iterator i; - std::list::iterator j; - // for all perspectives in the list ... - for (i = punsel.begin(); i != punsel.end(); ++i) { - Persp3D *persp = (*i).first; - // ... if the perspective has unselected boxes ... - if (!(*i).second.empty()) { - // create a new perspective and move these boxes over - SPDocument *document = SP_OBJECT_DOCUMENT(persp); - Persp3D * new_persp = persp3d_create_xml_element (document, persp->perspective_impl); - for (j = (*i).second.begin(); j != (*i).second.end(); ++j) { - SPBox3D *box = *j; - box3d_switch_perspectives(box, persp, new_persp); - } - } - } -} - /* some debugging stuff follows */ void @@ -722,9 +588,9 @@ persp3d_print_all_selected() { Persp3D *persp = SP_PERSP3D(*j); Persp3DImpl *persp_impl = persp->perspective_impl; g_print (" %s (%d): ", SP_OBJECT_REPR(persp)->attribute("id"), persp->perspective_impl->my_counter); - for (std::map::iterator i = persp_impl->boxes_transformed->begin(); - i != persp_impl->boxes_transformed->end(); ++i) { - g_print ("<%d,%d> ", (*i).first->my_counter, (*i).second); + for (std::vector::iterator i = persp_impl->boxes.begin(); + i != persp_impl->boxes.end(); ++i) { + g_print ("%d ", (*i)->my_counter); } g_print ("\n"); } diff --git a/src/persp3d.h b/src/persp3d.h index 31a6212c7..62cc586ef 100644 --- a/src/persp3d.h +++ b/src/persp3d.h @@ -32,15 +32,13 @@ class Box3DContext; class Persp3DImpl { public: Persp3DImpl(); - ~Persp3DImpl(); //private: Proj::TransfMat3x4 tmat; // Also write the list of boxes into the xml repr and vice versa link boxes to their persp3d? std::vector boxes; - std::map* boxes_transformed; // TODO: eventually we should merge this with 'boxes' - SPDocument *document; // should this rather be the SPDesktop? + SPDocument *document; // for debugging only int my_counter; @@ -82,13 +80,6 @@ void persp3d_add_box (Persp3D *persp, SPBox3D *box); void persp3d_remove_box (Persp3D *persp, SPBox3D *box); bool persp3d_has_box (Persp3D *persp, SPBox3D *box); -void persp3d_add_box_transform (Persp3D *persp, SPBox3D *box); -void persp3d_remove_box_transform (Persp3D *persp, SPBox3D *box); -void persp3d_set_box_transformed (Persp3D *persp, SPBox3D *box, bool transformed = true); -bool persp3d_was_transformed (Persp3D *persp); -bool persp3d_all_transformed(Persp3D *persp); -void persp3d_unset_transforms(Persp3D *persp); - void persp3d_update_box_displays (Persp3D *persp); void persp3d_update_box_reprs (Persp3D *persp); void persp3d_update_z_orders (Persp3D *persp); @@ -101,18 +92,12 @@ void persp3d_absorb(Persp3D *persp1, Persp3D *persp2); Persp3D * persp3d_create_xml_element (SPDocument *document, Persp3DImpl *dup = NULL); Persp3D * persp3d_document_first_persp (SPDocument *document); -bool persp3d_has_all_boxes_in_selection (Persp3D *persp); -std::map > persp3d_unselected_boxes(Inkscape::Selection *selection); -void persp3d_split_perspectives_according_to_selection(Inkscape::Selection *selection); +bool persp3d_has_all_boxes_in_selection (Persp3D *persp, Inkscape::Selection *selection); void persp3d_print_debugging_info (Persp3D *persp); void persp3d_print_debugging_info_all(SPDocument *doc); void persp3d_print_all_selected(); -/* Internally used functions; maybe these should be made more private? */ -void persp3d_update_with_point (Persp3DImpl *persp_impl, Proj::Axis const axis, Proj::Pt2 const &new_image); -gchar * persp3d_pt_to_str (Persp3DImpl *persp_impl, Proj::Axis const axis); - void print_current_persp3d(gchar *func_name, Persp3D *persp); #endif /* __PERSP3D_H__ */ diff --git a/src/selection-chemistry.cpp b/src/selection-chemistry.cpp index e55bba2a5..31e899d8a 100644 --- a/src/selection-chemistry.cpp +++ b/src/selection-chemistry.cpp @@ -76,6 +76,7 @@ #include "helper/units.h" #include "sp-item.h" #include "box3d.h" +#include "persp3d.h" #include "unit-constants.h" #include "xml/simple-document.h" #include "sp-filter-reference.h" @@ -1171,7 +1172,6 @@ selection_contains_both_clone_and_original(Inkscape::Selection *selection) return clone_with_original; } - /** Apply matrix to the selection. \a set_i2d is normally true, which means objects are in the original transform, synced with their reprs, and need to jump to the new transform in one go. A value of set_i2d==false is only used by seltrans when it's dragging objects live (not outlines); in @@ -1183,6 +1183,29 @@ void sp_selection_apply_affine(Inkscape::Selection *selection, Geom::Matrix cons if (selection->isEmpty()) return; + // For each perspective with a box in selection, check whether all boxes are selected and + // unlink all non-selected boxes. + Persp3D *persp; + Persp3D *transf_persp; + std::list plist = selection->perspList(); + for (std::list::iterator i = plist.begin(); i != plist.end(); ++i) { + persp = (Persp3D *) (*i); + + if (!persp3d_has_all_boxes_in_selection (persp, selection)) { + std::list selboxes = selection->box3DList(persp); + + // create a new perspective as a copy of the current one and link the selected boxes to it + transf_persp = persp3d_create_xml_element (SP_OBJECT_DOCUMENT(persp), persp->perspective_impl); + + for (std::list::iterator b = selboxes.begin(); b != selboxes.end(); ++b) + box3d_switch_perspectives(*b, persp, transf_persp); + } else { + transf_persp = persp; + } + + persp3d_apply_affine_transformation(transf_persp, affine); + } + for (GSList const *l = selection->itemList(); l != NULL; l = l->next) { SPItem *item = SP_ITEM(l->data); diff --git a/src/selection.cpp b/src/selection.cpp index ed8a9d57b..828a96968 100644 --- a/src/selection.cpp +++ b/src/selection.cpp @@ -162,24 +162,12 @@ void Selection::add(SPObject *obj, bool persist_selection_context/* = false */) _emitChanged(persist_selection_context); } -void Selection::add_box_perspective(SPBox3D *box) { - Persp3D *persp = box3d_get_perspective(box); - std::map::iterator p = _persps.find(persp); - if (p != _persps.end()) { - (*p).second++; - } else { - _persps[persp] = 1; - } -} - void Selection::add_3D_boxes_recursively(SPObject *obj) { std::list boxes = box3d_extract_boxes(obj); for (std::list::iterator i = boxes.begin(); i != boxes.end(); ++i) { SPBox3D *box = *i; - box3d_add_to_selection(box); _3dboxes.push_back(box); - add_box_perspective(box); } } @@ -220,33 +208,17 @@ void Selection::remove(SPObject *obj) { _emitChanged(); } -void Selection::remove_box_perspective(SPBox3D *box) { - Persp3D *persp = box3d_get_perspective(box); - std::map::iterator p = _persps.find(persp); - if (p == _persps.end()) { - //g_print ("Warning! Trying to remove unselected perspective from selection!\n"); - return; - } - if ((*p).second > 1) { - _persps[persp]--; - } else { - _persps.erase(p); - } -} - void Selection::remove_3D_boxes_recursively(SPObject *obj) { std::list boxes = box3d_extract_boxes(obj); for (std::list::iterator i = boxes.begin(); i != boxes.end(); ++i) { SPBox3D *box = *i; - box3d_remove_from_selection(box); std::list::iterator b = std::find(_3dboxes.begin(), _3dboxes.end(), box); if (b == _3dboxes.end()) { g_print ("Warning! Trying to remove unselected box from selection.\n"); return; } _3dboxes.erase(b); - remove_box_perspective(box); } } @@ -344,14 +316,27 @@ GSList const *Selection::reprList() { std::list const Selection::perspList() { std::list pl; - for (std::map::iterator p = _persps.begin(); p != _persps.end(); ++p) { - pl.push_back((*p).first); + for (std::list::iterator i = _3dboxes.begin(); i != _3dboxes.end(); ++i) { + Persp3D *persp = box3d_get_perspective(*i); + if (std::find(pl.begin(), pl.end(), persp) == pl.end()) + pl.push_back(persp); } return pl; } -std::list const Selection::box3DList() { - return _3dboxes; +std::list const Selection::box3DList(Persp3D *persp) { + std::list boxes; + if (persp) { + SPBox3D *box; + for (std::list::iterator i = _3dboxes.begin(); i != _3dboxes.end(); ++i) { + box = *i; + if (persp == box3d_get_perspective(box)) + boxes.push_back(box); + } + } else { + boxes = _3dboxes; + } + return boxes; } SPObject *Selection::single() { diff --git a/src/selection.h b/src/selection.h index ecb1ef45e..5e035fb60 100644 --- a/src/selection.h +++ b/src/selection.h @@ -229,11 +229,14 @@ public: /// method for that GSList const *reprList(); - /* list of all perspectives which have a 3D box in the current selection + /** @brief Returns a list of all perspectives which have a 3D box in the current selection (these may also be nested in groups) */ std::list const perspList(); - std::list const box3DList(); + /** @brief Returns a list of all 3D boxes in the current selection which are associated to @c + persp. If @c pers is @c NULL, return all selected boxes. + */ + std::list const box3DList(Persp3D *persp = NULL); /** @brief Returns the number of layers in which there are selected objects */ guint numberOfLayers(); @@ -351,7 +354,6 @@ private: void remove_box_perspective(SPBox3D *box); void remove_3D_boxes_recursively(SPObject *obj); - std::map _persps; std::list _3dboxes; GC::soft_ptr _desktop; diff --git a/src/sp-item-group.cpp b/src/sp-item-group.cpp index 7ac7880a7..3845be232 100644 --- a/src/sp-item-group.cpp +++ b/src/sp-item-group.cpp @@ -67,7 +67,6 @@ static void sp_group_set(SPObject *object, unsigned key, char const *value); static void sp_group_bbox(SPItem const *item, NRRect *bbox, Geom::Matrix const &transform, unsigned const flags); static void sp_group_print (SPItem * item, SPPrintContext *ctx); static gchar * sp_group_description (SPItem * item); -static Geom::Matrix sp_group_set_transform(SPItem *item, Geom::Matrix const &xform); static NRArenaItem *sp_group_show (SPItem *item, NRArena *arena, unsigned int key, unsigned int flags); static void sp_group_hide (SPItem * item, unsigned int key); static void sp_group_snappoints (SPItem const *item, bool const target, SnapPointsWithType &p, Inkscape::SnapPreferences const *snapprefs); @@ -129,7 +128,6 @@ sp_group_class_init (SPGroupClass *klass) item_class->bbox = sp_group_bbox; item_class->print = sp_group_print; item_class->description = sp_group_description; - item_class->set_transform = sp_group_set_transform; item_class->show = sp_group_show; item_class->hide = sp_group_hide; item_class->snappoints = sp_group_snappoints; @@ -291,24 +289,6 @@ static gchar * sp_group_description (SPItem * item) return SP_GROUP(item)->group->getDescription(); } -static Geom::Matrix -sp_group_set_transform(SPItem *item, Geom::Matrix const &xform) -{ - Inkscape::Selection *selection = sp_desktop_selection(inkscape_active_desktop()); - persp3d_split_perspectives_according_to_selection(selection); - - Geom::Matrix last_trans; - sp_svg_transform_read(SP_OBJECT_REPR(item)->attribute("transform"), &last_trans); - Geom::Matrix inc_trans = last_trans.inverse()*xform; - - std::list plist = selection->perspList(); - for (std::list::iterator i = plist.begin(); i != plist.end(); ++i) { - persp3d_apply_affine_transformation(*i, inc_trans); - } - - return xform; -} - static void sp_group_set(SPObject *object, unsigned key, char const *value) { SPGroup *group = SP_GROUP(object); diff --git a/src/transf_mat_3x4.cpp b/src/transf_mat_3x4.cpp index b7cd278d4..6b49dc44a 100644 --- a/src/transf_mat_3x4.cpp +++ b/src/transf_mat_3x4.cpp @@ -115,6 +115,7 @@ TransfMat3x4::pt_to_str (Proj::Axis axis) { return g_strdup(os.str().c_str()); } +/* Check for equality (with a small tolerance epsilon) */ bool TransfMat3x4::operator==(const TransfMat3x4 &rhs) const { @@ -129,29 +130,16 @@ TransfMat3x4::operator==(const TransfMat3x4 &rhs) const return true; } -/* multiply a projective matrix by an affine matrix */ +/* Multiply a projective matrix by an affine matrix (by only multiplying the 'affine part' of the + * projective matrix) */ TransfMat3x4 TransfMat3x4::operator*(Geom::Matrix const &A) const { TransfMat3x4 ret; - // Is it safe to always use the currently active document? - double h = sp_document_height(inkscape_active_document()); - - /* - * Note: The strange multiplication involving the document height is due to the buggy - * intertwining of SVG and document coordinates. Essentially, what we do is first - * convert from "real-world" to SVG coordinates, then apply the transformation A - * (by multiplying with the Geom::Matrix) and then convert back from SVG to real-world - * coordinates. Maybe there is even a more Inkscape-ish way to achieve this? - * Once Inkscape has gotton rid of the two different coordiate systems, we can change - * this function to an ordinary matrix multiplication. - */ for (int j = 0; j < 4; ++j) { - ret.tmat[0][j] = A[0]*tmat[0][j] + A[2]*(h*tmat[2][j] - tmat[1][j]) + A[4]*tmat[2][j]; - ret.tmat[1][j] = A[1]*tmat[0][j] + A[3]*(h*tmat[2][j] - tmat[1][j]) + A[5]*tmat[2][j]; + ret.tmat[0][j] = A[0]*tmat[0][j] + A[2]*tmat[1][j] + A[4]*tmat[2][j]; + ret.tmat[1][j] = A[1]*tmat[0][j] + A[3]*tmat[1][j] + A[5]*tmat[2][j]; ret.tmat[2][j] = tmat[2][j]; - - ret.tmat[1][j] = h*ret.tmat[2][j] - ret.tmat[1][j]; // switch back from SVG to desktop coordinates } return ret;