1 /* gEDA - GPL Electronic Design Automation
2  * libgeda - gEDA's library
3  * Copyright (C) 1998-2010 Ales Hvezda
4  * Copyright (C) 1998-2010 gEDA Contributors (see ChangeLog for details)
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19  */
20 #include <config.h>
21 
22 #include <stdio.h>
23 #include <ctype.h>
24 #ifdef HAVE_STDLIB_H
25 #include <stdlib.h>
26 #endif
27 
28 #include <math.h>
29 
30 #include "libgeda_priv.h"
31 
32 #ifdef HAVE_LIBDMALLOC
33 #include <dmalloc.h>
34 #endif
35 
36 /*! \todo Finish function documentation!!!
37  *  \brief
38  *  \par Function Description
39  *
40  */
s_cue_postscript_fillbox(TOPLEVEL * toplevel,FILE * fp,int x,int y)41 void s_cue_postscript_fillbox(TOPLEVEL * toplevel, FILE * fp, int x,
42 			      int y)
43 {
44   int offset;
45   int offset2;
46 
47   /* hard coded values */
48   offset = CUE_BOX_SIZE;
49   offset2 = offset*2;
50 
51   f_print_set_color(toplevel, fp, NET_ENDPOINT_COLOR);
52 
53   fprintf(fp, "%d %d %d %d fbox\n",
54 	   offset2, offset2, x-offset, y-offset);
55 }
56 
57 /*! \todo Finish function documentation!!!
58  *  \brief
59  *  \par Function Description
60  *
61  */
s_cue_postscript_junction(TOPLEVEL * toplevel,FILE * fp,int x,int y,int bus_involved)62 void s_cue_postscript_junction (TOPLEVEL * toplevel, FILE * fp,
63                                 int x, int y, int bus_involved)
64 {
65   int offset2;
66 
67   if (bus_involved) {
68     offset2 = JUNCTION_CUE_SIZE_BUS;
69   } else {
70     offset2 = JUNCTION_CUE_SIZE_NET;
71   }
72 
73   f_print_set_color(toplevel, fp, JUNCTION_COLOR);
74 
75   fprintf(fp, "newpath\n");
76   fprintf(fp, "%d %d\n", x, y);
77   fprintf(fp, "%d\n", offset2 / 2);
78   fprintf(fp, "0 360 arc\n");
79   fprintf(fp, "fill\n");
80 }
81 
82 /*! \brief Draw an arrow at the end of a net.
83  */
84 void
s_cue_postscript_arrow(TOPLEVEL * toplevel,FILE * fp,int x,int y,int dx,int dy)85 s_cue_postscript_arrow (TOPLEVEL *toplevel, FILE *fp,
86                         int x, int y, int dx, int dy)
87 {
88   int offset = CUE_BOX_SIZE;
89 
90   f_print_set_color (toplevel, fp, JUNCTION_COLOR);
91 
92   fprintf (fp, "gsave\n");
93 
94   /* We compute a transformation so that the arrowhead is aligned with
95    * the net segment. */
96   double len = hypot (dx, dy);
97   if (len != 0) {
98     double c = dx / len;
99     double s = dy / len;
100     fprintf (fp, "[ %.2f %.2f %.2f %.2f %d %d ] concat\n", c, -s, s, c, x, y);
101   } else {
102     fprintf (fp, "%d %d translate\n", x, y); /* Translate to centre point of the arrow */
103   }
104 
105   /* Now draw a simple arrowhead */
106   fprintf (fp, "newpath\n");
107   fprintf (fp, "%d %d moveto\n", -offset, -offset);
108   fprintf (fp, "%d %d lineto\n", -offset, offset);
109   fprintf (fp, "%d %d lineto\n", offset, 0);
110   fprintf (fp, "closepath\n"
111                "fill\n"
112                "grestore\n");
113 }
114 
115 /*! \todo Finish function documentation!!!
116  *  \brief
117  *  \par Function Description
118  *
119  */
s_cue_output_all(TOPLEVEL * toplevel,const GList * obj_list,FILE * fp,int type)120 void s_cue_output_all (TOPLEVEL * toplevel, const GList *obj_list, FILE * fp,
121                        int type)
122 {
123   OBJECT *o_current;
124   const GList *iter;
125 
126   iter = obj_list;
127   while (iter != NULL) {
128     o_current = (OBJECT *)iter->data;
129     switch (o_current->type) {
130       case (OBJ_NET):
131       case (OBJ_BUS):
132       case (OBJ_PIN):
133         s_cue_output_single(toplevel, o_current, fp, type);
134         break;
135 
136       case (OBJ_COMPLEX):
137       case (OBJ_PLACEHOLDER):
138         s_cue_output_all(toplevel, o_current->complex->prim_objs, fp,
139                          type);
140         break;
141 
142     }
143     iter = g_list_next (iter);
144   }
145 }
146 
147 /*! \todo Finish function documentation!!!
148  *  \brief
149  *  \par Function Description
150  *
151  */
s_cue_output_lowlevel(TOPLEVEL * toplevel,OBJECT * object,int whichone,FILE * fp,int output_type)152 void s_cue_output_lowlevel(TOPLEVEL * toplevel, OBJECT * object, int whichone,
153 			   FILE * fp, int output_type)
154 {
155   int x, y;
156   GList *cl_current;
157   CONN *conn;
158   int type, count = 0;
159   int done = FALSE;
160   int bus_involved = FALSE;
161 
162   x = object->line->x[whichone];
163   y = object->line->y[whichone];
164 
165   type = CONN_ENDPOINT;
166 
167   if (object->type == OBJ_BUS ||
168        (object->type == OBJ_PIN && object->pin_type == PIN_TYPE_BUS))
169     bus_involved = TRUE;
170 
171   cl_current = object->conn_list;
172   while (cl_current != NULL && !done) {
173     conn = (CONN *) cl_current->data;
174 
175     if (conn->x == x && conn->y == y) {
176 
177       if (conn->other_object &&
178            (conn->other_object->type == OBJ_BUS ||
179              (conn->other_object->type == OBJ_PIN &&
180               conn->other_object->pin_type == PIN_TYPE_BUS)))
181         bus_involved=TRUE;
182 
183       switch (conn->type) {
184 
185         case (CONN_ENDPOINT):
186           count++;
187           break;
188 
189         case (CONN_MIDPOINT):
190           type = CONN_MIDPOINT;
191           done = TRUE;
192           count = 0;
193           break;
194       }
195     }
196 
197     cl_current = g_list_next(cl_current);
198   }
199 
200 #if DEBUG
201   printf("type: %d count: %d\n", type, count);
202 #endif
203 
204   switch (type) {
205 
206     case (CONN_ENDPOINT):
207       if (object->type == OBJ_NET || object->type == OBJ_PIN) {
208         if (count < 1) {	/* Didn't find anything connected there */
209           if ((object->type == OBJ_NET)
210               && o_net_is_fully_connected (toplevel, object)) {
211             /* Probably connected, so draw friendly arrowhead. The
212              * additional parameters are needed to allow the arrowhead
213              * to be pointed in the direction of the net. */
214             if (output_type == POSTSCRIPT) {
215               s_cue_postscript_arrow (toplevel, fp, x, y,
216                                       object->line->x[whichone] - object->line->x[!whichone],
217                                       object->line->y[whichone] - object->line->y[!whichone]);
218             }
219           } else {
220             s_cue_postscript_fillbox (toplevel, fp, x, y);
221           }
222         } else if (count >= 2) {
223           if (output_type == POSTSCRIPT)
224             s_cue_postscript_junction (toplevel, fp, x, y, bus_involved);
225         }
226       }
227       break;
228 
229     case (CONN_MIDPOINT):
230       if (output_type == POSTSCRIPT)
231         s_cue_postscript_junction (toplevel, fp, x, y, bus_involved);
232       break;
233   }
234 
235 }
236 
237 /*! \todo Finish function documentation!!!
238  *  \brief
239  *  \par Function Description
240  *
241  */
s_cue_output_lowlevel_midpoints(TOPLEVEL * toplevel,OBJECT * object,FILE * fp,int output_type)242 void s_cue_output_lowlevel_midpoints(TOPLEVEL * toplevel, OBJECT * object,
243 				     FILE * fp, int output_type)
244 {
245   int x, y;
246   GList *cl_current;
247   CONN *conn;
248   int bus_involved = FALSE;
249 
250   if (object->type == OBJ_BUS)
251     bus_involved = TRUE;
252 
253   cl_current = object->conn_list;
254   while (cl_current != NULL) {
255     conn = (CONN *) cl_current->data;
256 
257     switch (conn->type) {
258       case (CONN_MIDPOINT):
259 
260         x = conn->x;
261         y = conn->y;
262 
263         if (conn->other_object && conn->other_object->type == OBJ_BUS)
264           bus_involved = TRUE;
265 
266         if (output_type == POSTSCRIPT) {
267           s_cue_postscript_junction (toplevel, fp, x, y, bus_involved);
268         }
269         break;
270     }
271 
272 
273     cl_current = g_list_next(cl_current);
274   }
275 }
276 
277 /*! \brief Output cues for a single object
278  *
279  *  \par Function Description
280  *  Cues are drawn on pins, nets and buses.
281  *  Two types of cues are drawn:
282  *   - endpoint cues (identifying unconnected ends of objects)
283  *   - junction cues (identifying net/pin/bus junctions)
284  *
285  *  \param [in] toplevel   The TOPLEVEL object
286  *  \param [in] object     The OBJECT to output cues for
287  *  \param [in] fp         The file handle to output to
288  *  \param [in] type       The type of output being produced
289  */
s_cue_output_single(TOPLEVEL * toplevel,OBJECT * object,FILE * fp,int type)290 void s_cue_output_single(TOPLEVEL * toplevel, OBJECT * object, FILE * fp,
291 			 int type)
292 {
293   g_return_if_fail (object != NULL);
294 
295   switch (object->type) {
296     case (OBJ_NET):
297       s_cue_output_lowlevel(toplevel, object, 0, fp, type);
298       s_cue_output_lowlevel(toplevel, object, 1, fp, type);
299       break;
300     case (OBJ_BUS):
301       s_cue_output_lowlevel(toplevel, object, 0, fp, type);
302       s_cue_output_lowlevel(toplevel, object, 1, fp, type);
303       break;
304     case (OBJ_PIN):
305       s_cue_output_lowlevel(toplevel, object, object->whichend, fp, type);
306       break;
307     default:
308       return;
309   }
310   s_cue_output_lowlevel_midpoints(toplevel, object, fp, type);
311 }
312 
313 
314 
315