summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorJabier Arraiza Cenoz <jabier.arraiza@marker.es>2016-03-01 01:42:13 +0000
committerjabiertxof <info@marker.es>2016-03-01 01:42:13 +0000
commit145f815859ba21f45e67d315e52f360f029355c7 (patch)
tree54448bc60a94415f63f7b6f46296c8d5e2ac58a6 /src
parentImprove fill rule and add mass option (diff)
parenttype in commit r14664 (diff)
downloadinkscape-145f815859ba21f45e67d315e52f360f029355c7.tar.gz
inkscape-145f815859ba21f45e67d315e52f360f029355c7.zip
update to trunk
(bzr r14648.1.3)
Diffstat (limited to 'src')
-rw-r--r--src/2geom/circle.cpp8
-rw-r--r--src/2geom/conicsec.cpp14
-rw-r--r--src/2geom/coord.cpp9
-rw-r--r--src/2geom/ellipse.cpp2
-rw-r--r--src/2geom/generic-interval.h3
-rw-r--r--src/2geom/generic-rect.h5
-rw-r--r--src/2geom/line.cpp38
-rw-r--r--src/2geom/line.h41
-rw-r--r--src/2geom/ray.h47
-rw-r--r--src/2geom/sbasis-to-bezier.cpp4
-rw-r--r--src/2geom/sweeper.h12
-rw-r--r--src/2geom/utils.h2
-rw-r--r--src/conn-avoid-ref.cpp4
-rw-r--r--src/desktop-style.cpp2
-rw-r--r--src/display/sp-canvas.cpp4
-rw-r--r--src/document.cpp67
-rw-r--r--src/document.h6
-rw-r--r--src/extension/internal/cdr-input.cpp8
-rw-r--r--src/extension/internal/emf-inout.cpp32
-rw-r--r--src/extension/internal/wmf-inout.cpp32
-rw-r--r--src/helper/geom-pathstroke.cpp362
-rw-r--r--src/helper/geom-pathstroke.h3
-rw-r--r--src/inkview.cpp361
-rw-r--r--src/io/inkjar.cpp17
-rw-r--r--src/live_effects/lpe-jointype.cpp3
-rw-r--r--src/object-snapper.cpp1
-rw-r--r--src/sp-marker.cpp3
-rw-r--r--src/sp-mask.cpp8
-rw-r--r--src/sp-text.cpp5
-rw-r--r--src/ui/dialog/document-properties.cpp4
-rw-r--r--src/ui/dialog/text-edit.cpp4
-rw-r--r--src/ui/tools/mesh-tool.cpp6
-rw-r--r--src/ui/tools/select-tool.cpp10
-rw-r--r--src/vanishing-point.cpp15
-rw-r--r--src/vanishing-point.h1
-rw-r--r--src/widgets/ruler.cpp344
-rw-r--r--src/widgets/text-toolbar.cpp2
37 files changed, 979 insertions, 510 deletions
diff --git a/src/2geom/circle.cpp b/src/2geom/circle.cpp
index 553981a72..934a8d3ab 100644
--- a/src/2geom/circle.cpp
+++ b/src/2geom/circle.cpp
@@ -144,7 +144,7 @@ bool Circle::contains(Circle const &other) const
bool Circle::intersects(Line const &l) const
{
// http://mathworld.wolfram.com/Circle-LineIntersection.html
- Coord dr = l.versor().length();
+ Coord dr = l.vector().length();
Coord r = _radius;
Coord D = cross(l.initialPoint(), l.finalPoint());
Coord delta = r*r * dr*dr - D*D;
@@ -163,9 +163,9 @@ bool Circle::intersects(Circle const &other) const
std::vector<ShapeIntersection> Circle::intersect(Line const &l) const
{
// http://mathworld.wolfram.com/Circle-LineIntersection.html
- Coord dr = l.versor().length();
- Coord dx = l.versor().x();
- Coord dy = l.versor().y();
+ Coord dr = l.vector().length();
+ Coord dx = l.vector().x();
+ Coord dy = l.vector().y();
Coord D = cross(l.initialPoint() - _center, l.finalPoint() - _center);
Coord delta = _radius*_radius * dr*dr - D*D;
diff --git a/src/2geom/conicsec.cpp b/src/2geom/conicsec.cpp
index 089db71a4..2d396ba30 100644
--- a/src/2geom/conicsec.cpp
+++ b/src/2geom/conicsec.cpp
@@ -114,8 +114,8 @@ double RatQuad::lambda() const {
RatQuad RatQuad::fromPointsTangents(Point P0, Point dP0,
Point P,
Point P2, Point dP2) {
- Line Line0 = Line::from_origin_and_versor(P0, dP0);
- Line Line2 = Line::from_origin_and_versor(P2, dP2);
+ Line Line0 = Line::from_origin_and_vector(P0, dP0);
+ Line Line2 = Line::from_origin_and_vector(P2, dP2);
try {
OptCrossing oc = intersection(Line0, Line2);
if(!oc) // what to do?
@@ -276,8 +276,8 @@ std::vector<Point> decompose_degenerate(xAx const & C1, xAx const & C2, xAx cons
n1 = Point(b-d, 1);
}
- Line L0 = Line::from_origin_and_versor(B0, rot90(n0));
- Line L1 = Line::from_origin_and_versor(B0, rot90(n1));
+ Line L0 = Line::from_origin_and_vector(B0, rot90(n0));
+ Line L1 = Line::from_origin_and_vector(B0, rot90(n1));
std::vector<double> rts = C1.roots(L0);
for(unsigned i = 0; i < rts.size(); i++) {
@@ -327,12 +327,12 @@ std::vector<Point> decompose_degenerate(xAx const & C1, xAx const & C2, xAx cons
*/
assert(L2sq(g) != 0);
- Line Lx = Line::from_origin_and_versor(trial_pt, g); // a line along the gradient
+ Line Lx = Line::from_origin_and_vector(trial_pt, g); // a line along the gradient
std::vector<double> rts = xC0.roots(Lx);
for(unsigned i = 0; i < rts.size(); i++) {
Point P0 = Lx.pointAt(rts[i]);
//std::cout << P0 << "\n";
- Line L = Line::from_origin_and_versor(P0, rot90(g));
+ Line L = Line::from_origin_and_vector(P0, rot90(g));
std::vector<double> cnrts;
// It's very likely that at least one of the conics is degenerate, this will hopefully pick the more generate of the two.
if(fabs(C1.hessian().det()) > fabs(C2.hessian().det()))
@@ -515,7 +515,7 @@ xAx xAx::operator*(double const &b) const {
if(L2sq(dA) <= 1e-10) { // perhaps a single point?
return boost::optional<RatQuad> ();
}
- LineSegment ls = intersection(Line::from_origin_and_versor(A, dA), bnd);
+ LineSegment ls = intersection(Line::from_origin_and_vector(A, dA), bnd);
return RatQuad::fromPointsTangents(A, dA, ls.pointAt(0.5), ls[1], dA);
}
else if(crs.size() >= 2 && crs.size() < 4) {
diff --git a/src/2geom/coord.cpp b/src/2geom/coord.cpp
index 8b5e28586..8c7485883 100644
--- a/src/2geom/coord.cpp
+++ b/src/2geom/coord.cpp
@@ -111,12 +111,6 @@ namespace Geom {
namespace {
-inline int StrLength(const char* string) {
- size_t length = strlen(string);
- ASSERT(length == static_cast<size_t>(static_cast<int>(length)));
- return static_cast<int>(length);
-}
-
template <typename T>
class Vector {
public:
@@ -1733,8 +1727,6 @@ enum FastDtoaMode {
FAST_DTOA_PRECISION
};
-static const int kFastDtoaMaximalLength = 17;
-
bool FastDtoa(double d,
FastDtoaMode mode,
int requested_digits,
@@ -2350,7 +2342,6 @@ bool FastFixedDtoa(double v,
return true;
}
-static const int kMaxExactDoubleIntegerDecimalDigits = 15;
static const int kMaxUint64DecimalDigits = 19;
static const int kMaxDecimalPower = 309;
diff --git a/src/2geom/ellipse.cpp b/src/2geom/ellipse.cpp
index afde428b1..f4704460f 100644
--- a/src/2geom/ellipse.cpp
+++ b/src/2geom/ellipse.cpp
@@ -417,7 +417,7 @@ std::vector<ShapeIntersection> Ellipse::intersect(Line const &line) const
// generic case
Coord a, b, c;
line.coefficients(a, b, c);
- Point lv = line.versor();
+ Point lv = line.vector();
if (fabs(lv[X]) > fabs(lv[Y])) {
// y = -a/b x - c/b
diff --git a/src/2geom/generic-interval.h b/src/2geom/generic-interval.h
index ce7945ab6..e7892e2dd 100644
--- a/src/2geom/generic-interval.h
+++ b/src/2geom/generic-interval.h
@@ -32,6 +32,7 @@
#define LIB2GEOM_SEEN_GENERIC_INTERVAL_H
#include <cassert>
+#include <iostream>
#include <boost/none.hpp>
#include <boost/optional.hpp>
#include <2geom/coord.h>
@@ -338,14 +339,12 @@ inline GenericOptInterval<C> operator&(GenericInterval<C> const &a, GenericInter
return GenericOptInterval<C>(a) & GenericOptInterval<C>(b);
}
-#ifdef _GLIBCXX_IOSTREAM
template <typename C>
inline std::ostream &operator<< (std::ostream &os,
Geom::GenericInterval<C> const &I) {
os << "Interval("<<I.min() << ", "<<I.max() << ")";
return os;
}
-#endif
} // namespace Geom
#endif // !LIB2GEOM_SEEN_GENERIC_INTERVAL_H
diff --git a/src/2geom/generic-rect.h b/src/2geom/generic-rect.h
index afd2cb8a7..fdc7f369b 100644
--- a/src/2geom/generic-rect.h
+++ b/src/2geom/generic-rect.h
@@ -41,6 +41,7 @@
#define LIB2GEOM_SEEN_GENERIC_RECT_H
#include <limits>
+#include <iostream>
#include <boost/optional.hpp>
#include <2geom/coord.h>
@@ -513,13 +514,11 @@ inline bool GenericRect<C>::contains(OptCRect const &r) const {
return !r || contains(*r);
}
-#ifdef _GLIBCXX_IOSTREAM
template <typename C>
inline std::ostream &operator<<(std::ostream &out, GenericRect<C> const &r) {
- out << "X: " << r[X] << " Y: " << r[Y];
+ out << "Rect " << r[X] << " x " << r[Y];
return out;
}
-#endif
} // end namespace Geom
diff --git a/src/2geom/line.cpp b/src/2geom/line.cpp
index ee2edeba7..a9cc0e251 100644
--- a/src/2geom/line.cpp
+++ b/src/2geom/line.cpp
@@ -103,7 +103,7 @@ void Line::setCoefficients (Coord a, Coord b, Coord c)
void Line::coefficients(Coord &a, Coord &b, Coord &c) const
{
- Point v = versor().cw();
+ Point v = vector().cw();
a = v[X];
b = v[Y];
c = cross(_initial, _final);
@@ -139,7 +139,7 @@ std::vector<Coord> Line::roots(Coord v, Dim2 d) const {
Coord Line::root(Coord v, Dim2 d) const
{
assert(d == X || d == Y);
- Point vs = versor();
+ Point vs = vector();
if (vs[d] != 0) {
return (v - _initial[d]) / vs[d];
} else {
@@ -149,7 +149,7 @@ Coord Line::root(Coord v, Dim2 d) const
boost::optional<LineSegment> Line::clip(Rect const &r) const
{
- Point v = versor();
+ Point v = vector();
// handle horizontal and vertical lines first,
// since the root-based code below will break for them
for (unsigned i = 0; i < 2; ++i) {
@@ -221,7 +221,7 @@ boost::optional<LineSegment> Line::clip(Rect const &r) const
* @see timeAtProjection */
Coord Line::timeAt(Point const &p) const
{
- Point v = versor();
+ Point v = vector();
// degenerate case
if (v[X] == 0 && v[Y] == 0) {
return 0;
@@ -243,8 +243,8 @@ Coord Line::timeAt(Point const &p) const
Affine Line::transformTo(Line const &other) const
{
Affine result = Translate(-_initial);
- result *= Rotate(angle_between(versor(), other.versor()));
- result *= Scale(other.versor().length() / versor().length());
+ result *= Rotate(angle_between(vector(), other.vector()));
+ result *= Scale(other.vector().length() / vector().length());
result *= Translate(other._initial);
return result;
}
@@ -253,8 +253,8 @@ std::vector<ShapeIntersection> Line::intersect(Line const &other) const
{
std::vector<ShapeIntersection> result;
- Point v1 = versor();
- Point v2 = other.versor();
+ Point v1 = vector();
+ Point v2 = other.vector();
Coord cp = cross(v1, v2);
if (cp == 0) return result;
@@ -333,8 +333,8 @@ OptCrossing intersection_impl(Ray const& r1, Line const& l2, unsigned int i)
using std::swap;
OptCrossing crossing =
- intersection_impl(r1.versor(), r1.origin(),
- l2.versor(), l2.origin() );
+ intersection_impl(r1.vector(), r1.origin(),
+ l2.vector(), l2.origin() );
if (crossing) {
if (crossing->ta < 0) {
@@ -363,7 +363,7 @@ OptCrossing intersection_impl( LineSegment const& ls1,
OptCrossing crossing =
intersection_impl(ls1.finalPoint() - ls1.initialPoint(),
ls1.initialPoint(),
- l2.versor(),
+ l2.vector(),
l2.origin() );
if (crossing) {
@@ -396,7 +396,7 @@ OptCrossing intersection_impl( LineSegment const& ls1,
OptCrossing crossing =
intersection_impl( direction,
ls1.initialPoint(),
- r2.versor(),
+ r2.vector(),
r2.origin() );
if (crossing) {
@@ -414,7 +414,7 @@ OptCrossing intersection_impl( LineSegment const& ls1,
}
if ( are_near(r2.origin(), ls1) ) {
- bool eqvs = (dot(direction, r2.versor()) > 0);
+ bool eqvs = (dot(direction, r2.vector()) > 0);
if ( are_near(ls1.initialPoint(), r2.origin()) && !eqvs) {
crossing->ta = crossing->tb = 0;
return crossing;
@@ -445,8 +445,8 @@ OptCrossing intersection_impl( LineSegment const& ls1,
OptCrossing intersection(Line const& l1, Line const& l2)
{
OptCrossing c = detail::intersection_impl(
- l1.versor(), l1.origin(),
- l2.versor(), l2.origin());
+ l1.vector(), l1.origin(),
+ l2.vector(), l2.origin());
if (!c && distance(l1.origin(), l2) == 0) {
THROW_INFINITESOLUTIONS();
@@ -457,8 +457,8 @@ OptCrossing intersection(Line const& l1, Line const& l2)
OptCrossing intersection(Ray const& r1, Ray const& r2)
{
OptCrossing crossing =
- detail::intersection_impl( r1.versor(), r1.origin(),
- r2.versor(), r2.origin() );
+ detail::intersection_impl( r1.vector(), r1.origin(),
+ r2.vector(), r2.origin() );
if (crossing)
{
@@ -477,7 +477,7 @@ OptCrossing intersection(Ray const& r1, Ray const& r2)
if ( are_near(r1.origin(), r2) || are_near(r2.origin(), r1) )
{
if ( are_near(r1.origin(), r2.origin())
- && !are_near(r1.versor(), r2.versor()) )
+ && !are_near(r1.vector(), r2.vector()) )
{
crossing->ta = crossing->tb = 0;
return crossing;
@@ -582,7 +582,7 @@ Line make_angle_bisector_line(Line const& l1, Line const& l2)
}
Point O = l1.pointAt(crossing->ta);
Point A = l1.pointAt(crossing->ta + 1);
- double angle = angle_between(l1.versor(), l2.versor());
+ double angle = angle_between(l1.vector(), l2.vector());
Point B = (angle > 0) ? l2.pointAt(crossing->tb + 1)
: l2.pointAt(crossing->tb - 1);
diff --git a/src/2geom/line.h b/src/2geom/line.h
index 8a66d4472..62b3652f1 100644
--- a/src/2geom/line.h
+++ b/src/2geom/line.h
@@ -98,7 +98,7 @@ public:
/// Create a line by extending a ray.
explicit Line(Ray const &r)
: _initial(r.origin())
- , _final(r.origin() + r.versor())
+ , _final(r.origin() + r.vector())
{}
/// Create a line normal to a vector at a specified distance from origin.
@@ -111,7 +111,7 @@ public:
* Note that each line direction has two possible unit vectors.
* @param o Point through which the line will pass
* @param v Unit vector of the line's direction */
- static Line from_origin_and_versor(Point const &o, Point const &v) {
+ static Line from_origin_and_vector(Point const &o, Point const &v) {
Line l(o, o + v);
return l;
}
@@ -126,9 +126,12 @@ public:
/// Get the line's origin point.
Point origin() const { return _initial; }
- /** @brief Get the line's direction vector.
- * Note that the retrieved vector is not normalized to unit length. */
- Point versor() const { return _final - _initial; }
+ /** @brief Get the line's raw direction vector.
+ * The retrieved vector is normalized to unit length. */
+ Point vector() const { return _final - _initial; }
+ /** @brief Get the line's normalized direction vector.
+ * The retrieved vector is normalized to unit length. */
+ Point versor() const { return (_final - _initial).normalized(); }
/// Angle the line makes with the X axis, in mathematical convention.
Coord angle() const {
Point d = _final - _initial;
@@ -147,7 +150,7 @@ public:
}
/** @brief Set the speed of the line.
* Origin remains unchanged. */
- void setVersor(Point const &v) {
+ void setVector(Point const &v) {
_final = _initial + v;
}
@@ -239,7 +242,7 @@ public:
* @return Time value corresponding to a point closest to @c p. */
Coord timeAtProjection(Point const& p) const {
if ( isDegenerate() ) return 0;
- Point v = versor();
+ Point v = vector();
return dot(p - _initial, v) / dot(v, v);
}
@@ -284,22 +287,22 @@ public:
boost::optional<LineSegment> clip(Rect const &r) const;
/** @brief Create a ray starting at the specified time value.
- * The created ray will go in the direction of the line's versor (in the direction
+ * The created ray will go in the direction of the line's vector (in the direction
* of increasing time values).
* @param t Time value where the ray should start
- * @return Ray starting at t and going in the direction of the versor */
+ * @return Ray starting at t and going in the direction of the vector */
Ray ray(Coord t) {
Ray result;
result.setOrigin(pointAt(t));
- result.setVersor(versor());
+ result.setVector(vector());
return result;
}
/** @brief Create a derivative of the line.
* The new line will always be degenerate. Its origin will be equal to this
- * line's versor. */
+ * line's vector. */
Line derivative() const {
- Point v = versor();
+ Point v = vector();
Line result(v, v);
return result;
}
@@ -314,7 +317,7 @@ public:
* If Y grows upwards, then this is the left normal. If Y grows downwards,
* then this is the right normal. */
Point normal() const {
- return rot90(versor()).normalized();
+ return rot90(vector()).normalized();
}
// what does this do?
@@ -326,7 +329,7 @@ public:
/// Compute an affine matrix representing a reflection about the line.
Affine reflection() const {
- Point v = versor().normalized();
+ Point v = versor();
Coord x2 = v[X]*v[X], y2 = v[Y]*v[Y], xy = v[X]*v[Y];
Affine m(x2-y2, 2.*xy,
2.*xy, y2-x2,
@@ -344,7 +347,7 @@ public:
* lower precision than e.g. a shear transform.
* @param d Which coordinate of points on the line should be zero after the transformation */
Affine rotationToZero(Dim2 d) const {
- Point v = versor();
+ Point v = vector();
if (d == X) {
std::swap(v[X], v[Y]);
} else {
@@ -421,7 +424,7 @@ bool are_near(Point const &p, Line const &line, double eps = EPSILON)
inline
bool are_parallel(Line const &l1, Line const &l2, double eps = EPSILON)
{
- return are_near(cross(l1.versor(), l2.versor()), 0, eps);
+ return are_near(cross(l1.vector(), l2.vector()), 0, eps);
}
/** @brief Test whether two lines are approximately the same.
@@ -442,7 +445,7 @@ bool are_same(Line const &l1, Line const &l2, double eps = EPSILON)
inline
bool are_orthogonal(Line const &l1, Line const &l2, double eps = EPSILON)
{
- return are_near(dot(l1.versor(), l2.versor()), 0, eps);
+ return are_near(dot(l1.vector(), l2.vector()), 0, eps);
}
// evaluate the angle between l1 and l2 rotating l1 in cw direction
@@ -451,7 +454,7 @@ bool are_orthogonal(Line const &l1, Line const &l2, double eps = EPSILON)
inline
double angle_between(Line const& l1, Line const& l2)
{
- double angle = angle_between(l1.versor(), l2.versor());
+ double angle = angle_between(l1.vector(), l2.vector());
if (angle < 0) angle += M_PI;
if (angle == M_PI) angle = 0;
return angle;
@@ -474,7 +477,7 @@ bool are_near(Point const &p, LineSegment const &seg, double eps = EPSILON)
inline
Line make_orthogonal_line(Point const &p, Line const &line)
{
- Point d = line.versor().cw();
+ Point d = line.vector().cw();
Line l(p, p + d);
return l;
}
diff --git a/src/2geom/ray.h b/src/2geom/ray.h
index a336e3132..4e60fd814 100644
--- a/src/2geom/ray.h
+++ b/src/2geom/ray.h
@@ -53,61 +53,62 @@ namespace Geom
class Ray {
private:
Point _origin;
- Point _versor;
+ Point _vector;
public:
- Ray() : _origin(0,0), _versor(1,0) {}
+ Ray() : _origin(0,0), _vector(1,0) {}
Ray(Point const& origin, Coord angle)
: _origin(origin)
{
- sincos(angle, _versor[Y], _versor[X]);
+ sincos(angle, _vector[Y], _vector[X]);
}
Ray(Point const& A, Point const& B) {
setPoints(A, B);
}
Point origin() const { return _origin; }
- Point versor() const { return _versor; }
+ Point vector() const { return _vector; }
+ Point versor() const { return _vector.normalized(); }
void setOrigin(Point const &o) { _origin = o; }
- void setVersor(Point const& v) { _versor = v; }
- Coord angle() const { return std::atan2(_versor[Y], _versor[X]); }
- void setAngle(Coord a) { sincos(a, _versor[Y], _versor[X]); }
+ void setVector(Point const& v) { _vector = v; }
+ Coord angle() const { return std::atan2(_vector[Y], _vector[X]); }
+ void setAngle(Coord a) { sincos(a, _vector[Y], _vector[X]); }
void setPoints(Point const &a, Point const &b) {
_origin = a;
- _versor = b - a;
- if (are_near(_versor, Point(0,0)) )
- _versor = Point(0,0);
+ _vector = b - a;
+ if (are_near(_vector, Point(0,0)) )
+ _vector = Point(0,0);
else
- _versor.normalize();
+ _vector.normalize();
}
bool isDegenerate() const {
- return ( _versor[X] == 0 && _versor[Y] == 0 );
+ return ( _vector[X] == 0 && _vector[Y] == 0 );
}
Point pointAt(Coord t) const {
- return _origin + _versor * t;
+ return _origin + _vector * t;
}
Coord valueAt(Coord t, Dim2 d) const {
- return _origin[d] + _versor[d] * t;
+ return _origin[d] + _vector[d] * t;
}
std::vector<Coord> roots(Coord v, Dim2 d) const {
std::vector<Coord> result;
- if ( _versor[d] != 0 ) {
- double t = (v - _origin[d]) / _versor[d];
+ if ( _vector[d] != 0 ) {
+ double t = (v - _origin[d]) / _vector[d];
if (t >= 0) result.push_back(t);
- } else if (_versor[(d+1)%2] == v) {
+ } else if (_vector[(d+1)%2] == v) {
THROW_INFINITESOLUTIONS();
}
return result;
}
Coord nearestTime(Point const& point) const {
if ( isDegenerate() ) return 0;
- double t = dot(point - _origin, _versor);
+ double t = dot(point - _origin, _vector);
if (t < 0) t = 0;
return t;
}
Ray reverse() const {
Ray result;
result.setOrigin(_origin);
- result.setVersor(-_versor);
+ result.setVector(-_vector);
return result;
}
Curve *portion(Coord f, Coord t) const {
@@ -117,7 +118,7 @@ public:
return LineSegment(pointAt(f), pointAt(t));
}
Ray transformed(Affine const& m) const {
- return Ray(_origin * m, (_origin + _versor) * m);
+ return Ray(_origin * m, (_origin + _vector) * m);
}
}; // end class Ray
@@ -134,7 +135,7 @@ bool are_near(Point const& _point, Ray const& _ray, double eps = EPSILON) {
inline
bool are_same(Ray const& r1, Ray const& r2, double eps = EPSILON) {
- return are_near(r1.versor(), r2.versor(), eps)
+ return are_near(r1.vector(), r2.vector(), eps)
&& are_near(r1.origin(), r2.origin(), eps);
}
@@ -142,7 +143,7 @@ bool are_same(Ray const& r1, Ray const& r2, double eps = EPSILON) {
// the returned value is an angle in the interval [0, 2PI[
inline
double angle_between(Ray const& r1, Ray const& r2, bool cw = true) {
- double angle = angle_between(r1.versor(), r2.versor());
+ double angle = angle_between(r1.vector(), r2.vector());
if (angle < 0) angle += 2*M_PI;
if (!cw) angle = 2*M_PI - angle;
return angle;
@@ -170,7 +171,7 @@ Ray make_angle_bisector_ray(Ray const& r1, Ray const& r2, bool cw = true)
THROW_RANGEERROR("passed rays do not have the same origin");
}
- Ray bisector(r1.origin(), r1.origin() + r1.versor() * Rotate(angle_between(r1, r2) / 2.0));
+ Ray bisector(r1.origin(), r1.origin() + r1.vector() * Rotate(angle_between(r1, r2) / 2.0));
return (cw ? bisector : bisector.reverse());
}
diff --git a/src/2geom/sbasis-to-bezier.cpp b/src/2geom/sbasis-to-bezier.cpp
index d9a90aace..8a18cfd4a 100644
--- a/src/2geom/sbasis-to-bezier.cpp
+++ b/src/2geom/sbasis-to-bezier.cpp
@@ -205,11 +205,11 @@ void sbasis_to_cubic_bezier (std::vector<Point> & bz, D2<SBasis> const& sb)
xprime[i] = sb[X][0][1] - sb[X][0][0];
yprime[i] = sb[Y][0][1] - sb[Y][0][0];
}
- if (sb[X].size() > 0) {
+ if (sb[X].size() > 1) {
xprime[0] += sb[X][1][0];
xprime[1] -= sb[X][1][1];
}
- if (sb[Y].size() > 0) {
+ if (sb[Y].size() > 1) {
yprime[0] += sb[Y][1][0];
yprime[1] -= sb[Y][1][1];
}
diff --git a/src/2geom/sweeper.h b/src/2geom/sweeper.h
index b3c96455f..469108465 100644
--- a/src/2geom/sweeper.h
+++ b/src/2geom/sweeper.h
@@ -52,10 +52,10 @@ public:
{}
std::vector<Item> const &items() { return _items; }
- Interval itemBounds(ItemIterator ii) { return Interval(); }
+ Interval itemBounds(ItemIterator /*ii*/) { return Interval(); }
- void addActiveItem(ItemIterator ii) {}
- void removeActiveItem(ItemIterator ii) {}
+ void addActiveItem(ItemIterator /*ii*/) {}
+ void removeActiveItem(ItemIterator /*ii*/) {}
private:
std::vector<Item> const &_items;
@@ -104,9 +104,9 @@ public:
}
/** @brief Process entry and exit events.
- * This will iterate over all inserted items, calling the virtual protected
- * functions _enter() and _leave() according to the order of the boundaries
- * of each item. */
+ * This will iterate over all inserted items, calling the methods
+ * addActiveItem and removeActiveItem on the SweepSet passed at construction
+ * according to the order of the boundaries of each item. */
void process() {
if (_set.items().empty()) return;
diff --git a/src/2geom/utils.h b/src/2geom/utils.h
index 3e0dd4717..01579d81b 100644
--- a/src/2geom/utils.h
+++ b/src/2geom/utils.h
@@ -68,7 +68,7 @@ struct NullIterator
NullIterator() {}
template <typename T>
- void operator=(T const &v) {}
+ void operator=(T const &) {}
};
/** @brief Get the next iterator in the container with wrap-around.
diff --git a/src/conn-avoid-ref.cpp b/src/conn-avoid-ref.cpp
index d43d000a7..9190fe633 100644
--- a/src/conn-avoid-ref.cpp
+++ b/src/conn-avoid-ref.cpp
@@ -296,14 +296,14 @@ static Avoid::Polygon avoid_item_poly(SPItem const *item)
Geom::Line hull_edge(hull[-1], hull[0]);
Geom::Line prev_parallel_hull_edge;
prev_parallel_hull_edge.setOrigin(hull_edge.origin()+hull_edge.versor().ccw()*spacing);
- prev_parallel_hull_edge.setVersor(hull_edge.versor());
+ prev_parallel_hull_edge.setVector(hull_edge.versor());
int hull_size = hull.size();
for (int i = 0; i < hull_size; ++i)
{
hull_edge.setPoints(hull[i], hull[i+1]);
Geom::Line parallel_hull_edge;
parallel_hull_edge.setOrigin(hull_edge.origin()+hull_edge.versor().ccw()*spacing);
- parallel_hull_edge.setVersor(hull_edge.versor());
+ parallel_hull_edge.setVector(hull_edge.versor());
// determine the intersection point
try {
diff --git a/src/desktop-style.cpp b/src/desktop-style.cpp
index 67c0687b7..a81cbdd1f 100644
--- a/src/desktop-style.cpp
+++ b/src/desktop-style.cpp
@@ -1267,7 +1267,7 @@ objects_query_writing_modes (const std::vector<SPItem*> &objects, SPStyle *style
int texts = 0;
- for (std::vector<SPItem*>::const_iterator i = objects.begin(); i != objects.end(); i++) {
+ for (std::vector<SPItem*>::const_iterator i = objects.begin(); i != objects.end(); ++i) {
SPObject *obj = *i;
if (!isTextualItem(obj)) {
diff --git a/src/display/sp-canvas.cpp b/src/display/sp-canvas.cpp
index 22765cb9d..d17271752 100644
--- a/src/display/sp-canvas.cpp
+++ b/src/display/sp-canvas.cpp
@@ -607,7 +607,7 @@ void sp_canvas_item_raise(SPCanvasItem *item, int positions)
g_assert (l != parent->items.end());
for (int i=0; i<=positions && l != parent->items.end(); ++i)
- l++;
+ ++l;
parent->items.remove(item);
parent->items.insert(l, item);
@@ -656,7 +656,7 @@ void sp_canvas_item_lower(SPCanvasItem *item, int positions)
g_assert (l != parent->items.end());
for (int i=0; i<positions && l != parent->items.begin(); ++i)
- l--;
+ --l;
parent->items.remove(item);
parent->items.insert(l, item);
diff --git a/src/document.cpp b/src/document.cpp
index d4bd29386..ae03b1ba1 100644
--- a/src/document.cpp
+++ b/src/document.cpp
@@ -108,7 +108,8 @@ SPDocument::SPDocument() :
oldSignalsConnected(false),
current_persp3d(NULL),
current_persp3d_impl(NULL),
- _parent_document(NULL)
+ _parent_document(NULL),
+ _node_cache_valid(false)
{
// Penalise libavoid for choosing paths with needless extra segments.
// This results in much better looking orthogonal connector paths.
@@ -130,6 +131,7 @@ SPDocument::SPDocument() :
// XXX only for testing!
priv->undoStackObservers.add(p->console_output_undo_observer);
+ _node_cache = std::deque<SPItem*>();
}
SPDocument::~SPDocument() {
@@ -986,6 +988,7 @@ void SPDocument::_emitModified() {
static guint const flags = SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_CHILD_MODIFIED_FLAG | SP_OBJECT_PARENT_MODIFIED_FLAG;
root->emitModified(0);
priv->modified_signal.emit(flags);
+ _node_cache_valid=false;
}
void SPDocument::bindObjectToId(gchar const *id, SPObject *object) {
@@ -1332,34 +1335,24 @@ SPItem *SPDocument::getItemFromListAtPointBottom(unsigned int dkey, SPGroup *gro
/**
Turn the SVG DOM into a flat list of nodes that can be searched from top-down.
The list can be persisted, which improves "find at multiple points" speed.
-Returns true if upto is reached.
*/
-static bool build_flat_item_list(std::deque<SPItem*> *nodes, unsigned int dkey, SPGroup *group, gboolean into_groups, bool take_insensitive = false, SPItem *upto = NULL)
+void SPDocument::build_flat_item_list(unsigned int dkey, SPGroup *group, gboolean into_groups) const
{
- bool found_upto = false;
for ( SPObject *o = group->firstChild() ; o ; o = o->getNext() ) {
if (!SP_IS_ITEM(o)) {
continue;
}
- if (upto && SP_ITEM(o) == upto) {
- found_upto = true;
- break;
- }
-
if (SP_IS_GROUP(o) && (SP_GROUP(o)->effectiveLayerMode(dkey) == SPGroup::LAYER || into_groups)) {
- found_upto = build_flat_item_list(nodes, dkey, SP_GROUP(o), into_groups, take_insensitive, upto);
- if (found_upto)
- break;
+ build_flat_item_list(dkey, SP_GROUP(o), into_groups);
} else {
SPItem *child = SP_ITEM(o);
- if (take_insensitive || child->isVisibleAndUnlocked(dkey)) {
- nodes->push_front(child);
+ if (child->isVisibleAndUnlocked(dkey)) {
+ _node_cache.push_front(child);
}
}
}
- return found_upto;
}
/**
@@ -1371,15 +1364,21 @@ upwards in z-order and returns what it has found so far (i.e. the found item is
guaranteed to be lower than upto). Requires a list of nodes built by
build_flat_item_list.
*/
-static SPItem *find_item_at_point(std::deque<SPItem*> *nodes, unsigned int dkey, Geom::Point const &p)
+static SPItem *find_item_at_point(std::deque<SPItem*> *nodes, unsigned int dkey, Geom::Point const &p, SPItem* upto=NULL)
{
Inkscape::Preferences *prefs = Inkscape::Preferences::get();
gdouble delta = prefs->getDouble("/options/cursortolerance/value", 1.0);
SPItem *seen = NULL;
SPItem *child;
- for (unsigned long i = 0; i < nodes->size(); ++i) {
- child = nodes->at(i);
+ bool seen_upto = (!upto);
+ for (std::deque<SPItem*>::const_iterator i = nodes->begin(); i != nodes->end(); ++i) {
+ child = *i;
+ if (!seen_upto){
+ if(child == upto)
+ seen_upto = true;
+ continue;
+ }
Inkscape::DrawingItem *arenaitem = child->get_arenaitem(dkey);
if (arenaitem && arenaitem->pick(p, delta, 1) != NULL) {
@@ -1451,7 +1450,7 @@ std::vector<SPItem*> SPDocument::getItemsPartiallyInBox(unsigned int dkey, Geom:
return find_items_in_area(x, SP_GROUP(this->root), dkey, box, overlaps, false, into_groups);
}
-std::vector<SPItem*> SPDocument::getItemsAtPoints(unsigned const key, std::vector<Geom::Point> points, bool all_layers, size_t limit) const
+std::vector<SPItem*> SPDocument::getItemsAtPoints(unsigned const key, std::vector<Geom::Point> points, bool all_layers, size_t limit) const
{
std::vector<SPItem*> items;
Inkscape::Preferences *prefs = Inkscape::Preferences::get();
@@ -1463,8 +1462,11 @@ std::vector<SPItem*> SPDocument::getItemsAtPoints(unsigned const key, std::vecto
prefs->setDouble("/options/cursortolerance/value", 0.25);
// Cache a flattened SVG DOM to speed up selection.
- std::deque<SPItem*> nodes;
- build_flat_item_list(&nodes, key, SP_GROUP(this->root), true, false, NULL);
+ if(!_node_cache_valid){
+ _node_cache.clear();
+ build_flat_item_list(key, SP_GROUP(this->root), true);
+ _node_cache_valid=true;
+ }
SPObject *current_layer = SP_ACTIVE_DESKTOP->currentLayer();
SPDesktop *desktop = SP_ACTIVE_DESKTOP;
Inkscape::LayerModel *layer_model = NULL;
@@ -1473,7 +1475,7 @@ std::vector<SPItem*> SPDocument::getItemsAtPoints(unsigned const key, std::vecto
}
size_t item_counter = 0;
for(int i = points.size()-1;i>=0; i--) {
- SPItem *item = find_item_at_point(&nodes, key, points[i]);
+ SPItem *item = find_item_at_point(&_node_cache, key, points[i]);
if (item && items.end()==find(items.begin(),items.end(), item))
if(all_layers || (layer_model && layer_model->layerForObject(item) == current_layer)){
items.push_back(item);
@@ -1493,15 +1495,26 @@ std::vector<SPItem*> SPDocument::getItemsAtPoints(unsigned const key, std::vecto
}
SPItem *SPDocument::getItemAtPoint( unsigned const key, Geom::Point const &p,
- bool const into_groups, SPItem *upto) const
+ bool const into_groups, SPItem *upto) const
{
g_return_val_if_fail(this->priv != NULL, NULL);
// Build a flattened SVG DOM for find_item_at_point.
- std::deque<SPItem*> nodes;
- build_flat_item_list(&nodes, key, SP_GROUP(this->root), into_groups, false, upto);
-
- return find_item_at_point(&nodes, key, p);
+ std::deque<SPItem*> bak(_node_cache);
+ if(!into_groups){
+ _node_cache.clear();
+ build_flat_item_list(key, SP_GROUP(this->root), into_groups);
+ }
+ if(!_node_cache_valid && into_groups){
+ _node_cache.clear();
+ build_flat_item_list(key, SP_GROUP(this->root), true);
+ _node_cache_valid=true;
+ }
+
+ SPItem *res = find_item_at_point(&_node_cache, key, p, upto);
+ if(!into_groups)
+ _node_cache = bak;
+ return res;
}
SPItem *SPDocument::getGroupAtPoint(unsigned int key, Geom::Point const &p) const
diff --git a/src/document.h b/src/document.h
index b4a8a8e8e..825049cd5 100644
--- a/src/document.h
+++ b/src/document.h
@@ -28,6 +28,7 @@
#include <boost/ptr_container/ptr_list.hpp>
#include <vector>
#include <set>
+#include <deque>
namespace Avoid {
class Router;
@@ -263,7 +264,7 @@ public:
std::vector<SPItem*> getItemsInBox(unsigned int dkey, Geom::Rect const &box, bool into_groups = false) const;
std::vector<SPItem*> getItemsPartiallyInBox(unsigned int dkey, Geom::Rect const &box, bool into_groups = false) const;
SPItem *getItemAtPoint(unsigned int key, Geom::Point const &p, bool into_groups, SPItem *upto = NULL) const;
- std::vector<SPItem*> getItemsAtPoints(unsigned const key, std::vector<Geom::Point> points, bool all_layers = true, size_t limit = 0) const;
+ std::vector<SPItem*> getItemsAtPoints(unsigned const key, std::vector<Geom::Point> points, bool all_layers = true, size_t limit = 0) const ;
SPItem *getGroupAtPoint(unsigned int key, Geom::Point const &p) const;
void changeUriAndHrefs(char const *uri);
@@ -277,6 +278,9 @@ private:
void do_change_uri(char const *const filename, bool const rebase);
void setupViewport(SPItemCtx *ctx);
void importDefsNode(SPDocument *source, Inkscape::XML::Node *defs, Inkscape::XML::Node *target_defs);
+ void build_flat_item_list(unsigned int dkey, SPGroup *group, gboolean into_groups) const;
+ mutable std::deque<SPItem*> _node_cache;
+ mutable bool _node_cache_valid;
};
/*
diff --git a/src/extension/internal/cdr-input.cpp b/src/extension/internal/cdr-input.cpp
index f4789a08f..a4e26e224 100644
--- a/src/extension/internal/cdr-input.cpp
+++ b/src/extension/internal/cdr-input.cpp
@@ -22,6 +22,7 @@
#include <string>
#include <cstring>
+#include <glibmm/regex.h>
#include <libcdr/libcdr.h>
@@ -281,7 +282,12 @@ SPDocument *CdrInput::open(Inkscape::Extension::Input * /*mod*/, const gchar * u
}
}
- SPDocument * doc = SPDocument::createNewDocFromMem(tmpSVGOutput[page_num-1].cstr(), strlen(tmpSVGOutput[page_num-1].cstr()), TRUE);
+ // remove consecutive closepath commands (see bug 1492153)
+ Glib::RefPtr<Glib::Regex> regex = Glib::Regex::create("(Z(?:\\s+Z)+)(?=[^<]+\")");
+ Glib::ustring outString1 = Glib::ustring(tmpSVGOutput[page_num-1].cstr());
+ Glib::ustring outString2 = regex->replace(outString1, 0, "Z", Glib::REGEX_MATCH_NEWLINE_ANY);
+
+ SPDocument * doc = SPDocument::createNewDocFromMem(outString2.c_str(), outString2.bytes(), TRUE);
// Set viewBox if it doesn't exist
if (doc && !doc->getRoot()->viewBox_set) {
diff --git a/src/extension/internal/emf-inout.cpp b/src/extension/internal/emf-inout.cpp
index 68b38f5ee..13520c40b 100644
--- a/src/extension/internal/emf-inout.cpp
+++ b/src/extension/internal/emf-inout.cpp
@@ -1617,6 +1617,17 @@ int Emf::myEnhMetaFileProc(char *contents, unsigned int length, PEMF_CALLBACK_DA
uint32_t tbkMode = U_TRANSPARENT; // holds proposed change to bkMode, if text is involved saving these to the DC must wait until the text is written
U_COLORREF tbkColor = U_RGB(255, 255, 255); // holds proposed change to bkColor
+ // code for end user debugging
+ int eDbgRecord=0;
+ int eDbgComment=0;
+ int eDbgFinal=0;
+ char const* eDbgString = getenv( "INKSCAPE_DBG_EMF" );
+ if ( eDbgString != NULL ) {
+ if(strstr(eDbgString,"RECORD")){ eDbgRecord = 1; }
+ if(strstr(eDbgString,"COMMENT")){ eDbgComment = 1; }
+ if(strstr(eDbgString,"FINAL")){ eDbgFinal = 1; }
+ }
+
/* initialize the tsp for text reassembly */
tsp.string = NULL;
tsp.ori = 0.0; /* degrees */
@@ -1659,8 +1670,11 @@ int Emf::myEnhMetaFileProc(char *contents, unsigned int length, PEMF_CALLBACK_DA
lpEMFR = (PU_ENHMETARECORD)(contents + off);
-// Uncomment the following to track down toxic records
-// std::cout << "record type: " << iType << " name " << U_emr_names(iType) << " length: " << nSize << " offset: " << off <<std::endl;
+// At run time define environment variable INKSCAPE_DBG_EMF to include string RECORD.
+// Users may employ this to track down toxic records
+ if(eDbgRecord){
+ std::cout << "record type: " << iType << " name " << U_emr_names(iType) << " length: " << nSize << " offset: " << off <<std::endl;
+ }
off += nSize;
SVGOStringStream tmp_outsvg;
@@ -3475,14 +3489,20 @@ std::cout << "BEFORE DRAW"
dbg_str << "<!-- U_EMR_??? -->\n";
break;
} //end of switch
-// When testing, uncomment the following to place a comment for each processed EMR record in the SVG
-// d->outsvg += dbg_str.str().c_str();
+// At run time define environment variable INKSCAPE_DBG_EMF to include string COMMENT.
+// Users may employ this to to place a comment for each processed EMR record in the SVG
+ if(eDbgComment){
+ d->outsvg += dbg_str.str().c_str();
+ }
d->outsvg += tmp_outsvg.str().c_str();
d->path += tmp_path.str().c_str();
} //end of while
-// When testing, uncomment the following to show the final SVG derived from the EMF
-// std::cout << d->outsvg << std::endl;
+// At run time define environment variable INKSCAPE_DBG_EMF to include string FINAL
+// Users may employ this to to show the final SVG derived from the EMF
+ if(eDbgFinal){
+ std::cout << d->outsvg << std::endl;
+ }
(void) emr_properties(U_EMR_INVALID); // force the release of the lookup table memory, returned value is irrelevant
return(file_status);
diff --git a/src/extension/internal/wmf-inout.cpp b/src/extension/internal/wmf-inout.cpp
index d17180d91..b8b0c73de 100644
--- a/src/extension/internal/wmf-inout.cpp
+++ b/src/extension/internal/wmf-inout.cpp
@@ -1528,6 +1528,17 @@ int Wmf::myMetaFileProc(const char *contents, unsigned int length, PWMF_CALLBACK
uint16_t tbkMode = U_TRANSPARENT; // holds proposed change to bkMode, if text is involved saving these to the DC must wait until the text is written
U_COLORREF tbkColor = U_RGB(255, 255, 255); // holds proposed change to bkColor
+ // code for end user debugging
+ int wDbgRecord=0;
+ int wDbgComment=0;
+ int wDbgFinal=0;
+ char const* wDbgString = getenv( "INKSCAPE_DBG_WMF" );
+ if ( wDbgString != NULL ) {
+ if(strstr(wDbgString,"RECORD")){ wDbgRecord = 1; }
+ if(strstr(wDbgString,"COMMENT")){ wDbgComment = 1; }
+ if(strstr(wDbgString,"FINAL")){ wDbgFinal = 1; }
+ }
+
/* initialize the tsp for text reassembly */
tsp.string = NULL;
tsp.ori = 0.0; /* degrees */
@@ -1692,8 +1703,11 @@ int Wmf::myMetaFileProc(const char *contents, unsigned int length, PWMF_CALLBACK
file_status = 0;
break;
}
-// Uncomment the following to track down toxic records
-// std::cout << "record type: " << (int) iType << " name " << U_wmr_names(iType) << " length: " << nSize << " offset: " << off <<std::endl;
+// At run time define environment variable INKSCAPE_DBG_WMF to include string RECORD.
+// Users may employ this to track down toxic records
+ if(wDbgRecord){
+ std::cout << "record type: " << iType << " name " << U_wmr_names(iType) << " length: " << nSize << " offset: " << off <<std::endl;
+ }
SVGOStringStream tmp_path;
SVGOStringStream tmp_str;
@@ -3034,8 +3048,11 @@ std::cout << "BEFORE DRAW"
dbg_str << "<!-- U_WMR_??? -->\n";
break;
} //end of switch
-// When testing, uncomment the following to place a comment for each processed WMR record in the SVG
-// d->outsvg += dbg_str.str().c_str();
+// At run time define environment variable INKSCAPE_DBG_WMF to include string COMMENT.
+// Users may employ this to to place a comment for each processed WMR record in the SVG
+ if(wDbgComment){
+ d->outsvg += dbg_str.str().c_str();
+ }
d->path += tmp_path.str().c_str();
if(!nSize){ // There was some problem with the processing of this record, it is not safe to continue
file_status = 0;
@@ -3043,8 +3060,11 @@ std::cout << "BEFORE DRAW"
}
} //end of while on OK
-// When testing, uncomment the following to show the final SVG derived from the WMF
-// std::cout << d->outsvg << std::endl;
+// At run time define environment variable INKSCAPE_DBG_WMF to include string FINAL
+// Users may employ this to to show the final SVG derived from the WMF
+ if(wDbgFinal){
+ std::cout << d->outsvg << std::endl;
+ }
(void) U_wmr_properties(U_WMR_INVALID); // force the release of the lookup table memory, returned value is irrelevant
return(file_status);
diff --git a/src/helper/geom-pathstroke.cpp b/src/helper/geom-pathstroke.cpp
index c73a9e9e7..3ef4b15da 100644
--- a/src/helper/geom-pathstroke.cpp
+++ b/src/helper/geom-pathstroke.cpp
@@ -15,6 +15,7 @@
#include <2geom/sbasis-to-bezier.h> // cubicbezierpath_from_sbasis
#include <2geom/path-intersection.h>
#include <2geom/circle.h>
+#include <math.h>
#include "helper/geom-pathstroke.h"
@@ -55,6 +56,53 @@ static Circle touching_circle( D2<SBasis> const &curve, double t, double tol=0.0
return Geom::Circle(center, fabs(radius));
}
+
+// Area of triangle given three corner points
+static double area( Geom::Point a, Geom::Point b, Geom::Point c ) {
+
+ using Geom::X;
+ using Geom::Y;
+ return( 0.5 * fabs( ( a[X]*(b[Y]-c[Y]) + b[X]*(c[Y]-a[Y]) + c[X]*(a[Y]-b[Y]) ) ) );
+}
+
+// Alternative touching circle routine directly using Beziers. Works only at end points.
+static Circle touching_circle( CubicBezier const &curve, bool start ) {
+
+ double k = 0;
+ Geom::Point p;
+ Geom::Point normal;
+ if ( start ) {
+ double distance = Geom::distance( curve[1], curve[0] );
+ k = 4.0/3.0 * area( curve[0], curve[1], curve[2] ) /
+ (distance * distance * distance);
+ if( Geom::cross(curve[0]-curve[1], curve[1]-curve[2]) < 0 ) {
+ k = -k;
+ }
+ p = curve[0];
+ normal = Geom::Point(curve[1] - curve[0]).cw();
+ normal.normalize();
+ // std::cout << "Start k: " << k << " d: " << distance << " normal: " << normal << std::endl;
+ } else {
+ double distance = Geom::distance( curve[3], curve[2] );
+ k = 4.0/3.0 * area( curve[1], curve[2], curve[3] ) /
+ (distance * distance * distance);
+ if( Geom::cross(curve[1]-curve[2], curve[2]-curve[3]) < 0 ) {
+ k = -k;
+ }
+ p = curve[3];
+ normal = Geom::Point(curve[3] - curve[2]).cw();
+ normal.normalize();
+ // std::cout << "End k: " << k << " d: " << distance << " normal: " << normal << std::endl;
+ }
+ if( k == 0 ) {
+ return Geom::Circle( Geom::Point(0,std::numeric_limits<float>::infinity()),
+ std::numeric_limits<float>::infinity());
+ } else {
+ double radius = 1/k;
+ Geom::Point center = p + normal * radius;
+ return Geom::Circle( center, fabs(radius) );
+ }
+}
}
namespace {
@@ -77,7 +125,7 @@ struct join_data {
// line parameters
double miter;
- double width;
+ double width; // half stroke width
};
// Join functions must append the outgoing path
@@ -115,7 +163,9 @@ void miter_join_internal(join_data jd, bool clip)
if (p.isFinite()) {
// check size of miter
Point point_on_path = incoming.finalPoint() + rot90(tang1)*width;
- satisfied = distance(p, point_on_path) <= miter * 2.0 * width;
+ // SVG defines miter length as distance between inner intersection and outer intersection,
+ // which is twice the distance from p to point_on_path but width is half stroke width.
+ satisfied = distance(p, point_on_path) <= miter * width;
if (satisfied) {
// miter OK, check to see if we can do a relocation
if (inc_ls) {
@@ -124,13 +174,16 @@ void miter_join_internal(join_data jd, bool clip)
res.appendNew<LineSegment>(p);
}
} else if (clip) {
+ // std::cout << " Clipping ------------ " << std::endl;
// miter needs clipping, find two points
Point bisector_versor = Line(point_on_path, p).versor();
- Point point_limit = point_on_path + miter * 2.0 * width * bisector_versor;
-
+ Point point_limit = point_on_path + miter * width * bisector_versor;
+ // std::cout << " bisector_versor: " << bisector_versor << std::endl;
+ // std::cout << " point_limit: " << point_limit << std::endl;
Point p1 = intersection_point(incoming.finalPoint(), tang1, point_limit, bisector_versor.cw());
Point p2 = intersection_point(outgoing.initialPoint(), tang2, point_limit, bisector_versor.cw());
-
+ // std::cout << " p1: " << p1 << std::endl;
+ // std::cout << " p2: " << p2 << std::endl;
if (inc_ls) {
res.setFinal(p1);
} else {
@@ -176,8 +229,132 @@ Geom::Point pick_solution(std::vector<Geom::ShapeIntersection> points, Geom::Poi
return sol;
}
-void extrapolate_join(join_data jd)
+// Arcs line join. If two circles don't intersect, expand inner circle.
+Geom::Point expand_circle( Geom::Circle &inner_circle, Geom::Circle const &outer_circle, Geom::Point const &start_pt, Geom::Point const &start_tangent ) {
+ // std::cout << "expand_circle:" << std::endl;
+ // std::cout << " outer_circle: radius: " << outer_circle.radius() << " center: " << outer_circle.center() << std::endl;
+ // std::cout << " start: point: " << start_pt << " tangent: " << start_tangent << std::endl;
+
+ if( !(outer_circle.contains(start_pt) ) ) {
+ // std::cout << " WARNING: Outer circle does not contain starting point!" << std::endl;
+ return Geom::Point(0,0);
+ }
+
+ Geom::Line secant1(start_pt, start_pt + start_tangent);
+ std::vector<Geom::ShapeIntersection> chord1_pts = outer_circle.intersect(secant1);
+ // std::cout << " chord1: " << chord1_pts[0].point() << ", " << chord1_pts[1].point() << std::endl;
+ Geom::LineSegment chord1(chord1_pts[0].point(), chord1_pts[1].point());
+
+ Geom::Line bisector = make_bisector_line( chord1 );
+ std::vector<Geom::ShapeIntersection> chord2_pts = outer_circle.intersect(bisector);
+ // std::cout << " chord2: " << chord2_pts[0].point() << ", " << chord2_pts[1].point() << std::endl;
+ Geom::LineSegment chord2(chord2_pts[0].point(), chord2_pts[1].point());
+
+ // Find D, point on chord2 and on circle closest to start point
+ Geom::Coord d0 = Geom::distance(chord2_pts[0].point(),start_pt);
+ Geom::Coord d1 = Geom::distance(chord2_pts[1].point(),start_pt);
+ // std::cout << " d0: " << d0 << " d1: " << d1 << std::endl;
+ Geom::Point d = (d0 < d1) ? chord2_pts[0].point() : chord2_pts[1].point();
+ Geom::Line da(d,start_pt);
+
+ // Chord through start point and point D
+ std::vector<Geom::ShapeIntersection> chord3_pts = outer_circle.intersect(da);
+ // std::cout << " chord3: " << chord3_pts[0].point() << ", " << chord3_pts[1].point() << std::endl;
+
+ // Find farthest point on chord3 and on circle (could be more robust)
+ Geom::Coord d2 = Geom::distance(chord3_pts[0].point(),d);
+ Geom::Coord d3 = Geom::distance(chord3_pts[1].point(),d);
+ // std::cout << " d2: " << d2 << " d3: " << d3 << std::endl;
+
+ // Find point P, the intersection of outer circle and new inner circle
+ Geom::Point p = (d2 > d3) ? chord3_pts[0].point() : chord3_pts[1].point();
+
+ // Find center of new circle: it is at the intersection of the bisector
+ // of the chord defined by the start point and point P and a line through
+ // the start point and parallel to the first bisector.
+ Geom::LineSegment chord4(start_pt,p);
+ Geom::Line bisector2 = make_bisector_line( chord4 );
+ Geom::Line diameter = make_parallel_line( start_pt, bisector );
+ std::vector<Geom::ShapeIntersection> center_new = bisector2.intersect( diameter );
+ // std::cout << " center_new: " << center_new[0].point() << std::endl;
+ Geom::Coord r_new = Geom::distance( center_new[0].point(), start_pt );
+ // std::cout << " r_new: " << r_new << std::endl;
+
+ inner_circle.setCenter( center_new[0].point() );
+ inner_circle.setRadius( r_new );
+ return p;
+}
+
+// Arcs line join. If two circles don't intersect, adjust both circles so they just touch.
+// Increase (decrease) the radius of circle 1 and decrease (increase) of circle 2 by the same amount keeping the given points and tangents fixed.
+Geom::Point adjust_circles( Geom::Circle &circle1, Geom::Circle &circle2, Geom::Point const &point1, Geom::Point const &point2, Geom::Point const &tan1, Geom::Point const &tan2 ) {
+
+ Geom::Point n1 = (circle1.center() - point1).normalized(); // Always points towards center
+ Geom::Point n2 = (circle2.center() - point2).normalized();
+ Geom::Point sum_n = n1 + n2;
+
+ double r1 = circle1.radius();
+ double r2 = circle2.radius();
+ double delta_r = r2 - r1;
+ Geom::Point c1 = circle1.center();
+ Geom::Point c2 = circle2.center();
+ Geom::Point delta_c = c2 - c1;
+
+ // std::cout << "adjust_circles:" << std::endl;
+ // std::cout << " norm: " << n1 << "; " << n2 << std::endl;
+ // std::cout << " sum_n: " << sum_n << std::endl;
+ // std::cout << " delta_r: " << delta_r << std::endl;
+ // std::cout << " delta_c: " << delta_c << std::endl;
+
+ // Quadratic equation
+ double A = 4 - sum_n.length() * sum_n.length();
+ double B = 4.0 * delta_r - 2.0 * Geom::dot( delta_c, sum_n );
+ double C = delta_r * delta_r - delta_c.length() * delta_c.length();
+
+ double s1 = 0;
+ double s2 = 0;
+
+ if( fabs(A) < 0.01 ) {
+ // std::cout << " A near zero! $$$$$$$$$$$$$$$$$$" << std::endl;
+ if( B != 0 ) {
+ s1 = -C/B;
+ s2 = -s1;
+ }
+ } else {
+ s1 = (-B + sqrt(B*B - 4*A*C))/(2*A);
+ s2 = (-B - sqrt(B*B - 4*A*C))/(2*A);
+ }
+
+ double dr = (fabs(s1)<=fabs(s2)?s1:s2);
+
+ // std::cout << " A: " << A << std::endl;
+ // std::cout << " B: " << B << std::endl;
+ // std::cout << " C: " << C << std::endl;
+ // std::cout << " s1: " << s1 << " s2: " << s2 << " dr: " << dr << std::endl;
+
+ circle1 = Geom::Circle( c1 - dr*n1, r1-dr );
+ circle2 = Geom::Circle( c2 + dr*n2, r2+dr );
+
+ // std::cout << " C1: " << circle1 << std::endl;
+ // std::cout << " C2: " << circle2 << std::endl;
+ // std::cout << " d': " << Geom::Point( circle1.center() - circle2.center() ).length() << std::endl;
+
+ Geom::Line bisector( circle1.center(), circle2.center() );
+ std::vector<Geom::ShapeIntersection> points = circle1.intersect( bisector );
+ Geom::Point p0 = points[0].point();
+ Geom::Point p1 = points[1].point();
+ // std::cout << " points: " << p0 << "; " << p1 << std::endl;
+ if( abs( Geom::distance( p0, circle2.center() ) - circle2.radius() ) <
+ abs( Geom::distance( p1, circle2.center() ) - circle2.radius() ) ) {
+ return p0;
+ } else {
+ return p1;
+ }
+}
+
+void extrapolate_join_internal(join_data jd, int alternative)
{
+ // std::cout << "\nextrapolate_join: entrance: alternative: " << alternative << std::endl;
using namespace Geom;
Geom::Path &res = jd.res;
@@ -187,10 +364,40 @@ void extrapolate_join(join_data jd)
Geom::Point endPt = outgoing.initialPoint();
Geom::Point tang1 = jd.in_tang;
Geom::Point tang2 = jd.out_tang;
+ // width is half stroke-width
double width = jd.width, miter = jd.miter;
- Geom::Circle circle1 = Geom::touching_circle(Geom::reverse(incoming.toSBasis()), 0.);
- Geom::Circle circle2 = Geom::touching_circle(outgoing.toSBasis(), 0);
+ // std::cout << " startPt: " << startPt << " endPt: " << endPt << std::endl;
+ // std::cout << " tang1: " << tang1 << " tang2: " << tang2 << std::endl;
+ // std::cout << " dot product: " << Geom::dot( tang1, tang2 ) << std::endl;
+ // std::cout << " width: " << width << std::endl;
+
+ // CIRCLE CALCULATION TESTING
+ Geom::Circle circle1 = touching_circle(Geom::reverse(incoming.toSBasis()), 0.);
+ Geom::Circle circle2 = touching_circle(outgoing.toSBasis(), 0);
+ // std::cout << " circle1: " << circle1 << std::endl;
+ // std::cout << " circle2: " << circle2 << std::endl;
+ if( Geom::CubicBezier const * in_bezier = dynamic_cast<Geom::CubicBezier const*>(&incoming) ) {
+ Geom::Circle circle_test1 = touching_circle(*in_bezier, false);
+ if( !Geom::are_near( circle1, circle_test1, 0.01 ) ) {
+ // std::cout << " Circle 1 error!!!!!!!!!!!!!!!!!" << std::endl;
+ // std::cout << " " << circle_test1 << std::endl;
+ }
+ }
+ if( Geom::CubicBezier const * out_bezier = dynamic_cast<Geom::CubicBezier const*>(&outgoing) ) {
+ Geom::Circle circle_test2 = touching_circle(*out_bezier, true);
+ if( !Geom::are_near( circle2, circle_test2, 0.01 ) ) {
+ // std::cout << " Circle 2 error!!!!!!!!!!!!!!!!!" << std::endl;
+ // std::cout << " " << circle_test2 << std::endl;
+ }
+ }
+ // END TESTING
+
+ Geom::Point center1 = circle1.center();
+ Geom::Point center2 = circle2.center();
+ double side1 = tang1[Geom::X]*(startPt[Geom::Y]-center1[Geom::Y]) - tang1[Geom::Y]*(startPt[Geom::X]-center1[Geom::X]);
+ double side2 = tang2[Geom::X]*( endPt[Geom::Y]-center2[Geom::Y]) - tang2[Geom::Y]*( endPt[Geom::X]-center2[Geom::X]);
+ // std::cout << " side1: " << side1 << " side2: " << side2 << std::endl;
bool inc_ls = !circle1.center().isFinite();
bool out_ls = !circle2.center().isFinite();
@@ -199,20 +406,120 @@ void extrapolate_join(join_data jd)
Geom::EllipticalArc *arc1 = NULL;
Geom::EllipticalArc *arc2 = NULL;
+ Geom::LineSegment *seg1 = NULL;
+ Geom::LineSegment *seg2 = NULL;
Geom::Point sol;
Geom::Point p1;
Geom::Point p2;
if (!inc_ls && !out_ls) {
+ // std::cout << " two circles" << std::endl;
+
+ // See if tangent is backwards (radius < width/2 and circle is inside stroke).
+ Geom::Point node_on_path = startPt + Geom::rot90(tang1)*width;
+ // std::cout << " node_on_path: " << node_on_path << " -------------- " << std::endl;
+ bool b1 = false;
+ bool b2 = false;
+ if (circle1.radius() < width && distance( circle1.center(), node_on_path ) < width) {
+ b1 = true;
+ }
+ if (circle2.radius() < width && distance( circle2.center(), node_on_path ) < width) {
+ b2 = true;
+ }
+ // std::cout << " b1: " << (b1?"true":"false")
+ // << " b2: " << (b2?"true":"false") << std::endl;
+
// Two circles
points = circle1.intersect(circle2);
+
+ if (points.size() != 2) {
+ // std::cout << " Circles do not intersect, do backup" << std::endl;
+ switch (alternative) {
+ case 1:
+ {
+ // Fallback to round if one path has radius smaller than half line width.
+ if(b1 || b2) {
+ // std::cout << "At one least path has radius smaller than half line width." << std::endl;
+ return( round_join(jd) );
+ }
+
+ Point p;
+ if( circle2.contains( startPt ) && !circle1.contains( endPt ) ) {
+ // std::cout << "Expand circle1" << std::endl;
+ p = expand_circle( circle1, circle2, startPt, tang1 );
+ points.push_back( ShapeIntersection( 0, 0, p) );
+ points.push_back( ShapeIntersection( 0, 0, p) );
+ } else if( circle1.contains( endPt ) && !circle2.contains( startPt ) ) {
+ // std::cout << "Expand circle2" << std::endl;
+ p = expand_circle( circle2, circle1, endPt, tang2 );
+ points.push_back( ShapeIntersection( 0, 0, p) );
+ points.push_back( ShapeIntersection( 0, 0, p) );
+ } else {
+ // std::cout << "Either both points inside or both outside" << std::endl;
+ return( miter_clip_join(jd) );
+ }
+ break;
+
+ }
+ case 2:
+ {
+ // Fallback to round if one path has radius smaller than half line width.
+ if(b1 || b2) {
+ // std::cout << "At one least path has radius smaller than half line width." << std::endl;
+ return( round_join(jd) );
+ }
+
+ if( ( circle2.contains( startPt ) && !circle1.contains( endPt ) ) ||
+ ( circle1.contains( endPt ) && !circle2.contains( startPt ) ) ) {
+
+ Geom::Point apex = adjust_circles( circle1, circle2, startPt, endPt, tang1, tang2 );
+ points.push_back( ShapeIntersection( 0, 0, apex) );
+ points.push_back( ShapeIntersection( 0, 0, apex) );
+ } else {
+ // std::cout << "Either both points inside or both outside" << std::endl;
+ return( miter_clip_join(jd) );
+ }
+
+ break;
+ }
+ case 3:
+ if( side1 > 0 ) {
+ Geom::Line secant(startPt, startPt + tang1);
+ points = circle2.intersect(secant);
+ circle1.setRadius(std::numeric_limits<float>::infinity());
+ circle1.setCenter(Geom::Point(0,std::numeric_limits<float>::infinity()));
+ } else {
+ Geom::Line secant(endPt, endPt + tang2);
+ points = circle1.intersect(secant);
+ circle2.setRadius(std::numeric_limits<float>::infinity());
+ circle2.setCenter(Geom::Point(0,std::numeric_limits<float>::infinity()));
+ }
+ break;
+
+
+ case 0:
+ default:
+ // Do nothing
+ break;
+ }
+ }
+
if (points.size() == 2) {
sol = pick_solution(points, tang2, endPt);
- arc1 = circle1.arc(startPt, 0.5*(startPt+sol), sol);
- arc2 = circle2.arc(sol, 0.5*(sol+endPt), endPt);
+ if( circle1.radius() != std::numeric_limits<float>::infinity() ) {
+ arc1 = circle1.arc(startPt, 0.5*(startPt+sol), sol);
+ } else {
+ seg1 = new Geom::LineSegment(startPt, sol);
+ }
+ if( circle2.radius() != std::numeric_limits<float>::infinity() ) {
+ arc2 = circle2.arc(sol, 0.5*(sol+endPt), endPt);
+ } else {
+ seg2 = new Geom::LineSegment(sol, endPt);
+ }
}
} else if (inc_ls && !out_ls) {
// Line and circle
+ // std::cout << " line circle" << std::endl;
points = circle2.intersect(Line(incoming.initialPoint(), incoming.finalPoint()));
if (points.size() == 2) {
sol = pick_solution(points, tang2, endPt);
@@ -220,16 +527,18 @@ void extrapolate_join(join_data jd)
}
} else if (!inc_ls && out_ls) {
// Circle and line
+ // std::cout << " circle line" << std::endl;
points = circle1.intersect(Line(outgoing.initialPoint(), outgoing.finalPoint()));
if (points.size() == 2) {
sol = pick_solution(points, tang2, endPt);
arc1 = circle1.arc(startPt, 0.5*(sol+startPt), sol);
}
}
-
- if (points.size() != 2)
+ if (points.size() != 2) {
+ // std::cout << " no solutions" << std::endl;
// no solutions available, fall back to miter
- return miter_clip_join(jd);
+ return miter_join(jd);
+ }
// We have a solution, thus sol is defined.
p1 = sol;
@@ -250,12 +559,13 @@ void extrapolate_join(join_data jd)
Geom::Line limit_line;
double miter_limit = 2.0 * width * miter;
bool clipped = false;
-
+
if (are_parallel(bisector_chord, ortho)) {
// No intersection (can happen if curvatures are equal but opposite)
if (Geom::distance(point_on_path, sol) > miter_limit) {
clipped = true;
- Geom::Point limit_point = point_on_path + miter_limit * bisector.versor();
+ Geom::Point temp = bisector.versor();
+ Geom::Point limit_point = point_on_path + miter_limit * temp;
limit_line = make_parallel_line( limit_point, ortho );
}
} else {
@@ -311,6 +621,8 @@ void extrapolate_join(join_data jd)
// Add initial
if (arc1) {
res.append(*arc1);
+ } else if (seg1 ) {
+ res.append(*seg1);
} else {
// Straight line segment: move last point
res.setFinal(p1);
@@ -324,6 +636,9 @@ void extrapolate_join(join_data jd)
if (arc2) {
res.append(*arc2);
res.append(outgoing);
+ } else if (seg2 ) {
+ res.append(*seg2);
+ res.append(outgoing);
} else {
// Straight line segment:
res.appendNew<Geom::LineSegment>(outgoing.finalPoint());
@@ -334,8 +649,16 @@ void extrapolate_join(join_data jd)
delete arc1;
delete arc2;
+ delete seg1;
+ delete seg2;
}
+void extrapolate_join( join_data jd) { extrapolate_join_internal(jd, 0); }
+void extrapolate_join_alt1(join_data jd) { extrapolate_join_internal(jd, 1); }
+void extrapolate_join_alt2(join_data jd) { extrapolate_join_internal(jd, 2); }
+void extrapolate_join_alt3(join_data jd) { extrapolate_join_internal(jd, 3); }
+
+
void join_inside(join_data jd)
{
Geom::Path &res = jd.res;
@@ -716,6 +1039,15 @@ void outline_join(Geom::Path &res, Geom::Path const& temp, Geom::Point in_tang,
case Inkscape::JOIN_EXTRAPOLATE:
jf = &extrapolate_join;
break;
+ case Inkscape::JOIN_EXTRAPOLATE1:
+ jf = &extrapolate_join_alt1;
+ break;
+ case Inkscape::JOIN_EXTRAPOLATE2:
+ jf = &extrapolate_join_alt2;
+ break;
+ case Inkscape::JOIN_EXTRAPOLATE3:
+ jf = &extrapolate_join_alt3;
+ break;
case Inkscape::JOIN_MITER_CLIP:
jf = &miter_clip_join;
break;
diff --git a/src/helper/geom-pathstroke.h b/src/helper/geom-pathstroke.h
index 6697273cf..6a753a6fd 100644
--- a/src/helper/geom-pathstroke.h
+++ b/src/helper/geom-pathstroke.h
@@ -21,6 +21,9 @@ enum LineJoinType {
JOIN_MITER,
JOIN_MITER_CLIP,
JOIN_EXTRAPOLATE,
+ JOIN_EXTRAPOLATE1,
+ JOIN_EXTRAPOLATE2,
+ JOIN_EXTRAPOLATE3,
};
enum LineCapType {
diff --git a/src/inkview.cpp b/src/inkview.cpp
index aab4b4a20..3fcd9ed8a 100644
--- a/src/inkview.cpp
+++ b/src/inkview.cpp
@@ -30,10 +30,6 @@
# include "config.h"
#endif
-#ifdef HAVE_GETOPT_H
-#include <getopt.h>
-#endif
-
#include <cstring>
#include <sys/stat.h>
#include <locale.h>
@@ -106,66 +102,67 @@ static GtkWidget *ctrlwin = NULL;
int sp_main_gui (int, char const**) { return 0; }
int sp_main_console (int, char const**) { return 0; }
-static int
-sp_svgview_main_delete (GtkWidget */*widget*/, GdkEvent */*event*/, struct SPSlideShow */*ss*/)
+static int sp_svgview_main_delete (GtkWidget */*widget*/,
+ GdkEvent */*event*/,
+ struct SPSlideShow */*ss*/)
{
gtk_main_quit ();
return FALSE;
}
-static int
-sp_svgview_main_key_press (GtkWidget */*widget*/, GdkEventKey *event, struct SPSlideShow *ss)
+static int sp_svgview_main_key_press (GtkWidget */*widget*/,
+ GdkEventKey *event,
+ struct SPSlideShow *ss)
{
switch (event->keyval) {
- case GDK_KEY_Up:
- case GDK_KEY_Home:
- sp_svgview_goto_first(ss);
- break;
- case GDK_KEY_Down:
- case GDK_KEY_End:
- sp_svgview_goto_last(ss);
- break;
- case GDK_KEY_F11:
- if (ss->fullscreen) {
- gtk_window_unfullscreen (GTK_WINDOW(ss->window));
- ss->fullscreen = false;
- } else {
- gtk_window_fullscreen (GTK_WINDOW(ss->window));
- ss->fullscreen = true;
- }
- break;
- case GDK_KEY_Return:
- sp_svgview_control_show (ss);
- break;
- case GDK_KEY_KP_Page_Down:
- case GDK_KEY_Page_Down:
- case GDK_KEY_Right:
- case GDK_KEY_space:
- sp_svgview_show_next (ss);
- break;
- case GDK_KEY_KP_Page_Up:
- case GDK_KEY_Page_Up:
- case GDK_KEY_Left:
- case GDK_KEY_BackSpace:
- sp_svgview_show_prev (ss);
- break;
- case GDK_KEY_Escape:
- case GDK_KEY_q:
- case GDK_KEY_Q:
- gtk_main_quit();
- break;
- default:
- break;
+ case GDK_KEY_Up:
+ case GDK_KEY_Home:
+ sp_svgview_goto_first(ss);
+ break;
+ case GDK_KEY_Down:
+ case GDK_KEY_End:
+ sp_svgview_goto_last(ss);
+ break;
+ case GDK_KEY_F11:
+ if (ss->fullscreen) {
+ gtk_window_unfullscreen (GTK_WINDOW(ss->window));
+ ss->fullscreen = false;
+ } else {
+ gtk_window_fullscreen (GTK_WINDOW(ss->window));
+ ss->fullscreen = true;
+ }
+ break;
+ case GDK_KEY_Return:
+ sp_svgview_control_show (ss);
+ break;
+ case GDK_KEY_KP_Page_Down:
+ case GDK_KEY_Page_Down:
+ case GDK_KEY_Right:
+ case GDK_KEY_space:
+ sp_svgview_show_next (ss);
+ break;
+ case GDK_KEY_KP_Page_Up:
+ case GDK_KEY_Page_Up:
+ case GDK_KEY_Left:
+ case GDK_KEY_BackSpace:
+ sp_svgview_show_prev (ss);
+ break;
+ case GDK_KEY_Escape:
+ case GDK_KEY_q:
+ case GDK_KEY_Q:
+ gtk_main_quit();
+ break;
+ default:
+ break;
}
gtk_window_set_title(GTK_WINDOW(ss->window), ss->doc->getName());
return TRUE;
}
-int
-main (int argc, const char **argv)
+int main (int argc, const char **argv)
{
if (argc == 1) {
- usage();
+ usage();
}
// Prevents errors like "Unable to wrap GdkPixbuf..." (in nr-filter-image.cpp for example)
@@ -175,21 +172,25 @@ main (int argc, const char **argv)
struct SPSlideShow ss;
- int option,
- num_parsed_options = 0;
+ int num_parsed_options = 0;
// the list of arguments is in the net line
- while ((option = getopt(argc, (char* const* )argv, "t:")) != -1)
- {
- switch(option) {
- case 't': // for timer
- // fprintf(stderr, "set timer arg %s\n", optarg );
- ss.timer = atoi(optarg);
- num_parsed_options += 2; // 2 because of flag + option
+ for (int i = 1; i < argc; i++) {
+ if ((argv[i][0] == '-')) {
+ if (!strcmp(argv[i], "--")) {
break;
- case '?':
- default:
- usage();
+ }
+ else if ((!strcmp(argv[i], "-t"))) {
+ if (i + 1 >= argc) {
+ usage();
+ }
+ ss.timer = atoi(argv[i+1]);
+ num_parsed_options = i+1;
+ i++;
+ }
+ else {
+ usage();
+ }
}
}
@@ -232,82 +233,84 @@ main (int argc, const char **argv)
// starting at where the commandline options stopped parsing because
// we want all the files to be in the list
for (i = num_parsed_options + 1 ; i < argc; i++) {
- struct stat st;
- if (stat (argv[i], &st)
- || !S_ISREG (st.st_mode)
- || (st.st_size < 64)) {
- fprintf(stderr, "could not open file %s\n", argv[i]);
- } else {
-
-#ifdef WITH_INKJAR
- if (is_jar(argv[i])) {
- Inkjar::JarFileReader jar_file_reader(argv[i]);
- for (;;) {
- GByteArray *gba = jar_file_reader.get_next_file();
- if (gba == NULL) {
- char *c_ptr;
- gchar *last_filename = jar_file_reader.get_last_filename();
- if (last_filename == NULL)
- break;
- if ((c_ptr = std::strrchr(last_filename, '/')) != NULL) {
- if (*(++c_ptr) == '\0') {
- g_free(last_filename);
- continue;
- }
- }
- } else if (gba->len > 0) {
- //::write(1, gba->data, gba->len);
- /* Append to list */
- if (ss.length >= ss.size) {
- /* Expand */
- ss.size <<= 1;
- ss.slides = g_renew (char *, ss.slides, ss.size);
- }
-
- ss.doc = SPDocument::createNewDocFromMem ((const gchar *)gba->data,
- gba->len,
- TRUE);
- gchar *last_filename = jar_file_reader.get_last_filename();
- if (ss.doc) {
- ss.slides[ss.length++] = strdup (last_filename);
- (ss.doc)->setUri (last_filename);
- }
- g_byte_array_free(gba, TRUE);
- g_free(last_filename);
- } else
- break;
- }
- } else {
-#endif /* WITH_INKJAR */
- /* Append to list */
- if (ss.length >= ss.size) {
- /* Expand */
- ss.size <<= 1;
- ss.slides = g_renew (char *, ss.slides, ss.size);
-
- }
-
- ss.slides[ss.length++] = strdup (argv[i]);
-
+ struct stat st;
+ if (stat (argv[i], &st)
+ || !S_ISREG (st.st_mode)
+ || (st.st_size < 64)) {
+ fprintf(stderr, "could not open file %s\n", argv[i]);
+ } else {
+
+ #ifdef WITH_INKJAR
+ if (is_jar(argv[i])) {
+ Inkjar::JarFileReader jar_file_reader(argv[i]);
+ for (;;) {
+ GByteArray *gba = jar_file_reader.get_next_file();
+ if (gba == NULL) {
+ char *c_ptr;
+ gchar *last_filename = jar_file_reader.get_last_filename();
+ if (last_filename == NULL)
+ break;
+ if ((c_ptr = std::strrchr(last_filename, '/')) != NULL) {
+ if (*(++c_ptr) == '\0') {
+ g_free(last_filename);
+ continue;
+ }
+ }
+ } else if (gba->len > 0) {
+ //::write(1, gba->data, gba->len);
+ /* Append to list */
+ if (ss.length >= ss.size) {
+ /* Expand */
+ ss.size <<= 1;
+ ss.slides = g_renew (char *, ss.slides, ss.size);
+ }
+
+ ss.doc = SPDocument::createNewDocFromMem ((const gchar *)gba->data,
+ gba->len,
+ TRUE);
+ gchar *last_filename = jar_file_reader.get_last_filename();
+ if (ss.doc) {
+ ss.slides[ss.length++] = strdup (last_filename);
+ (ss.doc)->setUri (last_filename);
+ }
+ g_byte_array_free(gba, TRUE);
+ g_free(last_filename);
+ } else {
+ break;
+ }
+ }
+ } else {
+ #endif /* WITH_INKJAR */
+ /* Append to list */
+ if (ss.length >= ss.size) {
+ /* Expand */
+ ss.size <<= 1;
+ ss.slides = g_renew (char *, ss.slides, ss.size);
+ }
+
+ ss.slides[ss.length++] = strdup (argv[i]);
+
+ if (!ss.doc) {
+ ss.doc = SPDocument::createNewDoc (ss.slides[ss.current], TRUE, false);
if (!ss.doc) {
- ss.doc = SPDocument::createNewDoc (ss.slides[ss.current], TRUE, false);
- if (!ss.doc)
- ++ss.current;
- }
-#ifdef WITH_INKJAR
- }
-#endif
- }
+ ++ss.current;
+ }
+ }
+ #ifdef WITH_INKJAR
+ }
+ #endif
+ }
}
- if(!ss.doc)
+ if(!ss.doc) {
return 1; /* none of the slides loadable */
-
+ }
+
w = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_window_set_title( GTK_WINDOW(w), ss.doc->getName() );
gtk_window_set_default_size (GTK_WINDOW (w),
- MIN ((int)(ss.doc)->getWidth().value("px"), (int)gdk_screen_width() - 64),
- MIN ((int)(ss.doc)->getHeight().value("px"), (int)gdk_screen_height() - 64));
+ MIN ((int)(ss.doc)->getWidth().value("px"), (int)gdk_screen_width() - 64),
+ MIN ((int)(ss.doc)->getHeight().value("px"), (int)gdk_screen_height() - 64));
ss.window = w;
g_signal_connect (G_OBJECT (w), "delete_event", (GCallback) sp_svgview_main_delete, &ss);
@@ -327,8 +330,9 @@ main (int argc, const char **argv)
return 0;
}
-static int
-sp_svgview_ctrlwin_delete (GtkWidget */*widget*/, GdkEvent */*event*/, void */*data*/)
+static int sp_svgview_ctrlwin_delete (GtkWidget */*widget*/,
+ GdkEvent */*event*/,
+ void */*data*/)
{
ctrlwin = NULL;
return FALSE;
@@ -337,97 +341,92 @@ sp_svgview_ctrlwin_delete (GtkWidget */*widget*/, GdkEvent */*event*/, void */*d
static GtkWidget* sp_svgview_control_show(struct SPSlideShow *ss)
{
if (!ctrlwin) {
- ctrlwin = gtk_window_new(GTK_WINDOW_TOPLEVEL);
+ ctrlwin = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_window_set_resizable(GTK_WINDOW(ctrlwin), FALSE);
gtk_window_set_transient_for(GTK_WINDOW(ctrlwin), GTK_WINDOW(ss->window));
g_signal_connect(G_OBJECT (ctrlwin), "key_press_event", (GCallback) sp_svgview_main_key_press, ss);
g_signal_connect(G_OBJECT (ctrlwin), "delete_event", (GCallback) sp_svgview_ctrlwin_delete, NULL);
#if GTK_CHECK_VERSION(3,0,0)
- GtkWidget *t = gtk_button_box_new(GTK_ORIENTATION_HORIZONTAL);
+ GtkWidget *t = gtk_button_box_new(GTK_ORIENTATION_HORIZONTAL);
#else
- GtkWidget *t = gtk_hbutton_box_new();
+ GtkWidget *t = gtk_hbutton_box_new();
#endif
- gtk_container_add(GTK_CONTAINER(ctrlwin), t);
+ gtk_container_add(GTK_CONTAINER(ctrlwin), t);
#if GTK_CHECK_VERSION(3,10,0)
GtkWidget *b = gtk_button_new_from_icon_name(INKSCAPE_ICON("go-first"), GTK_ICON_SIZE_BUTTON);
#else
- GtkWidget *b = gtk_button_new();
+ GtkWidget *b = gtk_button_new();
GtkWidget *img = gtk_image_new_from_icon_name(INKSCAPE_ICON("go-first"), GTK_ICON_SIZE_BUTTON);
gtk_button_set_image(GTK_BUTTON(b), img);
#endif
- gtk_container_add(GTK_CONTAINER(t), b);
+ gtk_container_add(GTK_CONTAINER(t), b);
- g_signal_connect(G_OBJECT(b), "clicked", (GCallback) sp_svgview_goto_first_cb, ss);
+ g_signal_connect(G_OBJECT(b), "clicked", (GCallback) sp_svgview_goto_first_cb, ss);
#if GTK_CHECK_VERSION(3,10,0)
b = gtk_button_new_from_icon_name(INKSCAPE_ICON("go-previous"), GTK_ICON_SIZE_BUTTON);
#else
- b = gtk_button_new();
+ b = gtk_button_new();
img = gtk_image_new_from_icon_name(INKSCAPE_ICON("go-previous"), GTK_ICON_SIZE_BUTTON);
gtk_button_set_image(GTK_BUTTON(b), img);
#endif
- gtk_container_add(GTK_CONTAINER(t), b);
+ gtk_container_add(GTK_CONTAINER(t), b);
- g_signal_connect(G_OBJECT(b), "clicked", (GCallback) sp_svgview_show_prev_cb, ss);
+ g_signal_connect(G_OBJECT(b), "clicked", (GCallback) sp_svgview_show_prev_cb, ss);
#if GTK_CHECK_VERSION(3,10,0)
b = gtk_button_new_from_icon_name(INKSCAPE_ICON("go-next"), GTK_ICON_SIZE_BUTTON);
#else
- b = gtk_button_new();
+ b = gtk_button_new();
img = gtk_image_new_from_icon_name(INKSCAPE_ICON("go-next"), GTK_ICON_SIZE_BUTTON);
gtk_button_set_image(GTK_BUTTON(b), img);
#endif
- gtk_container_add(GTK_CONTAINER(t), b);
+ gtk_container_add(GTK_CONTAINER(t), b);
- g_signal_connect(G_OBJECT(b), "clicked", (GCallback) sp_svgview_show_next_cb, ss);
+ g_signal_connect(G_OBJECT(b), "clicked", (GCallback) sp_svgview_show_next_cb, ss);
#if GTK_CHECK_VERSION(3,10,0)
b = gtk_button_new_from_icon_name(INKSCAPE_ICON("go-last"), GTK_ICON_SIZE_BUTTON);
#else
- b = gtk_button_new();
+ b = gtk_button_new();
img = gtk_image_new_from_icon_name(INKSCAPE_ICON("go-last"), GTK_ICON_SIZE_BUTTON);
gtk_button_set_image(GTK_BUTTON(b), img);
#endif
- gtk_container_add(GTK_CONTAINER(t), b);
- g_signal_connect(G_OBJECT(b), "clicked", (GCallback) sp_svgview_goto_last_cb, ss);
- gtk_widget_show_all(ctrlwin);
+ gtk_container_add(GTK_CONTAINER(t), b);
+ g_signal_connect(G_OBJECT(b), "clicked", (GCallback) sp_svgview_goto_last_cb, ss);
+ gtk_widget_show_all(ctrlwin);
} else {
- gtk_window_present(GTK_WINDOW(ctrlwin));
+ gtk_window_present(GTK_WINDOW(ctrlwin));
}
return NULL;
}
-static int
-sp_svgview_show_next_cb (GtkWidget */*widget*/, void *data)
+static int sp_svgview_show_next_cb (GtkWidget */*widget*/, void *data)
{
sp_svgview_show_next(static_cast<struct SPSlideShow *>(data));
return FALSE;
}
-static int
-sp_svgview_show_prev_cb (GtkWidget */*widget*/, void *data)
+static int sp_svgview_show_prev_cb (GtkWidget */*widget*/, void *data)
{
sp_svgview_show_prev(static_cast<struct SPSlideShow *>(data));
return FALSE;
}
-static int
-sp_svgview_goto_first_cb (GtkWidget */*widget*/, void *data)
+static int sp_svgview_goto_first_cb (GtkWidget */*widget*/, void *data)
{
sp_svgview_goto_first(static_cast<struct SPSlideShow *>(data));
return FALSE;
}
-static int
-sp_svgview_goto_last_cb (GtkWidget */*widget*/, void *data)
+static int sp_svgview_goto_last_cb (GtkWidget */*widget*/, void *data)
{
sp_svgview_goto_last(static_cast<struct SPSlideShow *>(data));
return FALSE;
}
-static void
-sp_svgview_waiting_cursor(struct SPSlideShow *ss)
+static void sp_svgview_waiting_cursor(struct SPSlideShow *ss)
{
GdkCursor *waiting = gdk_cursor_new(GDK_WATCH);
gdk_window_set_cursor(gtk_widget_get_window(GTK_WIDGET(ss->window)), waiting);
@@ -445,12 +444,12 @@ sp_svgview_waiting_cursor(struct SPSlideShow *ss)
gdk_cursor_unref(waiting);
#endif
}
- while(gtk_events_pending())
+ while(gtk_events_pending()) {
gtk_main_iteration();
+ }
}
-static void
-sp_svgview_normal_cursor(struct SPSlideShow *ss)
+static void sp_svgview_normal_cursor(struct SPSlideShow *ss)
{
gdk_window_set_cursor(gtk_widget_get_window(GTK_WIDGET(ss->window)), NULL);
if (ctrlwin) {
@@ -458,8 +457,9 @@ sp_svgview_normal_cursor(struct SPSlideShow *ss)
}
}
-static void
-sp_svgview_set_document(struct SPSlideShow *ss, SPDocument *doc, int current)
+static void sp_svgview_set_document(struct SPSlideShow *ss,
+ SPDocument *doc,
+ int current)
{
if (doc && doc != ss->doc) {
doc->ensureUpToDate();
@@ -469,8 +469,7 @@ sp_svgview_set_document(struct SPSlideShow *ss, SPDocument *doc, int current)
}
}
-static void
-sp_svgview_show_next (struct SPSlideShow *ss)
+static void sp_svgview_show_next (struct SPSlideShow *ss)
{
sp_svgview_waiting_cursor(ss);
@@ -485,8 +484,7 @@ sp_svgview_show_next (struct SPSlideShow *ss)
sp_svgview_normal_cursor(ss);
}
-static void
-sp_svgview_show_prev (struct SPSlideShow *ss)
+static void sp_svgview_show_prev (struct SPSlideShow *ss)
{
sp_svgview_waiting_cursor(ss);
@@ -501,16 +499,16 @@ sp_svgview_show_prev (struct SPSlideShow *ss)
sp_svgview_normal_cursor(ss);
}
-static void
-sp_svgview_goto_first (struct SPSlideShow *ss)
+static void sp_svgview_goto_first (struct SPSlideShow *ss)
{
sp_svgview_waiting_cursor(ss);
SPDocument *doc = NULL;
int current = 0;
while ( !doc && (current < ss->length - 1)) {
- if (current == ss->current)
+ if (current == ss->current) {
break;
+ }
doc = SPDocument::createNewDoc (ss->slides[current++], TRUE, false);
}
@@ -519,16 +517,16 @@ sp_svgview_goto_first (struct SPSlideShow *ss)
sp_svgview_normal_cursor(ss);
}
-static void
-sp_svgview_goto_last (struct SPSlideShow *ss)
+static void sp_svgview_goto_last (struct SPSlideShow *ss)
{
sp_svgview_waiting_cursor(ss);
SPDocument *doc = NULL;
int current = ss->length - 1;
while (!doc && (current >= 0)) {
- if (current == ss->current)
+ if (current == ss->current) {
break;
+ }
doc = SPDocument::createNewDoc (ss->slides[current--], TRUE, false);
}
@@ -538,8 +536,7 @@ sp_svgview_goto_last (struct SPSlideShow *ss)
}
#ifdef WITH_INKJAR
-static bool
-is_jar(char const *filename)
+static bool is_jar(char const *filename)
{
/* fixme: Check MIME type or something. /usr/share/misc/file/magic suggests that checking for
initial string "PK\003\004" in content should suffice. */
@@ -556,12 +553,12 @@ is_jar(char const *filename)
static void usage()
{
fprintf(stderr,
- "Usage: inkview [OPTIONS...] [FILES ...]\n"
- "\twhere FILES are SVG (.svg or .svgz)"
+ "Usage: inkview [OPTIONS...] [FILES ...]\n"
+ "\twhere FILES are SVG (.svg or .svgz)"
#ifdef WITH_INKJAR
- " or archives of SVGs (.sxw, .jar)"
+ " or archives of SVGs (.sxw, .jar)"
#endif
- "\n");
+ "\n");
exit(1);
}
diff --git a/src/io/inkjar.cpp b/src/io/inkjar.cpp
index fb1fedf55..345455c4a 100644
--- a/src/io/inkjar.cpp
+++ b/src/io/inkjar.cpp
@@ -103,14 +103,19 @@ bool JarFile::init_inflation()
bool JarFile::open()
{
+ if (_file != NULL) {
+ fclose(_file);
+ }
if ((_file = fopen(_filename, "r")) == NULL) {
- fprintf(stderr, "open failed.\n");
- return false;
+ fprintf(stderr, "open failed.\n");
+ return false;
+ }
+ if (!init_inflation()) {
+ return false;
+ }
+ else {
+ return true;
}
- if (!init_inflation())
- return false;
-
- return true;
}
bool JarFile::close()
diff --git a/src/live_effects/lpe-jointype.cpp b/src/live_effects/lpe-jointype.cpp
index 28f99eb94..2eef315dd 100644
--- a/src/live_effects/lpe-jointype.cpp
+++ b/src/live_effects/lpe-jointype.cpp
@@ -33,6 +33,9 @@ static const Util::EnumData<unsigned> JoinTypeData[] = {
{JOIN_MITER, N_("Miter"), "miter"},
{JOIN_MITER_CLIP, N_("Miter Clip"), "miter-clip"},
{JOIN_EXTRAPOLATE, N_("Extrapolated arc"), "extrp_arc"},
+ {JOIN_EXTRAPOLATE1, N_("Extrapolated arc Alt1"), "extrp_arc1"},
+ {JOIN_EXTRAPOLATE2, N_("Extrapolated arc Alt2"), "extrp_arc2"},
+ {JOIN_EXTRAPOLATE3, N_("Extrapolated arc Alt3"), "extrp_arc3"},
};
static const Util::EnumData<unsigned> CapTypeData[] = {
diff --git a/src/object-snapper.cpp b/src/object-snapper.cpp
index 5b7874c61..3e559ee7a 100644
--- a/src/object-snapper.cpp
+++ b/src/object-snapper.cpp
@@ -641,7 +641,6 @@ void Inkscape::ObjectSnapper::_snapPathsConstrained(IntermSnapResults &isr,
bool strict_snapping = _snapmanager->snapprefs.getStrictSnapping();
// Find all intersections of the constrained path with the snap target candidates
- std::vector<Geom::Point> intersections;
for (std::vector<SnapCandidatePath >::const_iterator k = _paths_to_snap_to->begin(); k != _paths_to_snap_to->end(); ++k) {
if (k->path_vector && _allowSourceToSnapToTarget(p.getSourceType(), (*k).target_type, strict_snapping)) {
// Do the intersection math
diff --git a/src/sp-marker.cpp b/src/sp-marker.cpp
index 88dfbe04e..3505e2fe8 100644
--- a/src/sp-marker.cpp
+++ b/src/sp-marker.cpp
@@ -394,7 +394,8 @@ sp_marker_show_instance ( SPMarker *marker, Inkscape::DrawingItem *parent,
if (marker->orient_mode == MARKER_ORIENT_AUTO) {
m = base;
} else if (marker->orient_mode == MARKER_ORIENT_AUTO_START_REVERSE) {
- m = Geom::Rotate::from_degrees( 180.0 ) * base;
+ // m = Geom::Rotate::from_degrees( 180.0 ) * base;
+ // Rotating is done at rendering time if necessary
m = base;
} else {
/* fixme: Orient units (Lauris) */
diff --git a/src/sp-mask.cpp b/src/sp-mask.cpp
index 7b9ab11c3..3537c7bac 100644
--- a/src/sp-mask.cpp
+++ b/src/sp-mask.cpp
@@ -139,12 +139,12 @@ void SPMask::update(SPCtx* ctx, unsigned int flags) {
flags &= SP_OBJECT_MODIFIED_CASCADE;
std::vector<SPObject *> children = this->childList(false);
- for (std::vector<SPObject *>::const_iterator child = children.begin();child != children.end();child++) {
+ for (std::vector<SPObject *>::const_iterator child = children.begin();child != children.end();++child) {
sp_object_ref(*child);
}
- for (std::vector<SPObject *>::const_iterator child = children.begin();child != children.end();child++) {
+ for (std::vector<SPObject *>::const_iterator child = children.begin();child != children.end();++child) {
if (flags || ((*child)->uflags & (SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_CHILD_MODIFIED_FLAG))) {
(*child)->updateDisplay(ctx, flags);
}
@@ -173,11 +173,11 @@ void SPMask::modified(unsigned int flags) {
flags &= SP_OBJECT_MODIFIED_CASCADE;
std::vector<SPObject *> children = this->childList(false);
- for (std::vector<SPObject *>::const_iterator child = children.begin();child != children.end();child++) {
+ for (std::vector<SPObject *>::const_iterator child = children.begin();child != children.end();++child) {
sp_object_ref(*child);
}
- for (std::vector<SPObject *>::const_iterator child = children.begin();child != children.end();child++) {
+ for (std::vector<SPObject *>::const_iterator child = children.begin();child != children.end();++child) {
if (flags || ((*child)->mflags & (SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_CHILD_MODIFIED_FLAG))) {
(*child)->emitModified(flags);
}
diff --git a/src/sp-text.cpp b/src/sp-text.cpp
index c7dfdd694..afbe0b147 100644
--- a/src/sp-text.cpp
+++ b/src/sp-text.cpp
@@ -367,8 +367,11 @@ gchar* SPText::description() const {
char *n = xml_quote_strdup( style->font_family.value );
+ Inkscape::Preferences *prefs = Inkscape::Preferences::get();
+ int unit = prefs->getInt("/options/font/unitType", SP_CSS_UNIT_PT);
Inkscape::Util::Quantity q = Inkscape::Util::Quantity(style->font_size.computed, "px");
- GString *xs = g_string_new(q.string(SP_ACTIVE_DESKTOP->getNamedView()->display_units).c_str());
+ q.quantity *= this->i2doc_affine().descrim();
+ GString *xs = g_string_new(q.string(sp_style_get_css_unit_string(unit)).c_str());
char const *trunc = "";
Inkscape::Text::Layout const *layout = te_get_layout((SPItem *) this);
diff --git a/src/ui/dialog/document-properties.cpp b/src/ui/dialog/document-properties.cpp
index 7cd48e62e..c2c5c5005 100644
--- a/src/ui/dialog/document-properties.cpp
+++ b/src/ui/dialog/document-properties.cpp
@@ -448,13 +448,13 @@ void DocumentProperties::populate_available_profiles(){
*/
static void sanitizeName( Glib::ustring& str )
{
- if (str.size() > 1) {
+ if (str.size() > 0) {
char val = str.at(0);
if (((val < 'A') || (val > 'Z'))
&& ((val < 'a') || (val > 'z'))
&& (val != '_')
&& (val != ':')) {
- str.replace(0, 1, "-");
+ str.insert(0, "_");
}
for (Glib::ustring::size_type i = 1; i < str.size(); i++) {
char val = str.at(i);
diff --git a/src/ui/dialog/text-edit.cpp b/src/ui/dialog/text-edit.cpp
index 05cf3a388..c01da8864 100644
--- a/src/ui/dialog/text-edit.cpp
+++ b/src/ui/dialog/text-edit.cpp
@@ -127,8 +127,8 @@ TextEdit::TextEdit()
gtk_combo_box_text_append_text((GtkComboBoxText *) spacing_combo, spacings[i]);
}
- gtk_widget_set_tooltip_text (px, _("Spacing between lines (percent of font size)"));
- gtk_widget_set_tooltip_text (spacing_combo, _("Spacing between lines (percent of font size)"));
+ gtk_widget_set_tooltip_text (px, _("Spacing between baselines (percent of font size)"));
+ gtk_widget_set_tooltip_text (spacing_combo, _("Spacing between baselines (percent of font size)"));
layout_hbox.pack_start(*Gtk::manage(Glib::wrap(spacing_combo)), false, false);
layout_frame.set_padding(4,4,4,4);
layout_frame.add(layout_hbox);
diff --git a/src/ui/tools/mesh-tool.cpp b/src/ui/tools/mesh-tool.cpp
index 7db4e09d8..47927667c 100644
--- a/src/ui/tools/mesh-tool.cpp
+++ b/src/ui/tools/mesh-tool.cpp
@@ -458,7 +458,7 @@ bool MeshTool::root_handler(GdkEvent* event) {
SPCtrlCurve *line = NULL;
if (! drag->lines.empty()) {
- for (std::vector<SPCtrlLine *>::const_iterator l = drag->lines.begin(); l != drag->lines.end() && (!over_line); l++) {
+ for (std::vector<SPCtrlLine *>::const_iterator l = drag->lines.begin(); l != drag->lines.end() && (!over_line); ++l) {
line = (SPCtrlCurve*) (*l);
over_line |= sp_mesh_context_is_over_line (this, (SPItem*) line, Geom::Point(event->motion.x, event->motion.y));
}
@@ -594,7 +594,7 @@ bool MeshTool::root_handler(GdkEvent* event) {
bool over_line = false;
if (!drag->lines.empty()) {
- for (std::vector<SPCtrlLine *>::const_iterator l = drag->lines.begin(); l != drag->lines.end() ; l++) {
+ for (std::vector<SPCtrlLine *>::const_iterator l = drag->lines.begin(); l != drag->lines.end() ; ++l) {
over_line |= sp_mesh_context_is_over_line (this, (SPItem*)(*l), Geom::Point(event->motion.x, event->motion.y));
}
}
@@ -625,7 +625,7 @@ bool MeshTool::root_handler(GdkEvent* event) {
SPCtrlLine *line = NULL;
if (!drag->lines.empty()) {
- for (std::vector<SPCtrlLine *>::const_iterator l = drag->lines.begin(); l != drag->lines.end() && (!over_line); l++) {
+ for (std::vector<SPCtrlLine *>::const_iterator l = drag->lines.begin(); l != drag->lines.end() && (!over_line); ++l) {
line = (SPCtrlLine*)(*l);
over_line = sp_mesh_context_is_over_line (this, (SPItem*) line, Geom::Point(event->motion.x, event->motion.y));
diff --git a/src/ui/tools/select-tool.cpp b/src/ui/tools/select-tool.cpp
index 2b85216d2..905e38f2b 100644
--- a/src/ui/tools/select-tool.cpp
+++ b/src/ui/tools/select-tool.cpp
@@ -405,13 +405,15 @@ void SelectTool::sp_select_context_cycle_through_items(Inkscape::Selection *sele
// Find next item and activate it
std::vector<SPItem *>::iterator next = this->cycling_cur_item;
if (scroll_event->direction == GDK_SCROLL_UP) {
- next++;
- if (next == this->cycling_items.end() && this->cycling_wrap)
+ ++next;
+ if (next == this->cycling_items.end() && this->cycling_wrap) {
next = this->cycling_items.begin();
+ }
} else {
- if(next == this->cycling_items.begin())
+ if(next == this->cycling_items.begin()) {
next = this->cycling_items.end();
- next--;
+ }
+ --next;
}
if (next!=this->cycling_items.end()) {
diff --git a/src/vanishing-point.cpp b/src/vanishing-point.cpp
index 9ce60fce7..32ccbad93 100644
--- a/src/vanishing-point.cpp
+++ b/src/vanishing-point.cpp
@@ -269,15 +269,14 @@ VanishingPoint::selectedBoxes(Inkscape::Selection *sel) {
return sel_boxes;
}
-VPDragger::VPDragger(VPDrag *parent, Geom::Point p, VanishingPoint &vp)
+VPDragger::VPDragger(VPDrag *parent, Geom::Point p, VanishingPoint &vp) :
+ parent(parent),
+ knot(NULL),
+ point(p),
+ point_original(p),
+ dragging_started(false),
+ vps()
{
- this->parent = parent;
-
- this->point = p;
- this->point_original = p;
-
- this->dragging_started = false;
-
if (vp.is_finite()) {
// create the knot
this->knot = new SPKnot(SP_ACTIVE_DESKTOP, NULL);
diff --git a/src/vanishing-point.h b/src/vanishing-point.h
index 28da8e7fa..ae2a88d6e 100644
--- a/src/vanishing-point.h
+++ b/src/vanishing-point.h
@@ -46,6 +46,7 @@ public:
inline VanishingPoint &operator=(VanishingPoint const &rhs) {
_persp = rhs._persp;
_axis = rhs._axis;
+ my_counter = rhs.my_counter;
return *this;
}
inline bool operator==(VanishingPoint const &rhs) const {
diff --git a/src/widgets/ruler.cpp b/src/widgets/ruler.cpp
index ab486eeeb..3a5e76277 100644
--- a/src/widgets/ruler.cpp
+++ b/src/widgets/ruler.cpp
@@ -41,8 +41,9 @@
#define GTK_PARAM_READWRITE G_PARAM_READWRITE|G_PARAM_STATIC_NAME|G_PARAM_STATIC_NICK|G_PARAM_STATIC_BLURB
-#define DEFAULT_RULER_FONT_SCALE PANGO_SCALE_X_SMALL
-#define MINIMUM_INCR 5
+#define DEFAULT_RULER_FONT_SCALE PANGO_SCALE_X_SMALL
+#define MINIMUM_INCR 5
+#define IMMEDIATE_REDRAW_THRESHOLD 20
using Inkscape::Util::unit_table;
@@ -71,11 +72,11 @@ typedef struct
GdkWindow *input_window;
cairo_surface_t *backing_store;
+ gboolean backing_store_valid;
+ GdkRectangle last_pos_rect;
+ guint pos_redraw_idle_id;
PangoLayout *layout;
gdouble font_scale;
-
- gint xsrc;
- gint ysrc;
GList *track_widgets;
} SPRulerPrivate;
@@ -132,18 +133,22 @@ static void sp_ruler_style_updated (GtkWidget *widget);
static void sp_ruler_size_request (GtkWidget *widget,
GtkRequisition *requisition);
static void sp_ruler_style_set (GtkWidget *widget,
- GtkStyle *prev_style);
+ GtkStyle *prev_style);
#endif
static gboolean sp_ruler_motion_notify (GtkWidget *widget,
GdkEventMotion *event);
static gboolean sp_ruler_draw (GtkWidget *widget,
- cairo_t *cr);
+ cairo_t *cr);
#if !GTK_CHECK_VERSION(3,0,0)
static gboolean sp_ruler_expose (GtkWidget *widget,
GdkEventExpose *event);
#endif
static void sp_ruler_draw_ticks (SPRuler *ruler);
+static GdkRectangle sp_ruler_get_pos_rect (SPRuler *ruler,
+ gdouble position);
+static gboolean sp_ruler_idle_queue_pos_redraw(gpointer data);
+static void sp_ruler_queue_pos_redraw (SPRuler *ruler);
static void sp_ruler_draw_pos (SPRuler *ruler,
cairo_t *cr);
static void sp_ruler_make_pixmap (SPRuler *ruler);
@@ -260,14 +265,23 @@ sp_ruler_init (SPRuler *ruler)
gtk_widget_set_has_window (GTK_WIDGET (ruler), FALSE);
- priv->orientation = GTK_ORIENTATION_HORIZONTAL;
- priv->unit = unit_table.getUnit("px");
- priv->lower = 0;
- priv->upper = 0;
- priv->position = 0;
- priv->max_size = 0;
- priv->backing_store = NULL;
- priv->font_scale = DEFAULT_RULER_FONT_SCALE;
+ priv->orientation = GTK_ORIENTATION_HORIZONTAL;
+ priv->unit = unit_table.getUnit("px");
+ priv->lower = 0;
+ priv->upper = 0;
+ priv->position = 0;
+ priv->max_size = 0;
+
+ priv->backing_store = NULL;
+ priv->backing_store_valid = FALSE;
+
+ priv->last_pos_rect.x = 0;
+ priv->last_pos_rect.y = 0;
+ priv->last_pos_rect.width = 0;
+ priv->last_pos_rect.height = 0;
+ priv->pos_redraw_idle_id = 0;
+
+ priv->font_scale = DEFAULT_RULER_FONT_SCALE;
#if GTK_CHECK_VERSION(3,0,0)
#if GTK_CHECK_VERSION(3,8,0)
@@ -299,6 +313,12 @@ sp_ruler_dispose (GObject *object)
while (priv->track_widgets)
sp_ruler_remove_track_widget (ruler, GTK_WIDGET(priv->track_widgets->data));
+ if (priv->pos_redraw_idle_id)
+ {
+ g_source_remove (priv->pos_redraw_idle_id);
+ priv->pos_redraw_idle_id = 0;
+ }
+
G_OBJECT_CLASS (parent_class)->dispose (object);
}
@@ -343,6 +363,7 @@ sp_ruler_set_range (SPRuler *ruler,
}
g_object_thaw_notify (G_OBJECT (ruler));
+ priv->backing_store_valid = FALSE;
gtk_widget_queue_draw (GTK_WIDGET (ruler));
}
@@ -513,7 +534,9 @@ sp_ruler_unrealize(GtkWidget *widget)
cairo_surface_destroy (priv->backing_store);
priv->backing_store = NULL;
}
-
+
+ priv->backing_store_valid = FALSE;
+
if (priv->layout)
{
g_object_unref (priv->layout);
@@ -689,7 +712,6 @@ sp_ruler_expose (GtkWidget *widget,
cairo_clip (cr);
gtk_widget_get_allocation (widget, &allocation);
- cairo_translate (cr, allocation.x, allocation.y);
gboolean result = sp_ruler_draw (widget, cr);
@@ -733,6 +755,8 @@ sp_ruler_make_pixmap (SPRuler *ruler)
CAIRO_CONTENT_COLOR,
allocation.width,
allocation.height);
+
+ priv->backing_store_valid = FALSE;
}
static void
@@ -743,118 +767,22 @@ sp_ruler_draw_pos (SPRuler *ruler,
#if GTK_CHECK_VERSION(3,0,0)
GtkStyleContext *context = gtk_widget_get_style_context (widget);
- GtkBorder border;
GdkRGBA color;
#else
GtkStyle *style = gtk_widget_get_style (widget);
GtkStateType state = gtk_widget_get_state (widget);
- gint xthickness;
- gint ythickness;
#endif
SPRulerPrivate *priv = SP_RULER_GET_PRIVATE (ruler);
- GtkAllocation allocation;
- gint x, y;
- gint width, height;
- gint bs_width, bs_height;
+ GdkRectangle pos_rect;
if (! gtk_widget_is_drawable (widget))
return;
- gtk_widget_get_allocation(widget, &allocation);
-
-#if GTK_CHECK_VERSION(3,0,0)
- gtk_style_context_get_border (context, static_cast<GtkStateFlags>(0), &border);
-#else
- xthickness = style->xthickness;
- ythickness = style->ythickness;
-#endif
-
- if (priv->orientation == GTK_ORIENTATION_HORIZONTAL)
- {
- width = allocation.width;
-#if GTK_CHECK_VERSION(3,0,0)
- height = allocation.height - (border.top + border.bottom);
-#else
- height = allocation.height - ythickness * 2;
-#endif
-
- bs_width = height / 2 + 2;
- bs_width |= 1; /* make sure it's odd */
- bs_height = bs_width / 2 + 1;
- }
- else
- {
-#if GTK_CHECK_VERSION(3,0,0)
- width = allocation.width - (border.left + border.right);
-#else
- width = allocation.width - xthickness * 2;
-#endif
- height = allocation.height;
-
- bs_height = width / 2 + 2;
- bs_height |= 1; /* make sure it's odd */
- bs_width = bs_height / 2 + 1;
- }
+ pos_rect = sp_ruler_get_pos_rect (ruler, sp_ruler_get_position (ruler));
- if ((bs_width > 0) && (bs_height > 0))
+ if ((pos_rect.width > 0) && (pos_rect.height > 0))
{
- gdouble lower;
- gdouble upper;
- gdouble position;
- gdouble increment;
-
- if (! cr)
- {
- cr = gdk_cairo_create (gtk_widget_get_window (widget));
- cairo_translate (cr, allocation.x, allocation.y);
- cairo_rectangle (cr, allocation.x, allocation.y, allocation.width, allocation.height);
- cairo_clip (cr);
-
- cairo_translate (cr, allocation.x, allocation.y);
-
- /* If a backing store exists, restore the ruler */
- if (priv->backing_store)
- {
- cairo_set_source_surface (cr, priv->backing_store, 0, 0);
- cairo_rectangle (cr, priv->xsrc, priv->ysrc, bs_width, bs_height);
- cairo_fill (cr);
- }
- }
- else
- {
- cairo_reference (cr);
- }
-
- position = sp_ruler_get_position (ruler);
-
- sp_ruler_get_range (ruler, &lower, &upper, NULL);
-
- if (priv->orientation == GTK_ORIENTATION_HORIZONTAL)
- {
- increment = (gdouble) width / (upper - lower);
-
-#if GTK_CHECK_VERSION(3,0,0)
- x = ROUND ((position - lower) * increment) + (border.left - bs_width) / 2 - 1;
- y = (height + bs_height) / 2 + border.top;
-#else
- x = ROUND ((position - lower) * increment) + (xthickness - bs_width) / 2 - 1;
- y = (height + bs_height) / 2 + ythickness;
-#endif
- }
- else
- {
- increment = (gdouble) height / (upper - lower);
-
-#if GTK_CHECK_VERSION(3,0,0)
- x = (width + bs_width) / 2 + border.left;
- y = ROUND ((position - lower) * increment) + (border.top - bs_height) / 2 - 1;
-#else
- x = (width + bs_width) / 2 + xthickness;
- y = ROUND ((position - lower) * increment) + (ythickness - bs_height) / 2 - 1;
-#endif
- }
-
#if GTK_CHECK_VERSION(3,0,0)
gtk_style_context_get_color (context, gtk_widget_get_state_flags (widget),
&color);
@@ -863,26 +791,28 @@ sp_ruler_draw_pos (SPRuler *ruler,
gdk_cairo_set_source_color (cr, &style->fg[state]);
#endif
- cairo_move_to (cr, x, y);
+ cairo_move_to (cr, pos_rect.x, pos_rect.y);
if (priv->orientation == GTK_ORIENTATION_HORIZONTAL)
{
- cairo_line_to (cr, x + bs_width / 2.0, y + bs_height);
- cairo_line_to (cr, x + bs_width, y);
+ cairo_line_to (cr, pos_rect.x + pos_rect.width / 2.0,
+ pos_rect.y + pos_rect.height);
+ cairo_line_to (cr, pos_rect.x + pos_rect.width,
+ pos_rect.y);
}
else
{
- cairo_line_to (cr, x + bs_width, y + bs_height / 2.0);
- cairo_line_to (cr, x, y + bs_height);
+ cairo_line_to (cr, pos_rect.x + pos_rect.width,
+
+ pos_rect.y + pos_rect.height / 2.0);
+ cairo_line_to (cr, pos_rect.x,
+ pos_rect.y + pos_rect.height);
}
cairo_fill (cr);
-
- cairo_destroy (cr);
-
- priv->xsrc = x;
- priv->ysrc = y;
}
+
+ priv->last_pos_rect = pos_rect;
}
/**
@@ -1096,6 +1026,7 @@ sp_ruler_set_unit (SPRuler *ruler,
priv->unit = unit;
g_object_notify(G_OBJECT(ruler), "unit");
+ priv->backing_store_valid = FALSE;
gtk_widget_queue_draw (GTK_WIDGET (ruler));
}
}
@@ -1131,10 +1062,39 @@ sp_ruler_set_position (SPRuler *ruler,
if (priv->position != position)
{
- priv->position = position;
- g_object_notify (G_OBJECT (ruler), "position");
-
- sp_ruler_draw_pos (ruler, NULL);
+ GdkRectangle rect;
+ gint xdiff, ydiff;
+
+ priv->position = position;
+ g_object_notify (G_OBJECT (ruler), "position");
+
+ rect = sp_ruler_get_pos_rect (ruler, priv->position);
+
+ xdiff = rect.x - priv->last_pos_rect.x;
+ ydiff = rect.y - priv->last_pos_rect.y;
+
+ /*
+ * If the position has changed far enough, queue a redraw immediately.
+ * Otherwise, we only queue a redraw in a low priority idle handler, to
+ * allow for other things (like updating the canvas) to run.
+ *
+ * TODO: This might not be necessary any more in GTK3 with the frame
+ * clock. Investigate this more after the port to GTK3.
+ */
+ if (priv->last_pos_rect.width != 0 &&
+ priv->last_pos_rect.height != 0 &&
+ (ABS (xdiff) > IMMEDIATE_REDRAW_THRESHOLD ||
+ ABS (ydiff) > IMMEDIATE_REDRAW_THRESHOLD))
+ {
+ sp_ruler_queue_pos_redraw (ruler);
+ }
+ else if (! priv->pos_redraw_idle_id)
+ {
+ priv->pos_redraw_idle_id =
+ g_idle_add_full (G_PRIORITY_LOW,
+ sp_ruler_idle_queue_pos_redraw,
+ ruler, NULL);
+ }
}
}
@@ -1154,7 +1114,7 @@ sp_ruler_get_position (SPRuler *ruler)
static gboolean
sp_ruler_motion_notify (GtkWidget *widget,
- GdkEventMotion *event)
+ GdkEventMotion *event)
{
SPRuler *ruler = SP_RULER(widget);
@@ -1347,7 +1307,7 @@ sp_ruler_draw_ticks (SPRuler *ruler)
if (ideal_length > ++length)
length = ideal_length;
- if (lower < upper)
+ if (lower < upper)
{
start = floor (lower / subd_incr) * subd_incr;
end = ceil (upper / subd_incr) * subd_incr;
@@ -1413,16 +1373,16 @@ sp_ruler_draw_ticks (SPRuler *ruler)
pango_layout_get_extents (layout, &logical_rect, NULL);
#if GTK_CHECK_VERSION(3,0,0)
- cairo_move_to (cr,
+ cairo_move_to (cr,
pos + 2,
border.top + PANGO_PIXELS (logical_rect.y - digit_offset));
#else
- cairo_move_to (cr,
+ cairo_move_to (cr,
pos + 2,
ythickness + PANGO_PIXELS (logical_rect.y - digit_offset));
#endif
- pango_cairo_show_layout(cr, layout);
+ pango_cairo_show_layout(cr, layout);
}
else
{
@@ -1435,15 +1395,15 @@ sp_ruler_draw_ticks (SPRuler *ruler)
pango_layout_get_extents (layout, NULL, &logical_rect);
#if GTK_CHECK_VERSION(3,0,0)
- cairo_move_to (cr,
+ cairo_move_to (cr,
border.left + 1,
pos + digit_height * j + 2 + PANGO_PIXELS (logical_rect.y - digit_offset));
#else
- cairo_move_to (cr,
+ cairo_move_to (cr,
xthickness + 1,
pos + digit_height * j + 2 + PANGO_PIXELS (logical_rect.y - digit_offset));
#endif
- pango_cairo_show_layout (cr, layout);
+ pango_cairo_show_layout (cr, layout);
}
}
}
@@ -1454,10 +1414,118 @@ sp_ruler_draw_ticks (SPRuler *ruler)
cairo_fill (cr);
+ priv->backing_store_valid = TRUE;
+
out:
cairo_destroy (cr);
}
+static GdkRectangle
+sp_ruler_get_pos_rect (SPRuler *ruler,
+ gdouble position)
+{
+ GtkWidget *widget = GTK_WIDGET (ruler);
+ GtkStyle *style = gtk_widget_get_style (widget);
+ SPRulerPrivate *priv = SP_RULER_GET_PRIVATE (ruler);
+ GtkAllocation allocation;
+ gint width, height;
+ gint xthickness;
+ gint ythickness;
+ gdouble upper, lower;
+ gdouble increment;
+ GdkRectangle rect = { 0, 0, 0, 0 };
+
+ if (! gtk_widget_is_drawable (widget))
+ return rect;
+
+ gtk_widget_get_allocation (widget, &allocation);
+
+ xthickness = style->xthickness;
+ ythickness = style->ythickness;
+
+ if (priv->orientation == GTK_ORIENTATION_HORIZONTAL)
+ {
+ width = allocation.width;
+ height = allocation.height - ythickness * 2;
+
+ rect.width = height / 2 + 2;
+ rect.width |= 1; /* make sure it's odd */
+ rect.height = rect.width / 2 + 1;
+ }
+ else
+ {
+ width = allocation.width - xthickness * 2;
+ height = allocation.height;
+
+ rect.height = width / 2 + 2;
+ rect.height |= 1; /* make sure it's odd */
+ rect.width = rect.height / 2 + 1;
+ }
+
+ sp_ruler_get_range (ruler, &lower, &upper, NULL);
+
+ if (priv->orientation == GTK_ORIENTATION_HORIZONTAL)
+ {
+ increment = (gdouble) width / (upper - lower);
+
+ rect.x = ROUND ((position - lower) * increment) + (xthickness - rect.width) / 2 - 1;
+ rect.y = (height + rect.height) / 2 + ythickness;
+ }
+ else
+ {
+ increment = (gdouble) height / (upper - lower);
+
+ rect.x = (width + rect.width) / 2 + xthickness;
+ rect.y = ROUND ((position - lower) * increment) + (ythickness - rect.height) / 2 - 1;
+ }
+
+ rect.x += allocation.x;
+ rect.y += allocation.y;
+
+ return rect;
+}
+
+static gboolean
+sp_ruler_idle_queue_pos_redraw (gpointer data)
+{
+ SPRuler *ruler = (SPRuler *)data;
+ SPRulerPrivate *priv = SP_RULER_GET_PRIVATE (ruler);
+
+ sp_ruler_queue_pos_redraw (ruler);
+
+ gboolean ret = g_source_remove(priv->pos_redraw_idle_id);
+ priv->pos_redraw_idle_id = 0;
+
+ return ret;
+}
+
+static void
+sp_ruler_queue_pos_redraw (SPRuler *ruler)
+{
+ SPRulerPrivate *priv = SP_RULER_GET_PRIVATE (ruler);
+ const GdkRectangle rect = sp_ruler_get_pos_rect (ruler, priv->position);
+
+ gtk_widget_queue_draw_area (GTK_WIDGET(ruler),
+ rect.x,
+ rect.y,
+ rect.width,
+ rect.height);
+
+ if (priv->last_pos_rect.width != 0 || priv->last_pos_rect.height != 0)
+ {
+ gtk_widget_queue_draw_area (GTK_WIDGET(ruler),
+ priv->last_pos_rect.x,
+ priv->last_pos_rect.y,
+ priv->last_pos_rect.width,
+ priv->last_pos_rect.height);
+
+ priv->last_pos_rect.x = 0;
+ priv->last_pos_rect.y = 0;
+ priv->last_pos_rect.width = 0;
+ priv->last_pos_rect.height = 0;
+ }
+}
+
static PangoLayout*
sp_ruler_create_layout (GtkWidget *widget,
const gchar *text)
diff --git a/src/widgets/text-toolbar.cpp b/src/widgets/text-toolbar.cpp
index c6cc7dc45..5ca92b4c0 100644
--- a/src/widgets/text-toolbar.cpp
+++ b/src/widgets/text-toolbar.cpp
@@ -1592,7 +1592,7 @@ void sp_text_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObje
"TextLineHeightAction", /* name */
_("Line Height"), /* label */
_("Line:"), /* short label */
- _("Spacing between lines (times font size)"), /* tooltip */
+ _("Spacing between baselines (times font size)"), /* tooltip */
"/tools/text/lineheight", /* preferences path */
0.0, /* default */
GTK_WIDGET(desktop->canvas), /* focusTarget */