Beispiel #1
0
Handle *
beziershape_closest_handle(BezierShape *bezier, Point *point)
{
  int i, hn;
  real dist = G_MAXDOUBLE;
  Handle *closest = NULL;
  
  for (i = 1, hn = 0; i < bezier->numpoints; i++, hn++) {
    real new_dist;

    new_dist = distance_point_point( point, &bezier->points[i].p1);
    if (new_dist < dist) {
      dist = new_dist;
      closest = bezier->object.handles[hn];
    }
    hn++;

    new_dist = distance_point_point( point, &bezier->points[i].p2);
    if (new_dist < dist) {
      dist = new_dist;
      closest = bezier->object.handles[hn];
    }

    hn++;
    new_dist = distance_point_point( point, &bezier->points[i].p3);
    if (new_dist < dist) {
      dist = new_dist;
      closest = bezier->object.handles[hn];
    }
  }
  return closest;
}
Beispiel #2
0
static real
arc_distance_from(Arc *arc, Point *point)
{
  Point *endpoints;
  Point from_center;
  real angle;
  real d, d2;
  
  endpoints = &arc->connection.endpoints[0];

  from_center = *point;
  point_sub(&from_center, &arc->center);

  angle = -atan2(from_center.y, from_center.x)*180.0/M_PI;
  if (angle<0)
    angle+=360.0;

  if (in_angle(angle, arc->angle1, arc->angle2)) {
    d = fabs(sqrt(point_dot(&from_center, &from_center)) - arc->radius);
    d -= arc->line_width/2.0;
    if (d<0)
      d = 0.0;
    return d;
  } else {
    d = distance_point_point(&endpoints[0], point);
    d2 = distance_point_point(&endpoints[1], point);

    return MIN(d,d2);
  }
}
Beispiel #3
0
/*!
 * \brief Calculate BezCornerType just from the _BezPoint
 *
 * The bezier line/shape is fully described just with the array of BezPoint.
 * For convenience and editing there also is an BezierConn::corner_types.
 * This function adjust the corner types in the given array to match
 * the bezier points.
 */
static void
bezier_calc_corner_types (BezierCommon *bezier)
{
  int i;
  int num = bezier->num_points;
  const real tolerance = 0.00001; /* EPSILON */

  g_return_if_fail (bezier->num_points > 1);

  bezier->corner_types = g_realloc (bezier->corner_types, bezier->num_points * sizeof(BezCornerType));
  bezier->corner_types[0] = BEZ_CORNER_CUSP;
  bezier->corner_types[num-1] = BEZ_CORNER_CUSP;
  
  for (i = 0; i < num - 2; ++i) {
    const Point *start = &bezier->points[i].p2;
    const Point *major = &bezier->points[i].p3;
    const Point *end   = &bezier->points[i+1].p2;

    if (bezier->points[i].type != BEZ_LINE_TO || bezier->points[i+1].type != BEZ_CURVE_TO)
      bezier->corner_types[i+1] = BEZ_CORNER_CUSP;
    else if (distance_point_point (start, end) < tolerance) /* last resort */
      bezier->corner_types[i+1] = BEZ_CORNER_CUSP;
    else if (distance_line_point (start, end, 0, major) > tolerance)
      bezier->corner_types[i+1] = BEZ_CORNER_CUSP;
    else if (fabs (   distance_point_point (start, major) 
		   -  distance_point_point (end, major) > tolerance))
      bezier->corner_types[i+1] = BEZ_CORNER_SMOOTH;
    else
      bezier->corner_types[i+1] = BEZ_CORNER_SYMMETRIC;
  }
}
Beispiel #4
0
/*!
 * \brief Move one of the objects handles
 * \memberof Outline
 */
static ObjectChange*
outline_move_handle (Outline *outline,
                     Handle *handle,
		     Point *to, ConnectionPoint *cp,
		     HandleMoveReason reason, ModifierKeys modifiers)
{
  DiaObject *obj = &outline->object;
  Point start = obj->position;
  Point end = outline->ink_rect[2];
  real dist, old_dist = distance_point_point (&start, &end);
  Point norm = end;
  point_sub (&norm, &start);
  point_normalize (&norm);
  /* we use this to modify angle and scale */
  switch (handle->id) {
  case HANDLE_RESIZE_NW :
    start = *to;
    break;
  case HANDLE_RESIZE_SE :
    end = *to;
    break;
  default :
    g_warning ("Outline unknown handle");
  }
  dist = distance_point_point (&start, &end);
  /* disallow everything below a certain level, otherwise the font-size could become invalid */
  if (dist > 0.1) {
    obj->position = start;

    outline->font_height *= (dist / old_dist);

    outline_update_data (outline);
  }
  return NULL;
}
Beispiel #5
0
static int 
cpl_get_pointbefore(ConnPointLine *cpl, Point *clickedpoint) 
{
  int i, pos = -1;
  GSList *elem;
  ConnectionPoint *cp;
  real dist = 65536.0;
  real tmpdist;

  if (!clickedpoint) return 0;

  for (i=0,elem=cpl->connections;
       i<cpl->num_connections; 
       i++,elem=g_slist_next(elem)) {
    cp = (ConnectionPoint *)(elem->data);

    tmpdist = distance_point_point(&cp->pos,clickedpoint);
    if (tmpdist < dist) {
      dist = tmpdist;
      pos = i;
    }
  }
  tmpdist = distance_point_point(&cpl->end,clickedpoint);
  if (tmpdist < dist) {
    /*dist = tmpdist; */
    pos = -1;
  }
  return pos;
}
Beispiel #6
0
/*!
 * \brief Find the next sub path to connect
 *
 * Ignores the crossing point of the Split, but just looks at the
 * start and end of the given sub path.
 */
