Code

Patch from Debian bug tracker from Daniel Kahn Gillmor
[inkscape.git] / src / livarot / PathConversion.cpp
index e6f7acb0c17319f396099b5d529e724ea43651b6..7c741ac4ce466838da20f4a2a6bc895e08c0075d 100644 (file)
@@ -400,6 +400,276 @@ void Path::Convert(double treshhold)
     }
 }
 
+#define POINT_RELATION_TO_AREA(pt, area) ((pt)[0] < (area)->x0 ? 1 : ((pt)[0] > (area)->x1 ? 2 : ((pt)[1] < (area)->y0 ? 3 : ((pt)[1] > (area)->y1 ? 4 : 0))))
+
+void Path::Convert(NRRectL *area, double treshhold)
+{
+    if ( descr_flags & descr_adding_bezier ) {
+        CancelBezier();
+    }
+
+    if ( descr_flags & descr_doing_subpath ) {
+        CloseSubpath();
+    }
+
+    SetBackData(false);
+    ResetPoints();
+    if ( descr_cmd.empty() ) {
+        return;
+    }
+
+    NR::Point curX;
+    int curP = 1;
+    int lastMoveTo = 0;
+    short last_point_relation = 0;
+    short curent_point_relation = 0;
+    bool last_start_elimination = false;
+    bool start_elimination = false;
+    bool replace = false;
+
+    // first point
+    {
+        int const firstTyp = descr_cmd[0]->getType();
+        if ( firstTyp == descr_moveto ) {
+            curX = dynamic_cast<PathDescrMoveTo *>(descr_cmd[0])->p;
+        } else {
+            curP = 0;
+            curX[0] = curX[1] = 0;
+        }
+        
+        last_point_relation = POINT_RELATION_TO_AREA(curX, area);
+        lastMoveTo = AddPoint(curX, true);
+    }
+    descr_cmd[0]->associated = lastMoveTo;
+
+    // process nodes one by one
+    while ( curP < int(descr_cmd.size()) ) {
+
+        int const nType = descr_cmd[curP]->getType();
+        NR::Point nextX;
+
+        switch (nType) {
+            case descr_forced: {
+                descr_cmd[curP]->associated = AddForcedPoint(curX);
+                last_point_relation = 0;
+                curP++;
+                break;
+            }
+
+            case descr_moveto: {
+                PathDescrMoveTo *nData = dynamic_cast<PathDescrMoveTo *>(descr_cmd[curP]);
+                nextX = nData->p;
+                lastMoveTo = AddPoint(nextX, true);
+                descr_cmd[curP]->associated = lastMoveTo;
+                last_point_relation = POINT_RELATION_TO_AREA(nextX, area);
+                start_elimination = false;
+
+                curP++;
+                break;
+            }
+
+            case descr_close: {
+                nextX = pts[lastMoveTo].p;
+                descr_cmd[curP]->associated = AddPoint(nextX, false);
+                if ( descr_cmd[curP]->associated < 0 ) {
+                    if ( curP == 0 ) {
+                        descr_cmd[curP]->associated = 0;
+                    } else {
+                        descr_cmd[curP]->associated = descr_cmd[curP - 1]->associated;
+                    }
+                }
+                last_point_relation = 0;
+                curP++;
+                break;
+            }
+
+            case descr_lineto: {
+                PathDescrLineTo *nData = dynamic_cast<PathDescrLineTo *>(descr_cmd[curP]);
+                nextX = nData->p;
+                curent_point_relation = POINT_RELATION_TO_AREA(nextX, area);
+                replace = false;
+                last_start_elimination = start_elimination;
+                if (curent_point_relation > 0 && curent_point_relation == last_point_relation) {
+                    if (!start_elimination) {
+                        start_elimination = true;
+                    } else {
+                        replace = true;
+                        descr_cmd[curP]->associated = ReplacePoint(nextX);
+                    }
+                } else {
+                    start_elimination = false;
+                }
+
+                if (!replace) {
+                    descr_cmd[curP]->associated = AddPoint(nextX, false);
+                }
+
+                if ( descr_cmd[curP]->associated < 0 ) {
+                    // point is not added as position is equal to the last added
+                    start_elimination = last_start_elimination;
+                    if ( curP == 0 ) {
+                        descr_cmd[curP]->associated = 0;
+                    } else {
+                        descr_cmd[curP]->associated = descr_cmd[curP - 1]->associated;
+                    }
+                }
+                last_point_relation = curent_point_relation;
+                curP++;
+                break;
+            }
+
+            case descr_cubicto: {
+                PathDescrCubicTo *nData = dynamic_cast<PathDescrCubicTo *>(descr_cmd[curP]);
+                nextX = nData->p;
+
+                curent_point_relation = POINT_RELATION_TO_AREA(nextX, area);
+                replace = false;
+                last_start_elimination = start_elimination;
+                if (curent_point_relation > 0 && curent_point_relation == last_point_relation &&
+                    curent_point_relation == POINT_RELATION_TO_AREA(curX + (nData->start), area) &&
+                    curent_point_relation == POINT_RELATION_TO_AREA(nextX + (nData->end), area))
+                {
+                    if (!start_elimination) {
+                        start_elimination = true;
+                    } else {
+                        replace = true;
+                        descr_cmd[curP]->associated = ReplacePoint(nextX);
+                    }
+                } else {
+                    start_elimination = false;
+                }
+                
+                if (!replace) {
+                    RecCubicTo(curX, nData->start, nextX, nData->end, treshhold, 8);
+                    descr_cmd[curP]->associated = AddPoint(nextX,false);
+                }
+
+                if ( descr_cmd[curP]->associated < 0 ) {
+                    // point is not added as position is equal to the last added
+                    start_elimination = last_start_elimination;
+                    if ( curP == 0 ) {
+                        descr_cmd[curP]->associated = 0;
+                    } else {
+                        descr_cmd[curP]->associated = descr_cmd[curP - 1]->associated;
+                    }
+                }
+                last_point_relation = curent_point_relation;
+                curP++;
+                break;
+            }
+
+            case descr_arcto: {
+                PathDescrArcTo *nData = dynamic_cast<PathDescrArcTo *>(descr_cmd[curP]);
+                nextX = nData->p;
+                DoArc(curX, nextX, nData->rx, nData->ry, nData->angle, nData->large, nData->clockwise, treshhold);
+                descr_cmd[curP]->associated = AddPoint(nextX, false);
+                if ( descr_cmd[curP]->associated < 0 ) {
+                    if ( curP == 0 ) {
+                        descr_cmd[curP]->associated = 0;
+                    } else {
+                        descr_cmd[curP]->associated = descr_cmd[curP - 1]->associated;
+                    }
+                }
+                last_point_relation = 0;
+
+                curP++;
+                break;
+            }
+
+            case descr_bezierto: {
+                PathDescrBezierTo *nBData = dynamic_cast<PathDescrBezierTo *>(descr_cmd[curP]);
+                int nbInterm = nBData->nb;
+                nextX = nBData->p;
+                int curBD = curP;
+
+                curP++;
+                int ip = curP;
+                PathDescrIntermBezierTo *nData = dynamic_cast<PathDescrIntermBezierTo *>(descr_cmd[ip]);
+
+                if ( nbInterm == 1 ) {
+                    NR::Point const midX = nData->p;
+                    RecBezierTo(midX, curX, nextX, treshhold, 8);
+                } else if ( nbInterm > 1 ) {
+                    NR::Point bx = curX;
+                    NR::Point cx = curX;
+                    NR::Point dx = curX;
+
+                    dx = nData->p;
+                    ip++;
+                    nData = dynamic_cast<PathDescrIntermBezierTo *>(descr_cmd[ip]);
+
+                    cx = 2 * bx - dx;
+
+                    for (int k = 0; k < nbInterm - 1; k++) {
+                        bx = cx;
+                        cx = dx;
+
+                        dx = nData->p;
+                        ip++;
+                        nData = dynamic_cast<PathDescrIntermBezierTo *>(descr_cmd[ip]);
+
+                        NR::Point stx = (bx + cx) / 2;
+                        if ( k > 0 ) {
+                            descr_cmd[ip - 2]->associated = AddPoint(stx, false);
+                            if ( descr_cmd[ip - 2]->associated < 0 ) {
+                                if ( curP == 0 ) {
+                                    descr_cmd[ip - 2]->associated = 0;
+                                } else {
+                                    descr_cmd[ip - 2]->associated = descr_cmd[ip - 3]->associated;
+                                }
+                            }
+                        }
+
+                        {
+                            NR::Point const mx = (cx + dx) / 2;
+                            RecBezierTo(cx, stx, mx, treshhold, 8);
+                        }
+                    }
+
+                    {
+                        bx = cx;
+                        cx = dx;
+
+                        dx = nextX;
+                        dx = 2 * dx - cx;
+
+                        NR::Point stx = (bx + cx) / 2;
+
+                        descr_cmd[ip - 1]->associated = AddPoint(stx, false);
+                        if ( descr_cmd[ip - 1]->associated < 0 ) {
+                            if ( curP == 0 ) {
+                                descr_cmd[ip - 1]->associated = 0;
+                            } else {
+                                descr_cmd[ip - 1]->associated = descr_cmd[ip - 2]->associated;
+                            }
+                        }
+
+                        {
+                            NR::Point mx = (cx + dx) / 2;
+                            RecBezierTo(cx, stx, mx, treshhold, 8);
+                        }
+                    }
+                }
+
+                descr_cmd[curBD]->associated = AddPoint(nextX, false);
+                if ( descr_cmd[curBD]->associated < 0 ) {
+                    if ( curP == 0 ) {
+                        descr_cmd[curBD]->associated = 0;
+                    } else {
+                        descr_cmd[curBD]->associated = descr_cmd[curBD - 1]->associated;
+                    }
+                }
+
+                last_point_relation = 0;
+
+                curP += nbInterm;
+                break;
+            }
+        }
+
+        curX = nextX;
+    }
+}
 
 
 void Path::ConvertEvenLines(double treshhold)