Ejemplo n.º 1
0
void start_selectregion(GdkEvent *event)
{
  double pt[2];
  reset_selection();
  
  ui.cur_item_type = ITEM_SELECTREGION;
  ui.selection = g_new(struct Selection, 1);
  ui.selection->type = ITEM_SELECTREGION;
  ui.selection->items = NULL;
  ui.selection->layer = ui.cur_layer;

  get_pointer_coords(event, pt);
  ui.selection->bbox.left = ui.selection->bbox.right = pt[0];
  ui.selection->bbox.top = ui.selection->bbox.bottom = pt[1];
  
  realloc_cur_path(1);
  ui.cur_path.num_points = 1;
  ui.cur_path.coords[0] = ui.cur_path.coords[2] = pt[0];
  ui.cur_path.coords[1] = ui.cur_path.coords[3] = pt[1];
 
  ui.selection->canvas_item = gnome_canvas_item_new(ui.cur_layer->group,
      gnome_canvas_polygon_get_type(), "width-pixels", 1, 
      "outline-color-rgba", 0x000000ff,
      "fill-color-rgba", 0x80808040,
      NULL);
  make_dashed(ui.selection->canvas_item);
  update_cursor();
}
Ejemplo n.º 2
0
void continue_selectregion(GdkEvent *event)
{
  double *pt;
  
  realloc_cur_path(ui.cur_path.num_points+1);
  pt = ui.cur_path.coords + 2*ui.cur_path.num_points;
  get_pointer_coords(event, pt);
  if (hypot(pt[0]-pt[-2], pt[1]-pt[-1]) < PIXEL_MOTION_THRESHOLD/ui.zoom)
    return; // not a meaningful motion
  ui.cur_path.num_points++;
  if (ui.cur_path.num_points>2)
    gnome_canvas_item_set(ui.selection->canvas_item, 
     "points", &ui.cur_path, NULL);
}
Ejemplo n.º 3
0
void make_circle_shape(double x0, double y0, double r)
{
  int npts, i;
  struct Item *item;
  struct UndoErasureData *erasure;
  
  npts = (int)(2*r);
  if (npts<12) npts = 12; // min. number of points
  realloc_cur_path(npts+1);
  ui.cur_path.num_points = npts+1;
  for (i=0;i<=npts; i++) {
    ui.cur_path.coords[2*i] = x0 + r*cos((2*M_PI*i)/npts);
    ui.cur_path.coords[2*i+1] = y0 + r*sin((2*M_PI*i)/npts);
  }
}
Ejemplo n.º 4
0
gboolean try_rectangle(void)
{
  struct RecoSegment *rs, *r1, *r2;
  int i;
  double dist, avg_angle;
  
  // first, we need whole strokes to combine to 4 segments...
  if (recognizer_queue_length<4) return FALSE;
  rs = recognizer_queue + recognizer_queue_length - 4;
  if (rs->startpt!=0) return FALSE;

  // check edges make angles ~= Pi/2 and vertices roughly match
  avg_angle = 0.;
  for (i=0; i<=3; i++) {
    r1 = rs+i; r2 = rs+(i+1)%4;
    if (fabs(fabs(r1->angle-r2->angle)-M_PI/2) > RECTANGLE_ANGLE_TOLERANCE)
      return FALSE;
    avg_angle += r1->angle;
    if (r2->angle > r1->angle) avg_angle += (i+1)*M_PI/2;
    else avg_angle -= (i+1)*M_PI/2;
    // test if r1 points away from r2 rather than towards it
    r1->reversed = ((r1->x2-r1->x1)*(r2->xcenter-r1->xcenter)+
                   (r1->y2-r1->y1)*(r2->ycenter-r1->ycenter)) < 0;
  }
  for (i=0; i<=3; i++) {
    r1 = rs+i; r2 = rs+(i+1)%4;
    dist = hypot((r1->reversed?r1->x1:r1->x2) - (r2->reversed?r2->x2:r2->x1),
                 (r1->reversed?r1->y1:r1->y2) - (r2->reversed?r2->y2:r2->y1));
    if (dist > RECTANGLE_LINEAR_TOLERANCE*(r1->radius+r2->radius)) return FALSE;
  }
  
  // make a rectangle of the correct size and slope
  avg_angle = avg_angle/4;
  if (fabs(avg_angle)<SLANT_TOLERANCE) avg_angle = 0.;
  if (fabs(avg_angle)>M_PI/2-SLANT_TOLERANCE) avg_angle = M_PI/2;
  realloc_cur_path(5);
  ui.cur_path.num_points = 5;
  for (i=0; i<=3; i++) rs[i].angle = avg_angle+i*M_PI/2;
  for (i=0; i<=3; i++) calc_edge_isect(rs+i, rs+(i+1)%4, ui.cur_path.coords+2*i+2);
  ui.cur_path.coords[0] = ui.cur_path.coords[8];
  ui.cur_path.coords[1] = ui.cur_path.coords[9];
  
  remove_recognized_strokes(rs, 4);
  insert_recognized_curpath();
  return TRUE;
}
Ejemplo n.º 5
0
gboolean try_closed_polygon(int nsides)
{
  struct RecoSegment *rs, *r1, *r2;
  int i;
  double dist, pt[2];
  
  // first, we need whole strokes to combine to nsides segments...
  if (recognizer_queue_length<nsides) return FALSE;
  rs = recognizer_queue + recognizer_queue_length - nsides;
  if (rs->startpt!=0) return FALSE;

  // check vertices roughly match
  for (i=0; i<nsides; i++) {
    r1 = rs+i; r2 = rs+(i+1)%nsides;
    // test if r1 points away from r2 rather than towards it
    calc_edge_isect(r1, r2, pt);
    r1->reversed = (hypot(pt[0]-r1->x1,pt[1]-r1->y1) < hypot(pt[0]-r1->x2,pt[1]-r1->y2));
  }
  for (i=0; i<nsides; i++) {
    r1 = rs+i; r2 = rs+(i+1)%nsides;
    calc_edge_isect(r1, r2, pt);
    dist = hypot((r1->reversed?r1->x1:r1->x2)-pt[0],(r1->reversed?r1->y1:r1->y2)-pt[1])
         + hypot((r2->reversed?r2->x2:r2->x1)-pt[0],(r2->reversed?r2->y2:r2->y1)-pt[1]);
    if (dist > POLYGON_LINEAR_TOLERANCE*(r1->radius+r2->radius)) return FALSE;
  }
  
  // make a polygon of the correct size and slope
  realloc_cur_path(nsides+1);
  ui.cur_path.num_points = nsides+1;
  for (i=0; i<nsides; i++) 
    calc_edge_isect(rs+i, rs+(i+1)%nsides, ui.cur_path.coords+2*i+2);
  ui.cur_path.coords[0] = ui.cur_path.coords[2*nsides];
  ui.cur_path.coords[1] = ui.cur_path.coords[2*nsides+1];
  
  remove_recognized_strokes(rs, nsides);
  insert_recognized_curpath();
  return TRUE;
}
Ejemplo n.º 6
0
/* the main pattern recognition function, called after finalize_stroke() */
void recognize_patterns(void)
{
  struct Item *it;
  struct Inertia s, ss[4];
  struct RecoSegment *rs;
  int n, i;
  int brk[5];
  double score;
  
  if (!undo || undo->type!=ITEM_STROKE) return;
  if (undo->next != last_item_checker) reset_recognizer(); // reset queue
  if (last_item_checker!=NULL && ui.cur_layer != last_item_checker->layer) reset_recognizer();

  it = undo->item;
  calc_inertia(it->path->coords, 0, it->path->num_points-1, &s);
#ifdef RECOGNIZER_DEBUG
  printf("DEBUG: Mass=%.0f, Center=(%.1f,%.1f), I=(%.0f,%.0f, %.0f), "
     "Rad=%.2f, Det=%.4f \n", 
     s.mass, center_x(s), center_y(s), I_xx(s), I_yy(s), I_xy(s), I_rad(s), I_det(s));
#endif

  // first see if it's a polygon
  n = find_polygonal(it->path->coords, 0, it->path->num_points-1, MAX_POLYGON_SIDES, brk, ss);
  if (n>0) {
    optimize_polygonal(it->path->coords, n, brk, ss);
#ifdef RECOGNIZER_DEBUG
    printf("DEBUG: Polygon, %d edges: ", n);
    for (i=0; i<n; i++)
      printf("DEBUG: %d-%d (M=%.0f, det=%.4f) ", brk[i], brk[i+1], ss[i].mass, I_det(ss[i]));
    printf("\n");
#endif
    /* update recognizer segment queue (most recent at end) */
    while (n+recognizer_queue_length > MAX_POLYGON_SIDES) {
      // remove oldest polygonal stroke
      i=1;
      while (i<recognizer_queue_length && recognizer_queue[i].startpt!=0) i++;
      recognizer_queue_length-=i;
      g_memmove(recognizer_queue, recognizer_queue+i, 
              recognizer_queue_length * sizeof(struct RecoSegment));
    }
#ifdef RECOGNIZER_DEBUG
    printf("DEBUG: Queue now has %d + %d edges\n", recognizer_queue_length, n);
#endif
    rs = recognizer_queue + recognizer_queue_length;
    recognizer_queue_length += n;
    for (i=0; i<n; i++) {
      rs[i].item = it;
      rs[i].startpt = brk[i];
      rs[i].endpt = brk[i+1];
      get_segment_geometry(it->path->coords, brk[i], brk[i+1], ss+i, rs+i);
    }  
    if (try_rectangle()) { reset_recognizer(); return; }
    if (try_arrow()) { reset_recognizer(); return; }
    if (try_closed_polygon(3)) { reset_recognizer(); return; }
    if (try_closed_polygon(4)) { reset_recognizer(); return; }
    if (n==1) { // current stroke is a line
      if (fabs(rs->angle)<SLANT_TOLERANCE) { // nearly horizontal
        rs->angle = 0.;
        rs->y1 = rs->y2 = rs->ycenter;
      }
      if (fabs(rs->angle)>M_PI/2-SLANT_TOLERANCE) { // nearly vertical
        rs->angle = (rs->angle>0)?(M_PI/2):(-M_PI/2);
        rs->x1 = rs->x2 = rs->xcenter;
      }
      realloc_cur_path(2);
      ui.cur_path.num_points = 2;
      ui.cur_path.coords[0] = rs->x1;
      ui.cur_path.coords[1] = rs->y1;
      ui.cur_path.coords[2] = rs->x2;
      ui.cur_path.coords[3] = rs->y2;
      remove_recognized_strokes(rs, 1);
      rs->item = insert_recognized_curpath();
    }
    last_item_checker = undo;
    return;
  }

  // not a polygon: maybe a circle ?
  reset_recognizer();
  if (I_det(s)>CIRCLE_MIN_DET) {
    score = score_circle(it->path->coords, 0, it->path->num_points-1, &s);
#ifdef RECOGNIZER_DEBUG
    printf("DEBUG: Circle score: %.2f\n", score);
#endif
    if (score < CIRCLE_MAX_SCORE) {
      make_circle_shape(center_x(s), center_y(s), I_rad(s));
      recognizer_queue[0].item = it;
      remove_recognized_strokes(recognizer_queue, 1);
      insert_recognized_curpath();
    }
  }
}
Ejemplo n.º 7
0
gboolean try_arrow(void)
{
  struct RecoSegment *rs;
  int i, j;
  double alpha[3], dist, pt[2], tmp, delta;
  double x1, y1, x2, y2, angle;
  gboolean rev[3];
  
  // first, we need whole strokes to combine to nsides segments...
  if (recognizer_queue_length<3) return FALSE;
  rs = recognizer_queue + recognizer_queue_length - 3;
  if (rs->startpt!=0) return FALSE;

  // check arrow head not too big, and orient main segment
  for (i=1; i<=2; i++) {
    if (rs[i].radius > ARROW_MAXSIZE*rs[0].radius) return FALSE;
    rev[i] = (hypot(rs[i].xcenter-rs->x1, rs[i].ycenter-rs->y1) <
              hypot(rs[i].xcenter-rs->x2, rs[i].ycenter-rs->y2));
  }
  if (rev[1]!=rev[2]) return FALSE;
  if (rev[1]) { 
    x1 = rs->x2; y1 = rs->y2; x2 = rs->x1; y2 = rs->y1; 
    angle = rs->angle + M_PI;
  }
  else { 
    x1 = rs->x1; y1 = rs->y1; x2 = rs->x2; y2 = rs->y2;
    angle = rs->angle;
  }
    
  // check arrow head not too big, and angles roughly ok
  for (i=1; i<=2; i++) {
    rs[i].reversed = FALSE;
    alpha[i] = rs[i].angle - angle;
    while (alpha[i]<-M_PI/2) { alpha[i]+=M_PI; rs[i].reversed = !rs[i].reversed; }
    while (alpha[i]>M_PI/2) { alpha[i]-=M_PI; rs[i].reversed = !rs[i].reversed; }
#ifdef RECOGNIZER_DEBUG
    printf("DEBUG: arrow: alpha[%d] = %.1f degrees\n", i, alpha[i]*180/M_PI);
#endif
    if (fabs(alpha[i])<ARROW_ANGLE_MIN || fabs(alpha[i])>ARROW_ANGLE_MAX) return FALSE;
  }
  
  // check arrow head segments are roughly symmetric
  if (alpha[1]*alpha[2]>0 || fabs(alpha[1]+alpha[2]) > ARROW_ASYMMETRY_MAX_ANGLE) return FALSE;
  if (rs[1].radius/rs[2].radius > 1+ARROW_ASYMMETRY_MAX_LINEAR) return FALSE;
  if (rs[2].radius/rs[1].radius > 1+ARROW_ASYMMETRY_MAX_LINEAR) return FALSE;

  // check vertices roughly match
  calc_edge_isect(rs+1, rs+2, pt);
  for (j=1; j<=2; j++) {
    dist = hypot(pt[0]-(rs[j].reversed?rs[j].x1:rs[j].x2),
                 pt[1]-(rs[j].reversed?rs[j].y1:rs[j].y2));
#ifdef RECOGNIZER_DEBUG
    printf("DEBUG: linear tolerance: tip[%d] = %.2f\n", j, dist/rs[j].radius);
#endif
    if (dist>ARROW_TIP_LINEAR_TOLERANCE*rs[j].radius) return FALSE;
  }
  dist = (pt[0]-x2)*sin(angle)-(pt[1]-y2)*cos(angle);
  dist /= rs[1].radius + rs[2].radius;
#ifdef RECOGNIZER_DEBUG
  printf("DEBUG: sideways gap tolerance = %.2f\n", dist);
#endif
  if (fabs(dist)>ARROW_SIDEWAYS_GAP_TOLERANCE) return FALSE;
  dist = (pt[0]-x2)*cos(angle)+(pt[1]-y2)*sin(angle);
  dist /= rs[1].radius + rs[2].radius;
#ifdef RECOGNIZER_DEBUG
  printf("DEBUG: main linear gap = %.2f\n", dist);
#endif
  if (dist<ARROW_MAIN_LINEAR_GAP_MIN || dist>ARROW_MAIN_LINEAR_GAP_MAX) return FALSE;

  // make an arrow of the correct size and slope
  if (fabs(rs->angle)<SLANT_TOLERANCE) { // nearly horizontal
    angle = angle - rs->angle;
    y1 = y2 = rs->ycenter;
  }
  if (rs->angle>M_PI/2-SLANT_TOLERANCE) { // nearly vertical
    angle = angle - (rs->angle-M_PI/2);
    x1 = x2 = rs->xcenter;
  }
  if (rs->angle<-M_PI/2+SLANT_TOLERANCE) { // nearly vertical
    angle = angle - (rs->angle+M_PI/2);
    x1 = x2 = rs->xcenter;
  }
  delta = fabs(alpha[1]-alpha[2])/2;
  dist = (hypot(rs[1].x1-rs[1].x2, rs[1].y1-rs[1].y2) +
          hypot(rs[2].x1-rs[2].x2, rs[2].y1-rs[2].y2))/2;
  
  realloc_cur_path(2);
  ui.cur_path.num_points = 2;
  ui.cur_path.coords[0] = x1; ui.cur_path.coords[1] = y1;
  ui.cur_path.coords[2] = x2; ui.cur_path.coords[3] = y2;
  remove_recognized_strokes(rs, 3);
  insert_recognized_curpath();

  realloc_cur_path(3);
  ui.cur_path.num_points = 3;
  ui.cur_path.coords[0] = x2 - dist*cos(angle+delta);
  ui.cur_path.coords[1] = y2 - dist*sin(angle+delta);
  ui.cur_path.coords[2] = x2; 
  ui.cur_path.coords[3] = y2;
  ui.cur_path.coords[4] = x2 - dist*cos(angle-delta);
  ui.cur_path.coords[5] = y2 - dist*sin(angle-delta);
  insert_recognized_curpath();

  return TRUE;
}