static gboolean
_find_split (GArray *splits, Point *pt, gboolean outside, Split **next)
{
  int i;

  for (i = 0; i < splits->len; ++i) {
    Split *sp = &g_array_index (splits, Split, i);
    /* one of two splits - prefer the one matching in start point */
    BezierSegment *bs = &g_array_index (sp->path, BezierSegment, 0);
    if (   !sp->used
	&& (sp->outside == outside)
	&& distance_point_point (&bs->p0, pt) < 1.4142 * EPSILON) {
      *next = sp;
      sp->used = TRUE;
      return TRUE;
    }
  }
  /* but also deliver segments ending in pt */
  for (i = 0; i < splits->len; ++i) {
    Split *sp = &g_array_index (splits, Split, i);
    BezierSegment *bs = &g_array_index (sp->path, BezierSegment, sp->path->len - 1);
    if (   !sp->used
	&& (sp->outside == outside)
        && distance_point_point (&bs->p3, pt) < 1.4142 * EPSILON) {
      *next = sp;
      sp->used = TRUE;
      return TRUE;
    }
  }
  return FALSE;
}
Beispiel #7
0
/*!
 * \brief Return the handle closest to a given point.
 * @param bezier A bezier object
 * @param point A point to find distances from
 * @return The handle on `bezier' closest to `point'.
 *
 * \memberof _BezierConn
 */
