예제 #1
0
        /* calculate best fit from i+.5 to j+.5.  Assume i<j (cyclically).
           Return 0 and set badness and parameters (alpha, beta), if
           possible. Return 1 if impossible. */
        static bool opti_penalty(Path pp, int i, int j, ref opti res, double opttolerance, int[] convc, double[] areac)
        {
            int m = pp.Curves.n;
            int k, k1, k2, conv, i1;
            double area, alpha, d, d1, d2;
            dPoint p0, p1, p2, p3, pt;
            double A, R, A1, A2, A3, A4;
            double s, t;

            /* check convexity, corner-freeness, and maximum bend < 179 degrees */

            if (i == j)
            {  /* sanity - a full loop can never be an opticurve */
                return true;
            }

            k = i;
            i1 = mod(i + 1, m);
            k1 = mod(k + 1, m);
            conv = convc[k1];
            if (conv == 0)
            {
                return true;
            }
            d = ddist(pp.Curves.vertex[i], pp.Curves.vertex[i1]);
            for (k = k1; k != j; k = k1)
            {
                k1 = mod(k + 1, m);
                k2 = mod(k + 2, m);
                if (convc[k1] != conv)
                {
                    return true;
                }
                if (sign(cprod(pp.Curves.vertex[i], pp.Curves.vertex[i1], pp.Curves.vertex[k1], pp.Curves.vertex[k2])) != conv)
                {
                    return true;
                }
                if (iprod1(pp.Curves.vertex[i], pp.Curves.vertex[i1], pp.Curves.vertex[k1], pp.Curves.vertex[k2]) < d * ddist(pp.Curves.vertex[k1], pp.Curves.vertex[k2]) * COS179)
                {
                    return true;
                }
            }

            /* the curve we're working in: */
            p0 = pp.Curves.ControlPoints[mod(i, m), 2];
            p1 = pp.Curves.vertex[mod(i + 1, m)];
            p2 = pp.Curves.vertex[mod(j, m)];
            p3 = pp.Curves.ControlPoints[mod(j, m), 2];

            /* determine its area */
            area = areac[j] - areac[i];
            area -= dpara(pp.Curves.vertex[0], pp.Curves.ControlPoints[i, 2], pp.Curves.ControlPoints[j, 2]) / 2;
            if (i >= j)
            {
                area += areac[m];
            }

            /* find intersection o of p0p1 and p2p3. Let t,s such that o =
               interval(t,p0,p1) = interval(s,p3,p2). Let A be the area of the
               triangle (p0,o,p3). */

            A1 = dpara(p0, p1, p2);
            A2 = dpara(p0, p1, p3);
            A3 = dpara(p0, p2, p3);
            /* A4 = dpara(p1, p2, p3); */
            A4 = A1 + A3 - A2;

            if (A2 == A1)
            {  /* this should never happen */
                return true;
            }

            t = A3 / (A3 - A4);
            s = A2 / (A2 - A1);
            A = A2 * t / 2.0;

            if (A == 0.0)
            {  /* this should never happen */
                return true;
            }

            R = area / A;	 /* relative area */
            alpha = 2 - Math.Sqrt(4 - R / 0.3);  /* overall alpha for p0-o-p3 curve */
            res.c = new dPoint[2];
            res.c[0] = interval(t * alpha, p0, p1);
            res.c[1] = interval(s * alpha, p3, p2);
            res.alpha = alpha;
            res.t = t;
            res.s = s;

            p1 = res.c[0];
            p2 = res.c[1];  /* the proposed curve is now (p0,p1,p2,p3) */

            res.pen = 0;

            /* calculate penalty */
            /* check tangency with edges */
            for (k = mod(i + 1, m); k != j; k = k1)
            {
                k1 = mod(k + 1, m);
                t = tangent(p0, p1, p2, p3, pp.Curves.vertex[k], pp.Curves.vertex[k1]);
                if (t < -.5)
                {
                    return true;
                }
                pt = bezier(t, p0, p1, p2, p3);
                d = ddist(pp.Curves.vertex[k], pp.Curves.vertex[k1]);
                if (d == 0.0)
                {  /* this should never happen */

                    return true;
                }
                d1 = dpara(pp.Curves.vertex[k], pp.Curves.vertex[k1], pt) / d;
                if (Math.Abs(d1) > opttolerance)
                {
                    return true;
                }
                if (iprod(pp.Curves.vertex[k], pp.Curves.vertex[k1], pt) < 0 || iprod(pp.Curves.vertex[k1], pp.Curves.vertex[k], pt) < 0)
                {
                    return true;
                }
                res.pen += d1 * d1;
            }

            /* check corners */
            for (k = i; k != j; k = k1)
            {
                k1 = mod(k + 1, m);
                t = tangent(p0, p1, p2, p3, pp.Curves.ControlPoints[k, 2], pp.Curves.ControlPoints[k1, 2]);
                if (t < -.5)
                {
                    return true;
                }
                pt = bezier(t, p0, p1, p2, p3);
                d = ddist(pp.Curves.ControlPoints[k, 2], pp.Curves.ControlPoints[k1, 2]);
                if (d == 0.0)
                {  /* this should never happen */
                    return true;
                }
                d1 = dpara(pp.Curves.ControlPoints[k, 2], pp.Curves.ControlPoints[k1, 2], pt) / d;
                d2 = dpara(pp.Curves.ControlPoints[k, 2], pp.Curves.ControlPoints[k1, 2], pp.Curves.vertex[k1]) / d;
                d2 *= 0.75 * pp.Curves.alpha[k1];
                if (d2 < 0)
                {
                    d1 = -d1;
                    d2 = -d2;
                }
                if (d1 < d2 - opttolerance)
                {
                    return true;
                }
                if (d1 < d2)
                {
                    res.pen += (d1 - d2) * (d1 - d2);
                }
            }

            return false;
        }
