[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]

gEDA-cvs: gaf.git: branch: master updated (1.5.0-20080706-252-gd4c19f0)



The branch, master has been updated
       via  d4c19f00f07050376c4ddac731d7569983a1817d (commit)
       via  69cf1b86ca4c8e4011efdbdaab3b4f858980714b (commit)
      from  2d2d9d90d07080ed18a899dcccc34e99c83a7402 (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.


=========
 Summary
=========

 libgeda/include/prototype_priv.h |   21 +++
 libgeda/include/struct.h         |   24 +++
 libgeda/src/Makefile.am          |    3 +
 libgeda/src/m_basic.c            |    5 -
 libgeda/src/m_bounds.c           |   74 +++++++++
 libgeda/src/m_hatch.c            |  311 ++++++++++++++++++++++++++++++++++++++
 libgeda/src/m_transform.c        |  209 +++++++++++++++++++++++++
 libgeda/src/o_box_basic.c        |  130 +++-------------
 libgeda/src/o_circle_basic.c     |   71 +++------
 9 files changed, 685 insertions(+), 163 deletions(-)
 create mode 100644 libgeda/src/m_bounds.c
 create mode 100644 libgeda/src/m_hatch.c
 create mode 100644 libgeda/src/m_transform.c


=================
 Commit Messages
=================

commit d4c19f00f07050376c4ddac731d7569983a1817d
Author: Edward Hennessy <ehennes@xxxxxxxxxxxxx>
Date:   Sun Oct 26 10:45:54 2008 +0000

    Changed postscript output functions to use generic hatch algorithms.
    
    Changed both box and circle postscript output functions to use the generic
    hatching algorithms.

:100644 100644 6d6a78e... b7a32f4... M	libgeda/src/o_box_basic.c
:100644 100644 503060a... f78b101... M	libgeda/src/o_circle_basic.c

commit 69cf1b86ca4c8e4011efdbdaab3b4f858980714b
Author: Edward Hennessy <ehennes@xxxxxxxxxxxxx>
Date:   Sun Oct 26 10:45:28 2008 +0000

    Added functionality to hatch arbitrary polygons.
    
    Added functions to hatch arbitrary polygons.  This patch also includes functions
    with similar signatures to hatch boxes and circles.  This patch also includes
    geometric transformations, which is required by the hatching functions.

:100644 100644 659f6c4... f97972e... M	libgeda/include/prototype_priv.h
:100644 100644 849b605... ae09abc... M	libgeda/include/struct.h
:100644 100644 bcae051... 5e3be39... M	libgeda/src/Makefile.am
:100644 100644 b0b5ea9... c8cc63f... M	libgeda/src/m_basic.c
:000000 100644 0000000... 049d64c... A	libgeda/src/m_bounds.c
:000000 100644 0000000... 0a61e8c... A	libgeda/src/m_hatch.c
:000000 100644 0000000... 8c028fd... A	libgeda/src/m_transform.c

=========
 Changes
=========

commit d4c19f00f07050376c4ddac731d7569983a1817d
Author: Edward Hennessy <ehennes@xxxxxxxxxxxxx>
Date:   Sun Oct 26 10:45:54 2008 +0000

    Changed postscript output functions to use generic hatch algorithms.
    
    Changed both box and circle postscript output functions to use the generic
    hatching algorithms.

diff --git a/libgeda/src/o_box_basic.c b/libgeda/src/o_box_basic.c
index 6d6a78e..b7a32f4 100644
--- a/libgeda/src/o_box_basic.c
+++ b/libgeda/src/o_box_basic.c
@@ -1302,11 +1302,12 @@ void o_box_print_hatch(TOPLEVEL *toplevel, FILE *fp,
 		       int angle2, int pitch2,
 		       int origin_x, int origin_y)
 {
-  int x3, y3, x4, y4;
-  double cos_a_, sin_a_;
-  double x0, y0, r;
-  double x1, y1, x2, y2;
-  double amin, amax, a[4], min1, min2, max1, max2;
+  BOX box;
+  gint index;
+  GArray *lines;
+
+  g_return_if_fail(toplevel != NULL);
+  g_return_if_fail(fp != NULL);
 
   if (toplevel->print_color) {
     f_print_set_color(fp, color);
@@ -1315,114 +1316,25 @@ void o_box_print_hatch(TOPLEVEL *toplevel, FILE *fp,
   /* Avoid printing line widths too small */
   if (fill_width <= 1) fill_width = 2;
 
-  /* The cosinus and sinus of <B>angle1</B> are computed once and reused later. */
-  cos_a_ = cos(((double) angle1) * M_PI/180);
-  sin_a_ = sin(((double) angle1) * M_PI/180);
+  lines = g_array_new(FALSE, FALSE, sizeof(LINE));
 
-  /*! \note
-   *  The function considers the smallest circle around the box. Its radius
-   *  is given by the following relation. Its center is given by the point
-   *  at the middle of the box horizontally and vertically (intersection of
-   *  its two diagonals).
-   */
-  r = sqrt((double) (pow(width, 2) + pow(height, 2))) / 2;
+  box.upper_x = x;
+  box.upper_y = y;
+  box.lower_x = x + width;
+  box.lower_y = y - height;    /* Hmmm... */
 
-  /*
-   *  When drawing a line in a circle there is two intersections. With the
-   *  previously described circle, these intersections are out of the box.
-   *  They can be easily calculated, the first by resolution of an equation
-   *  and the second one by symetry in relation to the vertical axis going
-   *  through the center of the circle.
-   *
-   *  These two points are then rotated of angle <B>angle1</B> using the matrix
-   *  previously mentioned.
-   */
-  y0 = 0;
-  while(y0 < r) {
-    x0 = pow(r, 2) - pow(y0, 2);
-    x0 = sqrt(x0);
-
-    x1 = (x0*cos_a_ - y0*sin_a_);
-    y1 = (x0*sin_a_ + y0*cos_a_);
-    x2 = ((-x0)*cos_a_ - y0*sin_a_);
-    y2 = ((-x0)*sin_a_ + y0*cos_a_);
-  
-    /*
-     * It now parametrizes the segment : first intersection is given the
-     * value of 0 and the second is given the value of 1. The four values for
-     * each intersection of the segment and the four sides (vertical or
-     * horizontal) of the box are given by the following relations :
-     */                                                             
-    if((int) (x2 - x1) != 0) {
-      a[0] = ((-width/2) - x1) / (x2 - x1);
-      a[1] = ((width/2)  - x1) / (x2 - x1);
-    } else {
-      a[0] = 0; a[1] = 1;
-    }
-    
-    if((int) (y2 - y1) != 0) {
-      a[2] = ((-height/2) - y1) / (y2 - y1);
-      a[3] = ((height/2)  - y1) / (y2 - y1);
-    } else {
-      a[2] = 0; a[3] = 1;
-    }
+  m_hatch_box(&box, angle1, pitch1, lines);
 
-    /*
-     * It now has to check which of these four values are for intersections
-     * with the sides of the box (some values may be for intersections out of
-     * the box). This is made by a min/max function.
-     */
-    if(a[0] < a[1]) {
-      min1 = a[0]; max1 = a[1];
-    } else {
-      min1 = a[1]; max1 = a[0];
-    }
-    
-    if(a[2] < a[3]) {
-      min2 = a[2]; max2 = a[3];
-    } else {
-      min2 = a[3]; max2 = a[2];
-    }
-    
-    amin = (min1 < min2) ? min2 : min1;
-    amin = (amin < 0) ? 0 : amin;
-    
-    amax = (max1 < max2) ? max1 : max2;
-    amax = (amax < 1) ? amax : 1;
-
-    /*
-     * If the segment really go through the box it prints the line. It also
-     * takes the opportunity of the symetry in the box in relation to its
-     * center to print the second line at the same time.
-     *
-     * If there is no intersection of the segment with any of the sides, then
-     * there is no need to continue : there would be no more segment in the
-     * box to print.
-     */
-    if((amax > amin) && (amax != 1) && (amin != 0)) {
-      /* There is intersection between the line and the box edges */
-      x3 = (int) (x1 + amin*(x2 - x1));
-      y3 = (int) (y1 + amin*(y2 - y1));
-      
-      x4 = (int) (x1 + amax*(x2 - x1));
-      y4 = (int) (y1 + amax*(y2 - y1));
-      
-      fprintf(fp,"%d %d %d %d %d line\n",
-	      x3 + (x + width/2), y3 + (y - height/2),
-	      x4 + (x + width/2), y4 + (y - height/2),
-	      fill_width);
-      
-      fprintf(fp,"%d %d %d %d %d line\n",
-	      -x3 + (x + width/2), -y3 + (y - height/2),
-	      -x4 + (x + width/2), -y4 + (y - height/2),
-	      fill_width);
-      
-    } else {
-      break;
-    }
-    
-    y0 = y0 + pitch1;
+  for(index=0; index<lines->len; index++) {
+    LINE *line = &g_array_index(lines, LINE, index);
+
+    fprintf(fp,"%d %d %d %d %d line\n",
+            line->x[0], line->y[0],
+            line->x[1], line->y[1],
+            fill_width);
   }
+
+  g_array_free(lines, TRUE);
 }
 
 /*! \brief Calculates the distance between the given point and the closest
diff --git a/libgeda/src/o_circle_basic.c b/libgeda/src/o_circle_basic.c
index 503060a..f78b101 100644
--- a/libgeda/src/o_circle_basic.c
+++ b/libgeda/src/o_circle_basic.c
@@ -1059,65 +1059,38 @@ void o_circle_print_hatch(TOPLEVEL *toplevel, FILE *fp,
 			  int angle2, int pitch2,
 			  int origin_x, int origin_y)
 {
-  double x0, y0, x1, y1, x2, y2;
-  double cos_a_, sin_a_;
+  CIRCLE circle;
+  gint index;
+  GArray *lines;
+
+  g_return_if_fail(toplevel != NULL);
+  g_return_if_fail(fp != NULL);
 
   if (toplevel->print_color) {
     f_print_set_color(fp, color);
   }
 
-  /* 
-   * The values of the cosinus and sinus of the angle
-   * <B>angle1</B> are calculated for future usage (repetitive).
-   */
-  cos_a_ = cos(((double) angle1) * M_PI/180);
-  sin_a_ = sin(((double) angle1) * M_PI/180);
+  /* Avoid printing line widths too small */
+  if (fill_width <= 1) fill_width = 2;
 
-  /*
-   * When printing a line in a circle there is two intersections.
-   * It looks for the coordinates of one of these points when the
-   * line is horizontal. The second one can be easily obtained by
-   * symmetry in relation to the vertical axis going through the
-   * centre of the circle.
-   *
-   * These two points are therefore rotated of angle <B>angle1</B>
-   * using the elements previously computed.
-   *
-   * The corresponding line can be printed providing that the
-   * coordinates are rounded.
-   *
-   * These operations are repeated for every horizontal line that
-   * can fit in the upper half of the circle (using and incrementing
-   * the variable #y0).
-   */
-  y0 = 0;
-  while(y0 < (double) radius) {
-    x0 = pow((double) radius, 2) - pow(y0, 2);
-    x0 = sqrt(x0);
+  lines = g_array_new(FALSE, FALSE, sizeof(LINE));
 
-    x1 = (x0*cos_a_ - y0*sin_a_) + x;
-    y1 = y + (x0*sin_a_ + y0*cos_a_);
-    x2 = ((-x0)*cos_a_ - y0*sin_a_) + x;
-    y2 = y + ((-x0)*sin_a_ + y0*cos_a_);
+  circle.center_x = x;
+  circle.center_y = y;
+  circle.radius   = radius;
 
-    fprintf(fp, "%d %d %d %d %d line\n",
-	    (int) x1, (int) y1, (int) x2, (int) y2, fill_width);
+  m_hatch_circle(&circle, angle1, pitch1, lines);
 
-    /*
-     * The function uses the symetry in relation to the centre of the
-     * circle. It avoid repetitive computation for the second half of
-     * the surface of the circle.
-     */
-    x1 = x + (x0*cos_a_ - (-y0)*sin_a_);
-    y1 = y + (x0*sin_a_ + (-y0)*cos_a_);
-    x2 = x + ((-x0)*cos_a_ - (-y0)*sin_a_);
-    y2 = y + ((-x0)*sin_a_ + (-y0)*cos_a_);
-    
-    fprintf(fp, "%d %d %d %d %d line\n",
-	    (int) x1, (int) y1, (int) x2, (int) y2, fill_width);
-    
-    y0 = y0 + pitch1;
+  for(index=0; index<lines->len; index++) {
+    LINE *line = &g_array_index(lines, LINE, index);
+
+    fprintf(fp,"%d %d %d %d %d line\n",
+            line->x[0], line->y[0],
+            line->x[1], line->y[1],
+            fill_width);
   }
+
+  g_array_free(lines, TRUE);
 }
 
 /*! \brief Calculates the distance between the given point and the closest

commit 69cf1b86ca4c8e4011efdbdaab3b4f858980714b
Author: Edward Hennessy <ehennes@xxxxxxxxxxxxx>
Date:   Sun Oct 26 10:45:28 2008 +0000

    Added functionality to hatch arbitrary polygons.
    
    Added functions to hatch arbitrary polygons.  This patch also includes functions
    with similar signatures to hatch boxes and circles.  This patch also includes
    geometric transformations, which is required by the hatching functions.

diff --git a/libgeda/include/prototype_priv.h b/libgeda/include/prototype_priv.h
index 659f6c4..f97972e 100644
--- a/libgeda/include/prototype_priv.h
+++ b/libgeda/include/prototype_priv.h
@@ -51,6 +51,27 @@ SCM g_get_line_width(SCM object_smob);
 void g_init_page_smob(void);
 SCM g_get_page_filename(SCM page_smob);
 
+/* m_bounds.c */
+void m_bounds_init(BOUNDS *bounds);
+void m_bounds_of_points(BOUNDS *bounds, POINT points[], gint count);
+
+/* m_hatch.c */
+void m_hatch_box(BOX *box, gint angle, gint pitch, GArray *lines);
+void m_hatch_circle(CIRCLE *circle, gint angle, gint pitch, GArray *lines);
+void m_hatch_polygon(GArray *points, gint angle, gint pitch, GArray *lines);
+
+/* m_transform.c */
+void m_transform_combine(TRANSFORM *result, TRANSFORM *a, TRANSFORM *b );
+void m_transform_init(TRANSFORM *transform);
+void m_transform_invert(TRANSFORM *transform, TRANSFORM *inverse);
+void m_transform_line(TRANSFORM *transform, LINE *line );
+void m_transform_lines(TRANSFORM *transform, GArray *lines);
+void m_transform_point(TRANSFORM *transform, gint *x, gint *y);
+void m_transform_points(TRANSFORM *transform, GArray *points);
+void m_transform_rotate(TRANSFORM *transform, gdouble angle);
+void m_transform_scale(TRANSFORM *transform, gdouble factor);
+void m_transform_translate(TRANSFORM *transform, gdouble dx, gdouble dy);
+
 /* o_arc_basic.c */
 OBJECT *o_arc_read(TOPLEVEL *toplevel, OBJECT *object_list, char buf[], unsigned int release_ver, unsigned int fileformat_ver);
 char *o_arc_save(OBJECT *object);
diff --git a/libgeda/include/struct.h b/libgeda/include/struct.h
index 849b605..ae09abc 100644
--- a/libgeda/include/struct.h
+++ b/libgeda/include/struct.h
@@ -36,6 +36,8 @@ typedef struct st_arc ARC;
 typedef struct st_box BOX;
 typedef struct st_picture PICTURE;
 typedef struct st_text TEXT;
+typedef struct st_point POINT;
+typedef struct st_transform TRANSFORM;
 
 typedef struct st_object OBJECT;
 typedef struct st_page PAGE;
@@ -43,6 +45,7 @@ typedef struct st_toplevel TOPLEVEL;
 typedef struct st_color COLOR;
 typedef struct st_undo UNDO;
 typedef struct st_tile TILE;
+typedef struct st_bounds BOUNDS;
 
 typedef struct st_conn CONN;
 typedef struct st_bus_ripper BUS_RIPPER;
@@ -94,6 +97,11 @@ struct st_line {
 
 };
 
+struct st_point {
+  gint x;
+  gint y;
+};
+
 /* pb20011014 - name the grips */
 #define LINE_END1 0
 #define LINE_END2 1
@@ -342,6 +350,22 @@ struct st_stretch
   STRETCH *next;
 };
 
+struct st_bounds {
+  gint min_x;
+  gint min_y;
+  gint max_x;
+  gint max_y;
+};
+
+/** A structure to store a 2D affine transform.
+ *
+ *  The transforms get stored in a 3x3 matrix. Code assumes the bottom row to
+ *  remain constant at [0 0 1].
+ */
+struct st_transform {
+  gdouble m[2][3];    /* m[row][column] */
+};
+
 struct st_undo {
 
   /* one of these is used, depending on if you are doing in-memory */
diff --git a/libgeda/src/Makefile.am b/libgeda/src/Makefile.am
index bcae051..5e3be39 100644
--- a/libgeda/src/Makefile.am
+++ b/libgeda/src/Makefile.am
@@ -25,6 +25,9 @@ libgeda_la_SOURCES = \
 	i_vars.c \
 	libgeda.c \
 	m_basic.c \
+        m_bounds.c \
+        m_hatch.c \
+        m_transform.c \
 	o_arc_basic.c \
 	o_attrib.c \
 	o_basic.c \
diff --git a/libgeda/src/m_basic.c b/libgeda/src/m_basic.c
index b0b5ea9..c8cc63f 100644
--- a/libgeda/src/m_basic.c
+++ b/libgeda/src/m_basic.c
@@ -372,11 +372,6 @@ struct st_halfspace {
   int bottom; 
 };
 
-/*! \brief */
-struct st_point {
-	int x, y;
-};
-
 /* \note 
  * encode_halfspace and clip are part of the cohen-sutherland clipping
  * algorithm.  They are used to determine if an object is visible or not 
diff --git a/libgeda/src/m_bounds.c b/libgeda/src/m_bounds.c
new file mode 100644
index 0000000..049d64c
--- /dev/null
+++ b/libgeda/src/m_bounds.c
@@ -0,0 +1,74 @@
+/* gEDA - GPL Electronic Design Automation
+ * libgeda - gEDA's library
+ * Copyright (C) 1998-2008 Ales Hvezda
+ * Copyright (C) 1998-2008 gEDA Contributors (see ChangeLog for details)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA
+ */
+#include <config.h>
+#include <libgeda_priv.h>
+
+/** \brief Initialize a bounds by setting it to empty
+ *
+ *  \param bounds [in] The bounds to set to empty.  This parameter must not
+ *  be NULL.
+ */
+void m_bounds_init(BOUNDS *bounds)
+{
+  bounds->min_x = G_MAXINT;
+  bounds->min_y = G_MAXINT;
+  bounds->max_x = G_MININT;
+  bounds->max_y = G_MININT;
+}
+
+/** \brief Calculate the bounds of a set of points
+ *
+ *  For an empty set of points, this function returns an empty bounds.
+ *
+ *  \param bounds [out] The bounds of the given set of points.  The bounds
+ *  does not need to be initialized before calling this function, but this
+ *  parameter must not be NULL.
+ *  \param points [in] The given set of points.  If the count is greater than
+ *  zero, this parameter must not be NULL.
+ *  \param count [in] The number of points in the set.
+ */
+void m_bounds_of_points(BOUNDS *bounds, POINT points[], gint count)
+{
+  gint index;
+
+  m_bounds_init(bounds);
+
+  for (index=0; index<count; index++) {
+    gint x = points[index].x;
+    gint y = points[index].y;
+
+    if (x < bounds->min_x) {
+      bounds->min_x = x;
+    }
+
+    if (y < bounds->min_y) {
+      bounds->min_y = y;
+    }
+
+    if (x > bounds->max_x) {
+      bounds->max_x = x;
+    }
+
+    if (y > bounds->max_y) {
+      bounds->max_y = y;
+    }
+  }
+}
+
diff --git a/libgeda/src/m_hatch.c b/libgeda/src/m_hatch.c
new file mode 100644
index 0000000..0a61e8c
--- /dev/null
+++ b/libgeda/src/m_hatch.c
@@ -0,0 +1,311 @@
+/* gEDA - GPL Electronic Design Automation
+ * libgeda - gEDA's library
+ * Copyright (C) 1998-2008 Ales Hvezda
+ * Copyright (C) 1998-2008 gEDA Contributors (see ChangeLog for details)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA
+ */
+#include <config.h>
+#include <math.h>
+#include <string.h>
+#include <libgeda_priv.h>
+
+typedef struct st_sweep_event SWEEP_EVENT;
+typedef struct st_sweep_status SWEEP_STATUS;
+
+struct st_sweep_status {
+  gint    x;     /* current x coordinate */
+  gint    y1;    /* ending y coordinate  */
+  gdouble m1;    /* inverse slope: y/x   */
+  gdouble b1;    /* x intercept          */
+};
+
+struct st_sweep_event {
+  gint         y0;        /* starting y coordinate */
+  SWEEP_STATUS status;
+};
+
+static gint calculate_initial_sweep(gint pitch, gint min_y, gint max_y);
+static gint compare_events(gconstpointer a, gconstpointer b);
+static gint compare_status(gconstpointer a, gconstpointer b);
+
+/** \brief Calculate the initial y cooridinate of the hatch sweep line
+ *
+ *  This function centers the hatch lines across the extents of the shape being
+ *  hatched.  This caclulation provides symmetrical hatch lines inside
+ *  symmetrical shapes, such as circles and squares.  This mechanism may not
+ *  provide as nice of an appearance in asymmetrical shapes.
+ *
+ *  \param pitch [in] The perpendicular distance between hatch lines.
+ *  \param min_y [in] The minimum y coordinate of the object being hatched.
+ *  \param max_y [in] The maximum y coordinate of the object being hatched.
+ *  \return The initital y coordinate of the sweep line.
+ */
+static gint calculate_initial_sweep(gint pitch, gint min_y, gint max_y)
+{
+  gint delta = max_y - min_y;
+
+  return min_y + ((delta - ((delta - pitch) / pitch * pitch)) / 2);
+}
+
+/** \brief Compares two sweep events
+ *
+ *  Compares two sweep events for ordering the event queue.  The prototype
+ *  and behavior are consistant with GCompareFunc.
+ *
+ *  \param a [in] The first sweep event.
+ *  \param a [in] The second sweep event.
+ *  \return A negative value if the first is less than the second, zero if the
+ *  first equals the second, and a positive value if the first is greater than
+ *  the second.
+ */
+static gint compare_events(gconstpointer a, gconstpointer b)
+{
+  SWEEP_EVENT *event_a = (SWEEP_EVENT*) a;
+  SWEEP_EVENT *event_b = (SWEEP_EVENT*) b;
+
+  return (event_a->y0 - event_b->y0);
+}
+
+/** \brief Compares two sweep status structs
+ *
+ *  Compares two sweep status for ordering the sweep status.  The prototype
+ *  and behavior are consistant with GCompareFunc.
+ *
+ *  \param a [in] The first sweep status.
+ *  \param a [in] The second sweep status.
+ *  \return A negative value if the first is less than the second, zero if the
+ *  first equals the second, and a positive value if the first is greater than
+ *  the second.
+ */
+static gint compare_status(gconstpointer a, gconstpointer b)
+{
+  SWEEP_STATUS *status_a = (SWEEP_STATUS*) a;
+  SWEEP_STATUS *status_b = (SWEEP_STATUS*) b;
+
+  return (status_b->x - status_a->x);
+}
+
+/** \brief Calculates line segments to hatch a box shape
+ *
+ *  This function appends new line segments to the lines GArray.  For creating
+ *  a hatch pattern, the GArray must be cleared before calling this function.
+ *  For creating cross hatch patterns, this function can be called multiple
+ *  times with a different angle or pitch while passing the same lines GArray.
+ *
+ *  \param box [in] The box shape to hatch.
+ *  \param angle [in] The angle of the hatch lines with respect to the x axis.
+ *  \param pitch [in] The distance between hatch lines
+ *  \param lines [inout] A GArray of LINE to contain the new hatch line
+ *  segments.  This function appends new line segments to the GArray and leaves
+ *  existing GArray contents unchanged.
+ */
+void m_hatch_box(BOX *box, gint angle, gint pitch, GArray *lines)
+{
+  GArray *corners;
+  POINT point;
+
+  g_return_if_fail(box!=NULL);
+  g_return_if_fail(lines!=NULL);
+
+  corners = g_array_sized_new(FALSE, FALSE, sizeof(POINT), 4);
+
+  point.x = box->upper_x;
+  point.y = box->upper_y;
+  g_array_append_val(corners, point);
+
+  point.x = box->lower_x;
+  point.y = box->upper_y;
+  g_array_append_val(corners, point);
+
+  point.x = box->lower_x;
+  point.y = box->lower_y;
+  g_array_append_val(corners, point);
+
+  point.x = box->upper_x;
+  point.y = box->lower_y;
+  g_array_append_val(corners, point);
+
+  m_hatch_polygon(corners, angle, pitch, lines);
+
+  g_array_free(corners, TRUE);
+}
+
+/** \brief Calculates line segments to hatch a circle.
+ *
+ *  This function appends new line segments to the lines GArray.  For creating
+ *  a hatch pattern, the GArray must be cleared before calling this function.
+ *  For creating cross hatch patterns, this function can be called multiple
+ *  times with a different angle or pitch while passing the same lines GArray.
+ *
+ *  \param circle [in] The circle shape to hatch.
+ *  \param angle [in] The angle of the hatch lines with respect to the x axis.
+ *  \param pitch [in] The distance between hatch lines
+ *  \param lines [inout] A GArray of LINE to contain the new hatch line
+ *  segments.  This function appends new line segments to the GArray and leaves
+ *  existing GArray contents unchanged.
+ */
+void m_hatch_circle(CIRCLE *circle, gint angle, gint pitch, GArray *lines)
+{
+  gint      radius;
+  gint      sweep_y;
+  TRANSFORM transform;
+
+  g_return_if_fail(circle!=NULL);
+  g_return_if_fail(lines!=NULL);
+
+  m_transform_init(&transform);
+  m_transform_rotate(&transform, angle);
+  m_transform_scale(&transform, 0.01);
+  m_transform_translate(&transform, circle->center_x, circle->center_y );
+
+  radius = 100 * circle->radius;
+  sweep_y = calculate_initial_sweep(100 * pitch, -radius, radius);
+
+  while ( sweep_y < radius ) {
+    LINE line;
+    gint x = round(sqrt(pow(radius,2) - pow(sweep_y,2)));
+
+    line.x[0] = -x;
+    line.y[0] = sweep_y;
+    line.x[1] = x;
+    line.y[1] = sweep_y;
+
+    m_transform_line(&transform, &line);
+    g_array_append_val(lines, line);
+
+    sweep_y += 100 * pitch;
+  }
+}
+
+/** \brief Calculates line segments to hatch an arbitrary polygon.
+ *
+ *  This function appends new line segments to the lines GArray.  For creating
+ *  a hatch pattern, the GArray must be cleared before calling this function.
+ *  For creating cross hatch patterns, this function can be called multiple
+ *  times with a different angle or pitch while passing the same lines GArray.
+ *
+ *  \param points [in] The endpoints of the arbitrary closed polygon to hatch.
+ *  \param angle [in] The angle of the hatch lines with respect to the x axis.
+ *  \param pitch [in] The distance between hatch lines.  This value must be
+ *  greater than zero.
+ *  \param lines [inout] A GArray of LINE to contain the new hatch line
+ *  segments.  This function appends new line segments to the GArray and leaves
+ *  existing GArray contents unchanged.
+ */
+void m_hatch_polygon(GArray *points, gint angle, gint pitch, GArray *lines)
+{
+  BOUNDS bounds;
+  GArray *events;
+  TRANSFORM inverse;
+  GArray *points2;
+  GArray *status;
+  gint sweep_y;
+  TRANSFORM transform;
+
+  g_return_if_fail(points!=NULL);
+  g_return_if_fail(pitch>0);
+  g_return_if_fail(lines!=NULL);
+
+  events = g_array_new(FALSE, FALSE, sizeof(SWEEP_EVENT));
+  points2 = g_array_sized_new(FALSE, FALSE, sizeof(POINT), points->len);
+  status = g_array_new(FALSE, FALSE, sizeof(SWEEP_STATUS));
+
+  m_transform_init(&transform);
+  m_transform_scale(&transform, 10);
+  m_transform_rotate(&transform, -angle);
+  m_transform_invert(&transform, &inverse);
+
+  g_array_append_vals(points2, points->data, points->len);
+  m_transform_points(&transform, points2);
+
+  /* build list of sweep events */
+  if ( points2->len > 1 ) {
+    gint index;
+    POINT *p0 = &g_array_index(points2, POINT, points2->len-1);
+    for (index=0; index<points2->len; index++) {
+      POINT *p1 = &g_array_index(points2, POINT, index);
+      if ( p0->y != p1->y ) {
+        SWEEP_EVENT event;
+        event.y0 = min(p0->y, p1->y);
+        event.status.y1 = max(p0->y, p1->y);
+        event.status.m1 = (gdouble)( p1->x - p0->x ) / (gdouble)( p1->y - p0->y );
+        event.status.b1 = p0->x - event.status.m1 * p0->y;
+        g_array_append_val(events, event);
+      }
+      p0 = p1;
+    }
+  }
+
+  /* sort sweep events in ascending order by starting y coordinate */
+  g_array_sort(events, compare_events);
+
+  m_bounds_of_points(&bounds, (POINT*)points2->data, points2->len);
+  sweep_y = calculate_initial_sweep(10 * pitch, bounds.min_y, bounds.max_y);
+
+  while ( events->len > 0 || status->len > 0 ) {
+    gint index;
+
+    /* add new segments that intersect the sweep line */
+    index = 0;
+    while ( index < events->len ) {
+      SWEEP_EVENT *event = &g_array_index(events, SWEEP_EVENT, index);
+      if ( sweep_y >= event->y0 ) {
+        SWEEP_STATUS st = event->status;
+        g_array_append_val(status, st);
+        g_array_remove_index(events, index);
+      } else {
+        index++;
+      }
+    }
+
+    /* remove status no longer intersecting sweep line */
+    index = status->len;
+    while ( index-- > 0 ) {
+      if ( sweep_y >= g_array_index(status, SWEEP_STATUS, index).y1 ) {
+        g_array_remove_index_fast(status, index);
+      }
+    }
+
+    /* (re)calculate x coordinates at sweep line */
+    for (index=0; index<status->len; index++) {
+      SWEEP_STATUS *st = &g_array_index(status, SWEEP_STATUS, index);
+      st->x = st->m1 * sweep_y + st->b1;
+    }
+
+    /* sort the sweep status in ascending order by x coordinate */
+    g_array_sort(status, compare_status);
+
+    /* draw hatch segments */
+    index = 0;
+    while ( index+1 < status->len ) {
+      LINE line;
+      line.x[0] = g_array_index(status, SWEEP_STATUS, index ).x;
+      line.y[0] = sweep_y;
+      line.x[1] = g_array_index(status, SWEEP_STATUS, index+1 ).x;
+      line.y[1] = sweep_y;
+      m_transform_line(&inverse, &line);
+      g_array_append_val(lines, line);
+      index += 2;
+    }
+
+    sweep_y += 10 * pitch;
+  }
+
+  g_array_free(events, TRUE);
+  g_array_free(points2, TRUE);
+  g_array_free(status, TRUE);
+}
+
diff --git a/libgeda/src/m_transform.c b/libgeda/src/m_transform.c
new file mode 100644
index 0000000..8c028fd
--- /dev/null
+++ b/libgeda/src/m_transform.c
@@ -0,0 +1,209 @@
+/* gEDA - GPL Electronic Design Automation
+ * libgeda - gEDA's library
+ * Copyright (C) 1998-2008 Ales Hvezda
+ * Copyright (C) 1998-2008 gEDA Contributors (see ChangeLog for details)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA
+ */
+#include <config.h>
+#include <math.h>
+#include <libgeda_priv.h>
+
+/** \brief Combines two transformations
+ *
+ *  Combines two matricies using matrix multiplication: a*b.
+ *
+ *  \param result [out] The resulting transformation.  If either operand is
+ *  NULL, the contents of the result remain unaltered.
+ *  \param transform0 [in] The first operand.
+ *  \param transform1 [in] The second operand.
+ */
+void m_transform_combine(TRANSFORM *result, TRANSFORM *a, TRANSFORM *b )
+{
+  g_return_if_fail(result!=NULL);
+  g_return_if_fail(a!=NULL);
+  g_return_if_fail(b!=NULL);
+
+  result->m[0][0] = a->m[0][0] * b->m[0][0] + a->m[0][1] * b->m[1][0];
+  result->m[0][1] = a->m[0][0] * b->m[0][1] + a->m[0][1] * b->m[1][1];
+  result->m[0][2] = a->m[0][0] * b->m[0][2] + a->m[0][1] * b->m[1][2] + a->m[0][2];
+  result->m[1][0] = a->m[1][0] * b->m[0][0] + a->m[1][1] * b->m[1][0];
+  result->m[1][1] = a->m[1][0] * b->m[0][1] + a->m[1][1] * b->m[1][1];
+  result->m[1][2] = a->m[1][0] * b->m[0][2] + a->m[1][1] * b->m[1][2] + a->m[1][2];
+}
+
+/** \brief Initialize a transform with the identity matrix.
+ *
+ *  \param transform [out] The transform to initialize with the identity matrix.
+ */
+void m_transform_init(TRANSFORM *transform)
+{
+  g_return_if_fail(transform!=NULL);
+
+  transform->m[0][0] = 1;
+  transform->m[0][1] = 0;
+  transform->m[0][2] = 0;
+  transform->m[1][0] = 0;
+  transform->m[1][1] = 1;
+  transform->m[1][2] = 0;
+}
+
+/** \brief Calculates the inverse transform
+ *
+ *  \param transform [in] The given matrix
+ *  \param inverse [out] The inverse of the given matrix.
+ */
+void m_transform_invert(TRANSFORM *transform, TRANSFORM *inverse)
+{
+  gdouble d;
+
+  g_return_if_fail(transform!=NULL);
+  g_return_if_fail(inverse!=NULL);
+
+  d = transform->m[0][0]*transform->m[1][1] - transform->m[1][0]*transform->m[0][1];
+
+  inverse->m[0][0] =  transform->m[1][1] / d;
+  inverse->m[0][1] = -transform->m[0][1] / d;
+  inverse->m[0][2] =  ( transform->m[0][1]*transform->m[1][2] - transform->m[1][1]*transform->m[0][2] ) / d;
+  inverse->m[1][0] = -transform->m[1][0] / d;
+  inverse->m[1][1] =  transform->m[0][0] / d;
+  inverse->m[1][2] = -( transform->m[0][0]*transform->m[1][2] - transform->m[1][0]*transform->m[0][2] ) / d;
+}
+
+/** \brief Transforms a line segment
+ *
+ *  \param transform [in] The transform function.
+ *  \param line [inout] The line to transform.
+ */
+void m_transform_line(TRANSFORM *transform, LINE *line)
+{
+  g_return_if_fail(transform!=NULL);
+  g_return_if_fail(line!=NULL);
+
+  m_transform_point(transform, &(line->x[0]), &(line->y[0]));
+  m_transform_point(transform, &(line->x[1]), &(line->y[1]));
+}
+
+/** \brief Transforms multiple line segments
+ *
+ *  \param transform [in] The transform function.
+ *  \param line [inout] The GArray of LINE to transform.
+ */
+void m_transform_lines(TRANSFORM *transform, GArray *lines)
+{
+  gint index;
+
+  g_return_if_fail(transform!=NULL);
+  g_return_if_fail(lines!=NULL);
+
+  for (index=0; index<lines->len; index++) {
+    LINE *line = &g_array_index(lines, LINE, index);
+    m_transform_line(transform, line);
+  }
+}
+
+/** \brief Transforms a point
+ *
+ *  \param x [inout] The x coordinate to transform.
+ *  \param y [inout] The y coordinate to transform.
+ *  \param transform [in] The transform function.
+ */
+void m_transform_point(TRANSFORM *transform, gint *x, gint *y)
+{
+  gdouble tx;
+  gdouble ty;
+
+  g_return_if_fail(transform!=NULL);
+  g_return_if_fail(x!=NULL);
+  g_return_if_fail(y!=NULL);
+
+  tx = *x;
+  ty = *y;
+
+  *x = round(transform->m[0][0] * tx + transform->m[0][1] * ty + transform->m[0][2]);
+  *y = round(transform->m[1][0] * tx + transform->m[1][1] * ty + transform->m[1][2]);
+}
+
+/** \brief Transforms a polyline or polygon
+ *
+ *  \param transform [in] The transform function.
+ *  \param line [inout] The GArray of POINT to transform.
+ */
+void m_transform_points(TRANSFORM *transform, GArray *points)
+{
+  gint index;
+
+  g_return_if_fail(transform!=NULL);
+  g_return_if_fail(points!=NULL);
+
+  for (index=0; index<points->len; index++) {
+    POINT *point = &g_array_index(points, POINT, index);
+    m_transform_point(transform, &(point->x), &(point->y));
+  }
+}
+
+/** \brief Adds a rotation to the transformation
+ *
+ *  \param transform [inout] The given matrix
+ *  \param angle [in] The angle to rotate
+ */
+void m_transform_rotate(TRANSFORM *transform, gdouble angle)
+{
+  gdouble r = G_PI*angle/180.0;
+  gdouble c = cos(r);
+  gdouble s = sin(r);
+  TRANSFORM temp;
+
+  g_return_if_fail(transform!=NULL);
+
+  temp = *transform;
+
+  transform->m[0][0] = temp.m[0][0] *  c + temp.m[0][1] * s;
+  transform->m[0][1] = temp.m[0][0] * -s + temp.m[0][1] * c;
+  transform->m[1][0] = temp.m[1][0] *  c + temp.m[1][1] * s;
+  transform->m[1][1] = temp.m[1][0] * -s + temp.m[1][1] * c;
+}
+
+/** \brief Adds a scaling to the transformation
+ *
+ *  \param transform [inout] The given matrix
+ *  \param factor [in] The amount to scale the transform.  This parameter must
+ *  not be zero, or the matrix becomes singular.
+ */
+void m_transform_scale(TRANSFORM *transform, gdouble factor)
+{
+  g_return_if_fail(transform!=NULL);
+  g_return_if_fail(factor!=0);
+
+  transform->m[0][0] *= factor;
+  transform->m[0][1] *= factor;
+  transform->m[1][0] *= factor;
+  transform->m[1][1] *= factor;
+}
+
+/** \brief Adds a translation to the transformation
+ *
+ *  \param transform [inout] The given matrix.
+ *  \param dx [in] The amount to translate on the x axis.
+ *  \param dy [in] The amount to translate on the y axis.
+ */
+void m_transform_translate(TRANSFORM *transform, gdouble dx, gdouble dy)
+{
+  g_return_if_fail(transform!=NULL);
+
+  transform->m[0][2] += dx;
+  transform->m[1][2] += dy;
+}
+




_______________________________________________
geda-cvs mailing list
geda-cvs@xxxxxxxxxxxxxx
http://www.seul.org/cgi-bin/mailman/listinfo/geda-cvs