Handle *
bezierconn_closest_handle (BezierConn *bezier,
			   Point *point)
{
  int i, hn;
  real dist;
  Handle *closest;
  
  closest = bezier->object.handles[0];
  dist = distance_point_point( point, &closest->pos);
  for (i = 1, hn = 1; i < bezier->bezier.num_points; i++, hn++) {
    real new_dist;

    new_dist = distance_point_point(point, &bezier->bezier.points[i].p1);
    if (new_dist < dist) {
      dist = new_dist;
      closest = bezier->object.handles[hn];
    }
    hn++;

    new_dist = distance_point_point(point, &bezier->bezier.points[i].p2);
    if (new_dist < dist) {
      dist = new_dist;
      closest = bezier->object.handles[hn];
    }
    hn++;

    new_dist = distance_point_point(point, &bezier->bezier.points[i].p3);
    if (new_dist < dist) {
      dist = new_dist;
      closest = bezier->object.handles[hn];
    }
  }
  return closest;
}
Beispiel #8
0
static GArray *
_path_to_segments (const GArray *path)
{
  GArray *segs = g_array_new (FALSE, FALSE, sizeof(BezierSegment));
  BezierSegment bs;
  int i;
  BezPoint *last_move = &g_array_index (path, BezPoint, 0);

  for (i = 1; i < path->len; ++i) {
    if (g_array_index (path, BezPoint, i).type == BEZ_MOVE_TO)
      last_move = &g_array_index (path, BezPoint, i);
    if (_segment_from_path (&bs, path, i))
      g_array_append_val (segs, bs);
  }
  /* if the path is not closed do an explicit line-to */
  if (distance_point_point (&last_move->p1, &bs.p3) < EPSILON) {
    /* if the error is small enough just modify the last point */
    BezierSegment *e = &g_array_index (segs, BezierSegment, segs->len - 1);
    if (_segment_is_lineto (e))
      e->p1 = e->p2 = e->p3 = last_move->p1;
    else
      e->p3 = last_move->p1;
  } else {
    bs.p0 = bs.p3;
    bs.p1 = bs.p2 = bs.p3 = last_move->p1;
    g_array_append_val (segs, bs);
  }

  return segs;
}
Beispiel #9
0
int 
three_point_circle (const Point *p1, const Point *p2, const Point *p3,
                    Point* center, real* radius)
{
  const real epsilon = 1e-4;
  real x1 = p1->x;
  real y1 = p1->y;
  real x2 = p2->x;
  real y2 = p2->y;
  real x3 = p3->x;
  real y3 = p3->y;
  real ma, mb;
  if (fabs(x2 - x1) < epsilon)
    return 0;
  if (fabs(x3 - x2) < epsilon)
    return 0;
  ma = (y2 - y1) / (x2 - x1);
  mb = (y3 - y2) / (x3 - x2);
  if (fabs (mb - ma) < epsilon)
    return 0;
  center->x = (ma*mb*(y1-y3)+mb*(x1+x2)-ma*(x2+x3))/(2*(mb-ma));
  if (fabs(ma)>epsilon)
    center->y = -1/ma*(center->x - (x1+x2)/2.0) + (y1+y2)/2.0;
  else if (fabs(mb)>epsilon)
    center->y = -1/mb*(center->x - (x2+x3)/2.0) + (y2+y3)/2.0;
  else
    return 0;
  *radius = distance_point_point(center, p1);
  return 1;
}
Beispiel #10
0
static void draw_dot(DiaRenderer *renderer,
		     Point *end, Point *vect, Color *col)
{
  DiaRendererClass *renderer_ops = DIA_RENDERER_GET_CLASS (renderer);
  Point vv,vp,vt,pt;
  real vlen;
  vv = *end;
  point_sub(&vv,vect);
  vlen = distance_point_point(vect,end);
  if (vlen < 1E-7) return;
  point_scale(&vv,1/vlen);

  vp.y = vv.x;
  vp.x = -vv.y;

  pt = *end;
    vt = vp;
  point_scale(&vt,ARROW_DOT_WOFFSET);
  point_add(&pt,&vt);
  vt = vv;
  point_scale(&vt,-ARROW_DOT_LOFFSET);
  point_add(&pt,&vt);
  
  renderer_ops->set_fillstyle(renderer,FILLSTYLE_SOLID);
  renderer_ops->fill_ellipse(renderer,&pt,
			 ARROW_DOT_RADIUS,ARROW_DOT_RADIUS,
			 col);
}
Beispiel #11
0
uint16_t
path_astar_heuristic_callback (uint8_t node)
{
    /* TODO: a better and faster heuristic can be found, considering that
     * movement is only allowed on the grid. */
    vect_t pos;
    path_pos (node, &pos);
    return distance_point_point (&pos, &path.endpoints[0]);
}
Beispiel #12
0
Handle *
polyconn_closest_handle(PolyConn *poly, Point *point)
{
  int i;
  real dist;
  Handle *closest;
  
  closest = poly->object.handles[0];
  dist = distance_point_point( point, &closest->pos);
  for (i=1;i<poly->numpoints;i++) {
    real new_dist;
    new_dist = distance_point_point( point, &poly->points[i]);
    if (new_dist < dist) {
      dist = new_dist;
      closest = poly->object.handles[i];
    }
  }
  return closest;
}
Beispiel #13
0
static Point
_append_segments (GArray  *path,
		  GArray  *segs)
{
  BezPoint bp;
  int      i;
  gboolean flip;
  BezPoint *ebp = &g_array_index (path, BezPoint, path->len - 1);
  const BezierSegment *sseg = &g_array_index (segs, BezierSegment, 0);
  const BezierSegment *eseg = &g_array_index (segs, BezierSegment, segs->len - 1);

  /* always try to join with what we have */
  if (distance_point_point (&sseg->p0,
      ebp->type == BEZ_CURVE_TO ? &ebp->p3 : &ebp->p1) < EPSILON) {
    /* matching in given direction */
    flip = FALSE;
  } else if (distance_point_point (&eseg->p3,
	     ebp->type == BEZ_CURVE_TO ? &ebp->p3 : &ebp->p1) < EPSILON) {
    /* change direction of segments */
    flip = TRUE;
  } else {
    /* neither matches so we can use any direction but should add a move-to */
    bp.type = BEZ_MOVE_TO;
    bp.p1 = sseg->p0;
    g_array_append_val (path, bp);
  }

  if (flip) {
    for (i = segs->len - 1; i >= 0; --i) { /* counting down - backwards append */
      _curve_from_segment (&bp, &g_array_index (segs, BezierSegment, i), flip);
      if (bp.type != BEZ_MOVE_TO) /* just ignore move-to here */
	g_array_append_val (path, bp);
    }
  } else {
    for (i = 0; i < segs->len; ++i) { /* preserve original direction */
      _curve_from_segment (&bp, &g_array_index (segs, BezierSegment, i), flip);
      if (bp.type != BEZ_MOVE_TO)
	g_array_append_val (path, bp);
    }
  }
  ebp = &g_array_index (path, BezPoint, path->len - 1);
  return ebp->type == BEZ_CURVE_TO ? ebp->p3 : ebp->p1;
}
Beispiel #14
0
static gboolean
point_projection_is_between (const Point *c,
                             const Point *a,
                             const Point *b)
{
    real len = distance_point_point (a, b);

    if (len > 0) {
        real r = ((a->y - c->y) * (a->y - b->y) - (a->x - c->x) * (b->x - a->x)) / (len * len);
        return (r >= 0 && r <= 1.0);
    }
    /* identity of three points ? */
    return (c->x == a->x && c->y == a->y);
}
Beispiel #15
0
static void
annotation_draw(Annotation *annotation, DiaRenderer *renderer)
{
  Point *endpoints;
  Point vect,rvect,v1,v2;
  Point pts[4];
  real vlen;
  DiaRendererClass *renderer_ops = DIA_RENDERER_GET_CLASS (renderer);

  assert(annotation != NULL);
  assert(renderer != NULL);

  endpoints = &annotation->connection.endpoints[0];
  
  renderer_ops->set_linewidth(renderer, ANNOTATION_LINE_WIDTH);
  renderer_ops->set_linestyle(renderer, LINESTYLE_SOLID);
  renderer_ops->set_linecaps(renderer, LINECAPS_BUTT);

  vect = annotation->connection.endpoints[1];
  point_sub(&vect,&annotation->connection.endpoints[0]);
  vlen = distance_point_point(&annotation->connection.endpoints[0],
			      &annotation->connection.endpoints[1]);
  if (vlen > 0.0) {
    /* draw the squiggle */
    point_scale(&vect,1/vlen);
    rvect.y = vect.x;
    rvect.x = -vect.y;
  
    pts[0] = annotation->connection.endpoints[0];
    pts[1] = annotation->connection.endpoints[0];
    v1 = vect;
    point_scale(&v1,.5*vlen);
    point_add(&pts[1],&v1);
    pts[2] = pts[1];
    /* pts[1] and pts[2] are currently both at the middle of (pts[0],pts[3]) */
    v1 = vect;
    point_scale(&v1,ANNOTATION_ZLEN);
    v2 = rvect;
    point_scale(&v2,ANNOTATION_ZLEN);
    point_sub(&v1,&v2);
    point_add(&pts[1],&v1);
    point_sub(&pts[2],&v1);
    pts[3] = annotation->connection.endpoints[1];
    renderer_ops->draw_polyline(renderer,
			     pts, sizeof(pts) / sizeof(pts[0]),
			     &color_black);
  }
  text_draw(annotation->text,renderer);
}
Beispiel #16
0
static ObjectChange*
radiocell_move_handle(RadioCell *radiocell, Handle *handle,
		      Point *to, ConnectionPoint *cp,
		      HandleMoveReason reason, ModifierKeys modifiers)
{
  real distance;
  gboolean larger;

  /* prevent flicker for "negative" resizing */
  if ((handle->id == HANDLE_CUSTOM1 && to->x < radiocell->center.x) ||
      (handle->id == HANDLE_CUSTOM4 && to->x > radiocell->center.x) ||
      ((handle->id == HANDLE_CUSTOM2 || handle->id == HANDLE_CUSTOM3) &&
       to->y < radiocell->center.y) ||
      ((handle->id == HANDLE_CUSTOM5 || handle->id == HANDLE_CUSTOM6) &&
       to->y > radiocell->center.y)) {
    return NULL;
  }

  /* prevent flicker for "diagonal" resizing */
  if (handle->id == HANDLE_CUSTOM1 || handle->id == HANDLE_CUSTOM4) {
    to->y = handle->pos.y;
  }
  else {
    to->x = handle->pos.x;
  }

  distance = distance_point_point(&handle->pos, to);
  larger = distance_point_point(&handle->pos, &radiocell->center) <
    distance_point_point(to, &radiocell->center);
  radiocell->radius += distance * (larger? 1: -1);
  if (radiocell->radius < 1.)
    radiocell->radius = 1.;
  radiocell_update_data(radiocell);

  return NULL;
}
Beispiel #17
0
static real
implements_distance_from(Implements *implements, Point *point)
{
  Point *endpoints;
  real dist1, dist2;
  
  endpoints = &implements->connection.endpoints[0];
  dist1 = distance_line_point( &endpoints[0], &endpoints[1],
			      IMPLEMENTS_WIDTH, point);
  dist2 = distance_point_point( &implements->circle_center, point)
    - implements->circle_diameter/2.0;
  if (dist2<0)
    dist2 = 0;
  
  return MIN(dist1, dist2);
}
Beispiel #18
0
/*! Not in the object interface but very important anyway. Used to recalculate the object data after a change  */
static void
measure_update_data (Measure *measure)
{
  Connection *conn = &measure->connection;
  DiaObject *obj = &measure->connection.object;
  real value;
  Point *ends = measure->connection.endpoints;
  LineBBExtras *extra = &conn->extra_spacing;
  Rectangle bbox;
  Arrow arrow = MEASURE_ARROW(measure);
  real ascent, width;
  
  g_return_if_fail (obj->handles != NULL);
  connection_update_handles(conn);
  
  extra->start_trans =
  extra->end_trans   =
  extra->start_long  =
  extra->end_long    = (measure->line_width / 2.0);

  g_free (measure->name);
  value = distance_point_point (&ends[0], &ends[1]);
  value *= measure->scale;
  value *= (28.346457 / units[measure->unit].factor);
  measure->name = g_strdup_printf ("%.*g %s", measure->precision, value, units[measure->unit].unit);
  
  ascent = dia_font_ascent (measure->name, measure->font, measure->font_height);
  width = dia_font_string_width (measure->name, measure->font, measure->font_height);

  measure->text_pos.x = (ends[0].x + ends[1].x) / 2;
  measure->text_pos.y = (ends[0].y + ends[1].y) / 2;
  /* for horizontal we could try to center over the line */
  
  line_bbox (&ends[0], &ends[0], &conn->extra_spacing,&conn->object.bounding_box);
  arrow_bbox (&arrow, measure->line_width, &ends[0], &ends[1], &bbox);
  rectangle_union(&obj->bounding_box, &bbox);
  arrow_bbox (&arrow, measure->line_width, &ends[1], &ends[0], &bbox);
  rectangle_union(&obj->bounding_box, &bbox);

  bbox.left = measure->text_pos.x;
  bbox.top = measure->text_pos.y - ascent;
  bbox.bottom = bbox.top + measure->font_height;
  bbox.right = bbox.left + width;
  rectangle_union(&obj->bounding_box, &bbox);

  obj->position = conn->endpoints[0];
}
Beispiel #19
0
static void draw_tunnel(DiaRenderer *renderer,
			     Point *end, Point *vect, Color *col)
{
  DiaRendererClass *renderer_ops = DIA_RENDERER_GET_CLASS (renderer);
  Point vv,vp,vt1,vt2;
  BezPoint curve1[2];
  BezPoint curve2[2];

  real vlen;
  vv = *end;
  point_sub(&vv,vect);
  vlen = distance_point_point(vect,end);
  if (vlen < 1E-7) return;
  point_scale(&vv,1/vlen);
  vp.y = vv.x;
  vp.x = -vv.y;

  curve1[0].type = curve2[0].type = BEZ_MOVE_TO;
  curve1[0].p1   = curve2[0].p1   = *end;
  vt1 = vv;
  point_scale(&vt1,-ARROW_PARENS_LOFFSET - (.5*ARROW_PARENS_LENGTH));
  point_add(&curve1[0].p1,&vt1); point_add(&curve2[0].p1,&vt1); 
                                           /* gcc, work for me, please. */
  vt2 = vp;
  point_scale(&vt2,ARROW_PARENS_WOFFSET);
  point_add(&curve1[0].p1,&vt2);  point_sub(&curve2[0].p1,&vt2);

  vt2 = vp;
  vt1 = vv;
  point_scale(&vt1,2.0*ARROW_PARENS_LENGTH / 6.0);
  point_scale(&vt2,ARROW_PARENS_LENGTH / 6.0);
  curve1[1].type = curve2[1].type = BEZ_CURVE_TO;
  curve1[1].p1 = curve1[0].p1;  curve2[1].p1 = curve2[0].p1;
  point_add(&curve1[1].p1,&vt1);  point_add(&curve2[1].p1,&vt1); 
  point_add(&curve1[1].p1,&vt2);  point_sub(&curve2[1].p1,&vt2); 
  curve1[1].p2 = curve1[1].p1;  curve2[1].p2 = curve2[1].p1;
  point_add(&curve1[1].p2,&vt1);  point_add(&curve2[1].p2,&vt1); 
  curve1[1].p3 = curve1[1].p2;  curve2[1].p3 = curve2[1].p2;
  point_add(&curve1[1].p3,&vt1);  point_add(&curve2[1].p3,&vt1); 
  point_sub(&curve1[1].p3,&vt2);  point_add(&curve2[1].p3,&vt2); 

  renderer_ops->draw_bezier(renderer,curve1,2,col);
  renderer_ops->draw_bezier(renderer,curve2,2,col);
}
Beispiel #20
0
Datei: line.c Projekt: mpuels/dia
/*!
 * \brief Gap calculation for _Line
 *
 * Calculate the absolute gap -- this gap is 'transient', in that
 * the actual end of the line is not moved, but it is made to look like
 * it is shorter.
 *
 * \protected \memberof Line
 */
