diff options
| author | Jabier Arraiza Cenoz <jabier.arraiza@marker.es> | 2015-02-16 20:49:53 +0000 |
|---|---|---|
| committer | Jabiertxof <jtx@jtx.marker.es> | 2015-02-16 20:49:53 +0000 |
| commit | 9593c78703845bfca18a3a135cbbc47cc03b54f6 (patch) | |
| tree | 4616e3cb7ed134d82367726aafaaf3f312d1cbc5 | |
| parent | added knots (diff) | |
| download | inkscape-9593c78703845bfca18a3a135cbbc47cc03b54f6.tar.gz inkscape-9593c78703845bfca18a3a135cbbc47cc03b54f6.zip | |
continuing fillet/chamfer
(bzr r13645.1.13)
| -rw-r--r-- | src/2geom/satellite.h | 31 | ||||
| -rw-r--r-- | src/live_effects/lpe-fillet-chamfer.cpp | 228 | ||||
| -rw-r--r-- | src/live_effects/lpe-fillet-chamfer.h | 14 | ||||
| -rw-r--r-- | src/live_effects/parameter/array.cpp | 9 | ||||
| -rw-r--r-- | src/live_effects/parameter/array.h | 14 | ||||
| -rw-r--r-- | src/live_effects/parameter/satellitepairarray.cpp | 4 | ||||
| -rw-r--r-- | src/live_effects/parameter/satellitepairarray.h | 7 |
7 files changed, 259 insertions, 48 deletions
diff --git a/src/2geom/satellite.h b/src/2geom/satellite.h index 8623ff1b0..06b4a1dd6 100644 --- a/src/2geom/satellite.h +++ b/src/2geom/satellite.h @@ -54,6 +54,12 @@ class Satellite _satellitetype = A; } + void setSatelliteType(gchar const * A) + { + std::map<gchar const *,SatelliteType> GcharMapToSatelliteType = boost::assign::map_list_of("FILLET", FILLET)("INVERSE_FILLET", INVERSE_FILLET)("CHAMFER",CHAMFER)("INVERSE_CHAMFER",INVERSE_CHAMFER)("INVALID_SATELLITE",INVALID_SATELLITE); + _satellitetype = GcharMapToSatelliteType[A]; + } + void setIsTime(bool A) { _isTime = A; @@ -84,42 +90,48 @@ class Satellite _size = A; } - SatelliteType satellitetype() const + SatelliteType getSatelliteType() const { return _satellitetype; } - bool isTime() const + gchar const * getSatelliteTypeGchar() const + { + std::map<SatelliteType,gchar const *> SatelliteTypeToGcharMap = boost::assign::map_list_of(FILLET, "FILLET")(INVERSE_FILLET, "INVERSE_FILLET")(CHAMFER,"CHAMFER")(INVERSE_CHAMFER,"INVERSE_CHAMFER")(INVALID_SATELLITE,"INVALID_SATELLITE"); + return SatelliteTypeToGcharMap[_satellitetype]; + } + + bool getIsTime() const { return _isTime; } - bool active() const + bool getActive() const { return _active; } - bool hasMirror() const + bool getHasMirror() const { return _hasMirror; } - bool hidden() const + bool getHidden() const { return _hidden; } - double size() const + double getSize() const { return _size; } - double time() const + double getTime() const { return _time; } - double time(Geom::D2<Geom::SBasis> curve) const + double getTime(Geom::D2<Geom::SBasis> curve) const { //todo make the process return _time; @@ -133,7 +145,10 @@ class Satellite static const std::map<gchar const *,SatelliteType> GcharMapToSatelliteType; + static double getOpositeTime(Geom::D2<Geom::SBasis> SBasisCurve, double time); + private: + SatelliteType _satellitetype; bool _isTime; bool _active; diff --git a/src/live_effects/lpe-fillet-chamfer.cpp b/src/live_effects/lpe-fillet-chamfer.cpp index 5d6358bb2..df9de81b7 100644 --- a/src/live_effects/lpe-fillet-chamfer.cpp +++ b/src/live_effects/lpe-fillet-chamfer.cpp @@ -17,25 +17,38 @@ #include "live_effects/lpe-fillet-chamfer.h" #include <sp-shape.h> +#include <sp-path.h> #include <2geom/pointwise.h> #include <2geom/satellite.h> #include <2geom/satellite-enum.h> +#include <2geom/svg-elliptical-arc.h> #include "helper/geom-nodetype.h" +#include "helper/geom-curves.h" #include "helper/geom.h" #include "display/curve.h" #include <vector> // TODO due to internal breakage in glibmm headers, this must be last: #include <glibmm/i18n.h> - +using namespace Geom; namespace Inkscape { namespace LivePathEffect { +static const Util::EnumData<FilletMethod> FilletMethodData[FM_END] = { + { FM_AUTO, N_("Auto"), "auto" }, + { FM_ARC, N_("Force arc"), "arc" }, + { FM_BEZIER, N_("Force bezier"), "bezier" } +}; +static const Util::EnumDataConverter<FilletMethod> +FMConverter(FilletMethodData, FM_END); + LPEFilletChamfer::LPEFilletChamfer(LivePathEffectObject *lpeobject) : Effect(lpeobject), - satellitepairarrayparam_values(_("Fillet point"), _("Fillet point"), "satellitepairarrayparam_values", &wr, this) + satellitepairarrayparam_values(_("Fillet point"), _("Fillet point"), "satellitepairarrayparam_values", &wr, this), + method(_("Method:"), _("Fillets methods"), "method", FMConverter, &wr, this, FM_AUTO) { registerParameter(&satellitepairarrayparam_values); + registerParameter(&method); } LPEFilletChamfer::~LPEFilletChamfer() {} @@ -46,23 +59,21 @@ void LPEFilletChamfer::doOnApply(SPLPEItem const *lpeItem) SPLPEItem * splpeitem = const_cast<SPLPEItem *>(lpeItem); SPShape * shape = dynamic_cast<SPShape *>(splpeitem); if (shape) { - Geom::PathVector const &original_pathv = pathv_to_linear_and_cubic_beziers(shape->getCurve()->get_pathvector()); - std::vector<std::pair<int,Geom::Satellite> > satellites; - Geom::Piecewise<Geom::D2<Geom::SBasis> > pwd2_in = paths_to_pw(original_pathv); + PathVector const &original_pathv = pathv_to_linear_and_cubic_beziers(shape->getCurve()->get_pathvector()); + std::vector<std::pair<int,Satellite> > satellites; + Piecewise<D2<SBasis> > pwd2_in = paths_to_pw(original_pathv); pwd2_in = remove_short_cuts(pwd2_in, .01); - Geom::Piecewise<Geom::D2<Geom::SBasis> > der = derivative(pwd2_in); - Geom::Piecewise<Geom::D2<Geom::SBasis> > n = rot90(unitVector(der)); - satellitepairarrayparam_values.set_pwd2(pwd2_in, n); - for (Geom::PathVector::const_iterator path_it = original_pathv.begin(); path_it != original_pathv.end(); ++path_it) { + satellitepairarrayparam_values.set_pwd2(pwd2_in); + for (PathVector::const_iterator path_it = original_pathv.begin(); path_it != original_pathv.end(); ++path_it) { if (path_it->empty()){ continue; } Geom::Path::const_iterator curve_it1 = path_it->begin(); Geom::Path::const_iterator curve_endit = path_it->end_default(); if (path_it->closed()) { - const Geom::Curve &closingline = path_it->back_closed(); + const Curve &closingline = path_it->back_closed(); // the closing line segment is always of type - // Geom::LineSegment. + // LineSegment. if (are_near(closingline.initialPoint(), closingline.finalPoint())) { // closingline.isDegenerate() did not work, because it only checks for // *exact* zero length, which goes wrong for relative coordinates and @@ -75,18 +86,18 @@ void LPEFilletChamfer::doOnApply(SPLPEItem const *lpeItem) --curve_end; int counter = 0; while (curve_it1 != curve_endit) { - Geom::Satellite satellite(Geom::FILLET, true, true, false, false, 0.0, 0.2); + Satellite satellite(FILLET, true, true, false, false, 0.0, 0.0); Geom::NodeType nodetype; if (counter==0) { if (path_it->closed()) { - nodetype = Geom::get_nodetype(*curve_end, *curve_it1); + nodetype = get_nodetype(*curve_end, *curve_it1); } else { - nodetype = Geom::NODE_NONE; + nodetype = NODE_NONE; } } else { nodetype = get_nodetype((*path_it)[counter - 1], *curve_it1); } - if (nodetype == Geom::NODE_CUSP) { + if (nodetype == NODE_CUSP) { satellites.push_back(std::make_pair(counter, satellite)); } ++curve_it1; @@ -101,11 +112,196 @@ void LPEFilletChamfer::doOnApply(SPLPEItem const *lpeItem) } } + +void LPEFilletChamfer::doBeforeEffect(SPLPEItem const *lpeItem) +{ + SPLPEItem * splpeitem = const_cast<SPLPEItem *>(lpeItem); + SPShape * shape = dynamic_cast<SPShape *>(splpeitem); + if (shape) { + SPCurve *c = shape->getCurve(); + SPPath * path = dynamic_cast<SPPath *>(shape); + if(path){ + c = path->get_original_curve(); + } + PathVector const &original_pathv = pathv_to_linear_and_cubic_beziers(c->get_pathvector()); + Piecewise<D2<SBasis> > pwd2_in = paths_to_pw(original_pathv); + pwd2_in = remove_short_cuts(pwd2_in, .01); + satellitepairarrayparam_values.set_pwd2(pwd2_in); + } else { + g_warning("LPE Fillet can only be applied to shapes (not groups)."); + } +} + +std::vector<Geom::Path> +LPEFilletChamfer::doEffect_path(std::vector<Geom::Path> const &path_in) +{ + std::vector<Geom::Path> pathvector_out; + Piecewise<D2<SBasis> > pwd2_in = paths_to_pw(pathv_to_linear_and_cubic_beziers(path_in)); + pwd2_in = remove_short_cuts(pwd2_in, .01); + satellitepairarrayparam_values.set_pwd2(pwd2_in); + std::vector<std::pair<int, Satellite> > filletChamferData = satellitepairarrayparam_values.data(); + unsigned int counter = 0; + const double K = (4.0 / 3.0) * (sqrt(2.0) - 1.0); + std::vector<Geom::Path> path_in_processed = pathv_to_linear_and_cubic_beziers(path_in); + for (PathVector::const_iterator path_it = path_in_processed.begin(); + path_it != path_in_processed.end(); ++path_it) { + if (path_it->empty()) + continue; + Geom::Path path_out; + Geom::Path::const_iterator curve_it1 = path_it->begin(); + Geom::Path::const_iterator curve_it2 = ++(path_it->begin()); + Geom::Path::const_iterator curve_endit = path_it->end_default(); + if (path_it->closed()) { + const Curve &closingline = path_it->back_closed(); + // the closing line segment is always of type + // LineSegment. + if (are_near(closingline.initialPoint(), closingline.finalPoint())) { + // closingline.isDegenerate() did not work, because it only checks for + // *exact* zero length, which goes wrong for relative coordinates and + // rounding errors... + // the closing line segment has zero-length. So stop before that one! + curve_endit = path_it->end_open(); + } + } + unsigned int counterCurves = 0; + while (curve_it1 != curve_endit) { + Curve *curve_it2Fixed = (*path_it->begin()).duplicate(); + int indexFix = 0; + if(!path_it->closed() || curve_it2 != curve_endit){ + curve_it2Fixed = (*curve_it2).duplicate(); + indexFix = counter; + } + bool last = curve_it2 == curve_endit; + std::vector<double> times; + times.push_back(filletChamferData[counter].second.getTime()); + times.push_back(filletChamferData[indexFix].second.getOpositeTime((*curve_it1).toSBasis(),filletChamferData[indexFix].second.getTime())); + times.push_back(filletChamferData[indexFix].second.getTime()); + Curve *knotCurve1 = curve_it1->portion(times[0], times[1]); + if (counterCurves > 0) { + knotCurve1->setInitial(path_out.finalPoint()); + } else { + path_out.start((*curve_it1).pointAt(times[0])); + } + Curve *knotCurve2 = curve_it2Fixed->portion(times[2], 1); + Point startArcPoint = knotCurve1->finalPoint(); + Point endArcPoint = curve_it2Fixed->pointAt(times[2]); + double k1 = distance(startArcPoint, curve_it1->finalPoint()) * K; + double k2 = distance(endArcPoint, curve_it1->finalPoint()) * K; + CubicBezier const *cubic1 = dynamic_cast<CubicBezier const *>(&*knotCurve1); + Ray ray1(startArcPoint, curve_it1->finalPoint()); + if (cubic1) { + ray1.setPoints((*cubic1)[2], startArcPoint); + } + Point handle1 = Point::polar(ray1.angle(),k1) + startArcPoint; + CubicBezier const *cubic2 = + dynamic_cast<CubicBezier const *>(&*knotCurve2); + Ray ray2(curve_it1->finalPoint(), endArcPoint); + if (cubic2) { + ray2.setPoints(endArcPoint, (*cubic2)[1]); + } + Point handle2 = endArcPoint - Point::polar(ray2.angle(),k2); + bool ccwToggle = cross(curve_it1->finalPoint() - startArcPoint, endArcPoint - startArcPoint) < 0; + double angle = angle_between(ray1, ray2, ccwToggle); + double handleAngle = ray1.angle() - angle; + if (ccwToggle) { + handleAngle = ray1.angle() + angle; + } + Point inverseHandle1 = Point::polar(handleAngle,k1) + startArcPoint; + handleAngle = ray2.angle() + angle; + if (ccwToggle) { + handleAngle = ray2.angle() - angle; + } + Point inverseHandle2 = endArcPoint - Point::polar(handleAngle,k2); + //straigth lines arc based + Line const x_line(Point(0,0),Point(1,0)); + Line const angled_line(startArcPoint,endArcPoint); + double angleArc = angle_between( x_line,angled_line); + double radius = distance(startArcPoint,middle_point(startArcPoint,endArcPoint))/sin(angle/2.0); + Coord rx = radius; + Coord ry = rx; + + if (times[1] != 1) { + if (times[1] != times[0]) { + path_out.append(*knotCurve1); + } + SatelliteType satType = FILLET; + if(path_it->closed() && last){ + satType = filletChamferData[counter - counterCurves].second.getSatelliteType(); + } else if (!path_it->closed() && last){ + //0 + } else { + satType = filletChamferData[counter + 1].second.getSatelliteType(); + } + if(are_near(middle_point(startArcPoint,endArcPoint),curve_it1->finalPoint(), 0.0001)){ + path_out.appendNew<LineSegment>(endArcPoint); + } else if (satType == CHAMFER) { + unsigned int chamferSubs = 0; + Geom::Path path_chamfer; + path_chamfer.start(path_out.finalPoint()); + if((is_straight_curve(*curve_it1) && is_straight_curve(*curve_it2Fixed) && method != FM_BEZIER )|| method == FM_ARC){ + path_chamfer.appendNew<SVGEllipticalArc>(rx, ry, angleArc, 0, ccwToggle, endArcPoint); + } else { + path_chamfer.appendNew<CubicBezier>(handle1, handle2, endArcPoint); + } + double chamfer_stepsTime = 1.0/chamferSubs; + for(unsigned int i = 1; i < chamferSubs; i++){ + Point chamferStep = path_chamfer.pointAt(chamfer_stepsTime * i); + path_out.appendNew<LineSegment>(chamferStep); + } + path_out.appendNew<LineSegment>(endArcPoint); + } else if (satType == INVERSE_CHAMFER) { + unsigned int chamferSubs = 2; + Geom::Path path_chamfer; + path_chamfer.start(path_out.finalPoint()); + if((is_straight_curve(*curve_it1) && is_straight_curve(*curve_it2Fixed) && method != FM_BEZIER )|| method == FM_ARC){ + ccwToggle = ccwToggle?0:1; + path_chamfer.appendNew<SVGEllipticalArc>(rx, ry, angleArc, 0, ccwToggle, endArcPoint); + }else{ + path_chamfer.appendNew<CubicBezier>(inverseHandle1, inverseHandle2, endArcPoint); + } + double chamfer_stepsTime = 1.0/chamferSubs; + for(unsigned int i = 1; i < chamferSubs; i++){ + Point chamferStep = path_chamfer.pointAt(chamfer_stepsTime * i); + path_out.appendNew<LineSegment>(chamferStep); + } + path_out.appendNew<LineSegment>(endArcPoint); + } else if (satType == INVERSE_FILLET) { + if((is_straight_curve(*curve_it1) && is_straight_curve(*curve_it2Fixed) && method != FM_BEZIER )|| method == FM_ARC){ + ccwToggle = ccwToggle?0:1; + path_out.appendNew<SVGEllipticalArc>(rx, ry, angleArc, 0, ccwToggle, endArcPoint); + }else{ + path_out.appendNew<CubicBezier>(inverseHandle1, inverseHandle2, endArcPoint); + } + } else if (satType == FILLET){ + if((is_straight_curve(*curve_it1) && is_straight_curve(*curve_it2Fixed) && method != FM_BEZIER )|| method == FM_ARC){ + path_out.appendNew<SVGEllipticalArc>(rx, ry, angleArc, 0, ccwToggle, endArcPoint); + } else { + path_out.appendNew<CubicBezier>(handle1, handle2, endArcPoint); + } + } + } else { + path_out.append(*knotCurve1); + } + if (path_it->closed() && last) { + path_out.close(); + } + ++curve_it1; + if (curve_it2 != curve_endit) { + ++curve_it2; + } + counter++; + counterCurves++; + } + pathvector_out.push_back(path_out); + } + return pathvector_out; +} + void LPEFilletChamfer::adjustForNewPath(std::vector<Geom::Path> const &path_in) { if (!path_in.empty()) { - //fillet_chamfer_values.recalculate_controlpoints_for_new_pwd2(pathv_to_linear_and_cubic_beziers(path_in)[0].toPwSb()); + //satellitepairarrayparam_values.recalculate_controlpoints_for_new_pwd2(pathv_to_linear_and_cubic_beziers(path_in)[0].toPwSb()); } } diff --git a/src/live_effects/lpe-fillet-chamfer.h b/src/live_effects/lpe-fillet-chamfer.h index 08000c0a5..94a2bd2b3 100644 --- a/src/live_effects/lpe-fillet-chamfer.h +++ b/src/live_effects/lpe-fillet-chamfer.h @@ -14,27 +14,35 @@ * * Released under GNU GPL, read the file 'COPYING' for more information */ - +#include "live_effects/parameter/enum.h" #include "2geom/pointwise.h" #include "live_effects/parameter/satellitepairarray.h" #include "live_effects/effect.h" +using namespace Geom; namespace Inkscape { namespace LivePathEffect { +enum FilletMethod { + FM_AUTO, + FM_ARC, + FM_BEZIER, + FM_END +}; class LPEFilletChamfer : public Effect { public: LPEFilletChamfer(LivePathEffectObject *lpeobject); virtual ~LPEFilletChamfer(); - + virtual void doBeforeEffect(SPLPEItem const *lpeItem); + virtual std::vector<Geom::Path> doEffect_path(std::vector<Geom::Path> const &path_in); virtual void doOnApply(SPLPEItem const *lpeItem); virtual void adjustForNewPath(std::vector<Geom::Path> const &path_in); SatellitePairArrayParam satellitepairarrayparam_values; private: - + EnumParam<FilletMethod> method; LPEFilletChamfer(const LPEFilletChamfer &); LPEFilletChamfer &operator=(const LPEFilletChamfer &); diff --git a/src/live_effects/parameter/array.cpp b/src/live_effects/parameter/array.cpp index d1d718b08..473b561d2 100644 --- a/src/live_effects/parameter/array.cpp +++ b/src/live_effects/parameter/array.cpp @@ -55,17 +55,16 @@ sp_svg_satellite_read_d(gchar const *str, Geom::Satellite *sat){ } gchar ** strarray = g_strsplit(str, "*", 0); if(strarray[6] && !strarray[7]){ - std::map< gchar const *, Geom::SatelliteType> gts = sat->GcharMapToSatelliteType; - sat->setSatelliteType(gts[strarray[0]]); + sat->setSatelliteType(strarray[0]); sat->setIsTime(helperfns_read_bool(strarray[1], true)); sat->setActive(helperfns_read_bool(strarray[2], true)); sat->setHasMirror(helperfns_read_bool(strarray[3], false)); sat->setHidden(helperfns_read_bool(strarray[4], false)); double time,size; - sp_svg_number_read_d(strarray[5], &time); - sp_svg_number_read_d(strarray[6], &size); - sat->setTime(time); + sp_svg_number_read_d(strarray[5], &size); + sp_svg_number_read_d(strarray[6], &time); sat->setSize(size); + sat->setTime(time); g_strfreev (strarray); return 1; } diff --git a/src/live_effects/parameter/array.h b/src/live_effects/parameter/array.h index ba1ed3d4e..c99777b08 100644 --- a/src/live_effects/parameter/array.h +++ b/src/live_effects/parameter/array.h @@ -116,19 +116,19 @@ protected: str << nVector.first; str << ","; std::map<Geom::SatelliteType, gchar const *> stg = nVector.second.SatelliteTypeToGcharMap; - str << stg[nVector.second.satellitetype()]; + str << nVector.second.getSatelliteTypeGchar(); str << "*"; - str << nVector.second.isTime(); + str << nVector.second.getIsTime(); str << "*"; - str << nVector.second.active(); + str << nVector.second.getActive(); str << "*"; - str << nVector.second.hasMirror(); + str << nVector.second.getHasMirror(); str << "*"; - str << nVector.second.hidden(); + str << nVector.second.getHidden(); str << "*"; - str << nVector.second.size(); + str << nVector.second.getSize(); str << "*"; - str <<nVector.second.time(); + str <<nVector.second.getTime(); } StorageType readsvg(const gchar * str); diff --git a/src/live_effects/parameter/satellitepairarray.cpp b/src/live_effects/parameter/satellitepairarray.cpp index a40e70e1f..bb72830d6 100644 --- a/src/live_effects/parameter/satellitepairarray.cpp +++ b/src/live_effects/parameter/satellitepairarray.cpp @@ -45,11 +45,9 @@ void SatellitePairArrayParam::set_oncanvas_looks(SPKnotShapeType shape, } void SatellitePairArrayParam::set_pwd2( - Piecewise<D2<SBasis> > const &pwd2_in, - Piecewise<D2<SBasis> > const &pwd2_normal_in) + Piecewise<D2<SBasis> > const &pwd2_in) { last_pwd2 = pwd2_in; - last_pwd2_normal = pwd2_normal_in; } void SatellitePairArrayParam::addKnotHolderEntities(KnotHolder *knotholder, diff --git a/src/live_effects/parameter/satellitepairarray.h b/src/live_effects/parameter/satellitepairarray.h index 82d04c790..ff1924829 100644 --- a/src/live_effects/parameter/satellitepairarray.h +++ b/src/live_effects/parameter/satellitepairarray.h @@ -47,14 +47,10 @@ public: return true; } virtual void addKnotHolderEntities(KnotHolder *knotholder, SPDesktop *desktop, SPItem *item); - void set_pwd2(Geom::Piecewise<Geom::D2<Geom::SBasis> > const &pwd2_in, - Geom::Piecewise<Geom::D2<Geom::SBasis> > const &pwd2_normal_in); + void set_pwd2(Geom::Piecewise<Geom::D2<Geom::SBasis> > const &pwd2_in); Geom::Piecewise<Geom::D2<Geom::SBasis> > const &get_pwd2() const { return last_pwd2; } - Geom::Piecewise<Geom::D2<Geom::SBasis> > const &get_pwd2_normal() const { - return last_pwd2_normal; - } friend class SatellitePairArrayParamKnotHolderEntity; private: @@ -66,7 +62,6 @@ private: guint32 knot_color; Geom::Piecewise<Geom::D2<Geom::SBasis> > last_pwd2; - Geom::Piecewise<Geom::D2<Geom::SBasis> > last_pwd2_normal; }; |
