Beispiel #1
0
void bicubicbezier2D_bbox(const Point *p0,const Point *p1,
                          const Point *p2,const Point *p3,
                          const PolyBBExtras *extra,
                          Rectangle *rect)
{
    double x[4],y[4];
    Point vl,vt,p,tt;
    double *xy;
    int i,extr;
    double u[2];

    rect->setLeft(p0->x());
    rect->setRight(p0->x());
    rect->setTop(p0->y());
    rect->setBottom(p0->y());

    rectangle_add_point(rect,p3);

    point_copy_add_scaled(&vl,p0,p1,-1);
    point_normalize(&vl);

    add_arrow_rectangle(rect,p0,&vl,extra->startLong,
            qMax(extra->startTrans, extra->middleTrans));

    point_copy_add_scaled(&vl,p3,p2,-1);
    point_normalize(&vl);

    add_arrow_rectangle(rect,p3,&vl,extra->endLong,
            qMax(extra->endTrans, extra->middleTrans));

    x[0] = p0->x(); x[1] = p1->x(); x[2] = p2->x(); x[3] = p3->x();
    y[0] = p0->y(); y[1] = p1->y(); y[2] = p2->y(); y[3] = p3->y();

    for (xy = x; xy ; xy=(xy==x?y:NULL) ) {
        extr = bicubicbezier_extrema(xy,u);
        for (i=0;i<extr;i++) {
            if ((u[i]<0) || (u[i]>1)) continue;
            p.setX(bezier_eval(x,u[i]));
            vl.setX(bezier_eval_tangent(x,u[i]));
            p.setY(bezier_eval(y,u[i]));
            vl.setY(bezier_eval_tangent(y,u[i]));
            point_normalize(&vl);
            point_get_perp(&vt,&vl);

            point_copy_add_scaled(&tt,&p,&vt,extra->middleTrans);
            rectangle_add_point(rect,&tt);
            point_copy_add_scaled(&tt,&p,&vt,-extra->middleTrans);
            rectangle_add_point(rect,&tt);
        }
    }
}
Beispiel #2
0
/** Calculate the boundingbox for a 2D bezier curve segment.
 * @param p0 start point
 * @param p1 1st control point
 * @param p2 2nd control point
 * @param p3 end point
 * @param extra information about extra space from linewidth and arrow to add to the bounding box
 * @param rect The rectangle that the segment fits inside.
 */
void
bicubicbezier2D_bbox(const Point *p0,const Point *p1,
                     const Point *p2,const Point *p3,
                     const PolyBBExtras *extra,
                     Rectangle *rect)
{
  real x[4],y[4];
  Point vl,vt,p,tt;
  real *xy;
  int i,extr;
  real u[2];

  rect->left = rect->right = p0->x;
  rect->top = rect->bottom = p0->y;

  rectangle_add_point(rect,p3);
  /* start point */  
  point_copy_add_scaled(&vl,p0,p1,-1);
  point_normalize(&vl); 
  add_arrow_rectangle(rect,p0,&vl,extra->start_long,MAX(extra->start_trans,
                                                         extra->middle_trans));

  /* end point */
  point_copy_add_scaled(&vl,p3,p2,-1);
  point_normalize(&vl); 
  add_arrow_rectangle(rect,p3,&vl,extra->end_long,MAX(extra->end_trans,
                                                      extra->middle_trans));

  /* middle part */  
  x[0] = p0->x; x[1] = p1->x; x[2] = p2->x; x[3] = p3->x;
  y[0] = p0->y; y[1] = p1->y; y[2] = p2->y; y[3] = p3->y;

  for (xy = x; xy ; xy=(xy==x?y:NULL) ) { /* sorry */
    extr = bicubicbezier_extrema(xy,u);
    for (i=0;i<extr;i++) {
      if ((u[i]<0) || (u[i]>1)) continue;
      p.x = bezier_eval(x,u[i]);
      vl.x = bezier_eval_tangent(x,u[i]);
      p.y = bezier_eval(y,u[i]);
      vl.y = bezier_eval_tangent(y,u[i]);
      point_normalize(&vl);
      point_get_perp(&vt,&vl);

      point_copy_add_scaled(&tt,&p,&vt,extra->middle_trans);
      rectangle_add_point(rect,&tt);
      point_copy_add_scaled(&tt,&p,&vt,-extra->middle_trans);
      rectangle_add_point(rect,&tt);
    }
  }
}
Beispiel #3
0
/** Calculate the bounding box for a simple line.
 * @param p1 One end of the line.
 * @param p2 The other end of the line.
 * @param extra Extra information 
 * @param rect The box that the line and extra stuff fits inside.
 */