static void
line_adjust_for_absolute_gap(Line *line, Point *gap_endpoints)
{
  Point endpoints[2];
  real line_length;

  endpoints[0] = line->connection.endpoints[0];
  endpoints[1] = line->connection.endpoints[1];

  line_length = distance_point_point(&endpoints[0], &endpoints[1]);

  /* puts new 0 to x% of  0->1  */
  point_convex(&gap_endpoints[0], &endpoints[0], &endpoints[1],
              1 - line->absolute_start_gap/line_length);

  /* puts new 1 to x% of  1->0  */
  point_convex(&gap_endpoints[1], &endpoints[1], &endpoints[0],
              1 - line->absolute_end_gap/line_length);
}
Beispiel #21
0
static const Handle *
_path_closest_corner_handle (StdPath *sp, const Point *pt)
{
  int i, j;
  real dist = G_MAXDOUBLE;
  Handle *closest = NULL;
  int corners[] = {0, 2, 5, 7};

  for (j = 0; j < 4; ++j) {
    real new_dist;

    i = corners[j];
    new_dist = distance_point_point (&sp->handles[i].pos, pt);
    if (new_dist < dist) {
      closest = &sp->handles[i];
      dist = new_dist;
    }
  }
  return closest;
}
Beispiel #22
0
static gboolean
_segment_from_path (BezierSegment *a, const GArray *p1, int i)
{
  const BezPoint *abp0 = &g_array_index (p1, BezPoint, i-1);
  const BezPoint *abp1 = &g_array_index (p1, BezPoint, i);
  a->p0 = abp0->type == BEZ_CURVE_TO ? abp0->p3 : abp0->p1;
  switch (abp1->type) {
  case BEZ_CURVE_TO :
    a->p1 = abp1->p1; a->p2 = abp1->p2; a->p3 = abp1->p3;
    break;
  case BEZ_LINE_TO :
    if (distance_point_point (&a->p0, &abp1->p1) < EPSILON)
      return FALSE; /* avoid a zero length line-to for confusion with move-to */
    a->p1 = a->p2 = a->p3 = abp1->p1;
    break;
  case BEZ_MOVE_TO :
    a->p0 = a->p1 = a->p2 = a->p3 = abp1->p1;
    break;
  }
  return TRUE;
}
Beispiel #23
0
int
aadlbox_point_near_port(Aadlbox *aadlbox, Point *p)
{
  int i, min;
  real dist = 1000.0;
  real d;

  min = -1;
  for (i=0;i<aadlbox->num_ports;i++) {
    d = distance_point_point(&aadlbox->ports[i]->handle->pos, p);

    if (d < dist) {
      dist = d;
      min = i;
    }
  }

  if (dist < 0.5)
    return min;
  else
    return -1;
}
Beispiel #24
0
static int
aadlbox_point_near_connection(Aadlbox *aadlbox, Point *p)
{
  int i, min;
  real dist = 1000.0;
  real d;

  min = -1;
  for (i=0;i<aadlbox->num_connections;i++) {
    d = distance_point_point(&aadlbox->connections[i]->pos, p);

    if (d < dist) {
      dist = d;
      min = i;
    }
  }

  if (dist < 0.5)
    return min;
  else
    return -1;
}
Beispiel #25
0
/** Return 1 if the direct path between a and b nodes is blocked, also compute
 * distance. */
