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 #include <config.h>
21 
22 #include <stdio.h>
23 #include <math.h>
24 
25 #include "liblepton_priv.h"
26 
27 
28 /*! \brief Test if object is a bus pin object.
29  *
30  *  \param [in] object The object to test.
31  *  \return TRUE, if the object is bus pin, otherwise FALSE.
32  */
33 gboolean
lepton_pin_object_is_bus_pin(const LeptonObject * object)34 lepton_pin_object_is_bus_pin (const LeptonObject *object)
35 {
36   g_return_val_if_fail (lepton_object_is_pin (object), FALSE);
37 
38   return (object->pin_type == PIN_TYPE_BUS);
39 }
40 
41 
42 /*! \brief Test if object is a net pin object.
43  *
44  *  \param [in] object The object to test.
45  *  \return TRUE, if the object is net pin, otherwise FALSE.
46  */
47 gboolean
lepton_pin_object_is_net_pin(const LeptonObject * object)48 lepton_pin_object_is_net_pin (const LeptonObject *object)
49 {
50   g_return_val_if_fail (lepton_object_is_pin (object), FALSE);
51 
52   return (object->pin_type == PIN_TYPE_NET);
53 }
54 
55 
56 /*! \file pin_object.c
57  *  \brief functions for the pin object
58  */
59 
60 /*! \brief Calculate the bounds of a pin
61  *
62  *  On failure, this function sets the bounds to empty.
63  *
64  *  \param [in]  object   The pin object
65  *  \param [out] bounds   The bounds of the pin
66  */
67 void
lepton_pin_object_calculate_bounds(const LeptonObject * object,LeptonBounds * bounds)68 lepton_pin_object_calculate_bounds (const LeptonObject *object,
69                                     LeptonBounds *bounds)
70 {
71   gint expand;
72   gint width;
73 
74   lepton_bounds_init (bounds);
75 
76   g_return_if_fail (lepton_object_is_pin (object));
77   g_return_if_fail (object->line != NULL);
78 
79   lepton_line_calculate_bounds (object->line, bounds);
80 
81   width = lepton_pin_object_get_width (object);
82 
83   expand = ceil (0.5 * G_SQRT2 * width);
84 
85   /* This isn't strictly correct, but a 1st order approximation */
86   lepton_bounds_expand (bounds, bounds, expand, expand);
87 }
88 
89 /*! \brief Get the width to draw the pin
90  *
91  *  On failure, this function returns PIN_WIDTH_NET.
92  *
93  *  \param [in]  object   The pin object
94  *  \return The line width to draw the pin
95  */
96 gint
lepton_pin_object_get_width(const LeptonObject * object)97 lepton_pin_object_get_width (const LeptonObject *object)
98 {
99   gint width = PIN_WIDTH_NET;
100 
101   g_return_val_if_fail (lepton_object_is_pin (object), PIN_WIDTH_NET);
102 
103   switch (object->pin_type)
104   {
105     case PIN_TYPE_NET:
106       width = PIN_WIDTH_NET;
107       break;
108 
109     case PIN_TYPE_BUS:
110       width = PIN_WIDTH_BUS;
111       break;
112 
113     default:
114       g_warning ("lepton_pin_object_calculate_bounds: invalid pin_type");
115   }
116 
117   return width;
118 }
119 
120 /*! \brief get the position of a whichend of the pin object
121  *  \par Function Description
122  *  This function gets the position of the whichend side of a pin object.
123  *
124  *  \param [in] object   The object to get the position.
125  *  \param [out] x       pointer to the x-position
126  *  \param [out] y       pointer to the y-position
127  *  \return TRUE if successfully determined the position, FALSE otherwise
128  */
129 gboolean
lepton_pin_object_get_position(const LeptonObject * object,gint * x,gint * y)130 lepton_pin_object_get_position (const LeptonObject *object,
131                                 gint *x,
132                                 gint *y)
133 {
134   g_return_val_if_fail (lepton_object_is_pin (object), FALSE);
135   g_return_val_if_fail (object->line != NULL, FALSE);
136   g_return_val_if_fail (object->whichend >= 0, FALSE);
137   g_return_val_if_fail (object->whichend < 2, FALSE);
138 
139   if (x != NULL) {
140     *x = object->line->x[object->whichend];
141   }
142 
143   if (y != NULL) {
144     *y = object->line->y[object->whichend];
145   }
146 
147   return TRUE;
148 }
149 
150 /*! \brief Get the x coordinate of first endpoint
151  *
152  *  The coordinate properties are broken out individually to make it easier for
153  *  the GUI. This way, the GUI does not need as many adapters to interface to
154  *  a line boxed type.
155  *
156  *  \param [in] object The line
157  *  \return The x coordinate for the first endpoint
158  */
159 gint
lepton_pin_object_get_x0(const LeptonObject * object)160 lepton_pin_object_get_x0 (const LeptonObject *object)
161 {
162   g_return_val_if_fail (lepton_object_is_pin (object), 0);
163   g_return_val_if_fail (object->line != NULL, 0);
164 
165   return object->line->x[0];
166 }
167 
168 /*! \brief Get the x coordinate of second endpoint
169  *
170  *  The coordinate properties are broken out individually to make it easier for
171  *  the GUI. This way, the GUI does not need as many adapters to interface to
172  *  a line boxed type.
173  *
174  *  \param [in] object The line
175  *  \return The x coordinate for the second endpoint
176  */
177 gint
lepton_pin_object_get_x1(const LeptonObject * object)178 lepton_pin_object_get_x1 (const LeptonObject *object)
179 {
180   g_return_val_if_fail (lepton_object_is_pin (object), 0);
181   g_return_val_if_fail (object->line != NULL, 0);
182 
183   return object->line->x[1];
184 }
185 
186 /*! \brief Get the y coordinate of first endpoint
187  *
188  *  The coordinate properties are broken out individually to make it easier for
189  *  the GUI. This way, the GUI does not need as many adapters to interface to
190  *  a line boxed type.
191  *
192  *  \param [in] object The line
193  *  \return The y coordinate for the first endpoint
194  */
195 gint
lepton_pin_object_get_y0(const LeptonObject * object)196 lepton_pin_object_get_y0 (const LeptonObject *object)
197 {
198   g_return_val_if_fail (lepton_object_is_pin (object), 0);
199   g_return_val_if_fail (object->line != NULL, 0);
200 
201   return object->line->y[0];
202 }
203 
204 /*! \brief Get the y coordinate of second endpoint
205  *
206  *  The coordinate properties are broken out individually to make it easier for
207  *  the GUI. This way, the GUI does not need as many adapters to interface to
208  *  a line boxed type.
209  *
210  *  \param [in] object The line
211  *  \return The y coordinate for the second endpoint
212  */
213 gint
lepton_pin_object_get_y1(const LeptonObject * object)214 lepton_pin_object_get_y1 (const LeptonObject *object)
215 {
216   g_return_val_if_fail (lepton_object_is_pin (object), 0);
217   g_return_val_if_fail (object->line != NULL, 0);
218 
219   return object->line->y[1];
220 }
221 
222 /*! \brief Set the x coordinate of first endpoint
223  *
224  *  The coordinate properties are broken out individually to make it easier for
225  *  the GUI. This way, the GUI does not need as many adapters to interface to
226  *  a line boxed type.
227  *
228  *  \param [in,out] object The line
229  *  \param [in] x The new x coordinate for the first endpoint
230  */
231 void
lepton_pin_object_set_x0(LeptonObject * object,gint x)232 lepton_pin_object_set_x0 (LeptonObject *object,
233                           gint x)
234 {
235   g_return_if_fail (lepton_object_is_pin (object));
236   g_return_if_fail (object->line != NULL);
237 
238   object->line->x[0] = x;
239 }
240 
241 /*! \brief Set the x coordinate of second endpoint
242  *
243  *  The coordinate properties are broken out individually to make it easier for
244  *  the GUI. This way, the GUI does not need as many adapters to interface to
245  *  a line boxed type.
246  *
247  *  \param [in,out] object The line
248  *  \param [in] x The new x coordinate for the second endpoint
249  */
250 void
lepton_pin_object_set_x1(LeptonObject * object,gint x)251 lepton_pin_object_set_x1 (LeptonObject *object,
252                           gint x)
253 {
254   g_return_if_fail (lepton_object_is_pin (object));
255   g_return_if_fail (object->line != NULL);
256 
257   object->line->x[1] = x;
258 }
259 
260 /*! \brief Set the y coordinate of first endpoint
261  *
262  *  The coordinate properties are broken out individually to make it easier for
263  *  the GUI. This way, the GUI does not need as many adapters to interface to
264  *  a line boxed type.
265  *
266  *  \param [in,out] object The line
267  *  \param [in] y The new y coordinate for the first endpoint
268  */
269 void
lepton_pin_object_set_y0(LeptonObject * object,gint y)270 lepton_pin_object_set_y0 (LeptonObject *object,
271                           gint y)
272 {
273   g_return_if_fail (lepton_object_is_pin (object));
274   g_return_if_fail (object->line != NULL);
275 
276   object->line->y[0] = y;
277 }
278 
279 /*! \brief Set the y coordinate of second endpoint
280  *
281  *  The coordinate properties are broken out individually to make it easier for
282  *  the GUI. This way, the GUI does not need as many adapters to interface to
283  *  a line boxed type.
284  *
285  *  \param [in,out] object The line
286  *  \param [in] y The new y coordinate for the second endpoint
287  */
288 void
lepton_pin_object_set_y1(LeptonObject * object,gint y)289 lepton_pin_object_set_y1 (LeptonObject *object,
290                           gint y)
291 {
292   g_return_if_fail (lepton_object_is_pin (object));
293   g_return_if_fail (object->line != NULL);
294 
295   object->line->y[1] = y;
296 }
297 
298 /*! \brief create a new pin object
299  *  \par Function Description
300  *  This function creates and returns a new pin object.
301  *
302  *  \param [in]     color       The color of the pin
303  *  \param [in]     x1          x-coord of the first point
304  *  \param [in]     y1          y-coord of the first point
305  *  \param [in]     x2          x-coord of the second point
306  *  \param [in]     y2          y-coord of the second point
307  *  \param [in]     pin_type    type of pin (PIN_TYPE_NET or PIN_TYPE_BUS)
308  *  \param [in]     whichend    The connectable end of the pin
309  *  \return A new pin LeptonObject
310  */
311 LeptonObject*
lepton_pin_object_new(int color,int x1,int y1,int x2,int y2,int pin_type,int whichend)312 lepton_pin_object_new (int color,
313                        int x1,
314                        int y1,
315                        int x2,
316                        int y2,
317                        int pin_type,
318                        int whichend)
319 {
320   LeptonObject *new_node;
321 
322   new_node = lepton_object_new (OBJ_PIN, "pin");
323   lepton_object_set_color (new_node, color);
324 
325   new_node->line = lepton_line_new ();
326 
327   new_node->line->x[0] = x1;
328   new_node->line->y[0] = y1;
329   new_node->line->x[1] = x2;
330   new_node->line->y[1] = y2;
331 
332   lepton_pin_object_set_type (new_node, pin_type);
333 
334   new_node->whichend = whichend;
335 
336   return new_node;
337 }
338 
339 /*! \brief Create a new net pin object.
340  *  \par Function Description
341  *  This function creates and returns a new net pin object.
342  *
343  *  \param [in] color    The color of the pin.
344  *  \param [in] x1       X-coord of the first point.
345  *  \param [in] y1       Y-coord of the first point.
346  *  \param [in] x2       X-coord of the second point.
347  *  \param [in] y2       Y-coord of the second point.
348  *  \param [in] whichend The connectible end of the pin.
349  *  \return A new pin LeptonObject
350  */
351 LeptonObject*
lepton_pin_object_new_net_pin(int color,int x1,int y1,int x2,int y2,int whichend)352 lepton_pin_object_new_net_pin (int color,
353                                int x1,
354                                int y1,
355                                int x2,
356                                int y2,
357                                int whichend)
358 {
359   return lepton_pin_object_new (color, x1, y1, x2, y2, PIN_TYPE_NET, whichend);
360 }
361 
362 
363 /*! \brief Create a new bus pin object.
364  *  \par Function Description
365  *  This function creates and returns a new bus pin object.
366  *
367  *  \param [in] color    The color of the pin.
368  *  \param [in] x1       X-coord of the first point.
369  *  \param [in] y1       Y-coord of the first point.
370  *  \param [in] x2       X-coord of the second point.
371  *  \param [in] y2       Y-coord of the second point.
372  *  \param [in] whichend The connectible end of the pin.
373  *  \return A new pin LeptonObject
374  */
375 LeptonObject*
lepton_pin_object_new_bus_pin(int color,int x1,int y1,int x2,int y2,int whichend)376 lepton_pin_object_new_bus_pin (int color,
377                                int x1,
378                                int y1,
379                                int x2,
380                                int y2,
381                                int whichend)
382 {
383   return lepton_pin_object_new (color, x1, y1, x2, y2, PIN_TYPE_BUS, whichend);
384 }
385 
386 /*! \brief read a pin object from a char buffer
387  *  \par Function Description
388  *  This function reads a pin object from the buffer \a buf.
389  *  If the pin object was read successfully, a new pin object is
390  *  allocated and appended to the \a object_list.
391  *
392  *  \param [in] buf          a text buffer (usually a line of a schematic file)
393  *  \param [in] release_ver  The release number gEDA
394  *  \param [in] fileformat_ver a integer value of the file format
395  *  \return The object list, or NULL on error.
396  */
397 LeptonObject*
lepton_pin_object_read(const char buf[],unsigned int release_ver,unsigned int fileformat_ver,GError ** err)398 lepton_pin_object_read (const char buf[],
399                         unsigned int release_ver,
400                         unsigned int fileformat_ver,
401                         GError **err)
402 {
403   LeptonObject *new_obj;
404   char type;
405   int x1, y1;
406   int x2, y2;
407   int color;
408   int pin_type;
409   int whichend;
410 
411   if (release_ver <= VERSION_20020825) {
412     if (sscanf (buf, "%c %d %d %d %d %d\n", &type, &x1, &y1, &x2, &y2, &color) != 6) {
413       g_set_error(err, EDA_ERROR, EDA_ERROR_PARSE, _("Failed to parse pin object"));
414       return NULL;
415     }
416     pin_type = PIN_TYPE_NET;
417     whichend = -1;
418   } else {
419     if (sscanf (buf, "%c %d %d %d %d %d %d %d\n", &type, &x1, &y1, &x2, &y2,
420                 &color, &pin_type, &whichend) != 8) {
421       g_set_error(err, EDA_ERROR, EDA_ERROR_PARSE, _("Failed to parse pin object"));
422       return NULL;
423     }
424   }
425 
426   if (whichend == -1) {
427     g_message (_("Found a pin which did not have the whichend field set.\n"
428                  "Verify and correct manually."));
429   } else if (whichend < -1 || whichend > 1) {
430     g_message (_("Found an invalid whichend on a pin (reseting to zero): %d"),
431                whichend);
432     whichend = 0;
433   }
434 
435   if (!color_id_valid (color)) {
436     g_message (_("Found an invalid color [ %1$s ]"), buf);
437     g_message (_("Setting color to default color."));
438     color = default_color_id();
439   }
440 
441   new_obj = lepton_pin_object_new (color,
442                                    x1,
443                                    y1,
444                                    x2,
445                                    y2,
446                                    pin_type,
447                                    whichend);
448 
449   return new_obj;
450 }
451 
452 /*! \brief Create a string representation of the pin object
453  *
454  *  This function takes a pin \a object and returns a string
455  *  according to the file format definition.
456  *
457  *  On failure, this function returns NULL.
458  *
459  *  The caller must free the returned string when no longer needed using
460  *  g_free().
461  *
462  *  \param [in] object a pin object
463  *  \return a string representation of the pin object
464  */
465 gchar*
lepton_pin_object_to_buffer(const LeptonObject * object)466 lepton_pin_object_to_buffer (const LeptonObject *object)
467 {
468   g_return_val_if_fail (lepton_object_is_pin (object), NULL);
469   g_return_val_if_fail (object->line != NULL, NULL);
470 
471   return g_strdup_printf ("%c %d %d %d %d %d %d %d",
472                           lepton_object_get_type (object),
473                           lepton_pin_object_get_x0 (object),
474                           lepton_pin_object_get_y0 (object),
475                           lepton_pin_object_get_x1 (object),
476                           lepton_pin_object_get_y1 (object),
477                           lepton_object_get_color (object),
478                           object->pin_type,
479                           object->whichend);
480 }
481 
482 /*! \brief move a pin object
483  *  \par Function Description
484  *  This function changes the position of a pin \a object.
485  *
486  *  \param [ref] object  The pin LeptonObject to be moved
487  *  \param [in] dx       The x-distance to move the object
488  *  \param [in] dy       The y-distance to move the object
489  */
490 void
lepton_pin_object_translate(LeptonObject * object,int dx,int dy)491 lepton_pin_object_translate (LeptonObject *object,
492                              int dx,
493                              int dy)
494 {
495   g_return_if_fail (lepton_object_is_pin (object));
496   g_return_if_fail (object->line != NULL);
497 
498   /* Update world coords */
499   object->line->x[0] = object->line->x[0] + dx;
500   object->line->y[0] = object->line->y[0] + dy;
501   object->line->x[1] = object->line->x[1] + dx;
502   object->line->y[1] = object->line->y[1] + dy;
503 }
504 
505 /*! \brief create a copy of a pin object
506  *  \par Function Description
507  *  This function creates a copy of the pin object \a o_current.
508  *
509  *  \param [in] o_current    The object that is copied
510  *  \return a new pin object
511  */
512 LeptonObject*
lepton_pin_object_copy(LeptonObject * o_current)513 lepton_pin_object_copy (LeptonObject *o_current)
514 {
515   LeptonObject *new_obj;
516 
517   g_return_val_if_fail (lepton_object_is_pin (o_current), NULL);
518   g_return_val_if_fail (o_current->line != NULL, NULL);
519 
520   new_obj = lepton_pin_object_new (lepton_object_get_color (o_current),
521                                    o_current->line->x[0],
522                                    o_current->line->y[0],
523                                    o_current->line->x[1],
524                                    o_current->line->y[1],
525                                    o_current->pin_type,
526                                    o_current->whichend);
527 
528   return new_obj;
529 }
530 
531 /*! \brief rotate a pin object around a centerpoint
532  *  \par Function Description
533  *  This function rotates a pin \a object around the point
534  *  (\a world_centerx, \a world_centery).
535  *
536  *  \param [in] world_centerx x-coord of the rotation center
537  *  \param [in] world_centery y-coord of the rotation center
538  *  \param [in] angle         The angle to rotat the pin object
539  *  \param [in] object        The pin object
540  *  \note only steps of 90 degrees are allowed for the \a angle
541  */
542 void
lepton_pin_object_rotate(int world_centerx,int world_centery,int angle,LeptonObject * object)543 lepton_pin_object_rotate (int world_centerx,
544                           int world_centery,
545                           int angle,
546                           LeptonObject *object)
547 {
548   int newx, newy;
549 
550   g_return_if_fail (lepton_object_is_pin (object));
551   g_return_if_fail (object->line != NULL);
552 
553   if (angle == 0)
554     return;
555 
556   /* translate object to origin */
557   lepton_pin_object_translate (object, -world_centerx, -world_centery);
558 
559   lepton_point_rotate_90 (object->line->x[0],
560                           object->line->y[0],
561                           angle,
562                           &newx,
563                           &newy);
564 
565   object->line->x[0] = newx;
566   object->line->y[0] = newy;
567 
568   lepton_point_rotate_90 (object->line->x[1],
569                           object->line->y[1],
570                           angle,
571                           &newx,
572                           &newy);
573 
574   object->line->x[1] = newx;
575   object->line->y[1] = newy;
576 
577   lepton_pin_object_translate (object, world_centerx, world_centery);
578 }
579 
580 /*! \brief mirror a pin object horizontaly at a centerpoint
581  *  \par Function Description
582  *  This function mirrors a pin \a object horizontaly at the point
583  *  (\a world_centerx, \a world_centery).
584  *
585  *  \param [in] world_centerx x-coord of the mirror position
586  *  \param [in] world_centery y-coord of the mirror position
587  *  \param [in] object        The pin object
588  */
589 void
lepton_pin_object_mirror(int world_centerx,int world_centery,LeptonObject * object)590 lepton_pin_object_mirror (int world_centerx,
591                           int world_centery,
592                           LeptonObject *object)
593 {
594   g_return_if_fail (lepton_object_is_pin (object));
595   g_return_if_fail (object->line != NULL);
596 
597   /* translate object to origin */
598   lepton_pin_object_translate (object, -world_centerx, -world_centery);
599 
600   object->line->x[0] = -object->line->x[0];
601 
602   object->line->x[1] = -object->line->x[1];
603 
604   lepton_pin_object_translate (object, world_centerx, world_centery);
605 }
606 
607 /*! \brief modify one point of a pin object
608  *  \par Function Description
609  *  This function modifies one point of a pin \a object. The point
610  *  is specified by the \a whichone variable and the new coordinate
611  *  is (\a x, \a y).
612  *
613  *  \param object     The pin LeptonObject to modify
614  *  \param x          new x-coord of the pin point
615  *  \param y          new y-coord of the pin point
616  *  \param whichone   pin point to modify
617  *
618  */
619 void
lepton_pin_object_modify(LeptonObject * object,int x,int y,int whichone)620 lepton_pin_object_modify (LeptonObject *object,
621                           int x,
622                           int y,
623                           int whichone)
624 {
625   g_return_if_fail (lepton_object_is_pin (object));
626   g_return_if_fail (object->line != NULL);
627   g_return_if_fail (object->whichend >= 0);
628   g_return_if_fail (object->whichend < 2);
629 
630   object->line->x[whichone] = x;
631   object->line->y[whichone] = y;
632 }
633 
634 /*! \brief guess the whichend of pins of object list
635  *  \par Function Description
636  *  This function determines the whichend of the pins in the \a object_list.
637  *  In older libgeda file format versions there was no information about the
638  *  active end of pins.
639  *  This function calculates the bounding box of all pins in the object list.
640  *  The side of the pins that are closer to the boundary of the box are
641  *  set as active ends of the pins.
642  *
643  *  \param object_list list of LeptonObjects
644  *  \param force_boundingbox Use the whole symbol bounding box to
645  *                           find pin connection points.
646  */
647 void
lepton_pin_object_update_whichend(GList * object_list,gboolean force_boundingbox)648 lepton_pin_object_update_whichend (GList *object_list,
649                                    gboolean force_boundingbox)
650 {
651   LeptonObject *o_current;
652   GList *iter;
653   GList *pin_list = NULL;
654   int top = 0, left = 0;
655   int right = 0, bottom = 0;
656   int d1, d2, d3, d4;
657   int min0, min1;
658   int min0_whichend, min1_whichend;
659 
660   /* No objects, nothing to update. */
661   if (object_list == NULL) return;
662 
663   for (iter = object_list;
664        iter != NULL;
665        iter = g_list_next (iter)) {
666     o_current = (LeptonObject *)iter->data;
667     if (lepton_object_is_pin (o_current))
668     {
669       pin_list = g_list_prepend (pin_list, o_current);
670     }
671   }
672 
673   /* No pins, nothing to update. */
674   if (pin_list == NULL) return;
675 
676   if (force_boundingbox) {
677     /* Include text objects since we need full bounds. */
678     world_get_object_glist_bounds (object_list,
679                                    /* Never consider hidden text. */
680                                    FALSE,
681                                    &left,
682                                    &top,
683                                    &right,
684                                    &bottom);
685   } else {
686     /* Only look at the pins to calculate symbol bounds. */
687     world_get_object_glist_bounds (pin_list,
688                                    FALSE,
689                                    &left,
690                                    &top,
691                                    &right,
692                                    &bottom);
693   }
694 
695   iter = pin_list;
696   while (iter != NULL) {
697     o_current = (LeptonObject *)iter->data;
698     /* Determine which end of the pin is on or nearest the boundary */
699     if (o_current->whichend == -1) {
700       if (o_current->line->y[0] == o_current->line->y[1]) {
701         /* horizontal */
702 
703         d1 = abs(o_current->line->x[0] - left);
704         d2 = abs(o_current->line->x[1] - left);
705         d3 = abs(o_current->line->x[0] - right);
706         d4 = abs(o_current->line->x[1] - right);
707 
708         if (d1 <= d2) {
709           min0 = d1;
710           min0_whichend = 0;
711         } else {
712           min0 = d2;
713           min0_whichend = 1;
714         }
715 
716         if (d3 <= d4) {
717           min1 = d3;
718           min1_whichend = 0;
719         } else {
720           min1 = d4;
721           min1_whichend = 1;
722         }
723 
724         if (min0 <= min1) {
725           o_current->whichend = min0_whichend;
726         } else {
727           o_current->whichend = min1_whichend;
728         }
729 
730       } else if (o_current->line->x[0] == o_current->line->x[1]) {
731         /* vertical */
732 
733         d1 = abs(o_current->line->y[0] - top);
734         d2 = abs(o_current->line->y[1] - top);
735         d3 = abs(o_current->line->y[0] - bottom);
736         d4 = abs(o_current->line->y[1] - bottom);
737 
738         if (d1 <= d2) {
739           min0 = d1;
740           min0_whichend = 0;
741         } else {
742           min0 = d2;
743           min0_whichend = 1;
744         }
745 
746         if (d3 <= d4) {
747           min1 = d3;
748           min1_whichend = 0;
749         } else {
750           min1 = d4;
751           min1_whichend = 1;
752         }
753 
754         if (min0 <= min1) {
755           o_current->whichend = min0_whichend;
756         } else {
757           o_current->whichend = min1_whichend;
758         }
759       }
760     }
761     iter = g_list_next (iter);
762   }
763 
764   g_list_free (pin_list);
765 }
766 
767 
768 /*! \brief Sets the type, and corresponding width of a pin
769  *
770  *  \par Function Description
771  *  Sets the pin's type and width to a particular style.
772  *
773  *  \param [in] o_current  The pin LeptonObject being modified
774  *  \param [in] pin_type   The new type of this pin
775  */
776 void
lepton_pin_object_set_type(LeptonObject * o_current,int pin_type)777 lepton_pin_object_set_type (LeptonObject *o_current,
778                             int pin_type)
779 {
780   g_return_if_fail (lepton_object_is_pin (o_current));
781 
782   lepton_object_emit_pre_change_notify (o_current);
783   switch (pin_type) {
784     default:
785       g_critical ("lepton_pin_object_set_type: Got invalid pin type %1$i\n", pin_type);
786       /* Fall through */
787     case PIN_TYPE_NET:
788       lepton_object_set_stroke_width (o_current, PIN_WIDTH_NET);
789       o_current->pin_type = PIN_TYPE_NET;
790       break;
791     case PIN_TYPE_BUS:
792       lepton_object_set_stroke_width (o_current, PIN_WIDTH_BUS);
793       o_current->pin_type = PIN_TYPE_BUS;
794       break;
795   }
796   lepton_object_emit_change_notify (o_current);
797 }
798