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 box_object.c
22  *  \brief functions for the box object
23  */
24 
25 #include <config.h>
26 #include <math.h>
27 #include <stdio.h>
28 
29 #include "liblepton_priv.h"
30 
31 /*! \brief Get the upper x coordinate of a box object.
32  *
33  *  \param [in] object The box object.
34  *  \return The x coordinate of the upper corner of the box.
35  */
36 int
lepton_box_object_get_upper_x(const LeptonObject * object)37 lepton_box_object_get_upper_x (const LeptonObject *object)
38 {
39   g_return_val_if_fail (lepton_object_is_box (object), 0);
40   g_return_val_if_fail (object->box != NULL, 0);
41 
42   return object->box->upper_x;
43 }
44 
45 /*! \brief Get the upper y coordinate of a box object.
46  *
47  *  \param [in] object The box object.
48  *  \return The y coordinate of the upper corner of the box.
49  */
50 int
lepton_box_object_get_upper_y(const LeptonObject * object)51 lepton_box_object_get_upper_y (const LeptonObject *object)
52 {
53   g_return_val_if_fail (lepton_object_is_box (object), 0);
54   g_return_val_if_fail (object->box != NULL, 0);
55 
56   return object->box->upper_y;
57 }
58 
59 /*! \brief Get the lower x coordinate of a box object.
60  *
61  *  \param [in] object The box object.
62  *  \return The x coordinate of the lower corner of the box.
63  */
64 int
lepton_box_object_get_lower_x(const LeptonObject * object)65 lepton_box_object_get_lower_x (const LeptonObject *object)
66 {
67   g_return_val_if_fail (lepton_object_is_box (object), 0);
68   g_return_val_if_fail (object->box != NULL, 0);
69 
70   return object->box->lower_x;
71 }
72 
73 /*! \brief Get the lower y coordinate of a box object.
74  *
75  *  \param [in] object The box object.
76  *  \return The y coordinate of the lower corner of the box.
77  */
78 int
lepton_box_object_get_lower_y(const LeptonObject * object)79 lepton_box_object_get_lower_y (const LeptonObject *object)
80 {
81   g_return_val_if_fail (lepton_object_is_box (object), 0);
82   g_return_val_if_fail (object->box != NULL, 0);
83 
84   return object->box->lower_y;
85 }
86 
87 
88 /*! \brief Set the value of the upper x coordinate of a box object.
89  *
90  *  \param [in,out] object The box object.
91  *  \param [in] x The new upper x coordinate of the box.
92  */
93 void
lepton_box_object_set_upper_x(LeptonObject * object,int val)94 lepton_box_object_set_upper_x (LeptonObject *object, int val)
95 {
96   g_return_if_fail (lepton_object_is_box (object));
97   g_return_if_fail (object->box != NULL);
98 
99   object->box->upper_x = val;
100 }
101 
102 /*! \brief Set the value of the upper y coordinate of a box object.
103  *
104  *  \param [in,out] object The box object.
105  *  \param [in] y The new upper y coordinate of the box.
106  */
107 void
lepton_box_object_set_upper_y(LeptonObject * object,int val)108 lepton_box_object_set_upper_y (LeptonObject *object, int val)
109 {
110   g_return_if_fail (lepton_object_is_box (object));
111   g_return_if_fail (object->box != NULL);
112 
113   object->box->upper_y = val;
114 }
115 
116 /*! \brief Set the value of the lower x coordinate of a box object.
117  *
118  *  \param [in,out] object The box object.
119  *  \param [in] x The new lower x coordinate of the box.
120  */
121 void
lepton_box_object_set_lower_x(LeptonObject * object,int val)122 lepton_box_object_set_lower_x (LeptonObject *object, int val)
123 {
124   g_return_if_fail (lepton_object_is_box (object));
125   g_return_if_fail (object->box != NULL);
126 
127   object->box->lower_x = val;
128 }
129 
130 /*! \brief Set the value of the lower y coordinate of a box object.
131  *
132  *  \param [in,out] object The box object.
133  *  \param [in] y The new lower y coordinate of the box.
134  */
135 void
lepton_box_object_set_lower_y(LeptonObject * object,int val)136 lepton_box_object_set_lower_y (LeptonObject *object, int val)
137 {
138   g_return_if_fail (lepton_object_is_box (object));
139   g_return_if_fail (object->box != NULL);
140 
141   object->box->lower_y = val;
142 }
143 
144 /*! \brief Create a box LeptonObject
145  *  \par Function Description
146  *  This function creates a new object representing a box.
147  *
148  *  The box is described by its upper left corner - <B>x1</B>, <B>y1</B> - and
149  *  its lower right corner - <B>x2</B>, <B>y2</B>.
150  *  The <B>type</B> parameter must be equal to <B>OBJ_BOX</B>. The <B>color</B>
151  *  corresponds to the color the box will be drawn with.
152  *  The <B>LeptonObject</B> structure is allocated with the #lepton_object_new()
153  *  function. The structure describing the box is allocated and initialized
154  *  with the parameters given to the function.
155  *
156  *  Both the line type and the filling type are set to default
157  *  values : solid line type with a width of 0, and no filling. It
158  *  can be changed after with the
159  *  #lepton_object_set_line_options() and
160  *  #lepton_object_set_fill_options().
161  *
162  *  \param [in]     color        Box border color.
163  *  \param [in]     x1           Upper x coordinate.
164  *  \param [in]     y1           Upper y coordinate.
165  *  \param [in]     x2           Lower x coordinate.
166  *  \param [in]     y2           Lower y coordinate.
167  *  \return The new LeptonObject
168  */
169 LeptonObject*
lepton_box_object_new(int color,int x1,int y1,int x2,int y2)170 lepton_box_object_new (int color,
171                        int x1,
172                        int y1,
173                        int x2,
174                        int y2)
175 {
176   LeptonObject *new_node;
177   LeptonBox *box;
178 
179   /* create the object */
180   new_node = lepton_object_new (OBJ_BOX, "box");
181   lepton_object_set_color (new_node, color);
182 
183   box = lepton_box_new ();
184   new_node->box   = box;
185 
186   /* describe the box with its upper left and lower right corner */
187   box->upper_x = x1;
188   box->upper_y = y1;
189   box->lower_x = x2;
190   box->lower_y = y2;
191 
192   /* line type and filling initialized to default */
193   lepton_object_set_line_options (new_node,
194                                   DEFAULT_OBJECT_END,
195                                   TYPE_SOLID,
196                                   LINE_WIDTH,
197                                   -1,
198                                   -1);
199 
200   lepton_object_set_fill_options (new_node,
201                                   FILLING_HOLLOW,
202                                   -1,
203                                   -1,
204                                   -1,
205                                   -1,
206                                   -1);
207 
208   return new_node;
209 }
210 
211 /*! \brief Copy a box to a list.
212  *  \par Function Description
213  *  The function #lepton_box_object_copy() creates a verbatim copy
214  *  of the object pointed by <B>o_current</B> describing a box.
215  *
216  *  \param [in]      o_current  Box LeptonObject to copy.
217  *  \return The new LeptonObject
218  */
219 LeptonObject*
lepton_box_object_copy(LeptonObject * o_current)220 lepton_box_object_copy (LeptonObject *o_current)
221 {
222   LeptonObject *new_obj;
223   int upper_x, upper_y, lower_x, lower_y;
224 
225   /* A new box object is created with #lepton_box_object_new().
226    * Values for its fields are default and need to be modified. */
227   new_obj = lepton_box_object_new (lepton_object_get_color (o_current),
228                                    0, 0, 0, 0);
229 
230   /*
231    * The dimensions of the new box are set with the ones of the original box.
232    * The two boxes have the same line type and the same filling options.
233    */
234   upper_x = lepton_box_object_get_upper_x (o_current);
235   upper_y = lepton_box_object_get_upper_y (o_current);
236   lower_x = lepton_box_object_get_lower_x (o_current);
237   lower_y = lepton_box_object_get_lower_y (o_current);
238 
239   lepton_box_object_set_upper_x (new_obj, upper_x);
240   lepton_box_object_set_upper_y (new_obj, upper_y);
241   lepton_box_object_set_lower_x (new_obj, lower_x);
242   lepton_box_object_set_lower_y (new_obj, lower_y);
243 
244   lepton_object_set_line_options (new_obj,
245                                   lepton_object_get_stroke_cap_type (o_current),
246                                   lepton_object_get_stroke_type (o_current),
247                                   lepton_object_get_stroke_width (o_current),
248                                   lepton_object_get_stroke_dash_length (o_current),
249                                   lepton_object_get_stroke_space_length (o_current));
250   lepton_object_set_fill_options (new_obj,
251                                   lepton_object_get_fill_type (o_current),
252                                   lepton_object_get_fill_width (o_current),
253                                   lepton_object_get_fill_pitch1 (o_current),
254                                   lepton_object_get_fill_angle1 (o_current),
255                                   lepton_object_get_fill_pitch2 (o_current),
256                                   lepton_object_get_fill_angle2 (o_current));
257 
258   return new_obj;
259 }
260 
261 /*! \brief Modify a box LeptonObject's coordinates.
262  *  \par Function Description
263  *  This function modifies the coordinates of one of the four corner of
264  *  the box. The new coordinates of the corner identified by <B>whichone</B>
265  *  are given by <B>x</B> and <B>y</B> in world unit.
266  *
267  *  The coordinates of the corner is modified in the world coordinate system.
268  *  Screen coordinates and boundings are then updated.
269  *
270  *  \param [in,out] object     Box LeptonObject to be modified.
271  *  \param [in]     x          x coordinate.
272  *  \param [in]     y          y coordinate.
273  *  \param [in]     whichone   coordinate to change.
274  *
275  *  \note
276  *  <B>whichone</B> can take the following values:
277  *  <DL>
278  *    <DT>*</DT><DD>BOX_UPPER_LEFT
279  *    <DT>*</DT><DD>BOX_LOWER_LEFT
280  *    <DT>*</DT><DD>BOX_UPPER_RIGHT
281  *    <DT>*</DT><DD>BOX_LOWER_RIGHT
282  *  </DL>
283  */
284 void
lepton_box_object_modify(LeptonObject * object,int x,int y,int whichone)285 lepton_box_object_modify (LeptonObject *object,
286                           int x,
287                           int y,
288                           int whichone)
289 {
290   int tmp;
291 
292   lepton_object_emit_pre_change_notify (object);
293 
294   /* change the position of the selected corner */
295   switch(whichone) {
296   case BOX_UPPER_LEFT:
297     lepton_box_object_set_upper_x (object, x);
298     lepton_box_object_set_upper_y (object, y);
299     break;
300 
301   case BOX_LOWER_LEFT:
302     lepton_box_object_set_upper_x (object, x);
303     lepton_box_object_set_lower_y (object, y);
304     break;
305 
306   case BOX_UPPER_RIGHT:
307     lepton_box_object_set_lower_x (object, x);
308     lepton_box_object_set_upper_y (object, y);
309     break;
310 
311   case BOX_LOWER_RIGHT:
312     lepton_box_object_set_lower_x (object, x);
313     lepton_box_object_set_lower_y (object, y);
314     break;
315 
316   default:
317     return;
318   }
319 
320   int upper_x, upper_y, lower_x, lower_y;
321   upper_x = lepton_box_object_get_upper_x (object);
322   upper_y = lepton_box_object_get_upper_y (object);
323   lower_x = lepton_box_object_get_lower_x (object);
324   lower_y = lepton_box_object_get_lower_y (object);
325 
326   /* need to update the upper left and lower right corners */
327   if (upper_x > lower_x)
328   {
329     tmp = upper_x;
330     lepton_box_object_set_upper_x (object, lower_x);
331     lepton_box_object_set_lower_x (object, tmp);
332   }
333 
334   if (upper_y < lower_y)
335   {
336     tmp = upper_y;
337     lepton_box_object_set_upper_y (object, lower_y);
338     lepton_box_object_set_lower_y (object, tmp);
339   }
340 
341   lepton_object_emit_change_notify (object);
342 
343 }
344 
345 /*! \brief Create a box from a character string.
346  *  \par Function Description
347  *  This function gets the description of a box from the <B>*buf</B> character
348  *  string.
349  *
350  *  Depending on <B>*version</B>, the correct file format is considered.
351  *  Currently two file format revisions are supported :
352  *  <DL>
353  *    <DT>*</DT><DD>the file format used until 20000704 release
354  *    <DT>*</DT><DD>the file format used for the releases after 2000704.
355  *  </DL>
356  *
357  *  \param [in]     buf             Character string with box description.
358  *  \param [in]     release_ver     libgeda release version number.
359  *  \param [in]     fileformat_ver  libgeda file format version number.
360  *  \return The box LeptonObject that was created, or NULL on error.
361  */
362 LeptonObject*
lepton_box_object_read(const char buf[],unsigned int release_ver,unsigned int fileformat_ver,GError ** err)363 lepton_box_object_read (const char buf[],
364                         unsigned int release_ver,
365                         unsigned int fileformat_ver,
366                         GError **err)
367 {
368   LeptonObject *new_obj;
369   char type;
370   int x1, y1;
371   int width, height;
372   int d_x1, d_y1;
373   int d_x2, d_y2;
374   int color;
375   int box_width, box_space, box_length;
376   int fill_width, angle1, pitch1, angle2, pitch2;
377   int box_end;
378   int box_type;
379   int box_filling;
380 
381   if (release_ver <= VERSION_20000704) {
382 
383   /*! \note
384    *  The old geda file format, i.e. releases 20000704 and older, does not
385    *  handle the line type and the filling of the box object. They are set
386    *  to default.
387    */
388 
389     if (sscanf (buf, "%c %d %d %d %d %d\n",
390                 &type, &x1, &y1, &width, &height, &color) != 6) {
391       g_set_error(err, EDA_ERROR, EDA_ERROR_PARSE, _("Failed to parse box object"));
392       return NULL;
393     }
394 
395     box_width   = 0;
396     box_end     = END_NONE;
397     box_type    = TYPE_SOLID;
398     box_length  = -1;
399     box_space   = -1;
400 
401     box_filling = FILLING_HOLLOW;
402     fill_width  = 0;
403     angle1      = -1;
404     pitch1      = -1;
405     angle2      = -1;
406     pitch2      = -1;
407 
408   } else {
409 
410     /*! \note
411      *  The current line format to describe a box is a space separated list of
412      *  characters and numbers in plain ASCII on a single line. The meaning of
413      *  each item is described in the file format documentation.
414      */
415     if (sscanf (buf, "%c %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d\n",
416                 &type, &x1, &y1, &width, &height, &color,
417                 &box_width, &box_end, &box_type, &box_length,
418                 &box_space, &box_filling,
419                 &fill_width, &angle1, &pitch1, &angle2, &pitch2) != 17) {
420       g_set_error(err, EDA_ERROR, EDA_ERROR_PARSE, _("Failed to parse box object"));
421       return NULL;
422     }
423   }
424 
425   if (width == 0 || height == 0) {
426     g_message (_("Found a zero width/height box "
427                  "[ %1$c %2$d %3$d %4$d %5$d %6$d ]"),
428                type, x1, y1, width, height, color);
429   }
430 
431   if (!color_id_valid (color)) {
432     g_message (_("Found an invalid color [ %1$s ]"), buf);
433     g_message (_("Setting color to default color."));
434     color = default_color_id();
435   }
436 
437   /*! \note
438    *  A box is internally described by its lower right and upper left corner
439    *  whereas the line describe it with the lower left corner and the width
440    *  and height.
441    *
442    *  A new object is allocated, initialized and added to the object list.
443    *  Its filling and line type are set according to the values of the field
444    *  on the line.
445    */
446 
447   /* upper left corner of the box */
448   d_x1 = x1;
449   d_y1 = y1 + height; /* move box origin to top left */
450 
451   /* lower right corner of the box */
452   d_x2 = x1 + width;  /* end points of the box */
453   d_y2 = y1;
454 
455   /* create a new box */
456   new_obj = lepton_box_object_new (color, d_x1, d_y1, d_x2, d_y2);
457   /* set its line options */
458   lepton_object_set_line_options (new_obj,
459                                   (LeptonStrokeCapType) box_end,
460                                   (LeptonStrokeType) box_type,
461                                   box_width,
462                                   box_length,
463                                   box_space);
464   /* set its fill options */
465   lepton_object_set_fill_options (new_obj,
466                                   (LeptonFillType) box_filling,
467                                   fill_width,
468                                   pitch1,
469                                   angle1,
470                                   pitch2,
471                                   angle2);
472 
473   return new_obj;
474 }
475 
476 /*! \brief Create a character string representation of a box object.
477  *  \par Function Description
478  *  This function formats a string in the buffer <B>*buff</B> to describe the
479  *  box object <B>*object</B>.
480  *  It follows the post-20000704 release file format that handle the line type
481  *  and fill options.
482  *
483  *  \param [in] object  The box LeptonObject to create string from.
484  *  \return A pointer to the box character string.
485  *
486  *  \warning
487  *  Caller must g_free returned character string.
488  */
489 gchar*
lepton_box_object_to_buffer(const LeptonObject * object)490 lepton_box_object_to_buffer (const LeptonObject *object)
491 {
492   int x1, y1;
493   int width, height;
494   int box_width, box_space, box_length;
495   int fill_width, angle1, pitch1, angle2, pitch2;
496   LeptonStrokeCapType box_end;
497   LeptonStrokeType box_type;
498   LeptonFillType box_fill;
499   char *buf;
500   int upper_x, upper_y, lower_x, lower_y;
501 
502   /*! \note
503    *  A box is internally represented by its lower right and upper left corner
504    *  whereas it is described in the file format as its lower left corner and
505    *  its width and height.
506    */
507 
508   upper_x = lepton_box_object_get_upper_x (object);
509   upper_y = lepton_box_object_get_upper_y (object);
510   lower_x = lepton_box_object_get_lower_x (object);
511   lower_y = lepton_box_object_get_lower_y (object);
512 
513   /* calculate the width and height of the box */
514   width  = abs (lower_x - upper_x);
515   height = abs (upper_y - lower_y);
516 
517   /* calculate the lower left corner of the box */
518   x1 = upper_x;
519   y1 = upper_y - height; /* move the origin to 0, 0*/
520 
521 #if DEBUG
522   printf("box: %d %d %d %d\n", x1, y1, width, height);
523 #endif
524 
525   /* description of the line type for the outline */
526   box_end    = lepton_object_get_stroke_cap_type (object);
527   box_width  = lepton_object_get_stroke_width (object);
528   box_type   = lepton_object_get_stroke_type (object);
529   box_length = lepton_object_get_stroke_dash_length (object);
530   box_space  = lepton_object_get_stroke_space_length (object);
531 
532   /* description of the filling of the box */
533   box_fill   = lepton_object_get_fill_type (object);
534   fill_width = lepton_object_get_fill_width (object);
535   angle1     = lepton_object_get_fill_angle1 (object);
536   pitch1     = lepton_object_get_fill_pitch1 (object);
537   angle2     = lepton_object_get_fill_angle2 (object);
538   pitch2     = lepton_object_get_fill_pitch2 (object);
539 
540   buf = g_strdup_printf("%c %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d",
541                         lepton_object_get_type (object),
542                         x1, y1, width, height, lepton_object_get_color (object),
543                         box_width, box_end, box_type, box_length, box_space,
544                         box_fill,
545                         fill_width, angle1, pitch1, angle2, pitch2);
546 
547   return(buf);
548 }
549 
550 /*! \brief Translate a box position in WORLD coordinates by a delta.
551  *  \par Function Description
552  *  This function applies a translation of (<B>x1</B>,<B>y1</B>) to the box
553  *  described by <B>*object</B>. <B>x1</B> and <B>y1</B> are in world unit.
554  *
555  *  \param [in,out] object     Box LeptonObject to translate.
556  *  \param [in]     dx         x distance to move.
557  *  \param [in]     dy         y distance to move.
558  */
559 void
lepton_box_object_translate(LeptonObject * object,int dx,int dy)560 lepton_box_object_translate (LeptonObject *object,
561                              int dx,
562                              int dy)
563 {
564   g_return_if_fail (lepton_object_is_box (object));
565   g_return_if_fail (object->box != NULL);
566   int upper_x, upper_y, lower_x, lower_y;
567 
568   /* Do world coords */
569   upper_x = lepton_box_object_get_upper_x (object);
570   upper_y = lepton_box_object_get_upper_y (object);
571   lower_x = lepton_box_object_get_lower_x (object);
572   lower_y = lepton_box_object_get_lower_y (object);
573 
574   lepton_box_object_set_upper_x (object, upper_x + dx);
575   lepton_box_object_set_upper_y (object, upper_y + dy);
576   lepton_box_object_set_lower_x (object, lower_x + dx);
577   lepton_box_object_set_lower_y (object, lower_y + dy);
578 }
579 
580 /*! \brief Rotate box LeptonObject using WORLD coordinates.
581  *  \par Function Description
582  *  The function #o_box_rotate_world() rotate the box described by
583  *  <B>*object</B> around the (<B>world_centerx</B>, <B>world_centery</B>) point by
584  *  <B>angle</B> degrees.
585  *  The center of rotation is in world unit.
586  *
587  *  \param [in]      world_centerx  Rotation center x coordinate in WORLD units.
588  *  \param [in]      world_centery  Rotation center y coordinate in WORLD units.
589  *  \param [in]      angle          Rotation angle in degrees (See note below).
590  *  \param [in,out]  object         Box LeptonObject to rotate.
591  *
592  */
593 void
lepton_box_object_rotate(int world_centerx,int world_centery,int angle,LeptonObject * object)594 lepton_box_object_rotate (int world_centerx,
595                           int world_centery,
596                           int angle,
597                           LeptonObject *object)
598 {
599   int newx1, newy1;
600   int newx2, newy2;
601 
602   g_return_if_fail (lepton_object_is_box (object));
603   g_return_if_fail (object->box != NULL);
604 
605   /*! \note
606    *  Only 90 degree multiple and positive angles are allowed.
607    */
608 
609   /* angle must be positive */
610   if(angle < 0) angle = -angle;
611   /* angle must be a 90 multiple or no rotation performed */
612   if((angle % 90) != 0) return;
613 
614   /*! \note
615    *  The center of rotation (<B>world_centerx</B>, <B>world_centery</B>) is
616    *  translated to the origin. The rotation of the upper left and lower right
617    *  corner are then performed. Finally, the rotated box is translated back
618    *  to its previous location.
619    */
620   /* translate object to origin */
621   lepton_box_object_translate (object, -world_centerx, -world_centery);
622 
623   /* rotate the upper left corner of the box */
624   lepton_point_rotate_90 (lepton_box_object_get_upper_x (object),
625                           lepton_box_object_get_upper_y (object),
626                           angle,
627                           &newx1,
628                           &newy1);
629 
630   /* rotate the lower left corner of the box */
631   lepton_point_rotate_90 (lepton_box_object_get_lower_x (object),
632                           lepton_box_object_get_lower_y (object),
633                           angle,
634                           &newx2,
635                           &newy2);
636 
637   /* reorder the corners after rotation */
638   lepton_box_object_set_upper_x (object, MIN (newx1, newx2));
639   lepton_box_object_set_upper_y (object, MAX (newy1, newy2));
640   lepton_box_object_set_lower_x (object, MAX (newx1, newx2));
641   lepton_box_object_set_lower_y (object, MIN (newy1, newy2));
642 
643   /* translate object back to normal position */
644   lepton_box_object_translate (object, world_centerx, world_centery);
645 }
646 
647 /*! \brief Mirror box using WORLD coordinates.
648  *  \par Function Description
649  *  This function mirrors the box from the point
650  *  (<B>world_centerx</B>,<B>world_centery</B>) in world unit.
651  *
652  *  The box is first translated to the origin, then mirrored and finally
653  *  translated back at its previous position.
654  *
655  *  \param [in]     world_centerx  Origin x coordinate in WORLD units.
656  *  \param [in]     world_centery  Origin y coordinate in WORLD units.
657  *  \param [in,out] object         Box LeptonObject to mirror.
658  */
659 void
lepton_box_object_mirror(int world_centerx,int world_centery,LeptonObject * object)660 lepton_box_object_mirror (int world_centerx,
661                           int world_centery,
662                           LeptonObject *object)
663 {
664   int upper_x, upper_y, lower_x, lower_y;
665   int newx1, newy1;
666   int newx2, newy2;
667 
668   g_return_if_fail (lepton_object_is_box (object));
669   g_return_if_fail (object->box != NULL);
670 
671   /* translate object to origin */
672   lepton_box_object_translate (object, -world_centerx, -world_centery);
673 
674   upper_x = lepton_box_object_get_upper_x (object);
675   upper_y = lepton_box_object_get_upper_y (object);
676   lower_x = lepton_box_object_get_lower_x (object);
677   lower_y = lepton_box_object_get_lower_y (object);
678 
679   /* mirror the corners */
680   newx1 = -upper_x;
681   newy1 = upper_y;
682   newx2 = -lower_x;
683   newy2 = lower_y;
684 
685   /* reorder the corners */
686   lepton_box_object_set_upper_x (object, MIN (newx1, newx2));
687   lepton_box_object_set_upper_y (object, MAX (newy1, newy2));
688   lepton_box_object_set_lower_x (object, MAX (newx1, newx2));
689   lepton_box_object_set_lower_y (object, MIN (newy1, newy2));
690 
691   /* translate back in position */
692   lepton_box_object_translate (object, world_centerx, world_centery);
693 }
694 
695 /*! \brief Get box bounding rectangle in WORLD coordinates.
696  *  \par Function Description
697  *  This function sets the <B>left</B>, <B>top</B>, <B>right</B> and <B>bottom</B>
698  *  parameters to the boundings of the box object described in <B>*box</B>
699  *  in world units.
700  *
701  *  \param [in]  object     Box LeptonObject to read coordinates from.
702  *  \param [out] left       Left box coordinate in WORLD units.
703  *  \param [out] top        Top box coordinate in WORLD units.
704  *  \param [out] right      Right box coordinate in WORLD units.
705  *  \param [out] bottom     Bottom box coordinate in WORLD units.
706  */
707 void
lepton_box_object_calculate_bounds(const LeptonObject * object,LeptonBounds * bounds)708 lepton_box_object_calculate_bounds (const LeptonObject *object,
709                                     LeptonBounds *bounds)
710 {
711   gint expand;
712 
713   lepton_bounds_init (bounds);
714 
715   g_return_if_fail (lepton_object_is_box (object));
716   g_return_if_fail (object->box != NULL);
717 
718   lepton_box_calculate_bounds (object->box, bounds);
719 
720   expand = (lepton_object_get_stroke_width (object) + 1) / 2;
721 
722   /* This isn't strictly correct, but a 1st order approximation */
723   lepton_bounds_expand (bounds, bounds, expand, expand);
724 }
725 
726 /*! \brief get the position of the left bottom point
727  *  \par Function Description
728  *  This function gets the position of the bottom left point of a box object.
729  *
730  *  \param [in] object   The object to get the position.
731  *  \param [out] x       pointer to the x-position
732  *  \param [out] y       pointer to the y-position
733  *  \return TRUE if successfully determined the position, FALSE otherwise
734  */
735 gboolean
lepton_box_object_get_position(const LeptonObject * object,gint * x,gint * y)736 lepton_box_object_get_position (const LeptonObject *object,
737                                 gint *x,
738                                 gint *y)
739 {
740   g_return_val_if_fail (lepton_object_is_box (object), FALSE);
741   g_return_val_if_fail (object->box != NULL, FALSE);
742 
743   if (x != NULL) {
744     *x = MIN (lepton_box_object_get_lower_x (object),
745               lepton_box_object_get_upper_x (object));
746   }
747 
748   if (y != NULL) {
749     *y = MIN (lepton_box_object_get_lower_y (object),
750               lepton_box_object_get_upper_y (object));
751   }
752 
753   return TRUE;
754 }
755 
756 /*! \brief Calculates the distance between the given point and the closest
757  * point on the perimeter of the box.
758  *
759  *  \param [in] object         The box LeptonObject.
760  *  \param [in] x              The x coordinate of the given point.
761  *  \param [in] y              The y coordinate of the given point.
762  *  \param [in] force_solid    If true, force treating the object as solid.
763  *  \param [in] include_hidden Take hidden text into account.
764  *  \return The shortest distance from the object to the point. With an
765  *  invalid parameter, this function returns G_MAXDOUBLE.
766  */
767 double
lepton_box_object_shortest_distance(LeptonObject * object,int x,int y,int force_solid,gboolean include_hidden)768 lepton_box_object_shortest_distance (LeptonObject *object,
769                                      int x,
770                                      int y,
771                                      int force_solid,
772                                      gboolean include_hidden)
773 {
774   int solid;
775 
776   g_return_val_if_fail (object->box != NULL, G_MAXDOUBLE);
777 
778   solid = force_solid ||
779     lepton_object_get_fill_type (object) != FILLING_HOLLOW;
780 
781   return lepton_box_shortest_distance (object->box, x, y, solid);
782 }
783