From df81a0651a143161602542fa98558a96feda1f0f Mon Sep 17 00:00:00 2001 From: "Johan B. C. Engelen" Date: Mon, 24 Mar 2014 20:41:57 +0100 Subject: fix potential calls on nullptr (bzr r13194) --- src/desktop.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/desktop.cpp b/src/desktop.cpp index a02baeac8..6b5f696e0 100644 --- a/src/desktop.cpp +++ b/src/desktop.cpp @@ -1537,7 +1537,9 @@ SPDesktop::updateCanvasNow() void SPDesktop::setDocument (SPDocument *doc) { - if (this->doc() && doc) { + if (!doc) return; + + if (this->doc()) { namedview->hide(this); this->doc()->getRoot()->invoke_hide(dkey); } -- cgit v1.2.3 From 505bff7c923d7cc223c870560343049c960e764a Mon Sep 17 00:00:00 2001 From: "Johan B. C. Engelen" Date: Mon, 24 Mar 2014 20:43:21 +0100 Subject: fix potential call on nullptr (bzr r13195) --- src/desktop.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/desktop.cpp b/src/desktop.cpp index 6b5f696e0..22c00d4f1 100644 --- a/src/desktop.cpp +++ b/src/desktop.cpp @@ -663,8 +663,8 @@ SPDesktop::change_document (SPDocument *theDocument) SPDesktopWidget *dtw = (SPDesktopWidget *) parent->get_data("desktopwidget"); if (dtw) { dtw->desktop = this; + dtw->updateNamedview(); } - dtw->updateNamedview(); _namedview_modified (namedview, SP_OBJECT_MODIFIED_FLAG, this); _document_replaced_signal.emit (this, theDocument); -- cgit v1.2.3 From c382941aa39a9d6318140cd01e153b4ab16902ec Mon Sep 17 00:00:00 2001 From: "Johan B. C. Engelen" Date: Mon, 24 Mar 2014 20:48:59 +0100 Subject: fix potential use of nullptr (item) (note that SPGroup inherits from SPItem) (bzr r13196) --- src/object-snapper.cpp | 54 +++++++++++++++++++++++++------------------------- 1 file changed, 27 insertions(+), 27 deletions(-) (limited to 'src') diff --git a/src/object-snapper.cpp b/src/object-snapper.cpp index de50f0dd8..3b8956bc8 100644 --- a/src/object-snapper.cpp +++ b/src/object-snapper.cpp @@ -119,35 +119,35 @@ void Inkscape::ObjectSnapper::_findCandidates(SPObject* parent, _findCandidates(obj, it, false, bbox_to_snap, true, item->i2doc_affine()); } } - } - if (SP_IS_GROUP(o)) { - _findCandidates(o, it, false, bbox_to_snap, clip_or_mask, additional_affine); - } else { - Geom::OptRect bbox_of_item; - Preferences *prefs = Preferences::get(); - int prefs_bbox = prefs->getBool("/tools/bounding_box", 0); - // We'll only need to obtain the visual bounding box if the user preferences tell - // us to, AND if we are snapping to the bounding box itself. If we're snapping to - // paths only, then we can just as well use the geometric bounding box (which is faster) - SPItem::BBoxType bbox_type = (!prefs_bbox && _snapmanager->snapprefs.isTargetSnappable(SNAPTARGET_BBOX_CATEGORY)) ? - SPItem::VISUAL_BBOX : SPItem::GEOMETRIC_BBOX; - if (clip_or_mask) { - // Oh oh, this will get ugly. We cannot use sp_item_i2d_affine directly because we need to - // insert an additional transformation in document coordinates (code copied from sp_item_i2d_affine) - bbox_of_item = item->bounds(bbox_type, item->i2doc_affine() * additional_affine * dt->doc2dt()); + if (SP_IS_GROUP(o)) { + _findCandidates(o, it, false, bbox_to_snap, clip_or_mask, additional_affine); } else { - bbox_of_item = item->desktopBounds(bbox_type); - } - if (bbox_of_item) { - // See if the item is within range - if (bbox_to_snap_incl.intersects(*bbox_of_item) - || (_snapmanager->snapprefs.isTargetSnappable(SNAPTARGET_ROTATION_CENTER) && bbox_to_snap_incl.contains(item->getCenter()))) { // rotation center might be outside of the bounding box - // This item is within snapping range, so record it as a candidate - _candidates->push_back(SnapCandidateItem(item, clip_or_mask, additional_affine)); - // For debugging: print the id of the candidate to the console - // SPObject *obj = (SPObject*)item; - // std::cout << "Snap candidate added: " << obj->getId() << std::endl; + Geom::OptRect bbox_of_item; + Preferences *prefs = Preferences::get(); + int prefs_bbox = prefs->getBool("/tools/bounding_box", 0); + // We'll only need to obtain the visual bounding box if the user preferences tell + // us to, AND if we are snapping to the bounding box itself. If we're snapping to + // paths only, then we can just as well use the geometric bounding box (which is faster) + SPItem::BBoxType bbox_type = (!prefs_bbox && _snapmanager->snapprefs.isTargetSnappable(SNAPTARGET_BBOX_CATEGORY)) ? + SPItem::VISUAL_BBOX : SPItem::GEOMETRIC_BBOX; + if (clip_or_mask) { + // Oh oh, this will get ugly. We cannot use sp_item_i2d_affine directly because we need to + // insert an additional transformation in document coordinates (code copied from sp_item_i2d_affine) + bbox_of_item = item->bounds(bbox_type, item->i2doc_affine() * additional_affine * dt->doc2dt()); + } else { + bbox_of_item = item->desktopBounds(bbox_type); + } + if (bbox_of_item) { + // See if the item is within range + if (bbox_to_snap_incl.intersects(*bbox_of_item) + || (_snapmanager->snapprefs.isTargetSnappable(SNAPTARGET_ROTATION_CENTER) && bbox_to_snap_incl.contains(item->getCenter()))) { // rotation center might be outside of the bounding box + // This item is within snapping range, so record it as a candidate + _candidates->push_back(SnapCandidateItem(item, clip_or_mask, additional_affine)); + // For debugging: print the id of the candidate to the console + // SPObject *obj = (SPObject*)item; + // std::cout << "Snap candidate added: " << obj->getId() << std::endl; + } } } } -- cgit v1.2.3 From 77c1e38b02cfc327e161afffd590473bcc7d4526 Mon Sep 17 00:00:00 2001 From: "Johan B. C. Engelen" Date: Mon, 24 Mar 2014 20:53:16 +0100 Subject: noop: code legibilty (bzr r13197) --- src/sp-object.cpp | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) (limited to 'src') diff --git a/src/sp-object.cpp b/src/sp-object.cpp index 764b5f260..c3ce3606b 100644 --- a/src/sp-object.cpp +++ b/src/sp-object.cpp @@ -967,31 +967,29 @@ static gchar const *sp_xml_get_space_string(unsigned int space) } Inkscape::XML::Node* SPObject::write(Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags) { - SPObject* object = this; - if (!repr && (flags & SP_OBJECT_WRITE_BUILD)) { - repr = object->getRepr()->duplicate(doc); + repr = this->getRepr()->duplicate(doc); if (!( flags & SP_OBJECT_WRITE_EXT )) { repr->setAttribute("inkscape:collect", NULL); } } else { - repr->setAttribute("id", object->getId()); + repr->setAttribute("id", this->getId()); - if (object->xml_space.set) { + if (this->xml_space.set) { char const *xml_space; - xml_space = sp_xml_get_space_string(object->xml_space.value); + xml_space = sp_xml_get_space_string(this->xml_space.value); repr->setAttribute("xml:space", xml_space); } if ( flags & SP_OBJECT_WRITE_EXT && - object->collectionPolicy() == SPObject::ALWAYS_COLLECT ) + this->collectionPolicy() == SPObject::ALWAYS_COLLECT ) { repr->setAttribute("inkscape:collect", "always"); } else { repr->setAttribute("inkscape:collect", NULL); } - SPStyle const *const obj_style = object->style; + SPStyle const *const obj_style = this->style; if (obj_style) { gchar *s = sp_style_write_string(obj_style, SP_STYLE_FLAG_IFSET); @@ -1028,7 +1026,7 @@ Inkscape::XML::Node* SPObject::write(Inkscape::XML::Document *doc, Inkscape::XML g_warning("Item's style is NULL; repr style attribute is %s", style_str); } - /** \note We treat object->style as authoritative. Its effects have + /** \note We treat this->style as authoritative. Its effects have * been written to the style attribute above; any properties that are * unset we take to be deliberately unset (e.g. so that clones can * override the property). @@ -1038,7 +1036,7 @@ Inkscape::XML::Node* SPObject::write(Inkscape::XML::Document *doc, Inkscape::XML * possibly we should write property attributes instead of a style * attribute. */ - sp_style_unset_property_attrs (object); + sp_style_unset_property_attrs (this); } return repr; -- cgit v1.2.3 From c12885a05f335fea74ba4239e3d0bebe220cee8d Mon Sep 17 00:00:00 2001 From: "Johan B. C. Engelen" Date: Mon, 24 Mar 2014 20:58:19 +0100 Subject: spobject: extra careful, check that repr is not nullptr (bzr r13198) --- src/sp-object.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/sp-object.cpp b/src/sp-object.cpp index c3ce3606b..be3a1ab9d 100644 --- a/src/sp-object.cpp +++ b/src/sp-object.cpp @@ -972,7 +972,7 @@ Inkscape::XML::Node* SPObject::write(Inkscape::XML::Document *doc, Inkscape::XML if (!( flags & SP_OBJECT_WRITE_EXT )) { repr->setAttribute("inkscape:collect", NULL); } - } else { + } else if (repr) { repr->setAttribute("id", this->getId()); if (this->xml_space.set) { -- cgit v1.2.3 From ce5229be907e72e96c711ae37bcb5919f7b31c3b Mon Sep 17 00:00:00 2001 From: "Johan B. C. Engelen" Date: Mon, 24 Mar 2014 21:21:12 +0100 Subject: sp_selected_path_combine: simplify code, prevent memleak waiting to happen upon refactoring (bzr r13199) --- src/path-chemistry.cpp | 21 ++++++++------------- 1 file changed, 8 insertions(+), 13 deletions(-) (limited to 'src') diff --git a/src/path-chemistry.cpp b/src/path-chemistry.cpp index 5f478435d..b613e6afa 100644 --- a/src/path-chemistry.cpp +++ b/src/path-chemistry.cpp @@ -83,10 +83,10 @@ sp_selected_path_combine(SPDesktop *desktop) gint position = 0; char const *id = NULL; char const *transform = NULL; - gchar *style = NULL; - gchar *path_effect = NULL; + Glib::ustring style; + Glib::ustring path_effect; - SPCurve* curve = 0; + SPCurve* curve = NULL; SPItem *first = NULL; Inkscape::XML::Node *parent = NULL; @@ -114,18 +114,15 @@ sp_selected_path_combine(SPDesktop *desktop) id = first->getRepr()->attribute("id"); transform = first->getRepr()->attribute("transform"); // FIXME: merge styles of combined objects instead of using the first one's style - style = g_strdup(first->getRepr()->attribute("style")); - path_effect = g_strdup(first->getRepr()->attribute("inkscape:path-effect")); + style = first->getRepr()->attribute("style"); + path_effect = first->getRepr()->attribute("inkscape:path-effect"); //c->transform(item->transform); curve = c; } else { c->transform(item->getRelativeTransform(first)); curve->append(c, false); c->unref(); - } - // unless this is the topmost object, - if (item != first) { // reduce position only if the same parent if (item->getRepr()->parent() == parent) { position--; @@ -149,16 +146,14 @@ sp_selected_path_combine(SPDesktop *desktop) if (transform) { repr->setAttribute("transform", transform); } - repr->setAttribute("style", style); - g_free(style); + repr->setAttribute("style", style.c_str()); - repr->setAttribute("inkscape:path-effect", path_effect); - g_free(path_effect); + repr->setAttribute("inkscape:path-effect", path_effect.c_str()); // set path data corresponding to new curve gchar *dstring = sp_svg_write_path(curve->get_pathvector()); curve->unref(); - if (path_effect) { + if (!path_effect.empty()) { repr->setAttribute("inkscape:original-d", dstring); } else { repr->setAttribute("d", dstring); -- cgit v1.2.3 From ec202fae382ed65338732fc722e2eb902cd15d27 Mon Sep 17 00:00:00 2001 From: Markus Engel Date: Mon, 24 Mar 2014 21:44:06 +0100 Subject: Fix for in-class initialisation of double const value. (bzr r13201) --- src/display/nr-filter-turbulence.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/display/nr-filter-turbulence.cpp b/src/display/nr-filter-turbulence.cpp index e63b335d2..a2a8c5756 100644 --- a/src/display/nr-filter-turbulence.cpp +++ b/src/display/nr-filter-turbulence.cpp @@ -288,7 +288,7 @@ private: static double constexpr PerlinOffset = 4096.0; #else #if (__cplusplus < 201103L) - static double const PerlinOffset = 4096.0; + static double const PerlinOffset; #else static double constexpr PerlinOffset = 4096.0; #endif @@ -309,6 +309,10 @@ private: bool _fractalnoise; }; +#if !defined(CPP11) && __cplusplus < 201103L + double const TurbulenceGenerator::PerlinOffset = 4096.0; +#endif + FilterTurbulence::FilterTurbulence() : gen(new TurbulenceGenerator()) , XbaseFrequency(0) -- cgit v1.2.3 From 23eef073797d1dcca437e25a248be959c3b2d121 Mon Sep 17 00:00:00 2001 From: Markus Engel Date: Mon, 24 Mar 2014 21:54:07 +0100 Subject: Patch for base constructor calls. (bzr r13202) --- src/extension/error-file.cpp | 2 +- src/extension/prefdialog.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/extension/error-file.cpp b/src/extension/error-file.cpp index 5a8bede70..f60af870f 100644 --- a/src/extension/error-file.cpp +++ b/src/extension/error-file.cpp @@ -39,7 +39,7 @@ namespace Extension { probably good to check anyway). */ ErrorFileNotice::ErrorFileNotice (void) : - Gtk::MessageDialog::MessageDialog( + Gtk::MessageDialog( "", /* message */ false, /* use markup */ Gtk::MESSAGE_WARNING, /* dialog type */ diff --git a/src/extension/prefdialog.cpp b/src/extension/prefdialog.cpp index f3c6508af..1b657f644 100644 --- a/src/extension/prefdialog.cpp +++ b/src/extension/prefdialog.cpp @@ -42,9 +42,9 @@ namespace Extension { */ PrefDialog::PrefDialog (Glib::ustring name, gchar const * help, Gtk::Widget * controls, Effect * effect) : #if WITH_GTKMM_3_0 - Gtk::Dialog::Dialog(_(name.c_str()), true), + Gtk::Dialog(_(name.c_str()), true), #else - Gtk::Dialog::Dialog(_(name.c_str()), true, true), + Gtk::Dialog(_(name.c_str()), true, true), #endif _help(help), _name(name), -- cgit v1.2.3 From 53d32bfc98a277a724732a0bc9df27f0992db125 Mon Sep 17 00:00:00 2001 From: "Johan B. C. Engelen" Date: Mon, 24 Mar 2014 22:26:34 +0100 Subject: add convenience functions to deal with Glib::ustrings for setting repr attributes (bzr r13203) --- src/path-chemistry.cpp | 4 ++-- src/xml/node.h | 16 +++++++++++++++- 2 files changed, 17 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/path-chemistry.cpp b/src/path-chemistry.cpp index b613e6afa..22928ccdd 100644 --- a/src/path-chemistry.cpp +++ b/src/path-chemistry.cpp @@ -146,9 +146,9 @@ sp_selected_path_combine(SPDesktop *desktop) if (transform) { repr->setAttribute("transform", transform); } - repr->setAttribute("style", style.c_str()); + repr->setAttribute("style", style); - repr->setAttribute("inkscape:path-effect", path_effect.c_str()); + repr->setAttribute("inkscape:path-effect", path_effect); // set path data corresponding to new curve gchar *dstring = sp_svg_write_path(curve->get_pathvector()); diff --git a/src/xml/node.h b/src/xml/node.h index e83d8a7b7..a41e4e350 100644 --- a/src/xml/node.h +++ b/src/xml/node.h @@ -19,6 +19,7 @@ #define SEEN_INKSCAPE_XML_NODE_H #include +#include #include "gc-anchored.h" #include "util/list.h" @@ -194,6 +195,7 @@ public: */ virtual void setContent(gchar const *value)=0; + //@{ /** * @brief Change an attribute of this node * @@ -204,7 +206,19 @@ public: * @param is_interactive Ignored */ virtual void setAttribute(gchar const *key, gchar const *value, bool is_interactive=false)=0; - + + void setAttribute(gchar const *key, Glib::ustring const &value, bool is_interactive=false) + { + setAttribute(key, value.empty() ? NULL : value.c_str(), is_interactive); + } + + void setAttribute(Glib::ustring const &key, Glib::ustring const &value, bool is_interactive=false) + { + setAttribute( key.empty() ? NULL : key.c_str(), + value.empty() ? NULL : value.c_str(), is_interactive); + } + //@} + /** * @brief Directly set the integer GQuark code for the name of the node * -- cgit v1.2.3 From 55b428abbb6d6664a1922984ca395a4bda811714 Mon Sep 17 00:00:00 2001 From: "Johan B. C. Engelen" Date: Mon, 24 Mar 2014 23:48:55 +0100 Subject: fix tiny mistake (bzr r13204) --- src/xml/node.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/xml/node.h b/src/xml/node.h index a41e4e350..c1977b0a8 100644 --- a/src/xml/node.h +++ b/src/xml/node.h @@ -207,7 +207,7 @@ public: */ virtual void setAttribute(gchar const *key, gchar const *value, bool is_interactive=false)=0; - void setAttribute(gchar const *key, Glib::ustring const &value, bool is_interactive=false) + void setAttribute(char const *key, Glib::ustring const &value, bool is_interactive=false) { setAttribute(key, value.empty() ? NULL : value.c_str(), is_interactive); } -- cgit v1.2.3 From 19a740b9617ef96a571b6dce3cf5aec2bae2d47c Mon Sep 17 00:00:00 2001 From: "Johan B. C. Engelen" Date: Tue, 25 Mar 2014 00:20:13 +0100 Subject: fix memory allocation bug (thanks to clang's static analyzer scan-build) (bzr r13205) --- src/unicoderange.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/unicoderange.cpp b/src/unicoderange.cpp index 803e1a884..5a9c4b331 100644 --- a/src/unicoderange.cpp +++ b/src/unicoderange.cpp @@ -39,7 +39,7 @@ int UnicodeRange::add_range(gchar* val){ while(val[i]!='\0' && val[i]!='-' && val[i]!=' ' && val[i]!=','){ i++; } - r.start = (gchar*) malloc((i+1)*sizeof(gchar*)); + r.start = (gchar*) malloc((i+1)*sizeof(gchar)); strncpy(r.start, val, i); r.start[i] = '\0'; val+=i; @@ -48,7 +48,7 @@ int UnicodeRange::add_range(gchar* val){ if (val[0]=='-'){ val++; while(val[i]!='\0' && val[i]!='-' && val[i]!=' ' && val[i]!=',') i++; - r.end = (gchar*) malloc((i+1)*sizeof(gchar*)); + r.end = (gchar*) malloc((i+1)*sizeof(gchar)); strncpy(r.end, val, i); r.end[i] = '\0'; // val+=i; -- cgit v1.2.3 From 07e3de19f564cb21064e712351318cb4fe55c9e4 Mon Sep 17 00:00:00 2001 From: Markus Engel Date: Tue, 25 Mar 2014 01:15:25 +0100 Subject: Replaced a free() with g_free(). (bzr r13208) --- src/style.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/style.cpp b/src/style.cpp index c57cf6349..bc869b127 100644 --- a/src/style.cpp +++ b/src/style.cpp @@ -3677,7 +3677,7 @@ sp_style_read_itextdecoration(SPITextDecorationLine *line, SPITextDecorationStyl int slen = str - hstr; gchar *frag = g_strndup(hstr,slen+1); // only send one piece at a time, since keywords may be intermixed sp_style_read_itextdecorationColor(color, frag); - free(frag); + g_free(frag); if(color->set)break; if(*str == '\0')break; hstr = str + 1; -- cgit v1.2.3 From 3e3246729a56694574405f5d72307f536d05dcad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vin=C3=ADcius=20dos=20Santos=20Oliveira?= Date: Mon, 24 Mar 2014 22:34:31 -0300 Subject: Updating libdepixelize. This update is not focused on new features, but on stability. Bugs affecting weird image sizes (single line or single row images) were fixed. A bug on algorithm that could cause wrong result of heuristics on very rare images was also fixed. The correct behaviour required storing all votes before really doing any removal and this extra work made this step of the algorithm 328% slower on one sample image. If the old *_safe function was used, the slowdown could be decreased to 7.7% on the same sample image, but current focus on Inkscape timeline is stabilization, then I'll delay performance optimization to later. Also, the affected step is only responsible for 18% (on the maximum case) of the performance. The performance tests were done using new profiling code that is disabled by default and shouldn't impact stability. (bzr r13209) --- src/libdepixelize/kopftracer2011.cpp | 415 ++++++++++++++++++++-------- src/libdepixelize/kopftracer2011.h | 26 +- src/libdepixelize/priv/homogeneoussplines.h | 21 +- src/libdepixelize/priv/pixelgraph.h | 80 +++++- src/libdepixelize/priv/simplifiedvoronoi.h | 271 ++++++++++++++++-- 5 files changed, 655 insertions(+), 158 deletions(-) (limited to 'src') diff --git a/src/libdepixelize/kopftracer2011.cpp b/src/libdepixelize/kopftracer2011.cpp index ab31d05c3..e2f387c86 100644 --- a/src/libdepixelize/kopftracer2011.cpp +++ b/src/libdepixelize/kopftracer2011.cpp @@ -31,7 +31,6 @@ #include #endif -#include #include #include "kopftracer2011.h" #include "priv/colorspace.h" @@ -40,6 +39,11 @@ #include "priv/splines-kopf2011.h" #include "priv/iterator.h" +#ifdef LIBDEPIXELIZE_PROFILE_KOPF2011 +#include +#include +#endif // LIBDEPIXELIZE_PROFILE_KOPF2011 + namespace Tracer { namespace Heuristics { @@ -86,7 +90,95 @@ Splines Kopf2011::to_voronoi(const std::string &filename, Splines Kopf2011::to_voronoi(const Glib::RefPtr &buf, const Options &options) { +#ifdef LIBDEPIXELIZE_PROFILE_KOPF2011 + SimplifiedVoronoi voronoi + = _voronoi(buf, options); + + Glib::DateTime profiling_info[2]; + profiling_info[0] = Glib::DateTime::create_now_utc(); + + Splines ret(voronoi); + + profiling_info[1] = Glib::DateTime::create_now_utc(); + std::cerr << "Tracer::Splines construction time: " + << profiling_info[1].difference(profiling_info[0]) + << std::endl; + + return ret; +#else // LIBDEPIXELIZE_PROFILE_KOPF2011 return Splines(_voronoi(buf, options)); +#endif // LIBDEPIXELIZE_PROFILE_KOPF2011 +} + +Splines Kopf2011::to_grouped_voronoi(const std::string &filename, + const Options &options) +{ + return to_grouped_voronoi(Gdk::Pixbuf::create_from_file(filename), options); +} + +Splines Kopf2011::to_grouped_voronoi(const Glib::RefPtr &buf, + const Options &options) +{ +#ifdef LIBDEPIXELIZE_PROFILE_KOPF2011 + SimplifiedVoronoi voronoi + = _voronoi(buf, options); + + Glib::DateTime profiling_info[2]; + profiling_info[0] = Glib::DateTime::create_now_utc(); + + HomogeneousSplines splines(voronoi); + +#else // LIBDEPIXELIZE_PROFILE_KOPF2011 + HomogeneousSplines splines(_voronoi + (buf, options)); +#endif // LIBDEPIXELIZE_PROFILE_KOPF2011 + +#ifdef LIBDEPIXELIZE_PROFILE_KOPF2011 + profiling_info[1] = Glib::DateTime::create_now_utc(); + std::cerr << "Tracer::HomogeneousSplines<" << typeid(Precision).name() + << ">(Tracer::SimplifiedVoronoi<" << typeid(Precision).name() + << ",false>) construction time: " + << profiling_info[1].difference(profiling_info[0]) + << std::endl; + profiling_info[0] = Glib::DateTime::create_now_utc(); +#endif // LIBDEPIXELIZE_PROFILE_KOPF2011 + + for ( HomogeneousSplines::iterator it = splines.begin(), + end = splines.end() ; it != end ; ++it ) { + for ( HomogeneousSplines::Polygon::points_iter + it2 = it->vertices.begin(), end2 = it->vertices.end() + ; it2 != end2 ; ++it2 ) { + it2->smooth = false; + } + for ( HomogeneousSplines::Polygon::holes_iter + it2 = it->holes.begin(), end2 = it->holes.end() + ; it2 != end2 ; ++it2 ) { + for ( HomogeneousSplines::Polygon::points_iter + it3 = it2->begin(), end3 = it2->end() + ; it3 != end3 ; ++it3 ) { + it3->smooth = false; + } + } + } + +#ifdef LIBDEPIXELIZE_PROFILE_KOPF2011 + profiling_info[1] = Glib::DateTime::create_now_utc(); + std::cerr << "Tracer::Kopf2011::to_grouped_voronoi internal work time: " + << profiling_info[1].difference(profiling_info[0]) + << std::endl; + profiling_info[0] = Glib::DateTime::create_now_utc(); + + Splines ret(splines, false, options.nthreads); + + profiling_info[1] = Glib::DateTime::create_now_utc(); + std::cerr << "Tracer::Splines construction time: " + << profiling_info[1].difference(profiling_info[0]) + << std::endl; + + return ret; +#else // LIBDEPIXELIZE_PROFILE_KOPF2011 + return Splines(splines, false, options.nthreads); +#endif // LIBDEPIXELIZE_PROFILE_KOPF2011 } Splines Kopf2011::to_splines(const std::string &filename, @@ -98,9 +190,36 @@ Splines Kopf2011::to_splines(const std::string &filename, Splines Kopf2011::to_splines(const Glib::RefPtr &buf, const Options &options) { +#ifdef LIBDEPIXELIZE_PROFILE_KOPF2011 + SimplifiedVoronoi voronoi + = _voronoi(buf, options); + + Glib::DateTime profiling_info[2]; + profiling_info[0] = Glib::DateTime::create_now_utc(); + + HomogeneousSplines splines(voronoi); + + profiling_info[1] = Glib::DateTime::create_now_utc(); + std::cerr << "Tracer::HomogeneousSplines<" << typeid(Precision).name() + << "> construction time: " + << profiling_info[1].difference(profiling_info[0]) + << std::endl; + + profiling_info[0] = Glib::DateTime::create_now_utc(); + + Splines ret(splines, options.optimize, options.nthreads); + + profiling_info[1] = Glib::DateTime::create_now_utc(); + std::cerr << "Tracer::Splines construction time: " + << profiling_info[1].difference(profiling_info[0]) + << std::endl; + + return ret; +#else // LIBDEPIXELIZE_PROFILE_KOPF2011 HomogeneousSplines splines(_voronoi (buf, options)); return Splines(splines, options.optimize, options.nthreads); +#endif // LIBDEPIXELIZE_PROFILE_KOPF2011 } template @@ -108,47 +227,131 @@ SimplifiedVoronoi Kopf2011::_voronoi(const Glib::RefPtr &buf, const Options &options) { +#ifdef LIBDEPIXELIZE_PROFILE_KOPF2011 + Glib::DateTime profiling_info[2]; + profiling_info[0] = Glib::DateTime::create_now_utc(); +#endif // LIBDEPIXELIZE_PROFILE_KOPF2011 + PixelGraph graph(buf); - /*if ( !graph.width() || !graph.height() ) - return;*/ +#ifdef LIBDEPIXELIZE_PROFILE_KOPF2011 + profiling_info[1] = Glib::DateTime::create_now_utc(); + std::cerr << "Tracer::PixelGraph creation time: " + << profiling_info[1].difference(profiling_info[0]) << std::endl; +#endif // LIBDEPIXELIZE_PROFILE_KOPF2011 + + // gdk-pixbuf2 already checks if image size is meaningful, but asserts state + // preconditions and will be useful if gdk-pixbuf is replaced later + assert(graph.width() > 0); + assert(graph.height() > 0); #ifndef NDEBUG graph.checkConsistency(); #endif +#ifdef LIBDEPIXELIZE_PROFILE_KOPF2011 + profiling_info[0] = Glib::DateTime::create_now_utc(); +#endif // LIBDEPIXELIZE_PROFILE_KOPF2011 + // This step could be part of the initialization of PixelGraph // and decrease the necessary number of passes graph.connectAllNeighbors(); +#ifdef LIBDEPIXELIZE_PROFILE_KOPF2011 + profiling_info[1] = Glib::DateTime::create_now_utc(); + std::cerr << "Tracer::PixelGraph::connectAllNeighbors() time: " + << profiling_info[1].difference(profiling_info[0]) << std::endl; +#endif // LIBDEPIXELIZE_PROFILE_KOPF2011 + #ifndef NDEBUG graph.checkConsistency(); #endif +#ifdef LIBDEPIXELIZE_PROFILE_KOPF2011 + profiling_info[0] = Glib::DateTime::create_now_utc(); +#endif // LIBDEPIXELIZE_PROFILE_KOPF2011 + // This step can't be part of PixelGraph initilization without adding some // cache misses due to random access patterns that might be injected _disconnect_neighbors_with_dissimilar_colors(graph); +#ifdef LIBDEPIXELIZE_PROFILE_KOPF2011 + profiling_info[1] = Glib::DateTime::create_now_utc(); + std::cerr << "Tracer::Kopf2011::" + "_disconnect_neighbors_with_dissimilar_colors(Tracer::PixelGraph) time: " + << profiling_info[1].difference(profiling_info[0]) << std::endl; +#endif // LIBDEPIXELIZE_PROFILE_KOPF2011 + #ifndef NDEBUG graph.checkConsistency(); #endif - // This and below steps must be executed in separate. - // Otherwise, there will be colateral effects due to misassumption about the - // data being read. - _remove_crossing_edges_safe(graph); +#ifdef LIBDEPIXELIZE_PROFILE_KOPF2011 + profiling_info[0] = Glib::DateTime::create_now_utc(); +#endif // LIBDEPIXELIZE_PROFILE_KOPF2011 + + { + // edges_safe and edges_unsafe must be executed in separate. + // Otherwise, there will be colateral effects due to misassumption about + // the data being read. + PixelGraph::EdgePairContainer edges = graph.crossingEdges(); + +#ifdef LIBDEPIXELIZE_PROFILE_KOPF2011 + profiling_info[1] = Glib::DateTime::create_now_utc(); + std::cerr << "Tracer::PixelGraph::crossingEdges() time: " + << profiling_info[1].difference(profiling_info[0]) << std::endl; + profiling_info[0] = Glib::DateTime::create_now_utc(); +#endif // LIBDEPIXELIZE_PROFILE_KOPF2011 + + _remove_crossing_edges_safe(edges); + +#ifdef LIBDEPIXELIZE_PROFILE_KOPF2011 + profiling_info[1] = Glib::DateTime::create_now_utc(); + std::cerr << "Tracer::Kopf2011::_remove_crossing_edges_safe" + "(Tracer::PixelGraph) time: " + << profiling_info[1].difference(profiling_info[0]) + << std::endl; +#endif // LIBDEPIXELIZE_PROFILE_KOPF2011 #ifndef NDEBUG - graph.checkConsistency(); + graph.checkConsistency(); #endif - _remove_crossing_edges_unsafe(graph, options); +#ifdef LIBDEPIXELIZE_PROFILE_KOPF2011 + profiling_info[0] = Glib::DateTime::create_now_utc(); +#endif // LIBDEPIXELIZE_PROFILE_KOPF2011 + + _remove_crossing_edges_unsafe(graph, edges, options); + } + +#ifdef LIBDEPIXELIZE_PROFILE_KOPF2011 + profiling_info[1] = Glib::DateTime::create_now_utc(); + std::cerr << "Tracer::Kopf2011::_remove_crossing_edges_unsafe" + "(Tracer::PixelGraph) time: " + << profiling_info[1].difference(profiling_info[0]) << std::endl; +#endif // LIBDEPIXELIZE_PROFILE_KOPF2011 #ifndef NDEBUG graph.checkConsistency(); #endif + assert(graph.crossingEdges().size() == 0); + +#ifdef LIBDEPIXELIZE_PROFILE_KOPF2011 + profiling_info[0] = Glib::DateTime::create_now_utc(); + + SimplifiedVoronoi ret(graph); + + profiling_info[1] = Glib::DateTime::create_now_utc(); + std::cerr << "Tracer::SimplifiedVoronoi<" << typeid(T).name() << ',' + << (adjust_splines ? "true" : "false") + << ">(Tracer::PixelGraph) construction time: " + << profiling_info[1].difference(profiling_info[0]) << std::endl; + + return ret; +#else // LIBDEPIXELIZE_PROFILE_KOPF2011 return SimplifiedVoronoi(graph); +#endif // LIBDEPIXELIZE_PROFILE_KOPF2011 } // TODO: move this function (plus connectAllNeighbors) to PixelGraph constructor @@ -192,123 +395,115 @@ Kopf2011::_disconnect_neighbors_with_dissimilar_colors(PixelGraph &graph) * * In this case the two diagonal connections can be safely removed without * affecting the final result. - * - * \TODO: It should remember/cache who are the unsafe crossing edges? */ -inline void Kopf2011::_remove_crossing_edges_safe(PixelGraph &graph) +template +void Kopf2011::_remove_crossing_edges_safe(T &container) { - if ( graph.width() < 2 || graph.height() < 2 ) - return; - - PixelGraph::iterator it = graph.begin(); - for ( int i = 0 ; i != graph.height() - 1 ; ++i, ++it ) { - for ( int j = 0 ; j != graph.width() - 1 ; ++j, ++it ) { - // this <-> right - if ( !it->adj.right ) - continue; - - // this <-> down - if ( !it->adj.bottom ) - continue; - - PixelGraph::iterator down_right = it + graph.width() + 1; - - // down_right <-> right - if ( !down_right->adj.top ) - continue; + for ( typename T::reverse_iterator it = container.rbegin(), + end = container.rend() ; it != end ; ) { + /* A | B + --+-- + C | D */ + PixelGraph::iterator a = it->first.first; + PixelGraph::iterator b = it->second.first; + PixelGraph::iterator c = it->second.second; + PixelGraph::iterator d = it->first.second; + + if ( !a->adj.right || !a->adj.bottom || !b->adj.bottom + || !c->adj.right ) { + ++it; + continue; + } - // down_right <-> down - if ( !down_right->adj.left ) - continue; + // main diagonal + a->adj.bottomright = 0; + d->adj.topleft = 0; - // main diagonal - // this <-> down_right - it->adj.bottomright = 0; - down_right->adj.topleft = 0; + // secondary diagonal + b->adj.bottomleft = 0; + c->adj.topright = 0; - // secondary diagonal - // right <-> down - (it + 1)->adj.bottomleft = 0; - (it + graph.width())->adj.topright = 0; - } + // base iterator is always past one + typename T::iterator current = --(it.base()); + ++it; + container.erase(current); } } /** * This method removes crossing edges using the heuristics. */ -inline -void Kopf2011::_remove_crossing_edges_unsafe(PixelGraph &graph, +template +void Kopf2011::_remove_crossing_edges_unsafe(PixelGraph &graph, T &edges, const Options &options) { - if ( graph.width() < 2 || graph.height() < 2 ) - return; - - // Iterate over the graph, 2x2 blocks at time - PixelGraph::iterator it = graph.begin(); - for (int i = 0 ; i != graph.height() - 1 ; ++i, ++it ) { - for ( int j = 0 ; j != graph.width() - 1 ; ++j, ++it ) { - using std::pair; - using std::make_pair; - - typedef pair Edge; - typedef pair EdgeWeight; - - EdgeWeight diagonals[2] = { - make_pair(make_pair(it, graph.nodeBottomRight(it)), 0), - make_pair(make_pair(graph.nodeRight(it), graph.nodeBottom(it)), - 0) - }; - - // Check if there are crossing edges - if ( !diagonals[0].first.first->adj.bottomright - || !diagonals[1].first.first->adj.bottomleft ) { - continue; - } - - // Compute weights - for ( int i = 0 ; i != 2 ; ++i ) { - // Curves and islands heuristics - PixelGraph::const_iterator a = diagonals[i].first.first; - PixelGraph::const_iterator b = diagonals[i].first.second; - - diagonals[i].second += Heuristics::curves(graph, a, b) - * options.curvesMultiplier; - - diagonals[i].second += Heuristics::islands(a, b) - * options.islandsWeight; - } - - { - // Sparse pixels heuristic - Heuristics::SparsePixels sparse_pixels; - - for ( int i = 0 ; i != 2 ; ++i ) - sparse_pixels.diagonals[i] = diagonals[i]; - - sparse_pixels(graph, options.sparsePixelsRadius); - - for ( int i = 0 ; i != 2 ; ++i ) { - diagonals[i].second += sparse_pixels.diagonals[i].second - * options.sparsePixelsMultiplier; - } - } + std::vector< std::pair > weights(edges.size(), + std::make_pair(0, 0)); + + // Compute weights + for ( typename T::size_type i = 0 ; i != edges.size() ; ++i ) { + /* A | B + --+-- + C | D */ + PixelGraph::iterator a = edges[i].first.first; + PixelGraph::iterator b = edges[i].second.first; + PixelGraph::iterator c = edges[i].second.second; + PixelGraph::iterator d = edges[i].first.second; + + // Curves heuristic + weights[i].first += Heuristics::curves(graph, a, d) + * options.curvesMultiplier; + weights[i].second += Heuristics::curves(graph, b, c) + * options.curvesMultiplier; + + // Islands heuristic + weights[i].first += Heuristics::islands(a, d) * options.islandsWeight; + weights[i].second += Heuristics::islands(b, c) * options.islandsWeight; + + // Sparse pixels heuristic + using Heuristics::SparsePixels; + SparsePixels sparse_pixels; + + sparse_pixels.diagonals[SparsePixels::MAIN_DIAGONAL].first + = edges[i].first; + sparse_pixels.diagonals[SparsePixels::SECONDARY_DIAGONAL].first + = edges[i].second; + + sparse_pixels(graph, options.sparsePixelsRadius); + + weights[i].first + += sparse_pixels.diagonals[SparsePixels::MAIN_DIAGONAL].second + * options.sparsePixelsMultiplier; + weights[i].second + += sparse_pixels.diagonals[SparsePixels::SECONDARY_DIAGONAL].second + * options.sparsePixelsMultiplier; + } - // Remove edges with lower weight - if ( diagonals[0].second > diagonals[1].second ) { - diagonals[1].first.first->adj.bottomleft = 0; - diagonals[1].first.second->adj.topright = 0; - } else if ( diagonals[0].second < diagonals[1].second ) { - diagonals[0].first.first->adj.bottomright = 0; - diagonals[0].first.second->adj.topleft = 0; - } else { - diagonals[0].first.first->adj.bottomright = 0; - diagonals[0].first.second->adj.topleft = 0; - diagonals[1].first.first->adj.bottomleft = 0; - diagonals[1].first.second->adj.topright = 0; - } + // Remove edges with lower weight + for ( typename T::size_type i = 0 ; i != edges.size() ; ++i ) { + /* A | B + --+-- + C | D */ + PixelGraph::iterator a = edges[i].first.first; + PixelGraph::iterator b = edges[i].second.first; + PixelGraph::iterator c = edges[i].second.second; + PixelGraph::iterator d = edges[i].first.second; + + if ( weights[i].first > weights[i].second ) { + b->adj.bottomleft = 0; + c->adj.topright = 0; + } else if ( weights[i].first < weights[i].second ) { + a->adj.bottomright = 0; + d->adj.topleft = 0; + } else { + a->adj.bottomright = 0; + b->adj.bottomleft = 0; + c->adj.topright = 0; + d->adj.topleft = 0; } } + + edges.clear(); } inline int Heuristics::curves(const PixelGraph &graph, diff --git a/src/libdepixelize/kopftracer2011.h b/src/libdepixelize/kopftracer2011.h index c224abe9a..598f6c79c 100644 --- a/src/libdepixelize/kopftracer2011.h +++ b/src/libdepixelize/kopftracer2011.h @@ -85,6 +85,23 @@ public: static Splines to_voronoi(const Glib::RefPtr &buf, const Options &options = Options()); + /** + * # Exceptions + * + * \p options.optimize and options.nthreads will be ignored + * + * Glib::FileError + * Gdk::PixbufError + */ + static Splines to_grouped_voronoi(const std::string &filename, + const Options &options = Options()); + + /* + * \p options.optimize and options.nthreads will be ignored + */ + static Splines to_grouped_voronoi(const Glib::RefPtr &buf, + const Options &options = Options()); + /** * # Exceptions * @@ -106,8 +123,13 @@ private: const Options &options); static void _disconnect_neighbors_with_dissimilar_colors(PixelGraph &graph); - static void _remove_crossing_edges_safe(PixelGraph &graph); - static void _remove_crossing_edges_unsafe(PixelGraph &graph, + + // here, T/template is only used as an easy way to not expose internal + // symbols + template + static void _remove_crossing_edges_safe(T &container); + template + static void _remove_crossing_edges_unsafe(PixelGraph &graph, T &edges, const Options &options); }; diff --git a/src/libdepixelize/priv/homogeneoussplines.h b/src/libdepixelize/priv/homogeneoussplines.h index 57c77a163..6c4894dd8 100644 --- a/src/libdepixelize/priv/homogeneoussplines.h +++ b/src/libdepixelize/priv/homogeneoussplines.h @@ -38,6 +38,12 @@ class HomogeneousSplines public: struct Polygon { + typedef std::vector< Point > Points; + typedef typename Points::iterator points_iter; + typedef typename Points::const_iterator const_points_iter; + typedef typename std::vector::iterator holes_iter; + typedef typename std::vector::const_iterator const_holes_iter; + Polygon() {} Polygon(const guint8 (&rgba)[4]) { @@ -59,7 +65,8 @@ public: typedef typename std::vector::const_iterator const_iterator; typedef typename std::vector::size_type size_type; - HomogeneousSplines(const SimplifiedVoronoi &voronoi); + template + HomogeneousSplines(const SimplifiedVoronoi &voronoi); // Iterators iterator begin() @@ -98,12 +105,7 @@ public: } private: - typedef typename SimplifiedVoronoi::Cell Cell; typedef std::vector< Point > Points; - - typedef typename SimplifiedVoronoi::iterator voronoi_iter; - typedef typename SimplifiedVoronoi::const_iterator voronoi_citer; - typedef typename Points::iterator points_iter; typedef typename Points::const_iterator points_citer; typedef typename Points::reverse_iterator points_riter; @@ -171,7 +173,9 @@ private: }; template -HomogeneousSplines::HomogeneousSplines(const SimplifiedVoronoi &voronoi) : +template +HomogeneousSplines::HomogeneousSplines(const SimplifiedVoronoi &voronoi) : _width(voronoi.width()), _height(voronoi.height()) { @@ -179,6 +183,9 @@ HomogeneousSplines::HomogeneousSplines(const SimplifiedVoronoi &voronoi) : // return; using colorspace::same_color; + typedef typename SimplifiedVoronoi::const_iterator + voronoi_citer; + // Identify visible edges (group polygons with the same color) for ( voronoi_citer cell_it = voronoi.begin(), cell_end = voronoi.end() ; cell_it != cell_end ; ++cell_it ) { diff --git a/src/libdepixelize/priv/pixelgraph.h b/src/libdepixelize/priv/pixelgraph.h index 9e8c2124a..112242647 100644 --- a/src/libdepixelize/priv/pixelgraph.h +++ b/src/libdepixelize/priv/pixelgraph.h @@ -28,6 +28,7 @@ #include #include #include +#include namespace Tracer { @@ -76,6 +77,10 @@ public: typedef std::vector::reverse_iterator reverse_iterator; typedef std::vector::const_reverse_iterator const_reverse_iterator; + typedef std::pair Edge; + typedef std::pair EdgePair; + typedef std::vector EdgePairContainer; + class ColumnView { public: @@ -162,6 +167,7 @@ public: // Algorithms void connectAllNeighbors(); + EdgePairContainer crossingEdges(); int toX(const_iterator n) const { @@ -389,14 +395,23 @@ inline void PixelGraph::connectAllNeighbors() // ...then the "top" nodes... if ( _width > 2 ) { Node *it = &_nodes[1]; - for ( int i = 1 ; i != _width - 1 ; ++i ) { - it->adj.right = 1; - it->adj.bottomright = 1; - it->adj.bottom = 1; - it->adj.bottomleft = 1; - it->adj.left = 1; + if ( _height > 1 ) { + for ( int i = 1 ; i != _width - 1 ; ++i ) { + it->adj.right = 1; + it->adj.bottomright = 1; + it->adj.bottom = 1; + it->adj.bottomleft = 1; + it->adj.left = 1; - ++it; + ++it; + } + } else { + for ( int i = 1 ; i != _width - 1 ; ++i ) { + it->adj.right = 1; + it->adj.left = 1; + + ++it; + } } } @@ -417,14 +432,23 @@ inline void PixelGraph::connectAllNeighbors() // ...then the "left" nodes... if ( _height > 2 ) { iterator it = nodeBottom(begin()); // [0][1] - for ( int i = 1 ; i != _height - 1 ; ++i ) { - it->adj.top = 1; - it->adj.topright = 1; - it->adj.right = 1; - it->adj.bottomright = 1; - it->adj.bottom = 1; + if ( _width > 1 ) { + for ( int i = 1 ; i != _height - 1 ; ++i ) { + it->adj.top = 1; + it->adj.topright = 1; + it->adj.right = 1; + it->adj.bottomright = 1; + it->adj.bottom = 1; - it = nodeBottom(it); + it = nodeBottom(it); + } + } else { + for ( int i = 1 ; i != _height - 1 ; ++i ) { + it->adj.top = 1; + it->adj.bottom = 1; + + it = nodeBottom(it); + } } } @@ -482,6 +506,34 @@ inline void PixelGraph::connectAllNeighbors() } } +PixelGraph::EdgePairContainer PixelGraph::crossingEdges() +{ + EdgePairContainer ret; + + if ( width() < 2 || height() < 2 ) + return ret; + + // Iterate over the graph, 2x2 blocks at time + PixelGraph::iterator it = begin(); + for (int i = 0 ; i != height() - 1 ; ++i, ++it ) { + for ( int j = 0 ; j != width() - 1 ; ++j, ++it ) { + EdgePair diagonals( + Edge(it, nodeBottomRight(it)), + Edge(nodeRight(it), nodeBottom(it))); + + // Check if there are crossing edges + if ( !diagonals.first.first->adj.bottomright + || !diagonals.second.first->adj.bottomleft ) { + continue; + } + + ret.push_back(diagonals); + } + } + + return ret; +} + inline PixelGraph::Node &PixelGraph::ColumnView::operator[](int line) { return _nodes[line * _width + _column]; diff --git a/src/libdepixelize/priv/simplifiedvoronoi.h b/src/libdepixelize/priv/simplifiedvoronoi.h index 8a25bc626..84feab08d 100644 --- a/src/libdepixelize/priv/simplifiedvoronoi.h +++ b/src/libdepixelize/priv/simplifiedvoronoi.h @@ -296,21 +296,40 @@ SimplifiedVoronoi PixelGraph::const_iterator graph_it = graph.begin() + 1; Cell *cells_it = &_cells.front() + 1; - for ( int i = 1 ; i != _width - 1 ; ++i, ++graph_it, ++cells_it ) { - for ( int j = 0 ; j != 4 ; ++j ) - cells_it->rgba[j] = graph_it->rgba[j]; + if ( _height > 1 ) { + for ( int i = 1 ; i != _width - 1 ; ++i, ++graph_it, ++cells_it ) { + for ( int j = 0 ; j != 4 ; ++j ) + cells_it->rgba[j] = graph_it->rgba[j]; - // Top-left - cells_it->vertices.push_back(Point(i, 0, false)); + // Top-left + cells_it->vertices.push_back(Point(i, 0, false)); - // Top-right - cells_it->vertices.push_back(Point(i + 1, 0, false)); + // Top-right + cells_it->vertices.push_back(Point(i + 1, 0, false)); - // Bottom-right - _complexBottomRight(graph, graph_it, cells_it, i, 0); + // Bottom-right + _complexBottomRight(graph, graph_it, cells_it, i, 0); - // Bottom-left - _complexBottomLeft(graph, graph_it, cells_it, i, 0); + // Bottom-left + _complexBottomLeft(graph, graph_it, cells_it, i, 0); + } + } else { + for ( int i = 1 ; i != _width - 1 ; ++i, ++graph_it, ++cells_it ) { + for ( int j = 0 ; j != 4 ; ++j ) + cells_it->rgba[j] = graph_it->rgba[j]; + + // Top-left + cells_it->vertices.push_back(Point(i, 0, false)); + + // Top-right + cells_it->vertices.push_back(Point(i + 1, 0, false)); + + // Bottom-right + cells_it->vertices.push_back(Point(i + 1, 1, false)); + + // Bottom-left + cells_it->vertices.push_back(Point(i, 1, false)); + } } } @@ -344,24 +363,46 @@ SimplifiedVoronoi PixelGraph::const_iterator graph_it = graph.begin() + _width; Cell *cells_it = &_cells.front() + _width; - for ( int i = 1 ; i != _height - 1 ; ++i) { - for ( int j = 0 ; j != 4 ; ++j ) - cells_it->rgba[j] = graph_it->rgba[j]; + if ( _width > 1 ) { + for ( int i = 1 ; i != _height - 1 ; ++i) { + for ( int j = 0 ; j != 4 ; ++j ) + cells_it->rgba[j] = graph_it->rgba[j]; - // Top-left - cells_it->vertices.push_back(Point(0, i, false)); + // Top-left + cells_it->vertices.push_back(Point(0, i, false)); - // Top-right - _complexTopRight(graph, graph_it, cells_it, 0, i); + // Top-right + _complexTopRight(graph, graph_it, cells_it, 0, i); - // Bottom-right - _complexBottomRight(graph, graph_it, cells_it, 0, i); + // Bottom-right + _complexBottomRight(graph, graph_it, cells_it, 0, i); - // Bottom-left - cells_it->vertices.push_back(Point(0, i + 1, false)); + // Bottom-left + cells_it->vertices.push_back(Point(0, i + 1, false)); - graph_it += _width; - cells_it += _width; + graph_it += _width; + cells_it += _width; + } + } else { + for ( int i = 1 ; i != _height - 1 ; ++i) { + for ( int j = 0 ; j != 4 ; ++j ) + cells_it->rgba[j] = graph_it->rgba[j]; + + // Top-left + cells_it->vertices.push_back(Point(0, i, false)); + + // Top-right + cells_it->vertices.push_back(Point(1, i, false)); + + // Bottom-right + cells_it->vertices.push_back(Point(1, i, false)); + + // Bottom-left + cells_it->vertices.push_back(Point(0, i + 1, false)); + + graph_it += _width; + cells_it += _width; + } } } @@ -890,7 +931,11 @@ SimplifiedVoronoi } if ( !smooth[0] && adjust_splines ) { - cells_it->vertices.push_back(vertices[0].invisible()); +#ifdef LIBDEPIXELIZE_ENABLE_EXPERIMENTAL_FEATURES_1ST_IS_INVISIBLE + cells_it->vertices.push_back(vertices[0].invisible()); +#else + cells_it->vertices.push_back(vertices[0]); +#endif { Point another = vertices[0]; transform(another, @@ -899,7 +944,11 @@ SimplifiedVoronoi // y - ( 0.5625 - ( topright(a_it) + topleft(b_it) ) * 0.1875 )); +#ifdef LIBDEPIXELIZE_ENABLE_EXPERIMENTAL_FEATURES_2ND_IS_INVISIBLE cells_it->vertices.push_back(another.invisible()); +#else + cells_it->vertices.push_back(another); +#endif } { Point another = vertices[0]; @@ -910,7 +959,11 @@ SimplifiedVoronoi - ( 0.1875 - ( topright(a_it) + topleft(b_it) ) * 0.0625) ); another.smooth = true; +#ifdef LIBDEPIXELIZE_ENABLE_EXPERIMENTAL_FEATURES_3RD_IS_INVISIBLE + cells_it->vertices.push_back(another.invisible()); +#else cells_it->vertices.push_back(another); +#endif } { Point another = vertices[0]; @@ -920,7 +973,11 @@ SimplifiedVoronoi // y 0.0625 + ( bottomright(b_it) - topright(d_it) ) * 0.0625); +#ifdef LIBDEPIXELIZE_ENABLE_EXPERIMENTAL_FEATURES_4TH_IS_INVISIBLE cells_it->vertices.push_back(another.invisible()); +#else + cells_it->vertices.push_back(another); +#endif } { transform(vertices[0], @@ -932,7 +989,9 @@ SimplifiedVoronoi + ( topright(d_it) - topright(a_it) - topleft(b_it) - bottomright(b_it) ) * 0.03125 )); +#ifdef LIBDEPIXELIZE_ENABLE_EXPERIMENTAL_FEATURES_5TH_IS_INVISIBLE vertices[0].visible = false; +#endif } } @@ -950,7 +1009,11 @@ SimplifiedVoronoi 0.0625 + ( bottomleft(a_it) - bottomleft(d_it) - topleft(c_it) - bottomright(c_it) ) * 0.03125); +#ifdef LIBDEPIXELIZE_ENABLE_EXPERIMENTAL_FEATURES_1ST_IS_INVISIBLE cells_it->vertices.push_back(another.invisible()); +#else + cells_it->vertices.push_back(another); +#endif } { Point another = vertices[1]; @@ -960,7 +1023,11 @@ SimplifiedVoronoi // y 0.1875 - ( bottomright(c_it) + bottomleft(d_it) ) * 0.0625); +#ifdef LIBDEPIXELIZE_ENABLE_EXPERIMENTAL_FEATURES_2ND_IS_INVISIBLE cells_it->vertices.push_back(another.invisible()); +#else + cells_it->vertices.push_back(another); +#endif } { Point another = vertices[1]; @@ -973,7 +1040,11 @@ SimplifiedVoronoi - ( bottomleft(a_it) - topleft(c_it) ) * 0.0625 )); another.smooth = true; +#ifdef LIBDEPIXELIZE_ENABLE_EXPERIMENTAL_FEATURES_3RD_IS_INVISIBLE + cells_it->vertices.push_back(another.invisible()); +#else cells_it->vertices.push_back(another); +#endif } { Point another = vertices[1]; @@ -985,9 +1056,15 @@ SimplifiedVoronoi - ( 0.1875 - ( bottomleft(a_it) - topleft(c_it) ) * 0.1875 )); +#ifdef LIBDEPIXELIZE_ENABLE_EXPERIMENTAL_FEATURES_4TH_IS_INVISIBLE cells_it->vertices.push_back(another.invisible()); +#else + cells_it->vertices.push_back(another); +#endif } +#ifdef LIBDEPIXELIZE_ENABLE_EXPERIMENTAL_FEATURES_5TH_IS_INVISIBLE vertices[1].visible = false; +#endif } cells_it->vertices.push_back(vertices[1]); @@ -1029,13 +1106,21 @@ SimplifiedVoronoi - ( ( bottomright(c_it) + topleft(c_it) ) * 0.03125 ); transform(another, - amount, amount); +#ifdef LIBDEPIXELIZE_ENABLE_EXPERIMENTAL_FEATURES_1ST_IS_INVISIBLE cells_it->vertices.push_back(another.invisible()); +#else + cells_it->vertices.push_back(another); +#endif } { Point another = vertex; T amount = 0.0625 * bottomright(c_it); transform(another, amount, 0.25 - amount); +#ifdef LIBDEPIXELIZE_ENABLE_EXPERIMENTAL_FEATURES_2ND_IS_INVISIBLE cells_it->vertices.push_back(another.invisible()); +#else + cells_it->vertices.push_back(another); +#endif } { Point another = vertex; @@ -1043,16 +1128,26 @@ SimplifiedVoronoi transform(another, - ( 0.25 - amount ), - amount); another.smooth = true; +#ifdef LIBDEPIXELIZE_ENABLE_EXPERIMENTAL_FEATURES_3RD_IS_INVISIBLE + cells_it->vertices.push_back(another.invisible()); +#else cells_it->vertices.push_back(another); +#endif } { Point another = vertex; T amount = 0.1875 * topleft(c_it); transform(another, - ( 0.75 - amount ), - amount); +#ifdef LIBDEPIXELIZE_ENABLE_EXPERIMENTAL_FEATURES_4TH_IS_INVISIBLE cells_it->vertices.push_back(another.invisible()); +#else + cells_it->vertices.push_back(another); +#endif } +#ifdef LIBDEPIXELIZE_ENABLE_EXPERIMENTAL_FEATURES_5TH_IS_INVISIBLE vertex.visible = false; +#endif } else if ( twin_is_contour ) { T amount = 0.125 - ( ( bottomleft(d_it) + topright(d_it) ) @@ -1076,7 +1171,11 @@ SimplifiedVoronoi - amount * ( topleft(c_it) + topright(d_it) - bottomleft(a_it) - bottomright(b_it) )); +#ifdef LIBDEPIXELIZE_ENABLE_EXPERIMENTAL_FEATURES_1ST_IS_INVISIBLE cells_it->vertices.push_back(another.invisible()); +#else + cells_it->vertices.push_back(another); +#endif } { Point another = vertex; @@ -1087,7 +1186,11 @@ SimplifiedVoronoi // y - amount * ( topright(d_it) - bottomright(b_it) )); +#ifdef LIBDEPIXELIZE_ENABLE_EXPERIMENTAL_FEATURES_2ND_IS_INVISIBLE cells_it->vertices.push_back(another.invisible()); +#else + cells_it->vertices.push_back(another); +#endif } { Point another = vertex; @@ -1099,7 +1202,11 @@ SimplifiedVoronoi - amount * ( topleft(c_it) - bottomleft(a_it) )); another.smooth = true; +#ifdef LIBDEPIXELIZE_ENABLE_EXPERIMENTAL_FEATURES_3RD_IS_INVISIBLE + cells_it->vertices.push_back(another.invisible()); +#else cells_it->vertices.push_back(another); +#endif } { Point another = vertex; @@ -1110,9 +1217,15 @@ SimplifiedVoronoi // y - amount * ( topleft(c_it) - bottomleft(a_it) )); +#ifdef LIBDEPIXELIZE_ENABLE_EXPERIMENTAL_FEATURES_4TH_IS_INVISIBLE cells_it->vertices.push_back(another.invisible()); +#else + cells_it->vertices.push_back(another); +#endif } +#ifdef LIBDEPIXELIZE_ENABLE_EXPERIMENTAL_FEATURES_5TH_IS_INVISIBLE vertex.visible = false; +#endif } } else { // {this, right} is the pair with the angle @@ -1146,13 +1259,21 @@ SimplifiedVoronoi if ( !vertex.smooth ) { if ( another_is_contour ) { +#ifdef LIBDEPIXELIZE_ENABLE_EXPERIMENTAL_FEATURES_1ST_IS_INVISIBLE cells_it->vertices.push_back(vertex.invisible()); +#else + cells_it->vertices.push_back(vertex); +#endif { Point another = vertex; T amount = 0.1875 * topleft(b_it); transform(another, - amount, - ( 0.75 - amount )); +#ifdef LIBDEPIXELIZE_ENABLE_EXPERIMENTAL_FEATURES_2ND_IS_INVISIBLE cells_it->vertices.push_back(another.invisible()); +#else + cells_it->vertices.push_back(another); +#endif } { Point another = vertex; @@ -1160,20 +1281,30 @@ SimplifiedVoronoi transform(another, - amount, - ( 0.25 - amount )); another.smooth = true; +#ifdef LIBDEPIXELIZE_ENABLE_EXPERIMENTAL_FEATURES_3RD_IS_INVISIBLE + cells_it->vertices.push_back(another.invisible()); +#else cells_it->vertices.push_back(another); +#endif } { Point another = vertex; T amount = 0.0625 * bottomright(b_it); transform(another, 0.25 - amount, amount); +#ifdef LIBDEPIXELIZE_ENABLE_EXPERIMENTAL_FEATURES_4TH_IS_INVISIBLE cells_it->vertices.push_back(another.invisible()); +#else + cells_it->vertices.push_back(another); +#endif } { T amount = 0.125 - (bottomright(b_it) + topleft(b_it)) * 0.03125; transform(vertex, amount, - amount); +#ifdef LIBDEPIXELIZE_ENABLE_EXPERIMENTAL_FEATURES_5TH_IS_INVISIBLE vertex.visible = false; +#endif } } else if ( twin_is_contour ) { T amount = 0.125 @@ -1187,7 +1318,11 @@ SimplifiedVoronoi // I REALLY NEED lambdas to improve this code without // creating yet another interface that takes a million // of function parameters and keep code locality +#ifdef LIBDEPIXELIZE_ENABLE_EXPERIMENTAL_FEATURES_1ST_IS_INVISIBLE cells_it->vertices.push_back(vertex.invisible()); +#else + cells_it->vertices.push_back(vertex); +#endif { Point another = vertex; T amount = 0.1875; @@ -1197,7 +1332,11 @@ SimplifiedVoronoi - ( 0.75 - ( topleft(b_it) + topright(a_it) ) * amount )); +#ifdef LIBDEPIXELIZE_ENABLE_EXPERIMENTAL_FEATURES_2ND_IS_INVISIBLE cells_it->vertices.push_back(another.invisible()); +#else + cells_it->vertices.push_back(another); +#endif } { Point another = vertex; @@ -1209,7 +1348,11 @@ SimplifiedVoronoi - ( topleft(b_it) + topright(a_it) ) * amount )); another.smooth = true; +#ifdef LIBDEPIXELIZE_ENABLE_EXPERIMENTAL_FEATURES_3RD_IS_INVISIBLE + cells_it->vertices.push_back(another.invisible()); +#else cells_it->vertices.push_back(another); +#endif } { Point another = vertex; @@ -1219,7 +1362,11 @@ SimplifiedVoronoi // y 0.25 - amount * ( bottomleft(d_it) + bottomright(c_it) )); +#ifdef LIBDEPIXELIZE_ENABLE_EXPERIMENTAL_FEATURES_4TH_IS_INVISIBLE cells_it->vertices.push_back(another.invisible()); +#else + cells_it->vertices.push_back(another); +#endif } { transform(vertex, @@ -1230,7 +1377,9 @@ SimplifiedVoronoi ( topleft(b_it) - bottomleft(d_it) + topright(a_it) - bottomright(c_it) ) * 0.03125); +#ifdef LIBDEPIXELIZE_ENABLE_EXPERIMENTAL_FEATURES_5TH_IS_INVISIBLE vertex.visible = false; +#endif } } } else { @@ -1273,28 +1422,46 @@ SimplifiedVoronoi - ( topleft(c_it) + bottomright(c_it) ) * 0.03125; transform(another, - amount, amount); +#ifdef LIBDEPIXELIZE_ENABLE_EXPERIMENTAL_FEATURES_1ST_IS_INVISIBLE cells_it->vertices.push_back(another.invisible()); +#else + cells_it->vertices.push_back(another); +#endif } { Point another = vertex; T amount = 0.0625 * bottomright(c_it); transform(another, amount, 0.25 - amount); +#ifdef LIBDEPIXELIZE_ENABLE_EXPERIMENTAL_FEATURES_2ND_IS_INVISIBLE cells_it->vertices.push_back(another.invisible()); +#else + cells_it->vertices.push_back(another); +#endif } { Point another = vertex; T amount = 0.0625 * topleft(c_it); transform(another, - ( 0.25 - amount ), - amount); another.smooth = true; +#ifdef LIBDEPIXELIZE_ENABLE_EXPERIMENTAL_FEATURES_3RD_IS_INVISIBLE + cells_it->vertices.push_back(another.invisible()); +#else cells_it->vertices.push_back(another); +#endif } { Point another = vertex; T amount = 0.1875 * topleft(c_it); transform(another, - ( 0.75 - amount ), - amount); +#ifdef LIBDEPIXELIZE_ENABLE_EXPERIMENTAL_FEATURES_4TH_IS_INVISIBLE cells_it->vertices.push_back(another.invisible()); +#else + cells_it->vertices.push_back(another); +#endif } +#ifdef LIBDEPIXELIZE_ENABLE_EXPERIMENTAL_FEATURES_5TH_IS_INVISIBLE vertex.visible = false; +#endif } else { special = true; } @@ -1308,7 +1475,11 @@ SimplifiedVoronoi } if ( special ) { +#ifdef LIBDEPIXELIZE_ENABLE_EXPERIMENTAL_FEATURES_1ST_IS_INVISIBLE cells_it->vertices.push_back(vertex.invisible()); +#else + cells_it->vertices.push_back(vertex); +#endif { Point another = vertex; T amount = 0.1875; @@ -1318,7 +1489,11 @@ SimplifiedVoronoi - ( 0.75 - ( topleft(b_it) + topright(a_it) ) * amount )); +#ifdef LIBDEPIXELIZE_ENABLE_EXPERIMENTAL_FEATURES_2ND_IS_INVISIBLE cells_it->vertices.push_back(another.invisible()); +#else + cells_it->vertices.push_back(another); +#endif } { Point another = vertex; @@ -1330,7 +1505,11 @@ SimplifiedVoronoi - ( topleft(b_it) + topright(a_it) ) * amount )); another.smooth = true; +#ifdef LIBDEPIXELIZE_ENABLE_EXPERIMENTAL_FEATURES_3RD_IS_INVISIBLE + cells_it->vertices.push_back(another.invisible()); +#else cells_it->vertices.push_back(another); +#endif } { Point another = vertex; @@ -1340,7 +1519,11 @@ SimplifiedVoronoi // y 0.25 - amount * ( bottomleft(d_it) + bottomright(c_it) )); +#ifdef LIBDEPIXELIZE_ENABLE_EXPERIMENTAL_FEATURES_4TH_IS_INVISIBLE cells_it->vertices.push_back(another.invisible()); +#else + cells_it->vertices.push_back(another); +#endif } { transform(vertex, @@ -1351,7 +1534,9 @@ SimplifiedVoronoi ( topleft(b_it) - bottomleft(d_it) + topright(a_it) - bottomright(c_it) ) * 0.03125); +#ifdef LIBDEPIXELIZE_ENABLE_EXPERIMENTAL_FEATURES_5TH_IS_INVISIBLE vertex.visible = false; +#endif } } } else if ( right(c_it) && adjust_splines ) { @@ -1372,31 +1557,49 @@ SimplifiedVoronoi if ( !vertex.smooth ) { if ( similar_neighbor_is_contour ) { +#ifdef LIBDEPIXELIZE_ENABLE_EXPERIMENTAL_FEATURES_1ST_IS_INVISIBLE cells_it->vertices.push_back(vertex.invisible()); +#else + cells_it->vertices.push_back(vertex); +#endif { Point another = vertex; T amount = 0.1875 * topleft(b_it); transform(another, - amount, - ( 0.75 - amount )); +#ifdef LIBDEPIXELIZE_ENABLE_EXPERIMENTAL_FEATURES_2ND_IS_INVISIBLE cells_it->vertices.push_back(another.invisible()); +#else + cells_it->vertices.push_back(another); +#endif } { Point another = vertex; T amount = 0.0625 * topleft(b_it); transform(another, - amount, - ( 0.25 - amount )); another.smooth = true; +#ifdef LIBDEPIXELIZE_ENABLE_EXPERIMENTAL_FEATURES_3RD_IS_INVISIBLE + cells_it->vertices.push_back(another.invisible()); +#else cells_it->vertices.push_back(another); +#endif } { Point another = vertex; T amount = 0.0625 * bottomright(b_it); transform(another, 0.25 - amount, amount); +#ifdef LIBDEPIXELIZE_ENABLE_EXPERIMENTAL_FEATURES_4TH_IS_INVISIBLE cells_it->vertices.push_back(another.invisible()); +#else + cells_it->vertices.push_back(another); +#endif } { T amount = 0.125 - 0.03125 * (topleft(b_it) + bottomright(b_it)); transform(vertex, amount, - amount); +#ifdef LIBDEPIXELIZE_ENABLE_EXPERIMENTAL_FEATURES_5TH_IS_INVISIBLE vertex.visible = false; +#endif } } else { special = true; @@ -1422,7 +1625,11 @@ SimplifiedVoronoi - amount * ( topleft(c_it) + topright(d_it) - bottomleft(a_it) - bottomright(b_it) )); +#ifdef LIBDEPIXELIZE_ENABLE_EXPERIMENTAL_FEATURES_1ST_IS_INVISIBLE cells_it->vertices.push_back(another.invisible()); +#else + cells_it->vertices.push_back(another); +#endif } { Point another = vertex; @@ -1433,7 +1640,11 @@ SimplifiedVoronoi // y - amount * ( topright(d_it) - bottomright(b_it) )); +#ifdef LIBDEPIXELIZE_ENABLE_EXPERIMENTAL_FEATURES_2ND_IS_INVISIBLE cells_it->vertices.push_back(another.invisible()); +#else + cells_it->vertices.push_back(another); +#endif } { Point another = vertex; @@ -1445,7 +1656,11 @@ SimplifiedVoronoi - amount * ( topleft(c_it) - bottomleft(a_it) )); another.smooth = true; +#ifdef LIBDEPIXELIZE_ENABLE_EXPERIMENTAL_FEATURES_3RD_IS_INVISIBLE + cells_it->vertices.push_back(another.invisible()); +#else cells_it->vertices.push_back(another); +#endif } { Point another = vertex; @@ -1456,9 +1671,15 @@ SimplifiedVoronoi // y - amount * ( topleft(c_it) - bottomleft(a_it) )); +#ifdef LIBDEPIXELIZE_ENABLE_EXPERIMENTAL_FEATURES_4TH_IS_INVISIBLE cells_it->vertices.push_back(another.invisible()); +#else + cells_it->vertices.push_back(another); +#endif } +#ifdef LIBDEPIXELIZE_ENABLE_EXPERIMENTAL_FEATURES_5TH_IS_INVISIBLE vertex.visible = false; +#endif } } else { // there is a 4-color pattern, where the current node -- cgit v1.2.3