예제 #1
0
        /* ---------------------------------------------------------------------- */
        /* Stage 5: Curve optimization (Sec. 2.4) */

        /* 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 int opti_penalty(Path path, int i, int j, Opti res, double opttolerance,
                                int[] convc, double[] areac)
        {
            int       m     = path.curve.n;
            privcurve curve = path.curve;

            dPoint[] vertex = curve.vertex;
            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,
                     s, t;

            /* check convexity, corner-freeness, and maximum bend < 179 degrees */
            if (i == j)
            {             /* sanity - a full loop can never be an opticurve */
                return(1);
            }

            k    = i;
            i1   = mod(i + 1, m);
            k1   = mod(k + 1, m);
            conv = convc[k1];
            if (conv == 0)
            {
                return(1);
            }
            d = ddist(vertex[i], vertex[i1]);
            for (k = k1; k != j; k = k1)
            {
                k1 = mod(k + 1, m);
                k2 = mod(k + 2, m);
                if (convc[k1] != conv)
                {
                    return(1);
                }
                if (sign(cprod(vertex[i], vertex[i1], vertex[k1], vertex[k2])) !=
                    conv)
                {
                    return(1);
                }
                if (iprod1(vertex[i], vertex[i1], vertex[k1], vertex[k2]) <
                    d * ddist(vertex[k1], vertex[k2]) * -0.999847695156)
                {
                    return(1);
                }
            }
            /* the curve we're working in: */
            p0 = curve.c[mod(i, m) * 3 + 2].copy();
            p1 = vertex[mod(i + 1, m)].copy();
            p2 = vertex[mod(j, m)].copy();
            p3 = curve.c[mod(j, m) * 3 + 2].copy();
            /* determine its area */
            area  = areac[j] - areac[i];
            area -= dpara(vertex[0], curve.c[i * 3 + 2], curve.c[j * 3 + 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 = A1 + A3 - A2;

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

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

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

            R     = area / A;                   /* relative area */
            alpha = 2 - Math.Sqrt(4 - R / 0.3); /* overall alpha for p0-o-p3 curve */

            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].copy();
            p2 = res.c[1].copy();             /* 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, vertex[k], vertex[k1]);
                if (t < -0.5)
                {
                    return(1);
                }
                pt = bezier(t, p0, p1, p2, p3);
                d  = ddist(vertex[k], vertex[k1]);
                if (d == 0.0)
                {
                    /* this should never happen */
                    return(1);
                }
                d1 = dpara(vertex[k], vertex[k1], pt) / d;
                if (Math.Abs(d1) > opttolerance)
                {
                    return(1);
                }
                if (iprod(vertex[k], vertex[k1], pt) < 0 ||
                    iprod(vertex[k1], vertex[k], pt) < 0)
                {
                    return(1);
                }
                res.pen += d1 * d1;
            }
            /* check corners */
            for (k = i; k != j; k = k1)
            {
                k1 = mod(k + 1, m);
                t  = tangent(p0, p1, p2, p3, curve.c[k * 3 + 2], curve.c[k1 * 3 + 2]);
                if (t < -0.5)
                {
                    return(1);
                }
                pt = bezier(t, p0, p1, p2, p3);
                d  = ddist(curve.c[k * 3 + 2], curve.c[k1 * 3 + 2]);
                if (d == 0.0)
                {
                    /* this should never happen */
                    return(1);
                }
                d1  = dpara(curve.c[k * 3 + 2], curve.c[k1 * 3 + 2], pt) / d;
                d2  = dpara(curve.c[k * 3 + 2], curve.c[k1 * 3 + 2], vertex[k1]) / d;
                d2 *= 0.75 * curve.alpha[k1];
                if (d2 < 0)
                {
                    d1 = -d1;
                    d2 = -d2;
                }
                if (d1 < d2 - opttolerance)
                {
                    return(1);
                }
                if (d1 < d2)
                {
                    res.pen += (d1 - d2) * (d1 - d2);
                }
            }

            return(0);
        }
예제 #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 path, double opttolerance)
        {
            privcurve curve = path.curve;
            int       m     = curve.n;

            dPoint[]  vert = curve.vertex;
            int[]     pt = new int[m + 1];
            double[]  pen = new double[m + 1];
            int[]     len = new int[m + 1];
            Opti[]    opt = new Opti[m + 1];
            Opti      o = new Opti();
            int       om, i, j, r;
            dPoint    p0;
            int       i1;
            double    area, alpha;
            privcurve ocurve;

            int[]    convc = new int[m];           /* conv[m]: pre-computed convexities */
            double[] areac = new double[m + 1];
            /* pre-calculate convexity: +1 = right turn, -1 = left turn, 0 = corner */
            for (i = 0; i < m; i++)
            {
                if (curve.tag[i] == POTRACE_CURVETO)
                {
                    convc[i] = sign(dpara(vert[mod(i - 1, m)], vert[i], vert[mod(i + 1, m)]));
                }
                else
                {
                    convc[i] = 0;
                }
            }
            /* pre-calculate areas */
            area     = 0.0;
            areac[0] = 0.0;
            p0       = curve.vertex[0];
            for (i = 0; i < m; i++)
            {
                i1 = mod(i + 1, m);
                if (curve.tag[i1] == POTRACE_CURVETO)
                {
                    alpha = curve.alpha[i1];
                    area += 0.3 * alpha * (4 - alpha) *
                            dpara(curve.c[i * 3 + 2], vert[i1], curve.c[i1 * 3 + 2]) / 2;
                    area += dpara(p0, curve.c[i * 3 + 2], curve.c[i1 * 3 + 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(path, i, mod(j, m), o, opttolerance, convc,
                                     areac);
                    if (r == 1)
                    {
                        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;
                        o      = new Opti();
                    }
                }
            }
            om     = len[m];
            ocurve = new privcurve(om);
            double[] s = new double[om];
            double[] t = new double[om];

            j = m;
            for (i = om - 1; i >= 0; i--)
            {
                if (pt[j] == j - 1)
                {
                    ocurve.tag[i]       = curve.tag[mod(j, m)];
                    ocurve.c[i * 3 + 0] = curve.c[mod(j, m) * 3 + 0];
                    ocurve.c[i * 3 + 1] = curve.c[mod(j, m) * 3 + 1];
                    ocurve.c[i * 3 + 2] = curve.c[mod(j, m) * 3 + 2];
                    ocurve.vertex[i]    = curve.vertex[mod(j, m)];
                    ocurve.alpha[i]     = curve.alpha[mod(j, m)];
                    ocurve.alpha0[i]    = curve.alpha0[mod(j, m)];
                    ocurve.beta[i]      = curve.beta[mod(j, m)];
                    s[i] = t[i] = 1.0;
                }
                else
                {
                    ocurve.tag[i]       = POTRACE_CURVETO;
                    ocurve.c[i * 3 + 0] = opt[j].c[0];
                    ocurve.c[i * 3 + 1] = opt[j].c[1];
                    ocurve.c[i * 3 + 2] = curve.c[mod(j, m) * 3 + 2];
                    ocurve.vertex[i]    = interval(opt[j].s, curve.c[mod(j, m) * 3 + 2],
                                                   vert[mod(j, m)]);
                    ocurve.alpha[i]  = opt[j].alpha;
                    ocurve.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);
                ocurve.beta[i] = s[i] / (s[i] + t[i1]);
            }
            ocurve.alphacurve = 1;
            path.curve        = ocurve;
        }