diff options
| author | Jabier Arraiza Cenoz <jabier.arraiza@marker.es> | 2014-09-11 03:30:09 +0000 |
|---|---|---|
| committer | Jabiertxof <jtx@jtx.marker.es> | 2014-09-11 03:30:09 +0000 |
| commit | 39d4d238a04162c559f83011999cc16feb6da88f (patch) | |
| tree | 0a6cb688607c53d2ae529a8f4a72a04698008060 /src | |
| parent | Back out changes in r13514 -- seems to break build (diff) | |
| download | inkscape-39d4d238a04162c559f83011999cc16feb6da88f.tar.gz inkscape-39d4d238a04162c559f83011999cc16feb6da88f.zip | |
add radius support to fillet-chamfer, bugfixes
(bzr r13341.1.203)
Diffstat (limited to 'src')
| -rw-r--r-- | src/live_effects/lpe-fillet-chamfer.cpp | 163 | ||||
| -rw-r--r-- | src/live_effects/lpe-fillet-chamfer.h | 2 | ||||
| -rw-r--r-- | src/live_effects/parameter/filletchamferpointarray.cpp | 262 | ||||
| -rw-r--r-- | src/live_effects/parameter/filletchamferpointarray.h | 8 | ||||
| -rw-r--r-- | src/ui/dialog/lpe-fillet-chamfer-properties.cpp | 71 | ||||
| -rw-r--r-- | src/ui/dialog/lpe-fillet-chamfer-properties.h | 31 |
6 files changed, 359 insertions, 178 deletions
diff --git a/src/live_effects/lpe-fillet-chamfer.cpp b/src/live_effects/lpe-fillet-chamfer.cpp index 1dffba1bf..0ad21a284 100644 --- a/src/live_effects/lpe-fillet-chamfer.cpp +++ b/src/live_effects/lpe-fillet-chamfer.cpp @@ -22,6 +22,9 @@ #include "desktop.h" #include "display/curve.h" #include "helper/geom-nodetype.h" +#include "helper/geom-curves.h" +#include "helper/geom.h" + #include "live_effects/parameter/filletchamferpointarray.h" // for programmatically updating knots @@ -49,6 +52,8 @@ LPEFilletChamfer::LPEFilletChamfer(LivePathEffectObject *lpeobject) : ignore_radius_0(_("Ignore 0 radius knots"), _("Ignore 0 radius knots"), "ignore_radius_0", &wr, this, false), only_selected(_("Change only selected nodes"), _("Change only selected nodes"), "only_selected", &wr, this, false), flexible(_("Flexible radius size (%)"), _("Flexible radius size (%)"), "flexible", &wr, this, false), + force_arcs(_("Use arcs in cubic curves"), _("Use arcs in cubic curves"), "force_arcs", &wr, this, false), + use_knot_distance(_("Use knots distance instead radius"), _("Use knots distance instead radius"), "use_knot_distance", &wr, this, false), unit(_("Unit"), _("Unit"), "unit", &wr, this), radius(_("Radius (unit or %)"), _("Radius, in unit or %"), "radius", &wr, this, 0.), helper_size(_("Helper size with direction"), _("Helper size with direction"), "helper_size", &wr, this, 0) @@ -58,9 +63,11 @@ LPEFilletChamfer::LPEFilletChamfer(LivePathEffectObject *lpeobject) : registerParameter(&radius); registerParameter(&helper_size); registerParameter(&flexible); + registerParameter(&use_knot_distance); registerParameter(&ignore_radius_0); registerParameter(&only_selected); registerParameter(&hide_knots); + registerParameter(&force_arcs); radius.param_set_range(0., infinity()); radius.param_set_increments(1, 1); @@ -270,10 +277,10 @@ void LPEFilletChamfer::doUpdateFillet(std::vector<Geom::Path> const& original_pa } std::vector<Point> filletChamferData = fillet_chamfer_values.data(); std::vector<Geom::Point> result; + std::vector<Geom::Path> original_pathv_processed = pathv_to_linear_and_cubic_beziers(original_pathv); int counter = 0; - for (PathVector::const_iterator path_it = original_pathv.begin(); - path_it != original_pathv.end(); ++path_it) { - int pathCounter = 0; + for (PathVector::const_iterator path_it = original_pathv_processed.begin(); + path_it != original_pathv_processed.end(); ++path_it) { if (path_it->empty()) continue; @@ -289,6 +296,9 @@ void LPEFilletChamfer::doUpdateFillet(std::vector<Geom::Path> const& original_pa double powerend = 0; while (curve_it1 != curve_endit) { powerend = power; + if (power < 0 && !use_knot_distance) { + powerend = fillet_chamfer_values.rad_to_len(counter,powerend); + } if (power > 0) { powerend = counter + (power / 100); } @@ -306,7 +316,6 @@ void LPEFilletChamfer::doUpdateFillet(std::vector<Geom::Path> const& original_pa ++curve_it1; ++curve_it2; counter++; - pathCounter++; } } fillet_chamfer_values.param_set_and_write_new_value(result); @@ -334,8 +343,9 @@ void LPEFilletChamfer::doChangeType(std::vector<Geom::Path> const& original_path } std::vector<Point> filletChamferData = fillet_chamfer_values.data(); std::vector<Geom::Point> result; + std::vector<Geom::Path> original_pathv_processed = pathv_to_linear_and_cubic_beziers(original_pathv); int counter = 0; - for (PathVector::const_iterator path_it = original_pathv.begin(); path_it != original_pathv.end(); ++path_it) { + for (PathVector::const_iterator path_it = original_pathv_processed.begin(); path_it != original_pathv_processed.end(); ++path_it) { int pathCounter = 0; if (path_it->empty()) continue; @@ -378,7 +388,7 @@ void LPEFilletChamfer::doOnApply(SPLPEItem const *lpeItem) { if (SP_IS_SHAPE(lpeItem)) { std::vector<Point> point; - PathVector const &original_pathv = SP_SHAPE(lpeItem)->_curve->get_pathvector(); + PathVector const &original_pathv = pathv_to_linear_and_cubic_beziers(SP_SHAPE(lpeItem)->_curve->get_pathvector()); Piecewise<D2<SBasis> > pwd2_in = paths_to_pw(original_pathv); for (PathVector::const_iterator path_it = original_pathv.begin(); path_it != original_pathv.end(); ++path_it) { if (path_it->empty()) @@ -401,10 +411,15 @@ void LPEFilletChamfer::doOnApply(SPLPEItem const *lpeItem) } int counter = 0; while (curve_it1 != curve_endit) { + std::pair<std::size_t, std::size_t> positions = fillet_chamfer_values.get_positions(counter, original_pathv); Geom::NodeType nodetype; - if (counter == 0) { + if (positions.second == 0) { if (path_it->closed()) { - nodetype = get_nodetype(path_it->back_default(), *curve_it1); + Piecewise<D2<SBasis> > u; + u.push_cut(0); + u.push(pwd2_in[fillet_chamfer_values.last_index(counter, original_pathv)], 1); + Geom::Curve const * A = path_from_piecewise(u, 0.1)[0][0].duplicate(); + nodetype = get_nodetype(*A, *curve_it1); } else { nodetype = NODE_NONE; } @@ -433,12 +448,15 @@ void LPEFilletChamfer::doBeforeEffect(SPLPEItem const *lpeItem) { if (SP_IS_SHAPE(lpeItem)) { fillet_chamfer_values.set_helper_size(helper_size); + fillet_chamfer_values.set_use_distance(use_knot_distance); fillet_chamfer_values.set_unit(unit.get_abbreviation()); - SPCurve *c = SP_IS_PATH(lpeItem) ? static_cast<SPPath const *>(lpeItem)->get_original_curve() : SP_SHAPE(lpeItem)->getCurve(); + SPCurve *c = SP_IS_PATH(lpeItem) ? static_cast<SPPath const *>(lpeItem) + ->get_original_curve() + : SP_SHAPE(lpeItem)->getCurve(); std::vector<Point> filletChamferData = fillet_chamfer_values.data(); if (!filletChamferData.empty() && getKnotsNumber(c) != (int) filletChamferData.size()) { - PathVector const original_pathv = c->get_pathvector(); + PathVector const original_pathv = pathv_to_linear_and_cubic_beziers(c->get_pathvector()); Piecewise<D2<SBasis> > pwd2_in = paths_to_pw(original_pathv); fillet_chamfer_values.recalculate_controlpoints_for_new_pwd2(pwd2_in); } @@ -450,7 +468,7 @@ void LPEFilletChamfer::doBeforeEffect(SPLPEItem const *lpeItem) int LPEFilletChamfer::getKnotsNumber(SPCurve const *c) { int nKnots = c->nodes_in_path(); - PathVector const pv = c->get_pathvector(); + PathVector const pv = pathv_to_linear_and_cubic_beziers(c->get_pathvector()); for (std::vector<Geom::Path>::const_iterator path_it = pv.begin(); path_it != pv.end(); ++path_it) { if (!(*path_it).closed()) { @@ -464,8 +482,7 @@ void LPEFilletChamfer::adjustForNewPath(std::vector<Geom::Path> const &path_in) { if (!path_in.empty()) { - fillet_chamfer_values.recalculate_controlpoints_for_new_pwd2(path_in[0] - .toPwSb()); + fillet_chamfer_values.recalculate_controlpoints_for_new_pwd2(pathv_to_linear_and_cubic_beziers(path_in)[0].toPwSb()); } } @@ -473,17 +490,17 @@ 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(path_in); + Piecewise<D2<SBasis> > pwd2_in = paths_to_pw(pathv_to_linear_and_cubic_beziers(path_in)); pwd2_in = remove_short_cuts(pwd2_in, .01); Piecewise<D2<SBasis> > der = derivative(pwd2_in); Piecewise<D2<SBasis> > n = rot90(unitVector(der)); fillet_chamfer_values.set_pwd2(pwd2_in, n); std::vector<Point> filletChamferData = fillet_chamfer_values.data(); unsigned int counter = 0; - //from http://launchpadlibrarian.net/12692602/rcp.svg const double K = (4.0 / 3.0) * (sqrt(2.0) - 1.0); - for (PathVector::const_iterator path_it = path_in.begin(); - path_it != path_in.end(); ++path_it) { + 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; @@ -504,81 +521,24 @@ LPEFilletChamfer::doEffect_path(std::vector<Geom::Path> const &path_in) } unsigned int counterCurves = 0; while (curve_it1 != curve_endit) { - Coord it1_length = (*curve_it1).length(tolerance); - double time_it1, time_it2, time_it1_B, intpart; - time_it1 = modf( - fillet_chamfer_values.to_time(counter, filletChamferData[counter][X]), - &intpart); - if (filletChamferData[counter][Y] == 0) { - time_it1 = 0; - } - if (path_it->closed() && curve_it2 == curve_endit) { - time_it2 = modf(fillet_chamfer_values.to_time( - counter - counterCurves, - filletChamferData[counter - counterCurves][X]), - &intpart); - } else if (!path_it->closed() && curve_it2 == curve_endit){ - time_it2 = 0; - } else { - time_it2 = modf(fillet_chamfer_values.to_time( - counter + 1, filletChamferData[counter + 1][X]), - &intpart); - } - double resultLenght = 0; - time_it1_B = 1; - if (path_it->closed() && curve_it2 == curve_endit) { - resultLenght = - it1_length + fillet_chamfer_values.to_len( - counter - counterCurves, - filletChamferData[counter - counterCurves][X]); - } else if (!path_it->closed() && curve_it2 == curve_endit){ - resultLenght = 0; - } else { - resultLenght = - it1_length + fillet_chamfer_values.to_len( - counter + 1, filletChamferData[counter + 1][X]); - } - if (resultLenght > 0 && time_it2 != 0) { - time_it1_B = modf(fillet_chamfer_values.to_time(counter, -resultLenght), - &intpart); - } else { - if (time_it2 == 0) { - time_it1_B = 1; - } else { - time_it1_B = gapHelper; - } - } - if (path_it->closed() && curve_it2 == curve_endit && - filletChamferData[counter - counterCurves][Y] == 0) { - time_it1_B = 1; - time_it2 = 0; - } else if (path_it->size() > counterCurves + 1 && - filletChamferData[counter + 1][Y] == 0) { - time_it1_B = 1; - time_it2 = 0; + Curve *curve_it2Fixed = (*path_it->begin()).duplicate(); + if(!path_it->closed() || curve_it2 != curve_endit){ + curve_it2Fixed = (*curve_it2).duplicate(); } - if (time_it1_B < time_it1) { - time_it1_B = time_it1 + gapHelper; - } - Curve *knotCurve1 = curve_it1->portion(time_it1, time_it1_B); + bool last = curve_it2 == curve_endit; + std::vector<double> times = fillet_chamfer_values.get_times(counter, path_in, last); + Curve *knotCurve1 = curve_it1->portion(times[0], times[1]); if (counterCurves > 0) { knotCurve1->setInitial(path_out.finalPoint()); } else { - path_out.start((*curve_it1).pointAt(time_it1)); - } - Curve *knotCurve2 = (*path_it).front().portion(time_it2, 1); - if (curve_it2 != curve_endit) { - knotCurve2 = (*curve_it2).portion(time_it2, 1); + path_out.start((*curve_it1).pointAt(times[0])); } + Curve *knotCurve2 = curve_it2Fixed->portion(times[2], 1); Point startArcPoint = knotCurve1->finalPoint(); - Point endArcPoint = (*path_it).front().pointAt(time_it2); - if (curve_it2 != curve_endit) { - endArcPoint = (*curve_it2).pointAt(time_it2); - } + Point endArcPoint = curve_it2Fixed->pointAt(times[2]); double k1 = distance(startArcPoint, curve_it1->finalPoint()) * K; double k2 = distance(endArcPoint, curve_it1->finalPoint()) * K; - Geom::CubicBezier const *cubic1 = - dynamic_cast<Geom::CubicBezier const *>(&*knotCurve1); + Geom::CubicBezier const *cubic1 = dynamic_cast<Geom::CubicBezier const *>(&*knotCurve1); Ray ray1(startArcPoint, curve_it1->finalPoint()); if (cubic1) { ray1.setPoints((*cubic1)[2], startArcPoint); @@ -591,8 +551,7 @@ LPEFilletChamfer::doEffect_path(std::vector<Geom::Path> const &path_in) ray2.setPoints(endArcPoint, (*cubic2)[1]); } Point handle2 = endArcPoint - Point::polar(ray2.angle(),k2); - bool ccwToggle = cross(curve_it1->finalPoint() - startArcPoint, - endArcPoint - startArcPoint) < 0; + bool ccwToggle = cross(curve_it1->finalPoint() - startArcPoint, endArcPoint - startArcPoint) < 0; double angle = angle_between(ray1, ray2, ccwToggle); double handleAngle = ray1.angle() - angle; if (ccwToggle) { @@ -604,14 +563,22 @@ LPEFilletChamfer::doEffect_path(std::vector<Geom::Path> const &path_in) handleAngle = ray2.angle() - angle; } Point inverseHandle2 = endArcPoint - Point::polar(handleAngle,k2); - if (time_it1_B != 1) { - if (time_it1_B != gapHelper && time_it1_B != time_it1 + gapHelper) { + //straigth lines arc based + Line const x_line(Geom::Point(0,0),Geom::Point(1,0)); + Line const angled_line(startArcPoint,endArcPoint); + double angleArc = Geom::angle_between( x_line,angled_line); + double radius = Geom::distance(startArcPoint,middle_point(startArcPoint,endArcPoint))/sin(angle/2.0); + Coord rx = radius; + Coord ry = rx; + + if (times[1] != 1) { + if (times[1] != gapHelper && times[1] != times[0] + gapHelper) { path_out.append(*knotCurve1); } int type = 0; - if(path_it->closed() && curve_it2 == curve_endit){ + if(path_it->closed() && last){ type = abs(filletChamferData[counter - counterCurves][Y]); - } else if (!path_it->closed() && curve_it2 == curve_endit){ + } else if (!path_it->closed() && last){ //0 } else { type = abs(filletChamferData[counter + 1][Y]); @@ -624,15 +591,23 @@ LPEFilletChamfer::doEffect_path(std::vector<Geom::Path> const &path_in) } path_out.appendNew<Geom::LineSegment>(endArcPoint); } else if (type == 2) { - path_out.appendNew<Geom::CubicBezier>(inverseHandle1, inverseHandle2, - endArcPoint); + if((is_straight_curve(*curve_it1) && is_straight_curve(*curve_it2Fixed)) || force_arcs){ + ccwToggle = ccwToggle?0:1; + path_out.appendNew<SVGEllipticalArc>(rx, ry, angleArc, 0, ccwToggle, endArcPoint); + }else{ + path_out.appendNew<Geom::CubicBezier>(inverseHandle1, inverseHandle2, endArcPoint); + } } else { - path_out.appendNew<Geom::CubicBezier>(handle1, handle2, endArcPoint); + if((is_straight_curve(*curve_it1) && is_straight_curve(*curve_it2Fixed)) || force_arcs){ + path_out.appendNew<SVGEllipticalArc>(rx, ry, angleArc, 0, ccwToggle, endArcPoint); + } else { + path_out.appendNew<Geom::CubicBezier>(handle1, handle2, endArcPoint); + } } } else { path_out.append(*knotCurve1); } - if (path_it->closed() && curve_it2 == curve_endit) { + if (path_it->closed() && last) { path_out.close(); } ++curve_it1; diff --git a/src/live_effects/lpe-fillet-chamfer.h b/src/live_effects/lpe-fillet-chamfer.h index 2c1d83b2b..49b407b71 100644 --- a/src/live_effects/lpe-fillet-chamfer.h +++ b/src/live_effects/lpe-fillet-chamfer.h @@ -67,6 +67,8 @@ private: BoolParam ignore_radius_0; BoolParam only_selected; BoolParam flexible; + BoolParam force_arcs; + BoolParam use_knot_distance; UnitParam unit; ScalarParam radius; ScalarParam helper_size; diff --git a/src/live_effects/parameter/filletchamferpointarray.cpp b/src/live_effects/parameter/filletchamferpointarray.cpp index a89a6279b..cfc0ebcf1 100644 --- a/src/live_effects/parameter/filletchamferpointarray.cpp +++ b/src/live_effects/parameter/filletchamferpointarray.cpp @@ -8,12 +8,15 @@ * Released under GNU GPL, read the file 'COPYING' for more information */ -#include "ui/dialog/lpe-fillet-chamfer-properties.h" -#include "live_effects/parameter/filletchamferpointarray.h" #include <2geom/piecewise.h> #include <2geom/sbasis-to-bezier.h> #include <2geom/sbasis-geometric.h> +#include <2geom/svg-elliptical-arc.h> +#include <2geom/line.h> +#include <2geom/path-intersection.h> +#include "ui/dialog/lpe-fillet-chamfer-properties.h" +#include "live_effects/parameter/filletchamferpointarray.h" #include "live_effects/effect.h" #include "svg/svg.h" #include "svg/stringstream.h" @@ -32,6 +35,7 @@ // this has to be included last. #include <glibmm/i18n.h> + using namespace Geom; namespace Inkscape { @@ -165,11 +169,12 @@ void FilletChamferPointArrayParam::recalculate_controlpoints_for_new_pwd2( } } if (last_pathv.size() > pathv.size() || - (last_pathv[counterPaths].size() > counter - offset && + (last_pathv.size() > counterPaths && + last_pathv[counterPaths].size() > counter - offset && !are_near(curve_it1->initialPoint(), last_pathv[counterPaths][counter - offset].initialPoint(), 0.1))) { - if (last_pathv.size() > counterPaths && curve_it2 == curve_endit) { + if ( curve_it2 == curve_endit) { if (last_pathv[counterPaths].size() < pathv[counterPaths].size()) { offset = abs(last_pathv[counterPaths].size() - pathv[counterPaths].size()); @@ -332,10 +337,10 @@ void FilletChamferPointArrayParam::recalculate_knots( result.push_back(Point(xPos, 0)); } ++curve_it1; + counter++; if (curve_it2 != curve_endit) { ++curve_it2; } - counter++; counterCurves++; } } @@ -359,6 +364,11 @@ void FilletChamferPointArrayParam::set_helper_size(int hs) helper_size = hs; } +void FilletChamferPointArrayParam::set_use_distance(bool use_knot_distance ) +{ + use_distance = use_knot_distance; +} + void FilletChamferPointArrayParam::set_unit(const gchar *abbr) { unit = abbr; @@ -398,6 +408,205 @@ void FilletChamferPointArrayParam::addCanvasIndicators( hp_vec.push_back(hp); } +double FilletChamferPointArrayParam::rad_to_len(int index, double rad) +{ + double len = 0; + std::vector<Geom::Path> subpaths = path_from_piecewise(last_pwd2, 0.1); + std::pair<std::size_t, std::size_t> positions = get_positions(index, subpaths); + D2<SBasis> A = last_pwd2[last_index(index, subpaths)]; + if(positions.second != 0){ + A = last_pwd2[index-1]; + }else{ + if(!subpaths[positions.first].closed()){ + return len; + } + } + D2<SBasis> B = last_pwd2[index]; + Piecewise<D2<SBasis> > offset_curve0 = Piecewise<D2<SBasis> >(A)+rot90(unitVector(derivative(A)))*(rad); + Piecewise<D2<SBasis> > offset_curve1 = Piecewise<D2<SBasis> >(B)+rot90(unitVector(derivative(B)))*(rad); + Geom::Path p0 = path_from_piecewise(offset_curve0, 0.1)[0]; + Geom::Path p1 = path_from_piecewise(offset_curve1, 0.1)[0]; + Geom::Crossings cs = Geom::crossings(p0, p1); + if(cs.size() > 0){ + Point cp =p0(cs[0].ta); + double p0pt = nearest_point(cp, B); + len = time_to_len(index,p0pt); + } else { + if(rad < 0){ + len = rad_to_len(index, rad * -1); + } + } + return len; +} + +double FilletChamferPointArrayParam::len_to_rad(int index, double len) +{ + double rad = 0; + double tmp_len = _vector[index][X]; + _vector[index] = Geom::Point(len,_vector[index][Y]); + std::vector<Geom::Path> subpaths = path_from_piecewise(last_pwd2, 0.1); + std::pair<std::size_t, std::size_t> positions = get_positions(index, subpaths); + Piecewise<D2<SBasis> > u; + u.push_cut(0); + u.push(last_pwd2[last_index(index, subpaths)], 1); + Geom::Curve * A = path_from_piecewise(u, 0.1)[0][0].duplicate(); + Geom::Curve * B = subpaths[positions.first][positions.second].duplicate(); + std::vector<double> times; + if(positions.second != 0){ + A = subpaths[positions.first][positions.second-1].duplicate(); + times = get_times(index-1, subpaths, false); + }else{ + if(!subpaths[positions.first].closed()){ + return rad; + } + times = get_times(last_index(index, subpaths), subpaths, true); + } + _vector[index] = Geom::Point(tmp_len,_vector[index][Y]); + Geom::Point startArcPoint = A->toSBasis().valueAt(times[1]); + Geom::Point endArcPoint = B->toSBasis().valueAt(times[2]); + Curve *knotCurve1 = A->portion(times[0], times[1]); + Curve *knotCurve2 = B->portion(times[2], 1); + Geom::CubicBezier const *cubic1 = dynamic_cast<Geom::CubicBezier const *>(&*knotCurve1); + Ray ray1(startArcPoint, A->finalPoint()); + if (cubic1) { + ray1.setPoints((*cubic1)[2], startArcPoint); + } + Geom::CubicBezier const *cubic2 = dynamic_cast<Geom::CubicBezier const *>(&*knotCurve2); + Ray ray2(B->initialPoint(), endArcPoint); + if (cubic2) { + ray2.setPoints(endArcPoint, (*cubic2)[1]); + } + bool ccwToggle = cross(A->finalPoint() - startArcPoint, endArcPoint - startArcPoint) < 0; + double distanceArc = Geom::distance(startArcPoint,middle_point(startArcPoint,endArcPoint)); + double angleBetween = angle_between(ray1, ray2, ccwToggle); + rad = distanceArc/sin(angleBetween/2.0); + return rad * -1; +} + +std::vector<double> FilletChamferPointArrayParam::get_times(int index, std::vector<Geom::Path> subpaths, bool last) +{ + const double tolerance = 0.001; + const double gapHelper = 0.00001; + std::pair<std::size_t, std::size_t> positions = get_positions(index, subpaths); + Curve *curve_it1; + curve_it1 = subpaths[positions.first][positions.second].duplicate(); + Coord it1_length = (*curve_it1).length(tolerance); + double time_it1, time_it2, time_it1_B, intpart; + time_it1 = modf(to_time(index, _vector[index][X]), &intpart); + if (_vector[index][Y] == 0) { + time_it1 = 0; + } + double resultLenght = 0; + time_it1_B = 1; + if (subpaths[positions.first].closed() && last) { + time_it2 = modf(to_time(index - positions.second , _vector[index - positions.second ][X]), &intpart); + resultLenght = it1_length + to_len(index - positions.second, _vector[index - positions.second ][X]); + } else if (!subpaths[positions.first].closed() && last){ + time_it2 = 0; + resultLenght = 0; + } else { + time_it2 = modf(to_time(index + 1, _vector[index + 1][X]), &intpart); + resultLenght = it1_length + to_len( index + 1, _vector[index + 1][X]); + } + if (resultLenght > 0 && time_it2 != 0) { + time_it1_B = modf(to_time(index, -resultLenght), &intpart); + } else { + if (time_it2 == 0) { + time_it1_B = 1; + } else { + time_it1_B = gapHelper; + } + } + + if ((subpaths[positions.first].closed() && last && _vector[index - positions.second][Y] == 0) || (subpaths[positions.first].size() > positions.second + 1 && _vector[index + 1][Y] == 0)) { + time_it1_B = 1; + time_it2 = 0; + } + if (time_it1_B < time_it1) { + time_it1_B = time_it1 + gapHelper; + } + std::vector<double> out; + out.push_back(time_it1); + out.push_back(time_it1_B); + out.push_back(time_it2); + return out; +} + +std::pair<std::size_t, std::size_t> FilletChamferPointArrayParam::get_positions(int index, std::vector<Geom::Path> subpaths) +{ + int counter = -1; + std::size_t first = 0; + std::size_t second = 0; + for (PathVector::const_iterator path_it = subpaths.begin(); path_it != subpaths.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(); + // the closing line segment is always of type + // Geom::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(); + } + } + first++; + second = 0; + while (curve_it1 != curve_endit) { + counter++; + second++; + if(counter == index){ + break; + } + ++curve_it1; + } + if(counter == index){ + break; + } + } + first--; + second--; + std::pair<std::size_t, std::size_t> out(first, second); + return out; +} + +int FilletChamferPointArrayParam::last_index(int index, std::vector<Geom::Path> subpaths) +{ + int counter = -1; + bool inSubpath = false; + for (PathVector::const_iterator path_it = subpaths.begin(); path_it != subpaths.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(); + if (are_near(closingline.initialPoint(), closingline.finalPoint())) { + curve_endit = path_it->end_open(); + } + } + while (curve_it1 != curve_endit) { + counter++; + if(counter == index){ + inSubpath = true; + } + ++curve_it1; + } + if(inSubpath){ + break; + } + } + if(!inSubpath){ + counter = -1; + } + return counter; +} + + double FilletChamferPointArrayParam::len_to_time(int index, double len) { double t = 0; @@ -405,7 +614,7 @@ double FilletChamferPointArrayParam::len_to_time(int index, double len) if (len != 0) { if (last_pwd2[index][0].degreesOfFreedom() != 2) { Piecewise<D2<SBasis> > u; - u.push_cut(0); + u.push_cut(0); u.push(last_pwd2[index], 1); std::vector<double> t_roots = roots(arcLengthSb(u) - std::abs(len)); if (t_roots.size() > 0) { @@ -586,34 +795,34 @@ void FilletChamferPointArrayParamKnotHolderEntity::knot_click(guint state) this->knot->tip = g_strdup(tip); this->knot->show(); } - } else if ((state & GDK_MOD1_MASK) || (state & GDK_SHIFT_MASK)) { - Geom::Point offset = Geom::Point(_pparam->_vector.at(_index).x(), - _pparam->_vector.at(_index).y()); + } else if (state & GDK_SHIFT_MASK) { + double xModified = _pparam->_vector.at(_index).x(); + if(xModified < 0 && !_pparam->use_distance){ + xModified = _pparam->len_to_rad(_index, _pparam->_vector.at(_index).x()); + } + std::vector<Geom::Path> subpaths = path_from_piecewise(_pparam->last_pwd2, 0.1); + std::pair<std::size_t, std::size_t> positions = _pparam->get_positions(_index, subpaths); + D2<SBasis> A = _pparam->last_pwd2[_pparam->last_index(_index, subpaths)]; + if(positions.second != 0){ + A = _pparam->last_pwd2[_index-1]; + } + D2<SBasis> B = _pparam->last_pwd2[_index]; + bool aprox = (A[0].degreesOfFreedom() != 2 || B[0].degreesOfFreedom() != 2) && !_pparam->use_distance?true:false; + Geom::Point offset = Geom::Point(xModified, _pparam->_vector.at(_index).y()); Inkscape::UI::Dialogs::FilletChamferPropertiesDialog::showDialog( - this->desktop, offset, this, _pparam->unit); + this->desktop, offset, this, _pparam->unit, _pparam->use_distance, aprox); } } -void -FilletChamferPointArrayParamKnotHolderEntity::knot_doubleclicked(guint state) -{ - //todo: fill the double click dialog whith this parameters in the added file - //src/ui/dialog/lpe-fillet-chamfer-properties.cpp(.h) - //My idea for when have enought time is: - //label whith radius in percent - //label whith radius in size -maybe handle units- - //entry whith actual radius -in flexible % mode or fixed -?px- - //2 radio options to switch entry from fixed or flexible, also update the - //entry - //Checkbox or two radios to swith fillet or chamfer - -} - void FilletChamferPointArrayParamKnotHolderEntity::knot_set_offset( Geom::Point offset) { - _pparam->_vector.at(_index) = Geom::Point(offset.x(), offset.y()); + double xModified = offset.x(); + if(xModified < 0 && !_pparam->use_distance){ + xModified = _pparam->rad_to_len(_index, offset.x()); + } + _pparam->_vector.at(_index) = Geom::Point(xModified, offset.y()); this->parent_holder->knot_ungrabbed_handler(this->knot, 0); } @@ -644,7 +853,6 @@ void FilletChamferPointArrayParam::addKnotHolderEntities(KnotHolder *knotholder, "<b>Shift+Click</b> open dialog, " "<b>Ctrl+Alt+Click</b> reset"); } - FilletChamferPointArrayParamKnotHolderEntity *e = new FilletChamferPointArrayParamKnotHolderEntity(this, i); e->create(desktop, item, knotholder, Inkscape::CTRL_TYPE_UNKNOWN, _(tip), diff --git a/src/live_effects/parameter/filletchamferpointarray.h b/src/live_effects/parameter/filletchamferpointarray.h index 93d6e9f4c..a1fa698ae 100644 --- a/src/live_effects/parameter/filletchamferpointarray.h +++ b/src/live_effects/parameter/filletchamferpointarray.h @@ -43,9 +43,15 @@ public: guint32 color); virtual double to_time(int index, double A); virtual double to_len(int index, double A); + virtual double rad_to_len(int index, double rad); + virtual double len_to_rad(int index, double len); virtual double len_to_time(int index, double len); virtual double time_to_len(int index, double time); + virtual std::pair<std::size_t, std::size_t> get_positions(int index, std::vector<Geom::Path> subpaths); + virtual int last_index(int index, std::vector<Geom::Path> subpaths); + std::vector<double> get_times(int index, std::vector<Geom::Path> subpaths, bool last); virtual void set_helper_size(int hs); + virtual void set_use_distance(bool use_knot_distance); virtual void set_unit(const gchar *abbr); virtual void addCanvasIndicators(SPLPEItem const *lpeitem, std::vector<Geom::PathVector> &hp_vec); @@ -79,6 +85,7 @@ private: SPKnotModeType knot_mode; guint32 knot_color; int helper_size; + bool use_distance; const gchar *unit; Geom::PathVector hp; @@ -96,7 +103,6 @@ public: guint state); virtual Geom::Point knot_get() const; virtual void knot_click(guint state); - virtual void knot_doubleclicked(guint state); virtual void knot_set_offset(Geom::Point offset); /*Checks whether the index falls within the size of the parameter's vector*/ diff --git a/src/ui/dialog/lpe-fillet-chamfer-properties.cpp b/src/ui/dialog/lpe-fillet-chamfer-properties.cpp index eef32d10d..ad8b66b8c 100644 --- a/src/ui/dialog/lpe-fillet-chamfer-properties.cpp +++ b/src/ui/dialog/lpe-fillet-chamfer-properties.cpp @@ -12,9 +12,9 @@ #include <glibmm/threads.h> #endif +#include <gtkmm.h> #include "lpe-fillet-chamfer-properties.h" #include <boost/lexical_cast.hpp> -#include <gtkmm/stock.h> #include <glibmm/main.h> #include <glibmm/i18n.h> #include "inkscape.h" @@ -31,9 +31,8 @@ #include "selection-chemistry.h" #include "ui/icon-names.h" #include "ui/widget/imagetoggler.h" -#include <cmath> -#include <gtkmm/radiobutton.h> #include "util/units.h" +#include <cmath> //#include "event-context.h" @@ -44,38 +43,24 @@ namespace Dialogs { FilletChamferPropertiesDialog::FilletChamferPropertiesDialog() : _desktop(NULL), _knotpoint(NULL), _position_visible(false) { -#if WITH_GTKMM_3_0 - Gtk::Box *mainVBox = get_content_area(); -#else Gtk::Box *mainVBox = get_vbox(); -#endif - mainVBox->set_homogeneous(false); - -#if WITH_GTKMM_3_0 - _layout_table.set_row_spacing(4); - _layout_table.set_column_spacing(4); -#else _layout_table.set_spacings(4); _layout_table.resize(2, 2); -#endif // Layer name widgets - _fillet_chamfer_position_entry.set_activates_default(true); + _fillet_chamfer_position_numeric.set_digits(4); + _fillet_chamfer_position_numeric.set_increments(1,1); + //todo: get tha max aloable infinity freeze the widget + _fillet_chamfer_position_numeric.set_range(0., 999999999999999999.); + _fillet_chamfer_position_label.set_label(_("Radius (pixels):")); _fillet_chamfer_position_label.set_alignment(1.0, 0.5); -#if WITH_GTKMM_3_0 - _layout_table.attach(_fillet_chamfer_position_label, 0, 0, 1, 1); - _layout_table.attach(_fillet_chamfer_position_entry, 1, 0, 1, 1); - _fillet_chamfer_position_entry.set_hexpand(); -#else _layout_table.attach(_fillet_chamfer_position_label, 0, 1, 0, 1, Gtk::FILL, Gtk::FILL); - _layout_table.attach(_fillet_chamfer_position_entry, 1, 2, 0, 1, + _layout_table.attach(_fillet_chamfer_position_numeric, 1, 2, 0, 1, Gtk::FILL | Gtk::EXPAND, Gtk::FILL); -#endif - _fillet_chamfer_type_fillet.set_label(_("Fillet")); _fillet_chamfer_type_fillet.set_group(_fillet_chamfer_type_group); _fillet_chamfer_type_inverse_fillet.set_label(_("Inverse fillet")); @@ -115,7 +100,7 @@ FilletChamferPropertiesDialog::FilletChamferPropertiesDialog() show_all_children(); - set_focus(_fillet_chamfer_position_entry); + set_focus(_fillet_chamfer_position_numeric); } FilletChamferPropertiesDialog::~FilletChamferPropertiesDialog() @@ -128,12 +113,16 @@ void FilletChamferPropertiesDialog::showDialog( SPDesktop *desktop, Geom::Point knotpoint, const Inkscape::LivePathEffect:: FilletChamferPointArrayParamKnotHolderEntity *pt, - const gchar *unit) + const gchar *unit, + bool use_distance, + bool aprox_radius) { FilletChamferPropertiesDialog *dialog = new FilletChamferPropertiesDialog(); dialog->_setDesktop(desktop); dialog->_setUnit(unit); + dialog->_set_use_distance(use_distance); + dialog->_set_aprox(aprox_radius); dialog->_setKnotPoint(knotpoint); dialog->_setPt(pt); @@ -150,9 +139,9 @@ void FilletChamferPropertiesDialog::showDialog( void FilletChamferPropertiesDialog::_apply() { - std::istringstream i_pos(_fillet_chamfer_position_entry.get_text()); - double d_pos, d_width; - if (i_pos >> d_pos) { + double d_width; + double d_pos = _fillet_chamfer_position_numeric.get_value(); + if (d_pos) { if (_fillet_chamfer_type_fillet.get_active() == true) { d_width = 1; } else if (_fillet_chamfer_type_inverse_fillet.get_active() == true) { @@ -203,6 +192,13 @@ void FilletChamferPropertiesDialog::_handleButtonEvent(GdkEventButton *event) void FilletChamferPropertiesDialog::_setKnotPoint(Geom::Point knotpoint) { double position; + std::string distance_or_radius = std::string(_("Radius ")); + if(aprox){ + distance_or_radius = std::string(_("Radius aproximated ")); + } + if(use_distance){ + distance_or_radius = std::string(_("Knot distance ")); + } if (knotpoint.x() > 0) { double intpart; position = modf(knotpoint[Geom::X], &intpart) * 100; @@ -211,16 +207,13 @@ void FilletChamferPropertiesDialog::_setKnotPoint(Geom::Point knotpoint) _fillet_chamfer_position_label.set_label(_("Position (%):")); } else { _flexible = false; - std::string posConcat = - std::string(_("Position (")) + std::string(unit) + std::string(")"); + std::string posConcat = distance_or_radius + + std::string(_("(")) + std::string(unit) + std::string(")"); _fillet_chamfer_position_label.set_label(_(posConcat.c_str())); position = knotpoint[Geom::X] * -1; position = Inkscape::Util::Quantity::convert(position, "px", unit); } - std::ostringstream s; - s.imbue(std::locale::classic()); - s << position; - _fillet_chamfer_position_entry.set_text(s.str()); + _fillet_chamfer_position_numeric.set_value(position); if (knotpoint.y() == 1) { _fillet_chamfer_type_fillet.set_active(true); } else if (knotpoint.y() == 2) { @@ -246,6 +239,16 @@ void FilletChamferPropertiesDialog::_setUnit(const gchar *abbr) unit = abbr; } +void FilletChamferPropertiesDialog::_set_use_distance(bool use_knot_distance) +{ + use_distance = use_knot_distance; +} + +void FilletChamferPropertiesDialog::_set_aprox(bool aprox_radius) +{ + aprox = aprox_radius; +} + void FilletChamferPropertiesDialog::_setDesktop(SPDesktop *desktop) { if (desktop) { diff --git a/src/ui/dialog/lpe-fillet-chamfer-properties.h b/src/ui/dialog/lpe-fillet-chamfer-properties.h index 9beca02e1..47ff97b00 100644 --- a/src/ui/dialog/lpe-fillet-chamfer-properties.h +++ b/src/ui/dialog/lpe-fillet-chamfer-properties.h @@ -8,24 +8,10 @@ #ifndef INKSCAPE_DIALOG_FILLET_CHAMFER_PROPERTIES_H #define INKSCAPE_DIALOG_FILLET_CHAMFER_PROPERTIES_H -#if HAVE_CONFIG_H - #include "config.h" -#endif - -#include <gtkmm/dialog.h> #include <2geom/point.h> +#include <gtkmm.h> #include "live_effects/parameter/filletchamferpointarray.h" -#include <gtkmm/entry.h> -#include <gtkmm/label.h> -#include <gtkmm/radiobutton.h> - -#if WITH_GTKMM_3_0 - #include <gtkmm/grid.h> -#else - #include <gtkmm/table.h> -#endif - class SPDesktop; namespace Inkscape { @@ -44,7 +30,9 @@ public: static void showDialog(SPDesktop *desktop, Geom::Point knotpoint, const Inkscape::LivePathEffect:: FilletChamferPointArrayParamKnotHolderEntity *pt, - const gchar *unit); + const gchar *unit, + bool use_distance, + bool aprox_radius); protected: @@ -53,19 +41,14 @@ protected: _knotpoint; Gtk::Label _fillet_chamfer_position_label; - Gtk::Entry _fillet_chamfer_position_entry; + Gtk::SpinButton _fillet_chamfer_position_numeric; Gtk::RadioButton::Group _fillet_chamfer_type_group; Gtk::RadioButton _fillet_chamfer_type_fillet; Gtk::RadioButton _fillet_chamfer_type_inverse_fillet; Gtk::RadioButton _fillet_chamfer_type_chamfer; Gtk::RadioButton _fillet_chamfer_type_double_chamfer; -#if WITH_GTKMM_3_0 - Gtk::Grid _layout_table; -#else Gtk::Table _layout_table; -#endif - bool _position_visible; double _index; @@ -83,10 +66,14 @@ protected: void _setPt(const Inkscape::LivePathEffect:: FilletChamferPointArrayParamKnotHolderEntity *pt); void _setUnit(const gchar *abbr); + void _set_use_distance(bool use_knot_distance); + void _set_aprox(bool aprox_radius); void _apply(); void _close(); bool _flexible; const gchar *unit; + bool use_distance; + bool aprox; void _setKnotPoint(Geom::Point knotpoint); void _prepareLabelRenderer(Gtk::TreeModel::const_iterator const &row); |
