diff options
Diffstat (limited to 'src/sp-offset.cpp')
| -rw-r--r-- | src/sp-offset.cpp | 648 |
1 files changed, 366 insertions, 282 deletions
diff --git a/src/sp-offset.cpp b/src/sp-offset.cpp index 95511aea3..f9759cac1 100644 --- a/src/sp-offset.cpp +++ b/src/sp-offset.cpp @@ -43,6 +43,16 @@ class SPDocument; +#include "sp-factory.h" + +namespace { + SPObject* createOffset() { + return new SPOffset(); + } + + bool offsetRegistered = SPFactory::instance().registerObject("inkscape:offset", createOffset); +} + #define noOFFSET_VERBOSE /** \note @@ -68,21 +78,6 @@ class SPDocument; * radius (look in object-edit). */ -static void sp_offset_finalize(GObject *obj); - -static void sp_offset_build (SPObject * object, SPDocument * document, - Inkscape::XML::Node * repr); -static Inkscape::XML::Node *sp_offset_write (SPObject * object, Inkscape::XML::Document *doc, Inkscape::XML::Node * repr, - guint flags); -static void sp_offset_set (SPObject * object, unsigned int key, - const gchar * value); -static void sp_offset_update (SPObject * object, SPCtx * ctx, guint flags); -static void sp_offset_release (SPObject * object); - -static gchar *sp_offset_description (SPItem * item); -static void sp_offset_snappoints(SPItem const *item, std::vector<Inkscape::SnapCandidatePoint> &p, Inkscape::SnapPreferences const *snapprefs); -static void sp_offset_set_shape (SPShape * shape); - static void refresh_offset_source(SPOffset* offset); static void sp_offset_start_listening(SPOffset *offset,SPObject* to); @@ -100,134 +95,89 @@ static void sp_offset_source_modified (SPObject *iSource, guint flags, SPItem *i // reappearing in offset when the radius becomes too large static bool use_slow_but_correct_offset_method=false; -G_DEFINE_TYPE(SPOffset, sp_offset, SP_TYPE_SHAPE); - -/** - * SPOffset vtable initialization. - */ -static void -sp_offset_class_init(SPOffsetClass *klass) -{ - GObjectClass *gobject_class = (GObjectClass *) klass; - SPObjectClass *sp_object_class = (SPObjectClass *) klass; - SPItemClass *item_class = (SPItemClass *) klass; - SPShapeClass *shape_class = (SPShapeClass *) klass; - - gobject_class->finalize = sp_offset_finalize; - - sp_object_class->build = sp_offset_build; - sp_object_class->write = sp_offset_write; - sp_object_class->set = sp_offset_set; - sp_object_class->update = sp_offset_update; - sp_object_class->release = sp_offset_release; - - item_class->description = sp_offset_description; - item_class->snappoints = sp_offset_snappoints; +SPOffset::SPOffset() : SPShape() { + this->rad = 1.0; + this->original = NULL; + this->originalPath = NULL; + this->knotSet = false; + this->sourceDirty=false; + this->isUpdating=false; + // init various connections + this->sourceHref = NULL; + this->sourceRepr = NULL; + this->sourceObject = NULL; - shape_class->set_shape = sp_offset_set_shape; -} + new (&this->_modified_connection) sigc::connection(); + new (&this->_delete_connection) sigc::connection(); + new (&this->_changed_connection) sigc::connection(); + new (&this->_transformed_connection) sigc::connection(); -/** - * Callback for SPOffset object initialization. - */ -static void -sp_offset_init(SPOffset *offset) -{ - offset->rad = 1.0; - offset->original = NULL; - offset->originalPath = NULL; - offset->knotSet = false; - offset->sourceDirty=false; - offset->isUpdating=false; - // init various connections - offset->sourceHref = NULL; - offset->sourceRepr = NULL; - offset->sourceObject = NULL; - new (&offset->_modified_connection) sigc::connection(); - new (&offset->_delete_connection) sigc::connection(); - new (&offset->_changed_connection) sigc::connection(); - new (&offset->_transformed_connection) sigc::connection(); // set up the uri reference - offset->sourceRef = new SPUseReference(offset); - offset->_changed_connection = offset->sourceRef->changedSignal().connect(sigc::bind(sigc::ptr_fun(sp_offset_href_changed), offset)); + this->sourceRef = new SPUseReference(this); + this->_changed_connection = this->sourceRef->changedSignal().connect(sigc::bind(sigc::ptr_fun(sp_offset_href_changed), this)); } -/** - * Callback for SPOffset finalization. - */ -static void -sp_offset_finalize(GObject *obj) -{ - SPOffset *offset = (SPOffset *) obj; - - delete offset->sourceRef; +SPOffset::~SPOffset() { + delete this->sourceRef; - offset->_modified_connection.disconnect(); - offset->_modified_connection.~connection(); - offset->_delete_connection.disconnect(); - offset->_delete_connection.~connection(); - offset->_changed_connection.disconnect(); - offset->_changed_connection.~connection(); - offset->_transformed_connection.disconnect(); - offset->_transformed_connection.~connection(); + this->_modified_connection.disconnect(); + this->_delete_connection.disconnect(); + this->_changed_connection.disconnect(); + this->_transformed_connection.disconnect(); } -/** - * Virtual build: set offset attributes from corresponding repr. - */ -static void -sp_offset_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *repr) -{ - if (((SPObjectClass *) sp_offset_parent_class)->build) - ((SPObjectClass *) sp_offset_parent_class)->build (object, document, repr); +void SPOffset::build(SPDocument *document, Inkscape::XML::Node *repr) { + SPShape::build(document, repr); //XML Tree being used directly here while it shouldn't be. - if (object->getRepr()->attribute("inkscape:radius")) { - object->readAttr( "inkscape:radius" ); + if (this->getRepr()->attribute("inkscape:radius")) { + this->readAttr( "inkscape:radius" ); } else { //XML Tree being used directly here (as object->getRepr) //in all the below lines in the block while it shouldn't be. - gchar const *oldA = object->getRepr()->attribute("sodipodi:radius"); - object->getRepr()->setAttribute("inkscape:radius",oldA); - object->getRepr()->setAttribute("sodipodi:radius",NULL); + gchar const *oldA = this->getRepr()->attribute("sodipodi:radius"); + this->getRepr()->setAttribute("inkscape:radius",oldA); + this->getRepr()->setAttribute("sodipodi:radius",NULL); - object->readAttr( "inkscape:radius" ); + this->readAttr( "inkscape:radius" ); } - if (object->getRepr()->attribute("inkscape:original")) { - object->readAttr( "inkscape:original" ); + + if (this->getRepr()->attribute("inkscape:original")) { + this->readAttr( "inkscape:original" ); } else { - gchar const *oldA = object->getRepr()->attribute("sodipodi:original"); - object->getRepr()->setAttribute("inkscape:original",oldA); - object->getRepr()->setAttribute("sodipodi:original",NULL); + gchar const *oldA = this->getRepr()->attribute("sodipodi:original"); + this->getRepr()->setAttribute("inkscape:original",oldA); + this->getRepr()->setAttribute("sodipodi:original",NULL); - object->readAttr( "inkscape:original" ); + this->readAttr( "inkscape:original" ); } - if (object->getRepr()->attribute("xlink:href")) { - object->readAttr( "xlink:href" ); + + if (this->getRepr()->attribute("xlink:href")) { + this->readAttr( "xlink:href" ); } else { - gchar const *oldA = object->getRepr()->attribute("inkscape:href"); + gchar const *oldA = this->getRepr()->attribute("inkscape:href"); + if (oldA) { size_t lA = strlen(oldA); char *nA=(char*)malloc((1+lA+1)*sizeof(char)); + memcpy(nA+1,oldA,lA*sizeof(char)); + nA[0]='#'; nA[lA+1]=0; - object->getRepr()->setAttribute("xlink:href",nA); + + this->getRepr()->setAttribute("xlink:href",nA); + free(nA); - object->getRepr()->setAttribute("inkscape:href",NULL); + + this->getRepr()->setAttribute("inkscape:href",NULL); } - object->readAttr( "xlink:href" ); + + this->readAttr( "xlink:href" ); } } -/** - * Virtual write: write offset attributes to corresponding repr. - */ -static Inkscape::XML::Node * -sp_offset_write(SPObject *object, Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags) -{ - SPOffset *offset = SP_OFFSET (object); - +Inkscape::XML::Node* SPOffset::write(Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags) { if ((flags & SP_OBJECT_WRITE_BUILD) && !repr) { repr = xml_doc->createElement("svg:path"); } @@ -238,66 +188,57 @@ sp_offset_write(SPObject *object, Inkscape::XML::Document *xml_doc, Inkscape::XM * inkscape:offset="cx cy exp revo rad arg t0" */ repr->setAttribute("sodipodi:type", "inkscape:offset"); - sp_repr_set_svg_double(repr, "inkscape:radius", offset->rad); - repr->setAttribute("inkscape:original", offset->original); - repr->setAttribute("inkscape:href", offset->sourceHref); + sp_repr_set_svg_double(repr, "inkscape:radius", this->rad); + repr->setAttribute("inkscape:original", this->original); + repr->setAttribute("inkscape:href", this->sourceHref); } - // Make sure the object has curve - SPCurve *curve = SP_SHAPE (offset)->getCurve(); + // Make sure the offset has curve + SPCurve *curve = SP_SHAPE (this)->getCurve(); + if (curve == NULL) { - sp_offset_set_shape (SP_SHAPE (offset)); + this->set_shape(); } // write that curve to "d" - char *d = sp_svg_write_path (offset->_curve->get_pathvector()); + char *d = sp_svg_write_path (this->_curve->get_pathvector()); repr->setAttribute("d", d); g_free (d); - if (((SPObjectClass *) (sp_offset_parent_class))->write) - ((SPObjectClass *) (sp_offset_parent_class))->write (object, xml_doc, repr, - flags | SP_SHAPE_WRITE_PATH); + SPShape::write(xml_doc, repr, flags | SP_SHAPE_WRITE_PATH); return repr; } -/** - * Virtual release callback. - */ -static void -sp_offset_release(SPObject *object) -{ - SPOffset *offset = (SPOffset *) object; +void SPOffset::release() { + if (this->original) { + free (this->original); + } - if (offset->original) free (offset->original); - if (offset->originalPath) delete ((Path *) offset->originalPath); - offset->original = NULL; - offset->originalPath = NULL; + if (this->originalPath) { + delete ((Path *) this->originalPath); + } - sp_offset_quit_listening(offset); + this->original = NULL; + this->originalPath = NULL; - offset->_changed_connection.disconnect(); - g_free(offset->sourceHref); - offset->sourceHref = NULL; - offset->sourceRef->detach(); + sp_offset_quit_listening(this); - if (((SPObjectClass *) sp_offset_parent_class)->release) { - ((SPObjectClass *) sp_offset_parent_class)->release (object); - } + this->_changed_connection.disconnect(); -} + g_free(this->sourceHref); -/** - * Set callback: the function that is called whenever a change is made to - * the description of the object. - */ -static void -sp_offset_set(SPObject *object, unsigned key, gchar const *value) -{ - SPOffset *offset = SP_OFFSET (object); + this->sourceHref = NULL; + this->sourceRef->detach(); - if ( offset->sourceDirty ) refresh_offset_source(offset); + SPShape::release(); +} + +void SPOffset::set(unsigned int key, const gchar* value) { + if ( this->sourceDirty ) { + refresh_offset_source(this); + } /* fixme: we should really collect updates */ switch (key) @@ -306,108 +247,114 @@ sp_offset_set(SPObject *object, unsigned key, gchar const *value) case SP_ATTR_SODIPODI_ORIGINAL: if (value == NULL) { } else { - if (offset->original) { - free (offset->original); - delete ((Path *) offset->originalPath); - offset->original = NULL; - offset->originalPath = NULL; + if (this->original) { + free (this->original); + delete ((Path *) this->originalPath); + + this->original = NULL; + this->originalPath = NULL; } - offset->original = strdup (value); + this->original = strdup (value); + + Geom::PathVector pv = sp_svg_read_pathv(this->original); + + this->originalPath = new Path; + reinterpret_cast<Path *>(this->originalPath)->LoadPathVector(pv); - Geom::PathVector pv = sp_svg_read_pathv(offset->original); - offset->originalPath = new Path; - reinterpret_cast<Path *>(offset->originalPath)->LoadPathVector(pv); + this->knotSet = false; - offset->knotSet = false; - if ( offset->isUpdating == false ) object->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); + if ( this->isUpdating == false ) { + this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); + } } break; + case SP_ATTR_INKSCAPE_RADIUS: case SP_ATTR_SODIPODI_RADIUS: - if (!sp_svg_length_read_computed_absolute (value, &offset->rad)) { - if (fabs (offset->rad) < 0.01) - offset->rad = (offset->rad < 0) ? -0.01 : 0.01; - offset->knotSet = false; // knotset=false because it's not set from the context + if (!sp_svg_length_read_computed_absolute (value, &this->rad)) { + if (fabs (this->rad) < 0.01) { + this->rad = (this->rad < 0) ? -0.01 : 0.01; + } + + this->knotSet = false; // knotset=false because it's not set from the context + } + + if ( this->isUpdating == false ) { + this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); } - if ( offset->isUpdating == false ) object->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); break; + case SP_ATTR_INKSCAPE_HREF: case SP_ATTR_XLINK_HREF: if ( value == NULL ) { - sp_offset_quit_listening(offset); - if ( offset->sourceHref ) g_free(offset->sourceHref); - offset->sourceHref = NULL; - offset->sourceRef->detach(); + sp_offset_quit_listening(this); + if ( this->sourceHref ) { + g_free(this->sourceHref); + } + + this->sourceHref = NULL; + this->sourceRef->detach(); } else { - if ( offset->sourceHref && ( strcmp(value, offset->sourceHref) == 0 ) ) { + if ( this->sourceHref && ( strcmp(value, this->sourceHref) == 0 ) ) { } else { - if ( offset->sourceHref ) g_free(offset->sourceHref); - offset->sourceHref = g_strdup(value); + if ( this->sourceHref ) { + g_free(this->sourceHref); + } + + this->sourceHref = g_strdup(value); + try { - offset->sourceRef->attach(Inkscape::URI(value)); + this->sourceRef->attach(Inkscape::URI(value)); } catch (Inkscape::BadURIException &e) { g_warning("%s", e.what()); - offset->sourceRef->detach(); + this->sourceRef->detach(); } } } break; + default: - if (((SPObjectClass *) sp_offset_parent_class)->set) - ((SPObjectClass *) sp_offset_parent_class)->set (object, key, value); + SPShape::set(key, value); break; } } -/** - * Update callback: the object has changed, recompute its shape. - */ -static void -sp_offset_update(SPObject *object, SPCtx *ctx, guint flags) -{ - SPOffset* offset = SP_OFFSET(object); - offset->isUpdating=true; // prevent sp_offset_set from requesting updates - if ( offset->sourceDirty ) refresh_offset_source(offset); +void SPOffset::update(SPCtx *ctx, guint flags) { + this->isUpdating=true; // prevent sp_offset_set from requesting updates + + if ( this->sourceDirty ) { + refresh_offset_source(this); + } + if (flags & (SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_STYLE_MODIFIED_FLAG | SP_OBJECT_VIEWPORT_MODIFIED_FLAG)) { - ((SPShape *) object)->setShape (); + + this->set_shape(); } - offset->isUpdating=false; + + this->isUpdating=false; - if (((SPObjectClass *) sp_offset_parent_class)->update) - ((SPObjectClass *) sp_offset_parent_class)->update (object, ctx, flags); + SPShape::update(ctx, flags); } -/** - * Returns a textual description of object. - */ -static gchar * -sp_offset_description(SPItem *item) -{ - SPOffset *offset = SP_OFFSET (item); - - if ( offset->sourceHref ) { - // TRANSLATORS COMMENT: %s is either "outset" or "inset" depending on sign - return g_strdup_printf(_("<b>Linked offset</b>, %s by %f pt"), - (offset->rad >= 0)? _("outset") : _("inset"), fabs (offset->rad)); +const char* SPOffset::display_name() { + if ( this->sourceHref ) { + return _("Linked Offset"); } else { - // TRANSLATORS COMMENT: %s is either "outset" or "inset" depending on sign - return g_strdup_printf(_("<b>Dynamic offset</b>, %s by %f pt"), - (offset->rad >= 0)? _("outset") : _("inset"), fabs (offset->rad)); + return _("Dynamic Offset"); } } -/** - * Compute and set shape's offset. - */ -static void -sp_offset_set_shape(SPShape *shape) -{ - SPOffset *offset = SP_OFFSET (shape); +gchar* SPOffset::description() { + // TRANSLATORS COMMENT: %s is either "outset" or "inset" depending on sign + return g_strdup_printf(_("%s by %f pt"), (this->rad >= 0) ? + _("outset") : _("inset"), fabs (this->rad)); +} - if ( offset->originalPath == NULL ) { +void SPOffset::set_shape() { + if ( this->originalPath == NULL ) { // oops : no path?! (the offset object should do harakiri) return; } @@ -416,30 +363,35 @@ sp_offset_set_shape(SPShape *shape) #endif // au boulot - if ( fabs(offset->rad) < 0.01 ) { + if ( fabs(this->rad) < 0.01 ) { // grosso modo: 0 - // just put the source shape as the offseted one, no one will notice + // just put the source this as the offseted one, no one will notice // it's also useless to compute the offset with a 0 radius //XML Tree being used directly here while it shouldn't be. - const char *res_d = shape->getRepr()->attribute("inkscape:original"); + const char *res_d = this->getRepr()->attribute("inkscape:original"); + if ( res_d ) { Geom::PathVector pv = sp_svg_read_pathv(res_d); SPCurve *c = new SPCurve(pv); g_assert(c != NULL); - ((SPShape *) offset)->setCurveInsync (c, TRUE); - ((SPShape *) offset)->setCurveBeforeLPE(c); + + this->setCurveInsync (c, TRUE); + this->setCurveBeforeLPE(c); + c->unref(); } + return; } // extra paraniac careful check. the preceding if () should take care of this case - if (fabs (offset->rad) < 0.01) - offset->rad = (offset->rad < 0) ? -0.01 : 0.01; + if (fabs (this->rad) < 0.01) { + this->rad = (this->rad < 0) ? -0.01 : 0.01; + } Path *orig = new Path; - orig->Copy ((Path *) offset->originalPath); + orig->Copy ((Path *)this->originalPath); if ( use_slow_but_correct_offset_method == false ) { // version par outline @@ -451,14 +403,14 @@ sp_offset_set_shape(SPShape *shape) // and now: offset float o_width; - if (offset->rad >= 0) + if (this->rad >= 0) { - o_width = offset->rad; + o_width = this->rad; orig->OutsideOutline (res, o_width, join_round, butt_straight, 20.0); } else { - o_width = -offset->rad; + o_width = -this->rad; orig->OutsideOutline (res, -o_width, join_round, butt_straight, 20.0); } @@ -478,13 +430,16 @@ sp_offset_set_shape(SPShape *shape) theRes->ConvertToForme (orig, 1, originaux); - SPItem *item = shape; - Geom::OptRect bbox = item->desktopVisualBounds(); + Geom::OptRect bbox = this->desktopVisualBounds(); + if ( bbox ) { gdouble size = L2(bbox->dimensions()); - gdouble const exp = item->transform.descrim(); - if (exp != 0) + gdouble const exp = this->transform.descrim(); + + if (exp != 0) { size /= exp; + } + orig->Coalesce (size * 0.001); //g_print ("coa %g exp %g item %p\n", size * 0.001, exp, item); } @@ -515,13 +470,13 @@ sp_offset_set_shape(SPShape *shape) // and now: offset float o_width; - if (offset->rad >= 0) + if (this->rad >= 0) { - o_width = offset->rad; + o_width = this->rad; } else { - o_width = -offset->rad; + o_width = -this->rad; } // one has to have a measure of the details @@ -533,24 +488,32 @@ sp_offset_set_shape(SPShape *shape) { orig->ConvertWithBackData (0.5*o_width); } + orig->Fill (theShape, 0); theRes->ConvertToShape (theShape, fill_positive); + Path *originaux[1]; originaux[0]=orig; + Path *res = new Path; theRes->ConvertToForme (res, 1, originaux); + int nbPart=0; Path** parts=res->SubPaths(nbPart,true); char *holes=(char*)malloc(nbPart*sizeof(char)); + // we offset contours separately, because we can. // this way, we avoid doing a unique big ConvertToShape when dealing with big shapes with lots of holes { Shape* onePart=new Shape; Shape* oneCleanPart=new Shape; + theShape->Reset(); + for (int i=0;i<nbPart;i++) { double partSurf=parts[i]->Surface(); parts[i]->Convert(1.0); + { // raffiner si besoin double bL,bT,bR,bB; @@ -560,29 +523,41 @@ sp_offset_set_shape(SPShape *shape) parts[i]->Convert(0.02*mesure); } } + if ( partSurf < 0 ) { // inverse par rapport a la realite // plein holes[i]=0; parts[i]->Fill(oneCleanPart,0); onePart->ConvertToShape(oneCleanPart,fill_positive); // there aren't intersections in that one, but maybe duplicate points and null edges - oneCleanPart->MakeOffset(onePart,offset->rad,join_round,20.0); + oneCleanPart->MakeOffset(onePart,this->rad,join_round,20.0); onePart->ConvertToShape(oneCleanPart,fill_positive); onePart->CalcBBox(); double typicalSize=0.5*((onePart->rightX-onePart->leftX)+(onePart->bottomY-onePart->topY)); - if ( typicalSize < 0.05 ) typicalSize=0.05; + + if ( typicalSize < 0.05 ) { + typicalSize=0.05; + } + typicalSize*=0.01; - if ( typicalSize > 1.0 ) typicalSize=1.0; + + if ( typicalSize > 1.0 ) { + typicalSize=1.0; + } + onePart->ConvertToForme (parts[i]); parts[i]->ConvertEvenLines (typicalSize); parts[i]->Simplify (typicalSize); + double nPartSurf=parts[i]->Surface(); + if ( nPartSurf >= 0 ) { // inversion de la surface -> disparait delete parts[i]; parts[i]=NULL; } else { } + /* int firstP=theShape->nbPt; for (int j=0;j<onePart->nbPt;j++) theShape->AddPoint(onePart->pts[j].x); for (int j=0;j<onePart->nbAr;j++) theShape->AddEdge(firstP+onePart->aretes[j].st,firstP+onePart->aretes[j].en);*/ @@ -591,19 +566,28 @@ sp_offset_set_shape(SPShape *shape) holes[i]=1; parts[i]->Fill(oneCleanPart,0,false,true,true); onePart->ConvertToShape(oneCleanPart,fill_positive); - oneCleanPart->MakeOffset(onePart,-offset->rad,join_round,20.0); + oneCleanPart->MakeOffset(onePart,-this->rad,join_round,20.0); onePart->ConvertToShape(oneCleanPart,fill_positive); // for (int j=0;j<onePart->nbAr;j++) onePart->Inverse(j); // pas oublier de reinverser onePart->CalcBBox(); double typicalSize=0.5*((onePart->rightX-onePart->leftX)+(onePart->bottomY-onePart->topY)); - if ( typicalSize < 0.05 ) typicalSize=0.05; + + if ( typicalSize < 0.05 ) { + typicalSize=0.05; + } + typicalSize*=0.01; - if ( typicalSize > 1.0 ) typicalSize=1.0; + + if ( typicalSize > 1.0 ) { + typicalSize=1.0; + } + onePart->ConvertToForme (parts[i]); parts[i]->ConvertEvenLines (typicalSize); parts[i]->Simplify (typicalSize); double nPartSurf=parts[i]->Surface(); + if ( nPartSurf >= 0 ) { // inversion de la surface -> disparait delete parts[i]; @@ -621,11 +605,14 @@ sp_offset_set_shape(SPShape *shape) delete onePart; delete oneCleanPart; } + if ( nbPart > 1 ) { theShape->Reset(); + for (int i=0;i<nbPart;i++) { if ( parts[i] ) { parts[i]->ConvertWithBackData(1.0); + if ( holes[i] ) { parts[i]->Fill(theShape,i,true,true,true); } else { @@ -633,12 +620,23 @@ sp_offset_set_shape(SPShape *shape) } } } + theRes->ConvertToShape (theShape, fill_positive); theRes->ConvertToForme (orig,nbPart,parts); - for (int i=0;i<nbPart;i++) if ( parts[i] ) delete parts[i]; + + for (int i=0;i<nbPart;i++) { + if ( parts[i] ) { + delete parts[i]; + } + } } else if ( nbPart == 1 ) { orig->Copy(parts[0]); - for (int i=0;i<nbPart;i++) if ( parts[i] ) delete parts[i]; + + for (int i=0;i<nbPart;i++) { + if ( parts[i] ) { + delete parts[i]; + } + } } else { orig->Reset(); } @@ -653,14 +651,21 @@ sp_offset_set_shape(SPShape *shape) orig->Simplify (1.0 * o_width); }*/ - if ( parts ) free(parts); - if ( holes ) free(holes); + if ( parts ) { + free(parts); + } + + if ( holes ) { + free(holes); + } + delete res; delete theShape; delete theRes; } { char *res_d = NULL; + if (orig->descr_cmd.size() <= 1) { // Aie.... nothing left. @@ -672,27 +677,23 @@ sp_offset_set_shape(SPShape *shape) res_d = orig->svg_dump_path (); } + delete orig; Geom::PathVector pv = sp_svg_read_pathv(res_d); SPCurve *c = new SPCurve(pv); g_assert(c != NULL); - ((SPShape *) offset)->setCurveInsync (c, TRUE); - ((SPShape *) offset)->setCurveBeforeLPE(c); + + this->setCurveInsync (c, TRUE); + this->setCurveBeforeLPE(c); c->unref(); free (res_d); } } -/** - * Virtual snappoints function. - */ -static void sp_offset_snappoints(SPItem const *item, std::vector<Inkscape::SnapCandidatePoint> &p, Inkscape::SnapPreferences const *snapprefs) -{ - if (((SPItemClass *) sp_offset_parent_class)->snappoints) { - ((SPItemClass *) sp_offset_parent_class)->snappoints (item, p, snapprefs); - } +void SPOffset::snappoints(std::vector<Inkscape::SnapCandidatePoint> &p, Inkscape::SnapPreferences const *snapprefs) { + SPShape::snappoints(p, snapprefs); } @@ -727,31 +728,53 @@ vectors_are_clockwise (Geom::Point A, Geom::Point B, Geom::Point C) double ca_c = dot(C, A); double ab_a = acos (ab_c); - if (ab_c <= -1.0) + + if (ab_c <= -1.0) { ab_a = M_PI; - if (ab_c >= 1.0) + } + + if (ab_c >= 1.0) { ab_a = 0; - if (ab_s < 0) + } + + if (ab_s < 0) { ab_a = 2 * M_PI - ab_a; + } + double bc_a = acos (bc_c); - if (bc_c <= -1.0) + + if (bc_c <= -1.0) { bc_a = M_PI; - if (bc_c >= 1.0) + } + + if (bc_c >= 1.0) { bc_a = 0; - if (bc_s < 0) + } + + if (bc_s < 0) { bc_a = 2 * M_PI - bc_a; + } + double ca_a = acos (ca_c); - if (ca_c <= -1.0) + + if (ca_c <= -1.0) { ca_a = M_PI; - if (ca_c >= 1.0) + } + + if (ca_c >= 1.0) { ca_a = 0; - if (ca_s < 0) + } + + if (ca_s < 0) { ca_a = 2 * M_PI - ca_a; + } double lim = 2 * M_PI - ca_a; - if (ab_a < lim) + if (ab_a < lim) { return true; + } + return false; } @@ -766,9 +789,10 @@ vectors_are_clockwise (Geom::Point A, Geom::Point B, Geom::Point C) double sp_offset_distance_to_original (SPOffset * offset, Geom::Point px) { - if (offset == NULL || offset->originalPath == NULL - || ((Path *) offset->originalPath)->descr_cmd.size() <= 1) + if (offset == NULL || offset->originalPath == NULL || ((Path *) offset->originalPath)->descr_cmd.size() <= 1) { return 1.0; + } + double dist = 1.0; Shape *theShape = new Shape; Shape *theRes = new Shape; @@ -797,14 +821,16 @@ sp_offset_distance_to_original (SPOffset * offset, Geom::Point px) bool ptSet = false; double arDist = -1.0; bool arSet = false; + // first get the minimum distance to the points for (int i = 0; i < theRes->numberOfPoints(); i++) { if (theRes->getPoint(i).totalDegree() > 0) - { + { Geom::Point nx = theRes->getPoint(i).x; Geom::Point nxpx = px-nx; double ndist = sqrt (dot(nxpx,nxpx)); + if (ptSet == false || fabs (ndist) < fabs (ptDist)) { // we have a new minimum distance @@ -816,6 +842,7 @@ sp_offset_distance_to_original (SPOffset * offset, Geom::Point px) fb = theRes->getPoint(i).incidentEdge[LAST]; pb = theRes->getPoint(i).incidentEdge[LAST]; cb = theRes->getPoint(i).incidentEdge[FIRST]; + do { // one angle @@ -826,10 +853,12 @@ sp_offset_distance_to_original (SPOffset * offset, Geom::Point px) nex = theRes->getEdge(cb).dx; nlen = sqrt (dot(nex , nex)); nex /= nlen; + if (theRes->getEdge(pb).en == i) { prx = -prx; } + if (theRes->getEdge(cb).en == i) { nex = -nex; @@ -850,13 +879,16 @@ sp_offset_distance_to_original (SPOffset * offset, Geom::Point px) } break; } + pb = cb; cb = theRes->NextAt (i, cb); } + while (cb >= 0 && pb >= 0 && pb != fb); } } } + // loop over the edges to try to improve the distance for (int i = 0; i < theRes->numberOfEdges(); i++) { @@ -864,14 +896,17 @@ sp_offset_distance_to_original (SPOffset * offset, Geom::Point px) Geom::Point ex = theRes->getPoint(theRes->getEdge(i).en).x; Geom::Point nx = ex - sx; double len = sqrt (dot(nx,nx)); + if (len > 0.0001) { Geom::Point pxsx=px-sx; double ab = dot(nx,pxsx); + if (ab > 0 && ab < len * len) { // we're in the zone of influence of the segment double ndist = (cross(pxsx,nx)) / len; + if (arSet == false || fabs (ndist) < fabs (arDist)) { arDist = ndist; @@ -880,16 +915,22 @@ sp_offset_distance_to_original (SPOffset * offset, Geom::Point px) } } } + if (arSet || ptSet) { - if (arSet == false) + if (arSet == false) { arDist = ptDist; - if (ptSet == false) + } + + if (ptSet == false) { ptDist = arDist; - if (fabs (ptDist) < fabs (arDist)) + } + + if (fabs (ptDist) < fabs (arDist)) { dist = ptDist; - else + } else { dist = arDist; + } } } @@ -909,8 +950,10 @@ void sp_offset_top_point (SPOffset const * offset, Geom::Point *px) { (*px) = Geom::Point(0, 0); - if (offset == NULL) + + if (offset == NULL) { return; + } if (offset->knotSet) { @@ -919,13 +962,19 @@ sp_offset_top_point (SPOffset const * offset, Geom::Point *px) } SPCurve *curve = SP_SHAPE (offset)->getCurve(); + if (curve == NULL) { - sp_offset_set_shape (SP_SHAPE (offset)); + // CPPIFY + //offset->set_shape(); + const_cast<SPOffset*>(offset)->set_shape(); + curve = SP_SHAPE (offset)->getCurve(); + if (curve == NULL) return; } + if (curve->is_empty()) { curve->unref(); @@ -968,8 +1017,9 @@ static void sp_offset_start_listening(SPOffset *offset,SPObject* to) static void sp_offset_quit_listening(SPOffset *offset) { - if ( offset->sourceObject == NULL ) + if ( offset->sourceObject == NULL ) { return; + } offset->_modified_connection.disconnect(); offset->_delete_connection.disconnect(); @@ -983,9 +1033,14 @@ static void sp_offset_href_changed(SPObject */*old_ref*/, SPObject */*ref*/, SPOffset *offset) { sp_offset_quit_listening(offset); + if (offset->sourceRef) { SPItem *refobj = offset->sourceRef->getObject(); - if (refobj) sp_offset_start_listening(offset,refobj); + + if (refobj) { + sp_offset_start_listening(offset,refobj); + } + offset->sourceDirty=true; offset->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); } @@ -997,6 +1052,7 @@ static void sp_offset_move_compensate(Geom::Affine const *mp, SPItem */*original guint mode = prefs->getInt("/options/clonecompensation/value", SP_CLONE_COMPENSATION_PARALLEL); Geom::Affine m(*mp); + if (!(m.isTranslation()) || mode == SP_CLONE_COMPENSATION_NONE) { self->sourceDirty=true; self->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); @@ -1037,7 +1093,11 @@ sp_offset_delete_self(SPObject */*deleted*/, SPOffset *offset) if (mode == SP_CLONE_ORPHANS_UNLINK) { // leave it be. just forget about the source sp_offset_quit_listening(offset); - if ( offset->sourceHref ) g_free(offset->sourceHref); + + if ( offset->sourceHref ) { + g_free(offset->sourceHref); + } + offset->sourceHref = NULL; offset->sourceRef->detach(); } else if (mode == SP_CLONE_ORPHANS_DELETE) { @@ -1050,6 +1110,7 @@ sp_offset_source_modified (SPObject */*iSource*/, guint flags, SPItem *item) { SPOffset *offset = SP_OFFSET(item); offset->sourceDirty=true; + if (flags & (SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_CHILD_MODIFIED_FLAG)) { offset->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); } @@ -1058,35 +1119,54 @@ sp_offset_source_modified (SPObject */*iSource*/, guint flags, SPItem *item) static void refresh_offset_source(SPOffset* offset) { - if ( offset == NULL ) return; + if ( offset == NULL ) { + return; + } + offset->sourceDirty=false; // le mauvais cas: pas d'attribut d => il faut verifier que c'est une SPShape puis prendre le contour // The bad case: no d attribute. Must check that it's an SPShape and then take the outline. SPObject *refobj=offset->sourceObject; - if ( refobj == NULL ) return; + + if ( refobj == NULL ) { + return; + } + SPItem *item = SP_ITEM (refobj); SPCurve *curve=NULL; - if (!SP_IS_SHAPE (item) && !SP_IS_TEXT (item)) return; + + if (!SP_IS_SHAPE (item) && !SP_IS_TEXT (item)) { + return; + } + if (SP_IS_SHAPE (item)) { curve = SP_SHAPE (item)->getCurve (); - if (curve == NULL) + + if (curve == NULL) { return; + } } + if (SP_IS_TEXT (item)) { curve = SP_TEXT (item)->getNormalizedBpath (); - if (curve == NULL) - return; + + if (curve == NULL) { + return; + } } + Path *orig = new Path; orig->LoadPathVector(curve->get_pathvector()); curve->unref(); if (!item->transform.isIdentity()) { gchar const *t_attr = item->getRepr()->attribute("transform"); + if (t_attr) { Geom::Affine t; + if (sp_svg_transform_read(t_attr, &t)) { orig->Transform(t); } @@ -1105,6 +1185,7 @@ refresh_offset_source(SPOffset* offset) css = sp_repr_css_attr (offset->sourceRepr , "style"); val = sp_repr_css_property (css, "fill-rule", NULL); + if (val && strcmp (val, "nonzero") == 0) { theRes->ConvertToShape (theShape, fill_nonZero); @@ -1143,9 +1224,12 @@ sp_offset_get_source (SPOffset *offset) { if (offset && offset->sourceRef) { SPItem *refobj = offset->sourceRef->getObject(); - if (SP_IS_ITEM (refobj)) + + if (SP_IS_ITEM (refobj)) { return (SPItem *) refobj; + } } + return NULL; } |
