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 
21 /*! \file o_bus_basic.c
22  *  \brief functions for the bus object
23  */
24 
25 #include <config.h>
26 #include <stdio.h>
27 #include <math.h>
28 
29 #include "libgeda_priv.h"
30 
31 #ifdef HAVE_LIBDMALLOC
32 #include <dmalloc.h>
33 #endif
34 
35 /*! \brief get the position of the first bus point
36  *  \par Function Description
37  *  This function gets the position of the first point of a bus object.
38  *
39  *  \param [in] toplevel The toplevel environment.
40  *  \param [out] x       pointer to the x-position
41  *  \param [out] y       pointer to the y-position
42  *  \param [in] object   The object to get the position.
43  *  \return TRUE if successfully determined the position, FALSE otherwise
44  */
o_bus_get_position(TOPLEVEL * toplevel,gint * x,gint * y,OBJECT * object)45 gboolean o_bus_get_position (TOPLEVEL *toplevel, gint *x, gint *y,
46                               OBJECT *object)
47 {
48   return o_line_get_position(toplevel, x, y, object);
49 }
50 
51 /*! \brief calculate and return the boundaries of a bus object
52  *  \par Function Description
53  *  This function calculates the object boudaries of a bus \a object.
54  *
55  *  \param [in]  toplevel  The TOPLEVEL object.
56  *  \param [in]  object    a bus object
57  *  \param [out] left      the left world coord
58  *  \param [out] top       the top world coord
59  *  \param [out] right     the right world coord
60  *  \param [out] bottom    the bottom world coord
61  */
world_get_bus_bounds(TOPLEVEL * toplevel,OBJECT * object,int * left,int * top,int * right,int * bottom)62 void world_get_bus_bounds(TOPLEVEL *toplevel, OBJECT *object, int *left, int *top,
63 			  int *right, int *bottom)
64 {
65   world_get_line_bounds( toplevel, object, left, top, right, bottom );
66 }
67 
68 /*! \brief create a new bus object
69  *  \par Function Description
70  *  This function creates and returns a new bus object.
71  *
72  *  \param [in]     toplevel    The TOPLEVEL object.
73  *  \param [in]     type        The OBJECT type (usually OBJ_BUS)
74  *  \param [in]     color       The color of the bus
75  *  \param [in]     x1          x-coord of the first point
76  *  \param [in]     y1          y-coord of the first point
77  *  \param [in]     x2          x-coord of the second point
78  *  \param [in]     y2          y-coord of the second point
79  *  \param [in]  bus_ripper_direction direction of the bus rippers
80  *  \return A new bus OBJECT
81  */
o_bus_new(TOPLEVEL * toplevel,char type,int color,int x1,int y1,int x2,int y2,int bus_ripper_direction)82 OBJECT *o_bus_new(TOPLEVEL *toplevel,
83 		  char type, int color,
84 		  int x1, int y1, int x2, int y2,
85 		  int bus_ripper_direction)
86 {
87   OBJECT *new_node;
88 
89   new_node = s_basic_new_object(type, "bus");
90   new_node->color = color;
91 
92   new_node->line = (LINE *) g_malloc(sizeof(LINE));
93   /* check for null */
94 
95   new_node->line->x[0] = x1;
96   new_node->line->y[0] = y1;
97   new_node->line->x[1] = x2;
98   new_node->line->y[1] = y2;
99   new_node->line_width = BUS_WIDTH;
100 
101   new_node->bus_ripper_direction = bus_ripper_direction;
102 
103   o_bus_recalc (toplevel, new_node);
104 
105   return new_node;
106 }
107 
108 /*! \brief recalc the visual properties of a bus object
109  *  \par Function Description
110  *  This function updates the visual coords of the \a o_current object.
111  *
112  *  \param [in]     toplevel    The TOPLEVEL object.
113  *  \param [in]     o_current   a bus object.
114  */
o_bus_recalc(TOPLEVEL * toplevel,OBJECT * o_current)115 void o_bus_recalc(TOPLEVEL *toplevel, OBJECT *o_current)
116 {
117   int left, right, top, bottom;
118 
119   if (o_current == NULL) {
120     return;
121   }
122 
123   if (o_current->line == NULL) {
124     return;
125   }
126 
127   world_get_bus_bounds(toplevel, o_current, &left, &top, &right, &bottom);
128 
129   o_current->w_left = left;
130   o_current->w_top = top;
131   o_current->w_right = right;
132   o_current->w_bottom = bottom;
133   o_current->w_bounds_valid = TRUE;
134 }
135 
136 /*! \brief read a bus object from a char buffer
137  *  \par Function Description
138  *  This function reads a bus object from the buffer \a buf.
139  *  If the bus object was read successfully, a new bus object is
140  *  allocated and appended to the \a object_list.
141  *
142  *  \param [in] toplevel     The TOPLEVEL object
143  *  \param [in] buf          a text buffer (usually a line of a schematic file)
144  *  \param [in] release_ver  The release number gEDA
145  *  \param [in] fileformat_ver a integer value of the file format
146  *  \return The object list, or NULL on error.
147  */
o_bus_read(TOPLEVEL * toplevel,const char buf[],unsigned int release_ver,unsigned int fileformat_ver,GError ** err)148 OBJECT *o_bus_read (TOPLEVEL *toplevel, const char buf[],
149                     unsigned int release_ver, unsigned int fileformat_ver, GError **err)
150 {
151   OBJECT *new_obj;
152   char type;
153   int x1, y1;
154   int x2, y2;
155   int color;
156   int ripper_dir;
157 
158   if (release_ver <= VERSION_20020825) {
159     if (sscanf (buf, "%c %d %d %d %d %d\n", &type, &x1, &y1, &x2, &y2, &color) != 6) {
160       g_set_error(err, EDA_ERROR, EDA_ERROR_PARSE, _("Failed to parse bus object"));
161       return NULL;
162     }
163     ripper_dir = 0;
164   } else {
165     if (sscanf (buf, "%c %d %d %d %d %d %d\n", &type, &x1, &y1, &x2, &y2, &color,
166 		&ripper_dir) != 7) {
167       g_set_error(err, EDA_ERROR, EDA_ERROR_PARSE, _("Failed to parse bus object"));
168       return NULL;
169     }
170   }
171 
172   if (x1 == x2 && y1 == y2) {
173     s_log_message (_("Found a zero length bus [ %c %d %d %d %d %d ]\n"),
174                     type, x1, y1, x2, y2, color);
175   }
176 
177   if (toplevel->override_bus_color != -1) {
178     color = toplevel->override_bus_color;
179   }
180 
181   if (color < 0 || color > MAX_COLORS) {
182     s_log_message (_("Found an invalid color [ %s ]\n"), buf);
183     s_log_message (_("Setting color to default color\n"));
184     color = DEFAULT_COLOR;
185   }
186 
187   if (ripper_dir < -1 || ripper_dir > 1) {
188     s_log_message (_("Found an invalid bus ripper direction [ %s ]\n"), buf);
189     s_log_message (_("Resetting direction to neutral (no direction)\n"));
190     ripper_dir = 0;
191   }
192 
193   new_obj = o_bus_new (toplevel, type, color, x1, y1, x2, y2, ripper_dir);
194 
195   return new_obj;
196 }
197 
198 /*! \brief Create a string representation of the bus object
199  *  \par Function Description
200  *  This function takes a bus \a object and return a string
201  *  according to the file format definition.
202  *
203  *  \param [in] toplevel  a TOPLEVEL structure
204  *  \param [in] object  a bus OBJECT
205  *  \return the string representation of the bus OBJECT
206  */
o_bus_save(TOPLEVEL * toplevel,OBJECT * object)207 char *o_bus_save(TOPLEVEL *toplevel, OBJECT *object)
208 {
209   int x1, x2, y1, y2;
210   char *buf;
211 
212   x1 = object->line->x[0];
213   y1 = object->line->y[0];
214   x2 = object->line->x[1];
215   y2 = object->line->y[1];
216 
217   buf = g_strdup_printf("%c %d %d %d %d %d %d", object->type,
218           x1, y1, x2, y2, object->color, object->bus_ripper_direction);
219   return(buf);
220 }
221 
222 /*! \brief move a bus object
223  *  \par Function Description
224  *  This function changes the position of a bus \a object.
225  *
226  *  \param [in] toplevel     The TOPLEVEL object
227  *  \param [in] dx           The x-distance to move the object
228  *  \param [in] dy           The y-distance to move the object
229  *  \param [in] object       The bus OBJECT to be moved
230  */
o_bus_translate_world(TOPLEVEL * toplevel,int dx,int dy,OBJECT * object)231 void o_bus_translate_world(TOPLEVEL *toplevel, int dx, int dy, OBJECT *object)
232 {
233   /* Update world coords */
234   object->line->x[0] = object->line->x[0] + dx;
235   object->line->y[0] = object->line->y[0] + dy;
236   object->line->x[1] = object->line->x[1] + dx;
237   object->line->y[1] = object->line->y[1] + dy;
238 
239   /* Update bounding box */
240   o_bus_recalc (toplevel, object);
241 
242   s_tile_update_object(toplevel, object);
243 }
244 
245 /*! \brief create a copy of a bus object
246  *  \par Function Description
247  *  This function creates a copy of the bus object \a o_current.
248  *
249  *  \param [in] toplevel     The TOPLEVEL object
250  *  \param [in] o_current    The object that is copied
251  *  \return a new bus object
252  */
o_bus_copy(TOPLEVEL * toplevel,OBJECT * o_current)253 OBJECT *o_bus_copy(TOPLEVEL *toplevel, OBJECT *o_current)
254 {
255   OBJECT *new_obj;
256 
257   /* make sure you fix this in pin and bus as well */
258   /* still doesn't work... you need to pass in the new values */
259   /* or don't update and update later */
260   /* I think for now I'll disable the update and manually update */
261   new_obj = o_bus_new (toplevel, OBJ_BUS, o_current->color,
262                        o_current->line->x[0], o_current->line->y[0],
263                        o_current->line->x[1], o_current->line->y[1],
264                        o_current->bus_ripper_direction);
265 
266   return new_obj;
267 }
268 
269 /*! \brief postscript print command for a bus object
270  *  \par Function Description
271  *  This function writes the postscript command of the bus object \a o_current
272  *  into the FILE \a fp points to.
273  *
274  *  \param [in] toplevel     The TOPLEVEL object
275  *  \param [in] fp           pointer to a FILE structure
276  *  \param [in] o_current    The OBJECT to print
277  *  \param [in] origin_x     x-coord of the postscript origin
278  *  \param [in] origin_y     y-coord of the postscript origin
279  */
o_bus_print(TOPLEVEL * toplevel,FILE * fp,OBJECT * o_current,int origin_x,int origin_y)280 void o_bus_print(TOPLEVEL *toplevel, FILE *fp, OBJECT *o_current,
281 		 int origin_x, int origin_y)
282 {
283   int bus_width;
284   int x1, y1;
285   int x2, y2;
286 
287   if (o_current == NULL) {
288     printf("got null in o_bus_print\n");
289     return;
290   }
291 
292   f_print_set_color(toplevel, fp, o_current->color);
293 
294   bus_width = 2;
295   if (toplevel->bus_style == THICK) {
296     bus_width = BUS_WIDTH;
297   }
298 
299   x1 = o_current->line->x[0]-origin_x,
300   y1 = o_current->line->y[0]-origin_y;
301   x2 = o_current->line->x[1]-origin_x,
302   y2 = o_current->line->y[1]-origin_y;
303 
304   fprintf(fp, "%d %d %d %d %d line\n",
305 	  x1,y1,x2,y2,bus_width);
306 
307 }
308 
309 
310 /*! \brief rotate a bus object around a centerpoint
311  *  \par Function Description
312  *  This function rotates a bus \a object around the point
313  *  (\a world_centerx, \a world_centery).
314  *
315  *  \param [in] toplevel      The TOPLEVEL object
316  *  \param [in] world_centerx x-coord of the rotation center
317  *  \param [in] world_centery y-coord of the rotation center
318  *  \param [in] angle         The angle to rotat the bus object
319  *  \param [in] object        The bus object
320  *  \note only steps of 90 degrees are allowed for the \a angle
321  */
o_bus_rotate_world(TOPLEVEL * toplevel,int world_centerx,int world_centery,int angle,OBJECT * object)322 void o_bus_rotate_world(TOPLEVEL *toplevel,
323 			int world_centerx, int world_centery, int angle,
324 			OBJECT *object)
325 {
326   int newx, newy;
327 
328   if (angle == 0)
329   return;
330 
331   /* translate object to origin */
332   o_bus_translate_world(toplevel, -world_centerx, -world_centery, object);
333 
334   rotate_point_90(object->line->x[0], object->line->y[0], angle,
335                   &newx, &newy);
336 
337   object->line->x[0] = newx;
338   object->line->y[0] = newy;
339 
340   rotate_point_90(object->line->x[1], object->line->y[1], angle,
341                   &newx, &newy);
342 
343   object->line->x[1] = newx;
344   object->line->y[1] = newy;
345 
346   o_bus_translate_world(toplevel, world_centerx, world_centery, object);
347 }
348 
349 /*! \brief mirror a bus object horizontaly at a centerpoint
350  *  \par Function Description
351  *  This function mirrors a bus \a object horizontaly at the point
352  *  (\a world_centerx, \a world_centery).
353  *
354  *  \param [in] toplevel      The TOPLEVEL object
355  *  \param [in] world_centerx x-coord of the mirror position
356  *  \param [in] world_centery y-coord of the mirror position
357  *  \param [in] object        The bus object
358  */
o_bus_mirror_world(TOPLEVEL * toplevel,int world_centerx,int world_centery,OBJECT * object)359 void o_bus_mirror_world(TOPLEVEL *toplevel,
360 			int world_centerx, int world_centery, OBJECT *object)
361 {
362   /* translate object to origin */
363   o_bus_translate_world(toplevel, -world_centerx, -world_centery, object);
364 
365   object->line->x[0] = -object->line->x[0];
366 
367   object->line->x[1] = -object->line->x[1];
368 
369   o_bus_translate_world(toplevel, world_centerx, world_centery, object);
370 }
371 
372 /*! \brief calculate the orientation of a bus object
373  *  \par Function Description
374  *  This function calculates the orientation of a bus object.
375  *
376  *  \param [in] object   The bus object
377  *  \return The orientation: HORIZONTAL, VERTICAL or NEITHER
378  */
o_bus_orientation(OBJECT * object)379 int o_bus_orientation(OBJECT *object)
380 {
381   if (object->line->y[0] == object->line->y[1]) {
382     return(HORIZONTAL);
383   }
384 
385   if (object->line->x[0] == object->line->x[1]) {
386     return(VERTICAL);
387   }
388 
389   return(NEITHER);
390 }
391 
392 
393 /* \brief
394  * \par Function Description
395  * This function does the actual work of making one bus segment out of two
396  * connected segments.
397  * The second object (del_object) is the object that should be deleted.
398  *
399  * \todo This function is currently not used. Check it before using it
400  */
o_bus_consolidate_lowlevel(OBJECT * object,OBJECT * del_object,int orient)401 static void o_bus_consolidate_lowlevel (OBJECT *object,
402                                         OBJECT *del_object, int orient)
403 {
404   int temp1, temp2;
405   int final1, final2;
406   int changed=0;
407   GList *a_iter;
408   OBJECT *a_current;
409 
410 #if DEBUG
411   printf("o %d %d %d %d\n", object->line->x[0], object->line->y[0], object->line->x[1], object->line->y[1]);
412   printf("d %d %d %d %d\n", del_object->line->x[0], del_object->line->y[0], del_object->line->x[1], del_object->line->y[1]);
413 #endif
414 
415 
416   if (orient == HORIZONTAL) {
417 
418     temp1 = min(object->line->x[0],
419                 del_object->line->x[0]);
420     temp2 = min(object->line->x[1],
421                 del_object->line->x[1]);
422 
423     final1 = min(temp1, temp2);
424 
425     temp1 = max(object->line->x[0],
426                 del_object->line->x[0]);
427     temp2 = max(object->line->x[1],
428                 del_object->line->x[1]);
429 
430     final2 = max(temp1, temp2);
431 
432     object->line->x[0] = final1;
433     object->line->x[1] = final2;
434     changed=1;
435   }
436 
437   if (orient == VERTICAL) {
438     temp1 = min(object->line->y[0],
439                 del_object->line->y[0]);
440     temp2 = min(object->line->y[1],
441                 del_object->line->y[1]);
442 
443     final1 = min(temp1, temp2);
444 
445     temp1 = max(object->line->y[0],
446                 del_object->line->y[0]);
447     temp2 = max(object->line->y[1],
448                 del_object->line->y[1]);
449 
450     final2 = max(temp1, temp2);
451 
452     object->line->y[0] = final1;
453     object->line->y[1] = final2;
454     changed=1;
455   }
456 
457 #if DEBUG
458   printf("fo %d %d %d %d\n", object->line->x[0], object->line->y[0], object->line->x[1], object->line->y[1]);
459 #endif
460 
461   /* Move any attributes from the deleted object*/
462   if (changed && del_object->attribs != NULL) {
463 
464     /* Reassign the attached_to pointer on attributes from the del object */
465     a_iter = del_object->attribs;
466     while (a_iter != NULL) {
467       a_current = a_iter->data;
468       a_current->attached_to = object;
469       a_iter = g_list_next (a_iter);
470     }
471 
472     object->attribs = g_list_concat (object->attribs, del_object->attribs);
473 
474     /* Don't free del_object->attribs as it's relinked into object's list */
475     del_object->attribs = NULL;
476   }
477 }
478 
479 /* \brief
480  * \par Function Description
481  *
482  * \todo Not Implemented Yet
483  */
o_bus_consolidate_segments(TOPLEVEL * toplevel,OBJECT * object)484 static int o_bus_consolidate_segments (TOPLEVEL *toplevel, OBJECT *object)
485 {
486 
487   return(0);
488 }
489 
490 /* \brief
491  * \par Function Description
492  *
493  * \todo Not Implemented Yet
494  */
o_bus_consolidate(TOPLEVEL * toplevel)495 void o_bus_consolidate(TOPLEVEL *toplevel)
496 {
497 
498 }
499 
500 /*! \brief modify one point of a bus object
501  *  \par Function Description
502  *  This function modifies one point of a bus \a object. The point
503  *  is specified by the \a whichone variable and the new coordinate
504  *  is (\a x, \a y).
505  *
506  *  \param toplevel   The TOPLEVEL object
507  *  \param object     The bus OBJECT to modify
508  *  \param x          new x-coord of the bus point
509  *  \param y          new y-coord of the bus point
510  *  \param whichone   bus point to modify
511  */
o_bus_modify(TOPLEVEL * toplevel,OBJECT * object,int x,int y,int whichone)512 void o_bus_modify(TOPLEVEL *toplevel, OBJECT *object,
513 		  int x, int y, int whichone)
514 {
515   object->line->x[whichone] = x;
516   object->line->y[whichone] = y;
517 
518   o_bus_recalc (toplevel, object);
519 
520   s_tile_update_object(toplevel, object);
521 }
522 
523 
524