void
line_bbox(const Point *p1, const Point *p2,
          const LineBBExtras *extra,
          Rectangle *rect)
{
  Point vl;
  
  rect->left = rect->right = p1->x;
  rect->top = rect->bottom = p1->y;

  rectangle_add_point(rect,p2); /* as a safety, so we don't need to care if it above or below p1 */
  
  point_copy_add_scaled(&vl,p1,p2,-1);
  point_normalize(&vl);
  add_arrow_rectangle(rect,p1,&vl,extra->start_long,extra->start_trans);
  point_scale(&vl,-1);
  add_arrow_rectangle(rect,p2,&vl,extra->end_long,extra->end_trans);
}
Beispiel #4
0
void line_bbox(const Point *p1, const Point *p2,
        const LineBBExtras *extra,
        Rectangle *rect)
{
    Point vl;

    rect->setLeft(p1->x());
    rect->setRight(p1->x());
    rect->setTop(p1->y());
    rect->setBottom(p1->y());

    rectangle_add_point(rect,p2);

    point_copy_add_scaled(&vl,p1,p2,-1);
    point_normalize(&vl);
    add_arrow_rectangle(rect,p1,&vl,extra->startLong,extra->startTrans);
    point_scale(&vl,-1);
    add_arrow_rectangle(rect,p2,&vl,extra->endLong,extra->endTrans);
}
Beispiel #5
0
void add_arrow_rectangle(Rectangle *rect,
                                const Point *vertex,
                                const Point *normed_dir,
                                double extra_long,double extra_trans)
{
    Point vl,vt,pt;
    vl = *normed_dir;

    point_get_perp(&vt,&vl);
    point_copy_add_scaled(&pt,vertex,&vl,extra_long);
    point_add_scaled(&pt,&vt,extra_trans);
    rectangle_add_point(rect,&pt);
    point_add_scaled(&pt,&vt,-2.0 * extra_trans);
    rectangle_add_point(rect,&pt);
    point_add_scaled(&pt,&vl,-2.0 * extra_long);
    rectangle_add_point(rect,&pt);
    point_add_scaled(&pt,&vt,2.0 * extra_trans);
    rectangle_add_point(rect,&pt);
}
Beispiel #6
0
void polybezier_bbox(const BezPoint *pts, int numpoints,
                     const PolyBBExtras *extra, bool closed,
                     Rectangle *rect)
{
    Point vx,vp,vn,vsc;
    int i,prev,next;
    Rectangle rt;
    PolyBBExtras bextra,start_bextra,end_bextra;
    LineBBExtras lextra,start_lextra,end_lextra,full_lextra;
    bool start,end;

    rect->setLeft(pts[0].p1.x());
    rect->setRight(pts[0].p1.x());

    rect->setTop(pts[0].p1.y());
    rect->setBottom(pts[0].p1.y());

    if (!closed) {
        start_lextra.startLong = extra->startLong;
        start_lextra.startTrans = qMax(extra->startTrans,extra->middleTrans);
        start_lextra.endLong = 0;
        start_lextra.endTrans = extra->middleTrans;

        end_lextra.startLong = 0;
        end_lextra.startTrans = extra->middleTrans;
        end_lextra.endLong = extra->endLong;
        end_lextra.endTrans = qMax(extra->endTrans,extra->middleTrans);
    }

    full_lextra.startLong = extra->startLong;
    full_lextra.startTrans = qMax(extra->startTrans,extra->middleTrans);
    full_lextra.endLong = extra->endLong;
    full_lextra.endTrans = qMax(extra->endTrans,extra->middleTrans);

    if (!closed) {
        lextra.startLong = 0;
        lextra.startTrans = extra->middleTrans;
        lextra.endLong = 0;
        lextra.endTrans = extra->middleTrans;

        start_bextra.startLong = extra->startLong;
        start_bextra.startTrans = extra->startTrans;
        start_bextra.middleTrans = extra->middleTrans;
        start_bextra.endLong = 0;
        start_bextra.endTrans = extra->middleTrans;

        end_bextra.startLong = 0;
        end_bextra.startTrans = extra->middleTrans;
        end_bextra.middleTrans = extra->middleTrans;
        end_bextra.endLong = extra->endLong;
        end_bextra.endTrans = extra->endTrans;
    }

    bextra.startLong = 0;
    bextra.startTrans = extra->middleTrans;
    bextra.middleTrans = extra->middleTrans;
    bextra.endLong = 0;
    bextra.endTrans = extra->middleTrans;


    for (i=1;i<numpoints;i++) {
        next = (i+1) % numpoints;
        prev = (i-1) % numpoints;
        if (closed && (next == 0)) next=1;
        if (closed && (prev == 0)) prev=numpoints-1;

        if (pts[i].type == BezPoint::BEZ_MOVE_TO) {
            continue;
        }

        switch(pts[i].type) {
            case BezPoint::BEZ_MOVE_TO:
                break;
            case BezPoint::BEZ_LINE_TO:
                vx = pts[i].p1;
                switch(pts[prev].type) {
                    case BezPoint::BEZ_MOVE_TO:
                    case BezPoint::BEZ_LINE_TO:
                        vsc = pts[prev].p1;
                        vp = pts[prev].p1;
                        break;
                    case BezPoint::BEZ_CURVE_TO:
                        vsc = pts[prev].p3;
                        vp = pts[prev].p3;
                        break;
                }
                break;
            case BezPoint::BEZ_CURVE_TO:
                vx = pts[i].p3;
                vp = pts[i].p2;
                switch(pts[prev].type) {
                    case BezPoint::BEZ_MOVE_TO:
                    case BezPoint::BEZ_LINE_TO:
                        vsc = pts[prev].p1;
                        break;
                    case BezPoint::BEZ_CURVE_TO:
                        vsc = pts[prev].p3;
                        break;
                }

                break;
        }
        start = (pts[prev].type == BezPoint::BEZ_MOVE_TO);
        end = (pts[next].type == BezPoint::BEZ_MOVE_TO);
        vn = pts[next].p1;

        if (closed) {
            if (pts[i].type == BezPoint::BEZ_LINE_TO) {
                line_bbox(&vsc,&vx,&full_lextra,&rt);
            } else {
                bicubicbezier2D_bbox(&vsc,
                        &pts[i].p1,&pts[i].p2,&pts[i].p3,
                        &bextra,
                        &rt);
            }
        } else if (start) {
            if (pts[i].type == BezPoint::BEZ_LINE_TO) {
                if (end) {
                    line_bbox(&vsc,&vx,&full_lextra,&rt);
                } else {
                    line_bbox(&vsc,&vx,&start_lextra,&rt);
                }
            } else {
                if (end) {
                    bicubicbezier2D_bbox(&vsc,
                            &pts[i].p1,&pts[i].p2,&pts[i].p3,
                            extra,
                            &rt);
                } else {
                    bicubicbezier2D_bbox(&vsc,
                            &pts[i].p1,&pts[i].p2,&pts[i].p3,
                            &start_bextra,
                            &rt);
                }
            }
        } else if (end) {
            if (pts[i].type == BezPoint::BEZ_LINE_TO) {
                line_bbox(&vsc,&vx,&end_lextra,&rt);
            } else {
                bicubicbezier2D_bbox(&vsc,
                        &pts[i].p1,&pts[i].p2,&pts[i].p3,
                        &end_bextra,
                        &rt);
            }
        } else {
            if (pts[i].type == BezPoint::BEZ_LINE_TO) {
                line_bbox(&vsc,&vx,&lextra,&rt);
            } else {
                bicubicbezier2D_bbox(&vsc,
                        &pts[i].p1,&pts[i].p2,&pts[i].p3,
                        &bextra,
                        &rt);
            }
        }
        *rect = rect->united(rt);

        if ((!start) && (!end)) {
            Point vpx,vxn;
            double co,alpha;

            point_copy_add_scaled(&vpx,&vx,&vp,-1);
            point_normalize(&vpx);
            point_copy_add_scaled(&vxn,&vn,&vx,-1);
            point_normalize(&vxn);

            co = point_dot(&vpx,&vxn);
            alpha = acos(-co);
            if ((co > -0.9816) && (finite(alpha))) {
                double overshoot = extra->middleTrans / sin(alpha/2.0);
                Point vovs,pto;

                point_copy_add_scaled(&vovs,&vpx,&vxn,-1);
                point_normalize(&vovs);
                point_copy_add_scaled(&pto,&vx,&vovs,overshoot);

                rectangle_add_point(rect,&pto);
            } else {
                Point vpxt,vxnt,tmp;

                point_get_perp(&vpxt,&vpx);
                point_get_perp(&vxnt,&vxn);

                point_copy_add_scaled(&tmp,&vx,&vpxt,1);
                rectangle_add_point(rect,&tmp);
                point_copy_add_scaled(&tmp,&vx,&vpxt,-1);
                rectangle_add_point(rect,&tmp);
                point_copy_add_scaled(&tmp,&vx,&vxnt,1);
                rectangle_add_point(rect,&tmp);
                point_copy_add_scaled(&tmp,&vx,&vxnt,-1);
                rectangle_add_point(rect,&tmp);
            }
        }
    }
}
Beispiel #7
0
/** Calculate a bounding box for a set of bezier points.
 * @param pts The bezier points
 * @param numpoints The number of elements in `pts'
 * @param extra Extra spacing information.
 * @param closed True if the bezier points form a closed line.
 * @param rect Return value: The enclosing rectangle will be stored here.
 * @bug This function is way too long (214 lines) and should be split.
 */
