1 /* Lepton EDA library
2 * Copyright (C) 1998-2010 Ales Hvezda
3 * Copyright (C) 1998-2016 gEDA Contributors
4 * Copyright (C) 2017-2021 Lepton EDA Contributors
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 lepton_bus_object.c
22 *
23 * \brief Functions operating on bus objects
24 */
25
26 #include <config.h>
27
28 #ifdef HAVE_MATH_H
29 #include <math.h>
30 #endif
31
32 #include "liblepton_priv.h"
33
34 /*! \brief Get the ripper direction
35 *
36 * \param [in] object The bus object
37 * \return The ripper direction
38 */
39 gint
lepton_bus_object_get_ripper_direction(const LeptonObject * object)40 lepton_bus_object_get_ripper_direction (const LeptonObject *object)
41 {
42 g_return_val_if_fail (lepton_object_is_bus (object), 0);
43 g_return_val_if_fail (object->bus_ripper_direction >= -1, -1);
44 g_return_val_if_fail (object->bus_ripper_direction <= 1, 1);
45
46 return object->bus_ripper_direction;
47 }
48
49 /*! \brief Get the x coordinate of first endpoint
50 *
51 * The coordinate properties are broken out individually to make it easier for
52 * the GUI. This way, the GUI does not need as many adapters to interface to
53 * a line boxed type.
54 *
55 * \param [in] object The line
56 * \return The x coordinate for the first endpoint
57 */
58 gint
lepton_bus_object_get_x0(const LeptonObject * object)59 lepton_bus_object_get_x0 (const LeptonObject *object)
60 {
61 g_return_val_if_fail (lepton_object_is_bus (object), 0);
62 g_return_val_if_fail (object->line != NULL, 0);
63
64 return object->line->x[0];
65 }
66
67 /*! \brief Get the x coordinate of second endpoint
68 *
69 * The coordinate properties are broken out individually to make it easier for
70 * the GUI. This way, the GUI does not need as many adapters to interface to
71 * a line boxed type.
72 *
73 * \param [in] object The line
74 * \return The x coordinate for the second endpoint
75 */
76 gint
lepton_bus_object_get_x1(const LeptonObject * object)77 lepton_bus_object_get_x1 (const LeptonObject *object)
78 {
79 g_return_val_if_fail (lepton_object_is_bus (object), 0);
80 g_return_val_if_fail (object->line != NULL, 0);
81
82 return object->line->x[1];
83 }
84
85 /*! \brief Get the y coordinate of first endpoint
86 *
87 * The coordinate properties are broken out individually to make it easier for
88 * the GUI. This way, the GUI does not need as many adapters to interface to
89 * a line boxed type.
90 *
91 * \param [in] object The line
92 * \return The y coordinate for the first endpoint
93 */
94 gint
lepton_bus_object_get_y0(const LeptonObject * object)95 lepton_bus_object_get_y0 (const LeptonObject *object)
96 {
97 g_return_val_if_fail (lepton_object_is_bus (object), 0);
98 g_return_val_if_fail (object->line != NULL, 0);
99
100 return object->line->y[0];
101 }
102
103 /*! \brief Get the y coordinate of second endpoint
104 *
105 * The coordinate properties are broken out individually to make it easier for
106 * the GUI. This way, the GUI does not need as many adapters to interface to
107 * a line boxed type.
108 *
109 * \param [in] object The line
110 * \return The y coordinate for the second endpoint
111 */
112 gint
lepton_bus_object_get_y1(const LeptonObject * object)113 lepton_bus_object_get_y1 (const LeptonObject *object)
114 {
115 g_return_val_if_fail (lepton_object_is_bus (object), 0);
116 g_return_val_if_fail (object->line != NULL, 0);
117
118 return object->line->y[1];
119 }
120
121 /*! \brief Set the ripper direction
122 *
123 * \param [in,out] object The bus object
124 * \param [in] direction The ripper direction
125 */
126 void
lepton_bus_object_set_ripper_direction(LeptonObject * object,gint direction)127 lepton_bus_object_set_ripper_direction (LeptonObject *object,
128 gint direction)
129 {
130 g_return_if_fail (lepton_object_is_bus (object));
131 g_return_if_fail (direction >= -1);
132 g_return_if_fail (direction <= 1);
133
134 object->bus_ripper_direction = direction;
135 }
136
137 /*! \brief Set the x coordinate of first endpoint
138 *
139 * The coordinate properties are broken out individually to make it easier for
140 * the GUI. This way, the GUI does not need as many adapters to interface to
141 * a line boxed type.
142 *
143 * \param [in,out] object The line
144 * \param [in] x The new x coordinate for the first endpoint
145 */
146 void
lepton_bus_object_set_x0(LeptonObject * object,gint x)147 lepton_bus_object_set_x0 (LeptonObject *object,
148 gint x)
149 {
150 g_return_if_fail (lepton_object_is_bus (object));
151 g_return_if_fail (object->line != NULL);
152
153 object->line->x[0] = x;
154 }
155
156 /*! \brief Set the x coordinate of second endpoint
157 *
158 * The coordinate properties are broken out individually to make it easier for
159 * the GUI. This way, the GUI does not need as many adapters to interface to
160 * a line boxed type.
161 *
162 * \param [in,out] object The line
163 * \param [in] x The new x coordinate for the second endpoint
164 */
165 void
lepton_bus_object_set_x1(LeptonObject * object,gint x)166 lepton_bus_object_set_x1 (LeptonObject *object,
167 gint x)
168 {
169 g_return_if_fail (lepton_object_is_bus (object));
170 g_return_if_fail (object->line != NULL);
171
172 object->line->x[1] = x;
173 }
174
175 /*! \brief Set the y coordinate of first endpoint
176 *
177 * The coordinate properties are broken out individually to make it easier for
178 * the GUI. This way, the GUI does not need as many adapters to interface to
179 * a line boxed type.
180 *
181 * \param [in,out] object The line
182 * \param [in] y The new y coordinate for the first endpoint
183 */
184 void
lepton_bus_object_set_y0(LeptonObject * object,gint y)185 lepton_bus_object_set_y0 (LeptonObject *object,
186 gint y)
187 {
188 g_return_if_fail (lepton_object_is_bus (object));
189 g_return_if_fail (object->line != NULL);
190
191 object->line->y[0] = y;
192 }
193
194 /*! \brief Set the y coordinate of second endpoint
195 *
196 * The coordinate properties are broken out individually to make it easier for
197 * the GUI. This way, the GUI does not need as many adapters to interface to
198 * a line boxed type.
199 *
200 * \param [in,out] object The line
201 * \param [in] y The new y coordinate for the second endpoint
202 */
203 void
lepton_bus_object_set_y1(LeptonObject * object,gint y)204 lepton_bus_object_set_y1 (LeptonObject *object,
205 gint y)
206 {
207 g_return_if_fail (lepton_object_is_bus (object));
208 g_return_if_fail (object->line != NULL);
209
210 object->line->y[1] = y;
211 }
212
213 /*! \brief get the position of the first bus point
214 * \par Function Description
215 * This function gets the position of the first point of a bus object.
216 *
217 * \param [in] object The object to get the position.
218 * \param [out] x pointer to the x-position
219 * \param [out] y pointer to the y-position
220 * \return TRUE if successfully determined the position, FALSE otherwise
221 */
222 gboolean
lepton_bus_object_get_position(const LeptonObject * object,gint * x,gint * y)223 lepton_bus_object_get_position (const LeptonObject *object,
224 gint *x,
225 gint *y)
226 {
227 g_return_val_if_fail (lepton_object_is_bus (object), FALSE);
228 g_return_val_if_fail (object->line != NULL, FALSE);
229
230 if (x != NULL) {
231 *x = object->line->x[0];
232 }
233
234 if (y != NULL) {
235 *y = object->line->y[0];
236 }
237
238 return TRUE;
239 }
240
241 /*! \brief Calculate the bounds of the bus
242 *
243 * On failure, this function sets the bounds to empty.
244 *
245 * \param [in] object The bus object
246 * \param [out] bounds The bounds of the bus
247 */
248 void
lepton_bus_object_calculate_bounds(const LeptonObject * object,LeptonBounds * bounds)249 lepton_bus_object_calculate_bounds (const LeptonObject *object,
250 LeptonBounds *bounds)
251 {
252 gint expand;
253
254 lepton_bounds_init (bounds);
255
256 g_return_if_fail (lepton_object_is_bus (object));
257 g_return_if_fail (object->line != NULL);
258
259 lepton_line_calculate_bounds (object->line, bounds);
260
261 expand = ceil (0.5 * G_SQRT2 * BUS_WIDTH);
262
263 /* This isn't strictly correct, but a 1st order approximation */
264 lepton_bounds_expand (bounds, bounds, expand, expand);
265 }
266
267 /*! \brief create a new bus object
268 * \par Function Description
269 * This function creates and returns a new bus object.
270 *
271 * \param [in] color The color of the bus
272 * \param [in] x1 x-coord of the first point
273 * \param [in] y1 y-coord of the first point
274 * \param [in] x2 x-coord of the second point
275 * \param [in] y2 y-coord of the second point
276 * \param [in] bus_ripper_direction direction of the bus rippers
277 * \return A new bus LeptonObject
278 */
279 LeptonObject*
lepton_bus_object_new(gint color,gint x1,gint y1,gint x2,gint y2,gint bus_ripper_direction)280 lepton_bus_object_new (gint color,
281 gint x1,
282 gint y1,
283 gint x2,
284 gint y2,
285 gint bus_ripper_direction)
286 {
287 LeptonObject *new_node;
288
289 new_node = lepton_object_new (OBJ_BUS, "bus");
290 lepton_object_set_color (new_node, color);
291
292 new_node->line = lepton_line_new ();
293 /* check for null */
294
295 new_node->line->x[0] = x1;
296 new_node->line->y[0] = y1;
297 new_node->line->x[1] = x2;
298 new_node->line->y[1] = y2;
299 lepton_object_set_stroke_width (new_node, BUS_WIDTH);
300
301 new_node->bus_ripper_direction = bus_ripper_direction;
302
303 return new_node;
304 }
305
306 /*! \brief read a bus object from a char buffer
307 * \par Function Description
308 * This function reads a bus object from the buffer \a buf.
309 * If the bus object was read successfully, a new bus object is
310 * allocated and appended to the \a object_list.
311 *
312 * \param [in] buf a text buffer (usually a line of a schematic file)
313 * \param [in] release_ver The release number gEDA
314 * \param [in] fileformat_ver a integer value of the file format
315 * \return The object list, or NULL on error.
316 */
317 LeptonObject*
o_bus_read(const char buf[],unsigned int release_ver,unsigned int fileformat_ver,GError ** err)318 o_bus_read (const char buf[],
319 unsigned int release_ver,
320 unsigned int fileformat_ver,
321 GError **err)
322 {
323 LeptonObject *new_obj;
324 char type;
325 int x1, y1;
326 int x2, y2;
327 int color;
328 int ripper_dir;
329
330 if (release_ver <= VERSION_20020825) {
331 if (sscanf (buf, "%c %d %d %d %d %d\n", &type, &x1, &y1, &x2, &y2, &color) != 6) {
332 g_set_error(err, EDA_ERROR, EDA_ERROR_PARSE, _("Failed to parse bus object"));
333 return NULL;
334 }
335 ripper_dir = 0;
336 } else {
337 if (sscanf (buf, "%c %d %d %d %d %d %d\n", &type, &x1, &y1, &x2, &y2, &color,
338 &ripper_dir) != 7) {
339 g_set_error(err, EDA_ERROR, EDA_ERROR_PARSE, _("Failed to parse bus object"));
340 return NULL;
341 }
342 }
343
344 if (x1 == x2 && y1 == y2) {
345 g_message (_("Found a zero length bus "
346 "[ %1$c %2$d %3$d %4$d %5$d %6$d ]"),
347 type, x1, y1, x2, y2, color);
348 }
349
350 if (!color_id_valid (color)) {
351 g_message (_("Found an invalid color [ %1$s ]"), buf);
352 g_message (_("Setting color to default color."));
353 color = default_color_id();
354 }
355
356 if (ripper_dir < -1 || ripper_dir > 1) {
357 g_message (_("Found an invalid bus ripper direction [ %1$s ]"), buf);
358 g_message (_("Resetting direction to neutral (no direction)."));
359 ripper_dir = 0;
360 }
361
362 new_obj = lepton_bus_object_new (color, x1, y1, x2, y2, ripper_dir);
363
364 return new_obj;
365 }
366
367 /*! \brief Create a string representation of the bus object
368 * \par Function Description
369 * This function takes a bus \a object and return a string
370 * according to the file format definition.
371 *
372 * \param [in] object a bus LeptonObject
373 * \return the string representation of the bus LeptonObject
374 */
375 gchar*
lepton_bus_object_to_buffer(const LeptonObject * object)376 lepton_bus_object_to_buffer (const LeptonObject *object)
377 {
378 g_return_val_if_fail (lepton_object_is_bus (object), NULL);
379 g_return_val_if_fail (object->line != NULL, NULL);
380
381 return g_strdup_printf ("%c %d %d %d %d %d %d",
382 lepton_object_get_type (object),
383 lepton_bus_object_get_x0 (object),
384 lepton_bus_object_get_y0 (object),
385 lepton_bus_object_get_x1 (object),
386 lepton_bus_object_get_y1 (object),
387 lepton_object_get_color (object),
388 lepton_bus_object_get_ripper_direction (object));
389 }
390
391 /*! \brief move a bus object
392 * \par Function Description
393 * This function changes the position of a bus \a object.
394 *
395 * \param [in,out] object The bus LeptonObject to be moved
396 * \param [in] dx The x-distance to move the object
397 * \param [in] dy The y-distance to move the object
398 */
399 void
lepton_bus_object_translate(LeptonObject * object,gint dx,gint dy)400 lepton_bus_object_translate (LeptonObject *object,
401 gint dx,
402 gint dy)
403 {
404 g_return_if_fail (lepton_object_is_bus (object));
405 g_return_if_fail (object->line != NULL);
406
407 /* Update world coords */
408 object->line->x[0] = object->line->x[0] + dx;
409 object->line->y[0] = object->line->y[0] + dy;
410 object->line->x[1] = object->line->x[1] + dx;
411 object->line->y[1] = object->line->y[1] + dy;
412 }
413
414 /*! \brief create a copy of a bus object
415 * \par Function Description
416 * This function creates a copy of the bus object \a o_current.
417 *
418 * \param [in] o_current The object that is copied
419 * \return a new bus object
420 */
421 LeptonObject*
lepton_bus_object_copy(const LeptonObject * object)422 lepton_bus_object_copy (const LeptonObject *object)
423 {
424 LeptonObject *new_obj;
425
426 g_return_val_if_fail (lepton_object_is_bus (object), NULL);
427 g_return_val_if_fail (object->line != NULL, NULL);
428
429 /* make sure you fix this in pin and bus as well */
430 /* still doesn't work... you need to pass in the new values */
431 /* or don't update and update later */
432 /* I think for now I'll disable the update and manually update */
433 new_obj = lepton_bus_object_new (lepton_object_get_color (object),
434 object->line->x[0],
435 object->line->y[0],
436 object->line->x[1],
437 object->line->y[1],
438 object->bus_ripper_direction);
439
440 return new_obj;
441 }
442
443 /*! \brief rotate a bus object around a centerpoint
444 * \par Function Description
445 * This function rotates a bus \a object around the point
446 * (\a world_centerx, \a world_centery).
447 *
448 * \param [in] world_centerx x-coord of the rotation center
449 * \param [in] world_centery y-coord of the rotation center
450 * \param [in] angle The angle to rotate the bus object
451 * \param [in,out] object The bus object
452 * \note only steps of 90 degrees are allowed for the \a angle
453 */
454 void
lepton_bus_object_rotate(gint world_centerx,gint world_centery,gint angle,LeptonObject * object)455 lepton_bus_object_rotate (gint world_centerx,
456 gint world_centery,
457 gint angle,
458 LeptonObject *object)
459 {
460 gint newx, newy;
461
462 g_return_if_fail (lepton_object_is_bus (object));
463 g_return_if_fail (object->line != NULL);
464 g_return_if_fail (lepton_angle_is_ortho (angle));
465
466 if (angle == 0) {
467 return;
468 }
469
470 /* translate object to origin */
471 lepton_bus_object_translate (object, -world_centerx, -world_centery);
472
473 lepton_point_rotate_90 (object->line->x[0],
474 object->line->y[0],
475 angle,
476 &newx,
477 &newy);
478
479 object->line->x[0] = newx;
480 object->line->y[0] = newy;
481
482 lepton_point_rotate_90 (object->line->x[1],
483 object->line->y[1],
484 angle,
485 &newx,
486 &newy);
487
488 object->line->x[1] = newx;
489 object->line->y[1] = newy;
490
491 lepton_bus_object_translate (object, world_centerx, world_centery);
492 }
493
494 /*! \brief mirror a bus object horizontaly at a centerpoint
495 * \par Function Description
496 * This function mirrors a bus \a object horizontaly at the point
497 * (\a world_centerx, \a world_centery).
498 *
499 * \param [in] world_centerx x-coord of the mirror position
500 * \param [in] world_centery y-coord of the mirror position
501 * \param [in,out] object The bus object
502 */
503 void
lepton_bus_object_mirror(gint world_centerx,gint world_centery,LeptonObject * object)504 lepton_bus_object_mirror (gint world_centerx,
505 gint world_centery,
506 LeptonObject *object)
507 {
508 g_return_if_fail (lepton_object_is_bus (object));
509 g_return_if_fail (object->line != NULL);
510
511 /* translate object to origin */
512 lepton_bus_object_translate (object, -world_centerx, -world_centery);
513
514 object->line->x[0] = -object->line->x[0];
515
516 object->line->x[1] = -object->line->x[1];
517
518 lepton_bus_object_translate (object, world_centerx, world_centery);
519 }
520
521 /*! \brief calculate the orientation of a bus object
522 * \par Function Description
523 * This function calculates the orientation of a bus object.
524 *
525 * \param [in] object The bus object
526 * \return The orientation: HORIZONTAL, VERTICAL or NEITHER
527 */
528 gint
lepton_bus_object_orientation(const LeptonObject * object)529 lepton_bus_object_orientation (const LeptonObject *object)
530 {
531 g_return_val_if_fail (lepton_object_is_bus (object), NEITHER);
532 g_return_val_if_fail (object->line != NULL, NEITHER);
533
534 if (object->line->y[0] == object->line->y[1]) {
535 return(HORIZONTAL);
536 }
537
538 if (object->line->x[0] == object->line->x[1]) {
539 return(VERTICAL);
540 }
541
542 return(NEITHER);
543 }
544
545 /*! \brief modify one point of a bus object
546 * \par Function Description
547 * This function modifies one point of a bus \a object. The point
548 * is specified by the \a whichone variable and the new coordinate
549 * is (\a x, \a y).
550 *
551 * \param [in,out] object The bus LeptonObject to modify
552 * \param [in] x new x-coord of the bus point
553 * \param [in] y new y-coord of the bus point
554 * \param [in] whichone bus point to modify
555 */
556 void
lepton_bus_object_modify(LeptonObject * object,gint x,gint y,gint whichone)557 lepton_bus_object_modify (LeptonObject *object,
558 gint x,
559 gint y,
560 gint whichone)
561 {
562 g_return_if_fail (lepton_object_is_bus (object));
563 g_return_if_fail (object->line != NULL);
564 g_return_if_fail (whichone >= LINE_END1);
565 g_return_if_fail (whichone <= LINE_END2);
566
567 object->line->x[whichone] = x;
568 object->line->y[whichone] = y;
569 }
570