static uint8_t
path_blocking (uint8_t a, uint8_t b, int16_t *dp)
{
    uint8_t i;
    vect_t va;
    vect_t vb;
    uint8_t escape_factor = 0;
    uint8_t factor = 1;
    uint8_t blocking = 0;
    if (a == PATH_SRC_NODE_INDEX || b == PATH_SRC_NODE_INDEX)
	escape_factor = path.escape_factor;
    path_pos (a, &va);
    path_pos (b, &vb);
    /* Test for green zone. */
    uint8_t a_green, b_green;
    a_green = va.x < PG_GREEN_WIDTH_MM || va.x > PG_WIDTH - PG_GREEN_WIDTH_MM;
    b_green = vb.x < PG_GREEN_WIDTH_MM || vb.x > PG_WIDTH - PG_GREEN_WIDTH_MM;
    if ((va.x < BOT_GREEN_ELEMENT_PLACE_DISTANCE_MM
	 && vb.x > BOT_GREEN_ELEMENT_PLACE_DISTANCE_MM)
	|| (va.x > BOT_GREEN_ELEMENT_PLACE_DISTANCE_MM
	    && vb.x < BOT_GREEN_ELEMENT_PLACE_DISTANCE_MM)
	|| (va.x > PG_WIDTH - BOT_GREEN_ELEMENT_PLACE_DISTANCE_MM
	    && vb.x < PG_WIDTH - BOT_GREEN_ELEMENT_PLACE_DISTANCE_MM)
	|| (va.x < PG_WIDTH - BOT_GREEN_ELEMENT_PLACE_DISTANCE_MM
	    && vb.x > PG_WIDTH - BOT_GREEN_ELEMENT_PLACE_DISTANCE_MM))
	return 1;
    if (a_green && b_green)
	return 1;
    if (a_green || b_green)
	factor = 4;
    /* Test for protected zone. */
    if (va.y <= 350 && va.x > PG_WIDTH / 2 - 350 && va.y < PG_WIDTH / 2 + 350
	&& (vb.x < PG_WIDTH / 2 - 350 || vb.x > PG_WIDTH / 2 + 350))
	return 1;
    if (vb.y <= 350 && vb.x > PG_WIDTH / 2 - 350 && vb.y < PG_WIDTH / 2 + 350
	&& (va.x < PG_WIDTH / 2 - 350 || va.x > PG_WIDTH / 2 + 350))
	return 1;
    /* Test for a blocking obstacle. */
    for (i = 0; i < PATH_OBSTACLES_NB && !blocking; i++)
      {
	if (path.obstacles[i].valid)
	  {
	    uint16_t d = distance_segment_point (&va, &vb,
						 &path.obstacles[i].c);
	    if (d < path.obstacles[i].r)
		blocking = 1;
	  }
      }
    /* Compute distance. */
    int16_t d = distance_point_point (&va, &vb);
    if (d == 0)
      {
	*dp = 0;
	return 0;
      }
    /* Test for a blocking element. */
    if (element_blocking_path (va, vb, d, path.escape_factor))
	blocking = 1;
    /* Handle escaping. */
    if (blocking)
      {
	if (escape_factor)
	  {
	    *dp = d * escape_factor;
	    return 0;
	  }
	else
	    return 1;
      }
    /* No blocking. */
    *dp = d * factor;
    return 0;
}
Beispiel #26
0
static DiaObject *
arc_load(ObjectNode obj_node, int version,DiaContext *ctx)
{
    Arc *arc;
    Connection *conn;
    DiaObject *obj;
    AttributeNode attr;

    arc = g_malloc0(sizeof(Arc));

    conn = &arc->connection;
    obj = &conn->object;

    obj->type = &arc_type;
    obj->ops = &arc_ops;

    connection_load(conn, obj_node, ctx);

    arc->arc_color = color_black;
    attr = object_find_attribute(obj_node, "arc_color");
    if (attr != NULL)
        data_color(attribute_first_data(attr), &arc->arc_color, ctx);

    arc->curve_distance = 0.1;
    attr = object_find_attribute(obj_node, "curve_distance");
    if (attr != NULL)
        arc->curve_distance = data_real(attribute_first_data(attr), ctx);

    arc->line_width = 0.1;
    attr = object_find_attribute(obj_node, PROP_STDNAME_LINE_WIDTH);
    if (attr != NULL)
        arc->line_width = data_real(attribute_first_data(attr), ctx);

    arc->line_style = LINESTYLE_SOLID;
    attr = object_find_attribute(obj_node, "line_style");
    if (attr != NULL)
        arc->line_style = data_enum(attribute_first_data(attr), ctx);

    arc->dashlength = DEFAULT_LINESTYLE_DASHLEN;
    attr = object_find_attribute(obj_node, "dashlength");
    if (attr != NULL)
        arc->dashlength = data_real(attribute_first_data(attr), ctx);

    arc->line_caps = LINECAPS_BUTT;
    attr = object_find_attribute(obj_node, "line_caps");
    if (attr != NULL)
        arc->line_caps = data_enum(attribute_first_data(attr), ctx);

    load_arrow(obj_node, &arc->start_arrow, "start_arrow",
               "start_arrow_length", "start_arrow_width", ctx);

    load_arrow(obj_node, &arc->end_arrow, "end_arrow",
               "end_arrow_length", "end_arrow_width", ctx);

    connection_init(conn, 4, 0);

    _arc_setup_handles (arc);

    /* older versions did not prohibit everything reduced to a single point
     * and afterwards failed on all the calculations producing nan.
     */
    if (distance_point_point (&arc->connection.endpoints[0],
                              &arc->connection.endpoints[1]) < 0.02) {
        arc->curve_distance = 0.0;
        arc->connection.endpoints[0].x -= 0.01;
        arc->connection.endpoints[1].x += 0.01;
        arc_update_handles (arc);
    }

    arc_update_data(arc);

    return &arc->connection.object;
}
Beispiel #27
0
/*!
 * \brief Calculate crossing points of two bezier segments
 *
 * Beware two bezier segments can intersect more than once, but this
 * function only returns the first or no intersection. It is the
 * responsibility of the caller to further split segments until there
 * is no intersection left.
 */
