libgeda

m_hatch.c

Go to the documentation of this file.
00001 /* gEDA - GPL Electronic Design Automation
00002  * libgeda - gEDA's library
00003  * Copyright (C) 1998-2010 Ales Hvezda
00004  * Copyright (C) 1998-2010 gEDA Contributors (see ChangeLog for details)
00005  *
00006  * This program is free software; you can redistribute it and/or modify
00007  * it under the terms of the GNU General Public License as published by
00008  * the Free Software Foundation; either version 2 of the License, or
00009  * (at your option) any later version.
00010  *
00011  * This program is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  * GNU General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU General Public License
00017  * along with this program; if not, write to the Free Software
00018  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
00019  */
00020 #include <config.h>
00021 #include <math.h>
00022 #include <string.h>
00023 #include <libgeda_priv.h>
00024 
00025 typedef struct st_sweep_event SWEEP_EVENT;
00026 typedef struct st_sweep_status SWEEP_STATUS;
00027 
00028 struct st_sweep_status {
00029   gint    x;     /* current x coordinate */
00030   gint    y1;    /* ending y coordinate  */
00031   gdouble m1;    /* inverse slope: y/x   */
00032   gdouble b1;    /* x intercept          */
00033 };
00034 
00035 struct st_sweep_event {
00036   gint         y0;        /* starting y coordinate */
00037   SWEEP_STATUS status;
00038 };
00039 
00040 static gint calculate_initial_sweep(gint pitch, gint min_y, gint max_y);
00041 static gint compare_events(gconstpointer a, gconstpointer b);
00042 static gint compare_status(gconstpointer a, gconstpointer b);
00043 
00056 static gint calculate_initial_sweep(gint pitch, gint min_y, gint max_y)
00057 {
00058   gint delta = max_y - min_y;
00059 
00060   return min_y + ((delta - ((delta - pitch) / pitch * pitch)) / 2);
00061 }
00062 
00074 static gint compare_events(gconstpointer a, gconstpointer b)
00075 {
00076   SWEEP_EVENT *event_a = (SWEEP_EVENT*) a;
00077   SWEEP_EVENT *event_b = (SWEEP_EVENT*) b;
00078 
00079   return (event_a->y0 - event_b->y0);
00080 }
00081 
00093 static gint compare_status(gconstpointer a, gconstpointer b)
00094 {
00095   SWEEP_STATUS *status_a = (SWEEP_STATUS*) a;
00096   SWEEP_STATUS *status_b = (SWEEP_STATUS*) b;
00097 
00098   return (status_b->x - status_a->x);
00099 }
00100 
00115 void m_hatch_box(BOX *box, gint angle, gint pitch, GArray *lines)
00116 {
00117   GArray *corners;
00118   sPOINT point;
00119 
00120   g_return_if_fail(box!=NULL);
00121   g_return_if_fail(lines!=NULL);
00122 
00123   corners = g_array_sized_new(FALSE, FALSE, sizeof(sPOINT), 4);
00124 
00125   point.x = box->upper_x;
00126   point.y = box->upper_y;
00127   g_array_append_val(corners, point);
00128 
00129   point.x = box->lower_x;
00130   point.y = box->upper_y;
00131   g_array_append_val(corners, point);
00132 
00133   point.x = box->lower_x;
00134   point.y = box->lower_y;
00135   g_array_append_val(corners, point);
00136 
00137   point.x = box->upper_x;
00138   point.y = box->lower_y;
00139   g_array_append_val(corners, point);
00140 
00141   m_hatch_polygon(corners, angle, pitch, lines);
00142 
00143   g_array_free(corners, TRUE);
00144 }
00145 
00160 void m_hatch_circle(CIRCLE *circle, gint angle, gint pitch, GArray *lines)
00161 {
00162   gint      radius;
00163   gint      sweep_y;
00164   TRANSFORM transform;
00165 
00166   g_return_if_fail(circle!=NULL);
00167   g_return_if_fail(lines!=NULL);
00168 
00169   m_transform_init(&transform);
00170   m_transform_rotate(&transform, angle);
00171   m_transform_scale(&transform, 0.01);
00172   m_transform_translate(&transform, circle->center_x, circle->center_y );
00173 
00174   radius = 100 * circle->radius;
00175   sweep_y = calculate_initial_sweep(100 * pitch, -radius, radius);
00176 
00177   while ( sweep_y < radius ) {
00178     LINE line;
00179     gint x = round(sqrt(pow(radius,2) - pow(sweep_y,2)));
00180 
00181     line.x[0] = -x;
00182     line.y[0] = sweep_y;
00183     line.x[1] = x;
00184     line.y[1] = sweep_y;
00185 
00186     m_transform_line(&transform, &line);
00187     g_array_append_val(lines, line);
00188 
00189     sweep_y += 100 * pitch;
00190   }
00191 }
00192 
00207 void m_hatch_path (PATH *path, gint angle, gint pitch, GArray *lines)
00208 {
00209   GArray *points;
00210 
00211   g_return_if_fail (path != NULL);
00212   g_return_if_fail (lines != NULL);
00213 
00214   points = g_array_new (FALSE, FALSE, sizeof (sPOINT));
00215 
00216   s_path_to_polygon (path, points);
00217   m_hatch_polygon (points, angle, pitch, lines);
00218 
00219   g_array_free (points, TRUE);
00220 }
00221 
00237 void m_hatch_polygon(GArray *points, gint angle, gint pitch, GArray *lines)
00238 {
00239   BOUNDS bounds;
00240   GArray *events;
00241   TRANSFORM inverse;
00242   GArray *points2;
00243   GArray *status;
00244   gint sweep_y;
00245   TRANSFORM transform;
00246 
00247   g_return_if_fail(points!=NULL);
00248   g_return_if_fail(pitch>0);
00249   g_return_if_fail(lines!=NULL);
00250 
00251   events = g_array_new(FALSE, FALSE, sizeof(SWEEP_EVENT));
00252   points2 = g_array_sized_new(FALSE, FALSE, sizeof(sPOINT), points->len);
00253   status = g_array_new(FALSE, FALSE, sizeof(SWEEP_STATUS));
00254 
00255   m_transform_init(&transform);
00256   m_transform_scale(&transform, 10);
00257   m_transform_rotate(&transform, -angle);
00258   m_transform_invert(&transform, &inverse);
00259 
00260   g_array_append_vals(points2, points->data, points->len);
00261   m_transform_points(&transform, points2);
00262 
00263   /* build list of sweep events */
00264   if ( points2->len > 1 ) {
00265     gint index;
00266     sPOINT *p0 = &g_array_index(points2, sPOINT, points2->len-1);
00267     for (index=0; index<points2->len; index++) {
00268       sPOINT *p1 = &g_array_index(points2, sPOINT, index);
00269       if ( p0->y != p1->y ) {
00270         SWEEP_EVENT event;
00271         event.y0 = min(p0->y, p1->y);
00272         event.status.y1 = max(p0->y, p1->y);
00273         event.status.m1 = (gdouble)( p1->x - p0->x ) / (gdouble)( p1->y - p0->y );
00274         event.status.b1 = p0->x - event.status.m1 * p0->y;
00275         g_array_append_val(events, event);
00276       }
00277       p0 = p1;
00278     }
00279   }
00280 
00281   /* sort sweep events in ascending order by starting y coordinate */
00282   g_array_sort(events, compare_events);
00283 
00284   m_bounds_of_points(&bounds, (sPOINT*)points2->data, points2->len);
00285   sweep_y = calculate_initial_sweep(10 * pitch, bounds.min_y, bounds.max_y);
00286 
00287   while ( events->len > 0 || status->len > 0 ) {
00288     gint index;
00289 
00290     /* add new segments that intersect the sweep line */
00291     index = 0;
00292     while ( index < events->len ) {
00293       SWEEP_EVENT *event = &g_array_index(events, SWEEP_EVENT, index);
00294       if ( sweep_y >= event->y0 ) {
00295         SWEEP_STATUS st = event->status;
00296         g_array_append_val(status, st);
00297         g_array_remove_index(events, index);
00298       } else {
00299         index++;
00300       }
00301     }
00302 
00303     /* remove status no longer intersecting sweep line */
00304     index = status->len;
00305     while ( index-- > 0 ) {
00306       if ( sweep_y >= g_array_index(status, SWEEP_STATUS, index).y1 ) {
00307         g_array_remove_index_fast(status, index);
00308       }
00309     }
00310 
00311     /* (re)calculate x coordinates at sweep line */
00312     for (index=0; index<status->len; index++) {
00313       SWEEP_STATUS *st = &g_array_index(status, SWEEP_STATUS, index);
00314       st->x = st->m1 * sweep_y + st->b1;
00315     }
00316 
00317     /* sort the sweep status in ascending order by x coordinate */
00318     g_array_sort(status, compare_status);
00319 
00320     /* draw hatch segments */
00321     index = 0;
00322     while ( index+1 < status->len ) {
00323       LINE line;
00324       line.x[0] = g_array_index(status, SWEEP_STATUS, index ).x;
00325       line.y[0] = sweep_y;
00326       line.x[1] = g_array_index(status, SWEEP_STATUS, index+1 ).x;
00327       line.y[1] = sweep_y;
00328       m_transform_line(&inverse, &line);
00329       g_array_append_val(lines, line);
00330       index += 2;
00331     }
00332 
00333     sweep_y += 10 * pitch;
00334   }
00335 
00336   g_array_free(events, TRUE);
00337   g_array_free(points2, TRUE);
00338   g_array_free(status, TRUE);
00339 }
00340 
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines