summaryrefslogtreecommitdiffstats
path: root/src/live_effects/lpe-fillet-chamfer.cpp
diff options
context:
space:
mode:
authorJabier Arraiza Cenoz <jabier.arraiza@marker.es>2015-02-16 20:49:53 +0000
committerJabiertxof <jtx@jtx.marker.es>2015-02-16 20:49:53 +0000
commit9593c78703845bfca18a3a135cbbc47cc03b54f6 (patch)
tree4616e3cb7ed134d82367726aafaaf3f312d1cbc5 /src/live_effects/lpe-fillet-chamfer.cpp
parentadded knots (diff)
downloadinkscape-9593c78703845bfca18a3a135cbbc47cc03b54f6.tar.gz
inkscape-9593c78703845bfca18a3a135cbbc47cc03b54f6.zip
continuing fillet/chamfer
(bzr r13645.1.13)
Diffstat (limited to 'src/live_effects/lpe-fillet-chamfer.cpp')
-rw-r--r--src/live_effects/lpe-fillet-chamfer.cpp228
1 files changed, 212 insertions, 16 deletions
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());
}
}