geom-pathstroke.cpp revision a9f579cc260027d89b33d51735963a98cc77d5e9
/* Author:
* Liam P. White
*
* Copyright (C) 2014-2015 Author
*
* Released under GNU GPL, read the file 'COPYING' for more information
*/
#include <iomanip>
#include "helper/geom-pathstroke.h"
namespace Geom {
// 2geom/circle-circle.cpp, no header
/**
* Determine the intersection points between a circle C0 and a line defined
* by two points, X0 and X1.
*
* Which intersection point is assigned to p0 or p1 is unspecified, and callers
* should not depend on any particular intersection always being assigned to p0.
*
* Returns:
* If the line and circle do not cross, 0 is returned.
* If solution(s) exist, 2 is returned, and the results are written to p0 and p1.
*/
{
/* equation of a circle: (x - h)^2 + (y - k)^2 = r^2 */
/* slope is undefined (vertical line) */
/* no intersection */
if (det < 0)
return 0;
/* solve for y */
// x == c (always)
x0 = c;
x1 = c;
} else {
/* equation of a line: y = mx + b */
/* obtain quadratic for x: */
Coord A = m*m + 1;
Coord C = b*b + h*h + k*k - r*r - 2*b*k;
/* no intersection, circle and line do not cross */
if (det < 0)
return 0;
/* solve quadratic */
/* substitute the calculated x times to determine the y values */
}
return 2;
}
{
}
}
/**
* Find circle that touches inside of the curve, with radius matching the curvature, at time value \c t.
* Because this method internally uses unitTangentAt, t should be smaller than 1.0 (see unitTangentAt).
*/
{
}
}
double curv = k(t); // note that this value is signed
}
}
namespace {
// Join functions may:
// - inspect any curve of the current path
// - append any type of curve to the current path
// - inspect the outgoing path
//
// Join functions must:
// - append the outgoing curve
// OR
// - end at outgoing.finalPoint
{
}
{
}
void miter_join_internal(Geom::Path& res, Geom::Curve const& outgoing, double miter, double width, bool clip)
{
Geom::Point p = Geom::intersection_point(incoming.finalPoint(), tang1, outgoing.initialPoint(), tang2);
bool satisfied = false;
if (p.isFinite()) {
// check size of miter
if (satisfied) {
// miter OK, check to see if we can do a relocation
if (inc_ls) {
} else {
}
} else if (clip) {
// miter needs clipping, find two points
Geom::Point p1 = Geom::intersection_point(incoming.finalPoint(), tang1, point_limit, bisector_versor.cw());
Geom::Point p2 = Geom::intersection_point(outgoing.initialPoint(), tang2, point_limit, bisector_versor.cw());
if (inc_ls) {
} else {
}
}
}
// check if we can do another relocation
} else {
}
}
}
}
{
// points[0] is bad, choose points[1]
// points[1] is bad, choose points[0]
} else {
// both points are good, choose nearest
}
return sol;
}
{
using namespace Geom;
int solutions = 0;
// Two circles
if (solutions == 2) {
}
// Line and circle
solutions = Geom::circle_line_intersection(circle2, incoming.initialPoint(), incoming.finalPoint(), points[0], points[1]);
if (solutions == 2) {
}
// Circle and line
solutions = Geom::circle_line_intersection(circle1, outgoing.initialPoint(), outgoing.finalPoint(), points[0], points[1]);
if (solutions == 2) {
}
}
if (solutions != 2)
// no solutions available, fall back to miter
// We have a solution, thus sol is defined.
// See if we need to clip. Miter length is measured along a circular arc that is tangent to the
// bisector of the incoming and out going angles and passes through the end point (sol) of the
// line join.
// Center of circle is intersection of a line orthogonal to bisector and a line bisecting
// a chord connecting the path end point (point_on_path) and the join end point (sol).
bool clipped = false;
// No intersection (can happen if curvatures are equal but opposite)
clipped = true;
}
} else {
} else {
}
Geom::EllipticalArc *arc_center = circle_center.arc(point_on_path, 0.5*(point_on_path + sol), sol, true);
// We need to clip
clipped = true;
if (!inc_ls) {
// Incoming circular
solutions = Geom::circle_line_intersection(circle1, limit_line.pointAt(0), limit_line.pointAt(1), points[0], points[1]);
if (solutions == 2) {
delete arc1;
}
} else {
}
if (!out_ls) {
// Outgoing circular
solutions = Geom::circle_line_intersection(circle2, limit_line.pointAt(0), limit_line.pointAt(1), points[0], points[1]);
if (solutions == 2) {
delete arc2;
}
} else {
}
}
}
// Add initial
if (arc1) {
} else {
// Straight line segment: move last point
}
if (clipped) {
}
// Add outgoing
if (arc2) {
} else {
// Straight line segment:
}
delete arc1;
delete arc2;
}
{
// yeah if we could avoid allocing that'd be great
res.erase_last();
delete d1;
delete d2;
} else {
}
}
{
}
void outline_helper(Geom::Path& res, Geom::Path const& to_add, double width, bool on_outside, double miter, Inkscape::LineJoinType join)
{
return;
// if the points are /that/ close, just ignore this one
return;
}
if (on_outside) {
switch (join) {
case Inkscape::JOIN_BEVEL:
jf = &bevel_join;
break;
case Inkscape::JOIN_ROUND:
jf = &round_join;
break;
case Inkscape::JOIN_EXTRAPOLATE:
jf = &extrapolate_join;
break;
case Inkscape::JOIN_MITER_CLIP:
jf = &miter_clip_join;
break;
default:
jf = &miter_join;
}
} else {
}
}
// Offsetting a line segment is mathematically stable and quick to do
{
}
{
// get derivatives
// TODO: we might want to consider using Geom::touching_circle to determine the
// curvature radius here. Less code duplication, but slower
return; // this isn't a segment...
}
rad = 1e8;
} else {
}
} else {
}
len = l;
}
void offset_cubic(Geom::Path& p, Geom::CubicBezier const& bez, double width, double tol, size_t levels)
{
using Geom::X;
using Geom::Y;
// offset the start and end control points out by the width
// --------
// correction of the lengths of the tangent to the offset
// --------
// create the estimate curve
// reached maximum recursive depth
// don't bother with any more correction
if (levels == 0) {
return;
}
// check the tolerance for our estimate to be a parallel curve
}
// we're good, curve is accurate enough
p.append(c);
return;
} else {
// split the curve in two
}
}
void offset_quadratic(Geom::Path& p, Geom::QuadraticBezier const& bez, double width, double tol, size_t levels)
{
// cheat
// it's faster
// seriously
}
{
double const tolerance = 0.005;
// TODO: we can handle SVGEllipticalArc here as well, do that!
switch (order) {
case 1:
break;
case 2: {
break;
}
case 3: {
break;
}
default: {
break;
}
}
} else {
}
}
typedef void cap_func(Geom::PathBuilder& res, Geom::Path const& with_dir, Geom::Path const& against_dir, double width);
{
}
void round_cap(Geom::PathBuilder& res, Geom::Path const&, Geom::Path const& against_dir, double width)
{
}
void square_cap(Geom::PathBuilder& res, Geom::Path const& with_dir, Geom::Path const& against_dir, double width)
{
width /= 2.;
}
void peak_cap(Geom::PathBuilder& res, Geom::Path const& with_dir, Geom::Path const& against_dir, double width)
{
width /= 2.;
Geom::Point midpoint = ((with_dir.finalPoint() + normal_1*width) + (against_dir.initialPoint() + normal_2*width)) * 0.5;
}
} // namespace
namespace Inkscape {
Geom::PathVector outline(Geom::Path const& input, double width, double miter, LineJoinType join, LineCapType butt)
{
switch (butt) {
case BUTT_ROUND:
break;
case BUTT_SQUARE:
cf = &square_cap;
break;
case BUTT_PEAK:
break;
default:
}
// glue caps
} else {
}
}
}
{
// Do two curves at a time for efficiency, since the join function needs to know the outgoing curve as well
for (size_t u = 0; u < k; u += 2) {
// on the first run through, there isn't a join
if (u == 0) {
} else {
}
// odd number of paths
if (u < k - 1) {
}
}
res.erase_last();
//
}
return res;
}
} // namespace Inkscape
/*
Local Variables:
mode:c++
c-file-style:"stroustrup"
c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
indent-tabs-mode:nil
fill-column:99
End:
*/
// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8 :