예제 #2
0
        /* optimize the path p, replacing sequences of Bezier segments by a
           single segment when possible. Return 0 on success, 1 with errno set
           on failure. */
        static void opticurve(Path pp, double opttolerance)
        {
            int m = pp.Curves.n;
            int[] pt = new int[m + 1];     /* pt[m+1] */
            double[] pen = new double[m + 1];  /* pen[m+1] */
            int[] len = new int[m + 1];     /* len[m+1] */
            opti[] opt = new opti[m + 1];    /* opt[m+1] */
            int[] convc = new int[m];       /* conv[m]: pre-computed convexities */
            double[] areac = new double[m + 1];  /* cumarea[m+1]: cache for fast area computation */

            int om;
            int i, j;
            bool r;
            opti o = new opti();
            dPoint p0;
            int i1;
            double area;
            double alpha;
            double[] s;
            double[] t;

            /* pre-calculate convexity: +1 = right turn, -1 = left turn, 0 = corner */
            for (i = 0; i < m; i++)
            {
                if (pp.Curves.tag[i] == POTRACE_CURVETO)
                {
                    convc[i] = sign(dpara(pp.Curves.vertex[mod(i - 1, m)], pp.Curves.vertex[i], pp.Curves.vertex[mod(i + 1, m)]));
                }
                else
                {
                    convc[i] = 0;
                }
            }

            /* pre-calculate areas */
            area = 0.0;
            areac[0] = 0.0;
            p0 = pp.Curves.vertex[0];
            for (i = 0; i < m; i++)
            {
                i1 = mod(i + 1, m);
                if (pp.Curves.tag[i1] == POTRACE_CURVETO)
                {
                    alpha = pp.Curves.alpha[i1];
                    area += 0.3 * alpha * (4 - alpha) * dpara(pp.Curves.ControlPoints[i, 2], pp.Curves.vertex[i1], pp.Curves.ControlPoints[i1, 2]) / 2;
                    area += dpara(p0, pp.Curves.ControlPoints[i, 2], pp.Curves.ControlPoints[i1, 2]) / 2;
                }
                areac[i + 1] = area;
            }

            pt[0] = -1;
            pen[0] = 0;
            len[0] = 0;

            /* Fixme: we always start from a fixed point -- should find the best
               curve cyclically ### */

            for (j = 1; j <= m; j++)
            {
                /* calculate best path from 0 to j */
                pt[j] = j - 1;
                pen[j] = pen[j - 1];
                len[j] = len[j - 1] + 1;

                for (i = j - 2; i >= 0; i--)
                {
                    r = opti_penalty(pp, i, mod(j, m), ref o, opttolerance, convc, areac);
                    if (r)
                    {
                        break;
                    }
                    if (len[j] > len[i] + 1 || (len[j] == len[i] + 1 && pen[j] > pen[i] + o.pen))
                    {
                        pt[j] = i;
                        pen[j] = pen[i] + o.pen;
                        len[j] = len[i] + 1;
                        opt[j] = o;
                    }
                }
            }
            om = len[m];
            pp.OptimizedCurves = new privcurve(om);

            s = new double[om];
            t = new double[om];

            j = m;
            for (i = om - 1; i >= 0; i--)
            {
                if (pt[j] == j - 1)
                {
                    pp.OptimizedCurves.tag[i] = pp.Curves.tag[mod(j, m)];
                    pp.OptimizedCurves.ControlPoints[i, 0] = pp.Curves.ControlPoints[mod(j, m), 0];
                    pp.OptimizedCurves.ControlPoints[i, 1] = pp.Curves.ControlPoints[mod(j, m), 1];
                    pp.OptimizedCurves.ControlPoints[i, 2] = pp.Curves.ControlPoints[mod(j, m), 2];
                    pp.OptimizedCurves.vertex[i] = pp.Curves.vertex[mod(j, m)];
                    pp.OptimizedCurves.alpha[i] = pp.Curves.alpha[mod(j, m)];
                    pp.OptimizedCurves.alpha0[i] = pp.Curves.alpha0[mod(j, m)];
                    pp.OptimizedCurves.beta[i] = pp.Curves.beta[mod(j, m)];
                    s[i] = t[i] = 1.0;
                }
                else
                {
                    pp.OptimizedCurves.tag[i] = POTRACE_CURVETO;
                    pp.OptimizedCurves.ControlPoints[i, 0] = opt[j].c[0];
                    pp.OptimizedCurves.ControlPoints[i, 1] = opt[j].c[1];
                    pp.OptimizedCurves.ControlPoints[i, 2] = pp.Curves.ControlPoints[mod(j, m), 2];
                    pp.OptimizedCurves.vertex[i] = interval(opt[j].s, pp.Curves.ControlPoints[mod(j, m), 2], pp.Curves.vertex[mod(j, m)]);
                    pp.OptimizedCurves.alpha[i] = opt[j].alpha;
                    pp.OptimizedCurves.alpha0[i] = opt[j].alpha;
                    s[i] = opt[j].s;
                    t[i] = opt[j].t;
                }
                j = pt[j];
            }

            /* calculate beta parameters */
            for (i = 0; i < om; i++)
            {
                i1 = mod(i + 1, om);
                pp.OptimizedCurves.beta[i] = s[i] / (s[i] + t[i1]);
            }
        }