summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorJabier Arraiza Cenoz <jabier.arraiza@marker.es>2014-09-11 03:30:09 +0000
committerJabiertxof <jtx@jtx.marker.es>2014-09-11 03:30:09 +0000
commit39d4d238a04162c559f83011999cc16feb6da88f (patch)
tree0a6cb688607c53d2ae529a8f4a72a04698008060 /src
parentBack out changes in r13514 -- seems to break build (diff)
downloadinkscape-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.cpp163
-rw-r--r--src/live_effects/lpe-fillet-chamfer.h2
-rw-r--r--src/live_effects/parameter/filletchamferpointarray.cpp262
-rw-r--r--src/live_effects/parameter/filletchamferpointarray.h8
-rw-r--r--src/ui/dialog/lpe-fillet-chamfer-properties.cpp71
-rw-r--r--src/ui/dialog/lpe-fillet-chamfer-properties.h31
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);