pathoutlineprovider.cpp revision 9c206d6178c0f4855e414e9e9ae5467b224493b7
#include <glib.h> //g_critical
#include "pathoutlineprovider.h"
#include "livarot/path-description.h"
#include "helper/geom-nodetype.h"
namespace Geom {
/**
* Refer to: Weisstein, Eric W. "Circle-Circle Intersection."
From MathWorld--A Wolfram Web Resource.
*
* @return 0 if no intersection
* @return 1 if one circle is contained in the other
* @return 2 if intersections are found (they are written to p0 and p1)
*/
{
/* dx and dy are the vertical and horizontal distances between
* the circle centers.
*/
/* Determine the straight-line distance between the centers. */
double d = L2(D);
/* Check for solvability. */
/* no solution. circles do not intersect. */
return 0;
}
/* no solution. one circle is contained in the other */
return 1;
}
/* 'point 2' is the point where the line through the circle
* intersection points crosses the line between the circle
* centers.
*/
/* Determine the distance from point 0 to point 2. */
/* Determine the coordinates of point 2. */
/* Determine the distance from point 2 to either of the
* intersection points.
*/
/* Now determine the offsets of the intersection points from
* point 2.
*/
/* Determine the absolute intersection points. */
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
}
{
}
}
}
return out;
}
{
}
static boost::optional<Geom::Point> intersection_point( Geom::Point const & origin_a, Geom::Point const & vector_a,
{
}
}
}
namespace Outline {
{
using namespace Geom;
}
return 0;
}
//returns true if the angle formed by the curves and their handles
//is >180 clockwise, otherwise false.
{
//assert(cbc1.finalPoint() == cbc2.initialPoint());
//short circuiting?
printf("There was an issue when asserting that one curve's end is the start of the other. Line %d, File %s\n"
"By default we are going to say that this is an inside join, so we cannot make a line join for it.\n", __LINE__, __FILE__);
return false;
}
//let's try:
//stupid thing Inkscape does:
}
}
//got our three points, now let's see what their clockwise angle is
//Much credit to Wikipedia for the following ( http://en.wikipedia.org/wiki/Graham_scan )
/********************************************************************
# Three points are a counter-clockwise turn if ccw > 0, clockwise if
# ccw < 0, and collinear if ccw = 0 because ccw is a determinant that
# gives the signed area of the triangle formed by p1, p2 and p3.
function ccw(p1, p2, p3):
return (p2.x - p1.x)*(p3.y - p1.y) - (p2.y - p1.y)*(p3.x - p1.x)
*********************************************************************/
if (ccw > 0) return true;
return false;
}
void extrapolate_curves(Geom::Path& path_builder, Geom::Curve* cbc1, Geom::Curve* cbc2, Geom::Point endPt,
{
bool lineProblem = (dynamic_cast<Geom::BezierCurveN<1u> *>(cbc1)) || (dynamic_cast<Geom::BezierCurveN<1u> *>(cbc2));
if ( outside && !lineProblem ) {
if (solutions == 2) {
// points[0] is bad, choose points[1]
// points[1] is bad, choose points[0]
} else {
// both points are good, choose nearest
}
Geom::EllipticalArc *arc0 = circle1.arc(cbc1->finalPoint(), 0.5*(cbc1->finalPoint()+sol), sol, true);
try {
if (arc0) {
delete arc0;
}
if (arc1) {
delete arc1;
}
}
} else {
if (p) {
//check size of miter
if (len <= miter_limit) {
// miter OK
}
}
}
}
if ( outside && lineProblem ) {
if (p) {
//check size of miter
if (len <= miter_limit) {
// miter OK
}
}
}
if ( !outside ) {
/*path_builder.appendNew<Geom::LineSegment> (endPt);*/
} else {
}
}
}
void reflect_curves(Geom::Path& path_builder, Geom::Curve* cbc1, Geom::Curve* cbc2, Geom::Point endPt,
{
//the most important work for the reflected join is done here
//determine where we are in the path. If we're on the inside, ignore
//and just lineTo. On the outside, we'll do a little reflection magic :)
if (outside) {
//reflect curves along the bevel
cbc1->finalPoint() );
cbc2->initialPoint() );
//curves didn't cross; default to miter
if (p) {
//check size of miter
if (len <= miter_limit) {
// miter OK
}
}
//bevel
} else {
//join
//@TODO joins have a strange tendency to cross themselves twice. Check this.
//sections commented out are for general stability
path_builder.appendNew <Geom::CubicBezier> (sub1.first[1], sub1.first[2], /*sub1.first[3]*/ sub2.second[0] );
path_builder.appendNew <Geom::CubicBezier> (sub2.second[1], sub2.second[2], /*sub2.second[3]*/ endPt );
}
} else {
//probably on the inside of the corner
/*path_builder.appendNew<Geom::LineSegment> ( endPt );*/
} else {
}
}
}
/** @brief Converts a path to one half of an outline.
* path_in: The input path to use. (To create the other side use path_in.reverse() )
* line_width: the line width to use (usually you want to divide this by 2)
* miter_limit: the miter parameter
* extrapolate: whether the join should be extrapolated instead of reflected
*/
Geom::Path doAdvHalfOutline(const Geom::Path& path_in, double line_width, double miter_limit, bool extrapolate = false)
{
// NOTE: it is important to notice the distinction between a Geom::Path and a livarot Path here!
// if you do not see "Geom::" there is a different function set!
for (unsigned u = 0; u < k; u+=2) {
to_outline = Path();
outlined_result = Path();
//now a curve has been outside outlined and loaded into outlined_result
//get the Geom::Path
//thing to do on the first run through
if (u == 0) {
//I could use the pv->operator[] (0) notation but that looks terrible
} else {
//get the curves ready for the operation
//do the reflection/extrapolation:
if (extrapolate) {
extrapolate_curves(path_builder, cbc1, cbc2, (*path_vec)[0].initialPoint(), miter_limit, line_width,
} else {
}
}
//outline the next segment, but don't store it yet
if (u < k - 1) {
outlined_result = Path();
to_outline = Path();
//get the curves ready for the operation
//do the reflection/extrapolation:
if (extrapolate) {
extrapolate_curves(path_builder, cbc1, cbc2, (*path_vec)[0].initialPoint(), miter_limit, line_width,
} else {
}
//Now we can store it.
}
}
return path_builder;
}
{
for (unsigned i = 0; i < pv_size; i++) {
//since you've made it this far, hopefully all this is obvious :P
against_direction = Outline::doAdvHalfOutline( path_in[i].reverse(), -line_width, miter_lim, extrapolate );
} else {
//Geom::Path absolutely refuses to do what I want with these
//fuk this
against_direction = Outline::doAdvHalfOutline( newPath.reverse(), -line_width, miter_lim, extrapolate );
/*if (dynamic_cast<const Geom::BezierCurveN<1u> *>(&newPath[newPath.size()])) {
//delete the 'Z'
newPath.erase_last();
newPath.append(path_in[i][path_in[i].size() - 1]);
newPath.appendNew<Geom::LineSegment>(newPath.initialPoint());
newPath.erase_last();
} else {
//delete the 'Z'
newPath.erase_last();
newPath.append(path_in[i][path_in[i].size() - 1]);
newPath.appendNew<Geom::LineSegment>(newPath.initialPoint());
newPath.erase_last();
}*/
}
//add in the...do I really need to say this?
//add in our line caps
switch (butt) {
case butt_straight:
break;
case butt_round:
break;
case butt_pointy:
//I have ZERO idea what to do here.
break;
case butt_square:
break;
}
} else {
}
//cap (if necessary)
switch (butt) {
case butt_straight:
break;
case butt_round:
break;
case butt_pointy:
//I have ZERO idea what to do here.
break;
case butt_square:
break;
}
}
}
} else {
//somewhat hack-ish
}
}
return path_out;
}
Geom::PathVector PathVectorOutline(Geom::PathVector const & path_in, double line_width, ButtType linecap_type,
{
return path_out;
}
}
//magic!
if (linejoin_type <= 2) {
//fix memory leak
delete pv_p;
} else if (linejoin_type == 3) {
//reflected arc join
linecap_type , miter_lim, false);
} else if (linejoin_type == 4) {
//extrapolated arc join
}
return path_out;
}
Geom::Path PathOutsideOutline(Geom::Path const & path_in, double line_width, LineJoinType linejoin_type, double miter_limit)
{
path_outline.OutsideOutline(&path_tangent, line_width / 2, static_cast<join_typ>(linejoin_type), butt_straight, miter_lim);
delete pathvec;
return path_out;
} else if (linejoin_type == LINEJOIN_REFLECTED) {
//reflected half outline
return path_out;
} else if (linejoin_type == LINEJOIN_EXTRAPOLATED) {
//what the hell do you think this is? :P
return path_out;
}
return path_out;
}
} // namespace Outline
/*
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:textwidth=99 :