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