void 
polybezier_bbox(const BezPoint *pts, int numpoints,
                const PolyBBExtras *extra, gboolean closed,            
                Rectangle *rect)
{
  Point vx,vn,vsc,vp;
  int i,prev,next;
  Rectangle rt;
  PolyBBExtras bextra,start_bextra,end_bextra;
  LineBBExtras lextra,start_lextra,end_lextra,full_lextra;
  gboolean start,end;

  vp.x=0;
  vp.y=0;

  g_assert(pts[0].type == BEZ_MOVE_TO);

  rect->left = rect->right = pts[0].p1.x;
  rect->top = rect->bottom = pts[0].p1.y;

  /* First, we build derived BBExtras structures, so we have something to feed 
     the primitives. */ 
  if (!closed) {
    start_lextra.start_long = extra->start_long;
    start_lextra.start_trans = MAX(extra->start_trans,extra->middle_trans);
    start_lextra.end_long = 0;
    start_lextra.end_trans = extra->middle_trans;

    end_lextra.start_long = 0;
    end_lextra.start_trans = extra->middle_trans;
    end_lextra.end_long = extra->end_long;
    end_lextra.end_trans = MAX(extra->end_trans,extra->middle_trans);
  }

  full_lextra.start_long = extra->start_long;
  full_lextra.start_trans = MAX(extra->start_trans,extra->middle_trans);
  full_lextra.end_long = extra->end_long;
  full_lextra.end_trans = MAX(extra->end_trans,extra->middle_trans);

  if (!closed) {
    lextra.start_long = 0;
    lextra.start_trans = extra->middle_trans;
    lextra.end_long = 0;
    lextra.end_trans = extra->middle_trans;

    start_bextra.start_long = extra->start_long;
    start_bextra.start_trans = extra->start_trans;
    start_bextra.middle_trans = extra->middle_trans;
    start_bextra.end_long = 0;
    start_bextra.end_trans = extra->middle_trans;

    end_bextra.start_long = 0;
    end_bextra.start_trans = extra->middle_trans;
    end_bextra.middle_trans = extra->middle_trans;
    end_bextra.end_long = extra->end_long;
    end_bextra.end_trans = extra->end_trans;
  }

  bextra.start_long = 0;
  bextra.start_trans = extra->middle_trans;
  bextra.middle_trans = extra->middle_trans;
  bextra.end_long = 0;
  bextra.end_trans = extra->middle_trans;        


  for (i=1;i<numpoints;i++) {
    next = (i+1) % numpoints;
    prev = (i-1) % numpoints;
    if (closed && (next == 0)) next=1;
    if (closed && (prev == 0)) prev=numpoints-1;

    /* We have now: 
       i = index of current vertex. 
       prev,next: index of previous/next vertices (of the control polygon) 

       We want:
        vp, vx, vn: the previous, current and next vertices;
        start, end: TRUE if we're at an end of poly (then, vp and/or vn are not
        valid, respectively).

       Some values *will* be recomputed a few times across iterations (but stored in 
       different boxes). Either gprof says it's a real problem, or gcc finally gets 
       a clue.
    */

    if (pts[i].type == BEZ_MOVE_TO) {
      continue;
    }

    switch(pts[i].type) {
    case BEZ_MOVE_TO:
      g_assert_not_reached();
      break;
    case BEZ_LINE_TO:
      point_copy(&vx,&pts[i].p1);
      switch(pts[prev].type) {
      case BEZ_MOVE_TO:
      case BEZ_LINE_TO:
        point_copy(&vsc,&pts[prev].p1);
        point_copy(&vp,&pts[prev].p1);
        break;
      case BEZ_CURVE_TO:
        point_copy(&vsc,&pts[prev].p3);
        point_copy(&vp,&pts[prev].p3);
        break;
      }
      break;
    case BEZ_CURVE_TO:
      point_copy(&vx,&pts[i].p3);
      point_copy(&vp,&pts[i].p2);
      switch(pts[prev].type) {
      case BEZ_MOVE_TO:
      case BEZ_LINE_TO:
        point_copy(&vsc,&pts[prev].p1);
        break;
      case BEZ_CURVE_TO:
        point_copy(&vsc,&pts[prev].p3);
        break;
      } /* vsc is the start of the curve. */
      
      break;
    }
    start = (pts[prev].type == BEZ_MOVE_TO);
    end = (pts[next].type == BEZ_MOVE_TO);
    point_copy(&vn,&pts[next].p1); /* whichever type pts[next] is. */

    /* Now, we know about a few vertices around the one we're dealing with.
       Depending on the shape of the (previous,current) segment, and whether 
       it's a middle or end segment, we'll be doing different stuff. */ 
    if (closed) {
      if (pts[i].type == BEZ_LINE_TO) {
        line_bbox(&vsc,&vx,&full_lextra,&rt);
      } else {
        bicubicbezier2D_bbox(&vsc,
                             &pts[i].p1,&pts[i].p2,&pts[i].p3,
                             &bextra,
                             &rt);
      }    
    } else if (start) {
      if (pts[i].type == BEZ_LINE_TO) {
        if (end) {
          line_bbox(&vsc,&vx,&full_lextra,&rt);
        } else {
          line_bbox(&vsc,&vx,&start_lextra,&rt);
        }
      } else { /* BEZ_MOVE_TO */ 
        if (end) {
          bicubicbezier2D_bbox(&vsc,
                               &pts[i].p1,&pts[i].p2,&pts[i].p3,
                               extra,
                               &rt);
        } else {
          bicubicbezier2D_bbox(&vsc,
                               &pts[i].p1,&pts[i].p2,&pts[i].p3,
                               &start_bextra,
                               &rt);
        }
      }
    } else if (end) { /* end but not start. Not closed anyway. */
      if (pts[i].type == BEZ_LINE_TO) {
        line_bbox(&vsc,&vx,&end_lextra,&rt);
      } else {
        bicubicbezier2D_bbox(&vsc,
                             &pts[i].p1,&pts[i].p2,&pts[i].p3,
                             &end_bextra,
                             &rt);
      } 
    } else { /* normal case : middle segment (not closed shape). */
      if (pts[i].type == BEZ_LINE_TO) {
        line_bbox(&vsc,&vx,&lextra,&rt);
      } else {
        bicubicbezier2D_bbox(&vsc,
                             &pts[i].p1,&pts[i].p2,&pts[i].p3,
                             &bextra,
                             &rt);
      } 
    }   
    rectangle_union(rect,&rt);

    /* The following code enlarges a little the bounding box (if necessary) to 
       account with the "pointy corners" X (and PS) add when LINEJOIN_MITER mode is 
       in force. */

    if ((!start) && (!end)) { /* We have a non-extremity vertex. */
      Point vpx,vxn;
      real co,alpha;

      point_copy_add_scaled(&vpx,&vx,&vp,-1);
      point_normalize(&vpx);
      point_copy_add_scaled(&vxn,&vn,&vx,-1);
      point_normalize(&vxn);

      co = point_dot(&vpx,&vxn);      
      alpha = acos(-co); 
      if (co > -0.9816) { /* 0.9816 = cos(11deg) */
        /* we have a pointy join. */
        real overshoot;
        Point vovs,pto;

	if (finite(alpha))
	  overshoot = extra->middle_trans / sin(alpha/2.0);
	else /* prependicular? */
	  overshoot = extra->middle_trans;

        point_copy_add_scaled(&vovs,&vpx,&vxn,-1);
        point_normalize(&vovs);
        point_copy_add_scaled(&pto,&vx,&vovs,overshoot);
        
        rectangle_add_point(rect,&pto);
      } else {
        /* we don't have a pointy join. */
        Point vpxt,vxnt,tmp;

        point_get_perp(&vpxt,&vpx);
        point_get_perp(&vxnt,&vxn);
        
        point_copy_add_scaled(&tmp,&vx,&vpxt,1);
        rectangle_add_point(rect,&tmp);
        point_copy_add_scaled(&tmp,&vx,&vpxt,-1);
        rectangle_add_point(rect,&tmp);
        point_copy_add_scaled(&tmp,&vx,&vxnt,1);
        rectangle_add_point(rect,&tmp);
        point_copy_add_scaled(&tmp,&vx,&vxnt,-1);
        rectangle_add_point(rect,&tmp);
      }
    }
  }
}