static gboolean
bezier_bezier_intersection (GArray *crossing,
			    const BezierSegment *a,
			    const BezierSegment *b,
			    int depth,
			    real asplit,
			    real bsplit)
{
  Rectangle abox, bbox;
  PolyBBExtras extra = { 0, };
  gboolean small_a, small_b;

  /* Avoid intersection overflow: if start and end are on the other segment
   * assume full overlap and no crossing.
   */
  if (   (_segment_has_point (a, &b->p0) && _segment_has_point (a, &b->p3))
      || (_segment_has_point (b, &a->p0) && _segment_has_point (b, &a->p3)))
    return FALSE; /* XXX: more variants pending, partial overlap */

  /* With very similar segments we would create a lot of points with not
   * a very deep recursion (test with ying-yang symbol).
   * Just comparing the segments on depth=1 is not good enough, so for
   * now we are limiting the number of intersections
   */
  if (crossing->len > 127) { /* XXX: arbitrary limit */
    g_warning ("Crossing limit (%d) reached", crossing->len);
    return FALSE;
  }

  bicubicbezier2D_bbox (&a->p0, &a->p1, &a->p2, &a->p3, &extra, &abox);
  bicubicbezier2D_bbox (&b->p0, &b->p1, &b->p2, &b->p3, &extra, &bbox);

  if (!rectangle_intersects (&abox, &bbox))
    return FALSE;
  small_a = (abox.right - abox.left) < EPSILON && (abox.bottom - abox.top) < EPSILON;
  small_b = (bbox.right - bbox.left) < EPSILON && (bbox.bottom - bbox.top) < EPSILON;
  /* if the boxes are small enough we can calculate the point */
  if (small_a && small_b) {
    /* intersecting and both small, should not matter which one is used */
    Point pt = { (abox.right + abox.left + bbox.right + bbox.left) / 4,
		 (abox.bottom + abox.top + bbox.bottom + bbox.top) / 4 };
    Intersection is;
    int i;

    for (i = 0; i < crossing->len; ++i) {
      /* if it's already included we are done */
      if (distance_point_point (&g_array_index (crossing, Intersection, i).pt, &pt) < 1.4142*EPSILON)
        return TRUE; /* although we did not add it */
    }
    is.split_one = asplit;
    is.split_two = bsplit;
    is.pt = pt;
    g_print ("d=%d; as=%g; bs=%g; ", depth, asplit, bsplit);
    g_array_append_val (crossing, is);
    return TRUE;
  } else {
    /* further splitting of a and b; it could be smart to only search in the
     * intersection of a-box and b-box ... */
    BezierSegment a1, a2;
    BezierSegment b1, b2;
    real ofs = 1.0/(1<<(depth+1));
    gboolean ret = FALSE;

    bezier_split (a, &a1, &a2);
    bezier_split (b, &b1, &b2);

    ret |= bezier_bezier_intersection (crossing, &a1, &b1, depth+1, asplit-ofs, bsplit-ofs);
    ret |= bezier_bezier_intersection (crossing, &a2, &b1, depth+1, asplit+ofs, bsplit-ofs);
    ret |= bezier_bezier_intersection (crossing, &a1, &b2, depth+1, asplit-ofs, bsplit+ofs);
    ret |= bezier_bezier_intersection (crossing, &a2, &b2, depth+1, asplit+ofs, bsplit+ofs);
    /* XXX: check !ret case, not sure if it should happen */
    return ret;
  }
}
Beispiel #28
0
static void
ellipse_update_data(Ellipse *ellipse, AnchorShape horiz, AnchorShape vert)
{
  Element *elem = &ellipse->element;
  ElementBBExtras *extra = &elem->extra_spacing;
  DiaObject *obj = &elem->object;
  Point center, bottom_right;
  Point p, c;
  real dw, dh;
  real width, height;
  real radius1, radius2;
  int i;

  /* save starting points */
  center = bottom_right = elem->corner;
  center.x += elem->width/2;
  bottom_right.x += elem->width;
  center.y += elem->height/2;
  bottom_right.y += elem->height;

  text_calc_boundingbox(ellipse->text, NULL);
  width = ellipse->text->max_width + 2 * ellipse->padding;
  height = ellipse->text->height * ellipse->text->numlines +
    2 * ellipse->padding;

  /* stop ellipse from getting infinite width/height */
  if (elem->width / elem->height > 4)
    elem->width = elem->height * 4;
  else if (elem->height / elem->width > 4)
    elem->height = elem->width * 4;

  c.x = elem->corner.x + elem->width / 2;
  c.y = elem->corner.y + elem->height / 2;
  p.x = c.x - width  / 2;
  p.y = c.y - height / 2;
  radius1 = ellipse_radius(ellipse, p.x, p.y) - ellipse->border_width/2;
  radius2 = distance_point_point(&c, &p);
  
  if (   radius1 < radius2
      && (   ellipse->text_fitting == TEXTFIT_ALWAYS
          || ellipse->text_fitting == TEXTFIT_WHEN_NEEDED)) {
    /* increase size of the ellipse while keeping its aspect ratio */
    elem->width  *= radius2 / radius1;
    elem->height *= radius2 / radius1;
  }

  /* move shape if necessary ... */
  switch (horiz) {
  case ANCHOR_MIDDLE:
    elem->corner.x = center.x - elem->width/2; break;
  case ANCHOR_END:
    elem->corner.x = bottom_right.x - elem->width; break;
  default:
    break;
  }
  switch (vert) {
  case ANCHOR_MIDDLE:
    elem->corner.y = center.y - elem->height/2; break;
  case ANCHOR_END:
    elem->corner.y = bottom_right.y - elem->height; break;
  default:
    break;
  }

  p = elem->corner;
  p.x += elem->width / 2.0;
  p.y += elem->height / 2.0 - ellipse->text->height*ellipse->text->numlines/2 +
    ellipse->text->ascent;
  switch (ellipse->text->alignment) {
  case ALIGN_LEFT:
    p.x -= (elem->width - 2*(ellipse->padding + ellipse->border_width))/2;
    break;
  case ALIGN_RIGHT:
    p.x += (elem->width - 2*(ellipse->padding + ellipse->border_width))/2;
    break;
  case ALIGN_CENTER:
    break;
  }
  text_set_position(ellipse->text, &p);

  /* Update connections: */
  c.x = elem->corner.x + elem->width / 2;
  c.y = elem->corner.y + elem->height / 2;
  dw = elem->width  / 2.0;
  dh = elem->height / 2.0;
  for (i = 0; i < NUM_CONNECTIONS-1; i++) {
    real theta = M_PI / 8.0 * i;
    real costheta = cos(theta);
    real sintheta = sin(theta);
    connpoint_update(&ellipse->connections[i],
		      c.x + dw * costheta,
		      c.y - dh * sintheta,
		      (costheta > .5?DIR_EAST:(costheta < -.5?DIR_WEST:0))|
		      (sintheta > .5?DIR_NORTH:(sintheta < -.5?DIR_SOUTH:0)));
  }
  connpoint_update(&ellipse->connections[16],
		   c.x, c.y, DIR_ALL);

  extra->border_trans = ellipse->border_width / 2.0;
  element_update_boundingbox(elem);

  obj->position = elem->corner;
  
  element_update_handles(elem);
}
Beispiel #29
0
/** Return 1 if the direct path between a and b nodes is blocked, also compute
 * distance. */
static uint8_t
path_blocking (uint8_t a, uint8_t b, int16_t *dp)
{
    uint8_t i;
    vect_t va;
    vect_t vb;
    uint8_t escape_factor = 0;
    if (a == PATH_SRC_NODE_INDEX || b == PATH_SRC_NODE_INDEX)
	escape_factor = path.escape_factor;
    path_pos (a, &va);
    path_pos (b, &vb);
    /* Test for a blocking obstacle. */
    for (i = 0; i < PATH_OBSTACLES_NB; i++)
      {
	if (path.obstacles[i].valid)
	  {
	    uint16_t d = distance_segment_point (&va, &vb,
						 &path.obstacles[i].c);
	    if (d < path.obstacles[i].r)
	      {
		if (escape_factor)
		  {
		    int16_t d = distance_point_point (&va, &vb);
		    *dp = d * escape_factor;
		    return 0;
		  }
		else
		    return 1;
	      }
	  }
      }
    /* Test for a blocking food. */
    int16_t d = distance_point_point (&va, &vb);
    if (d == 0)
      {
	*dp = 0;
	return 0;
      }
    else if (food_blocking_path (va, vb, d))
      {
	if (escape_factor)
	  {
	    *dp = d * escape_factor;
	    return 0;
	  }
	else
	    return 1;
      }
    /* Test for the wall. */
    if (va.x < BOT_SIZE_RADIUS || va.x >= PG_WIDTH - BOT_SIZE_RADIUS
	|| vb.x < BOT_SIZE_RADIUS || vb.x >= PG_WIDTH - BOT_SIZE_RADIUS)
      {
	int16_t dx = va.x - vb.x;
	int16_t dy = va.y - vb.y;
	/* Do not authorise path going parallel to the wall. */
	if (UTILS_ABS (dx) < UTILS_ABS (dy))
	  {
	    if (escape_factor)
	      {
		*dp = d * escape_factor;
		return 0;
	      }
	    else
		return 1;
	  }
      }
    /* No blocking. */
    *dp = d;
    return 0;
}
Beispiel #30
0
static DiaObject *
fig_read_arc(FILE *file, DiaContext *ctx)
{
    int sub_type;
    int line_style;
    int thickness;
    int pen_color;
    int fill_color;
    int depth;
    int pen_style;
    int area_fill;
    real style_val;
    int cap_style;
    int direction;
    int forward_arrow, backward_arrow;
    Arrow *forward_arrow_info = NULL, *backward_arrow_info = NULL;
    DiaObject *newobj = NULL;
    real center_x, center_y;
    int x1, y1;
    int x2, y2;
    int x3, y3;
    char* old_locale;
    Point p2, pm;
    real distance;

    old_locale = setlocale(LC_NUMERIC, "C");
    if (fscanf(file, "%d %d %d %d %d %d %d %d %lf %d %d %d %d %lf %lf %d %d %d %d %d %d\n",
	       &sub_type,
	       &line_style,
	       &thickness,
	       &pen_color,
	       &fill_color,
	       &depth,
	       &pen_style,
	       &area_fill,
	       &style_val,
	       &cap_style,
	       &direction,
	       &forward_arrow,
	       &backward_arrow,
	       &center_x, &center_y,
	       &x1, &y1,
	       &x2, &y2,
	       &x3, &y3) != 21) {
	dia_context_add_message_with_errno(ctx, errno, _("Couldn't read arc info."));
	goto exit;
    }

    if (forward_arrow == 1) {
	forward_arrow_info = fig_read_arrow(file, ctx);
    }

    if (backward_arrow == 1) {
	backward_arrow_info = fig_read_arrow(file, ctx);
    }

    p2.x = x2/FIG_UNIT; p2.y = y2/FIG_UNIT;
    pm.x = (x1+x3)/(2*FIG_UNIT); pm.y = (y1+y3)/(2*FIG_UNIT);
    distance = distance_point_point (&p2, &pm);

    switch (sub_type) {
    case 0: 
    case 1: 
    case 2: /* We can't do pie-wedge properly yet */
	newobj = create_standard_arc(x1/FIG_UNIT, y1/FIG_UNIT,
				     x3/FIG_UNIT, y3/FIG_UNIT,
				     direction ? distance : -distance, 
				     forward_arrow_info,
				     backward_arrow_info);
	if (newobj == NULL) goto exit;
	if (sub_type == 2) {
		/* set new fill property on arc? */
		dia_context_add_message(ctx, _("Filled arc treated as unfilled"));
	}
	break;
    default: 
	dia_context_add_message(ctx, _("Unknown polyline arc: %d\n"), sub_type);
	goto exit;
    }

    fig_simple_properties(newobj, line_style, style_val, thickness,
			  pen_color, fill_color, area_fill, ctx);

    /* Pen style field (not used) */
    /* Style_val (size of dots and dashes) in 1/80 inch*/
    /* Join style */
    /* Cap style */
     
    /* Depth field */
    add_at_depth(newobj, depth, ctx);

 exit:
    setlocale(LC_NUMERIC, old_locale);
    g_free(forward_arrow_info);
    g_free(backward_arrow_info);
    return newobj;
}