source: trunk/libdjvu/GMapAreas.cpp @ 280

Last change on this file since 280 was 280, checked in by rbri, 11 years ago

DJVU plugin: djvulibre updated to version 3.5.22

File size: 25.6 KB
Line 
1//C-  -*- C++ -*-
2//C- -------------------------------------------------------------------
3//C- DjVuLibre-3.5
4//C- Copyright (c) 2002  Leon Bottou and Yann Le Cun.
5//C- Copyright (c) 2001  AT&T
6//C-
7//C- This software is subject to, and may be distributed under, the
8//C- GNU General Public License, either Version 2 of the license,
9//C- or (at your option) any later version. The license should have
10//C- accompanied the software or you may obtain a copy of the license
11//C- from the Free Software Foundation at http://www.fsf.org .
12//C-
13//C- This program is distributed in the hope that it will be useful,
14//C- but WITHOUT ANY WARRANTY; without even the implied warranty of
15//C- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16//C- GNU General Public License for more details.
17//C-
18//C- DjVuLibre-3.5 is derived from the DjVu(r) Reference Library from
19//C- Lizardtech Software.  Lizardtech Software has authorized us to
20//C- replace the original DjVu(r) Reference Library notice by the following
21//C- text (see doc/lizard2002.djvu and doc/lizardtech2007.djvu):
22//C-
23//C-  ------------------------------------------------------------------
24//C- | DjVu (r) Reference Library (v. 3.5)
25//C- | Copyright (c) 1999-2001 LizardTech, Inc. All Rights Reserved.
26//C- | The DjVu Reference Library is protected by U.S. Pat. No.
27//C- | 6,058,214 and patents pending.
28//C- |
29//C- | This software is subject to, and may be distributed under, the
30//C- | GNU General Public License, either Version 2 of the license,
31//C- | or (at your option) any later version. The license should have
32//C- | accompanied the software or you may obtain a copy of the license
33//C- | from the Free Software Foundation at http://www.fsf.org .
34//C- |
35//C- | The computer code originally released by LizardTech under this
36//C- | license and unmodified by other parties is deemed "the LIZARDTECH
37//C- | ORIGINAL CODE."  Subject to any third party intellectual property
38//C- | claims, LizardTech grants recipient a worldwide, royalty-free,
39//C- | non-exclusive license to make, use, sell, or otherwise dispose of
40//C- | the LIZARDTECH ORIGINAL CODE or of programs derived from the
41//C- | LIZARDTECH ORIGINAL CODE in compliance with the terms of the GNU
42//C- | General Public License.   This grant only confers the right to
43//C- | infringe patent claims underlying the LIZARDTECH ORIGINAL CODE to
44//C- | the extent such infringement is reasonably necessary to enable
45//C- | recipient to make, have made, practice, sell, or otherwise dispose
46//C- | of the LIZARDTECH ORIGINAL CODE (or portions thereof) and not to
47//C- | any greater extent that may be necessary to utilize further
48//C- | modifications or combinations.
49//C- |
50//C- | The LIZARDTECH ORIGINAL CODE is provided "AS IS" WITHOUT WARRANTY
51//C- | OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
52//C- | TO ANY WARRANTY OF NON-INFRINGEMENT, OR ANY IMPLIED WARRANTY OF
53//C- | MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
54//C- +------------------------------------------------------------------
55//
56// $Id: GMapAreas.cpp,v 1.11 2008/08/05 20:50:35 bpearlmutter Exp $
57// $Name: release_3_5_22 $
58
59#ifdef HAVE_CONFIG_H
60# include "config.h"
61#endif
62#if NEED_GNUG_PRAGMAS
63# pragma implementation
64#endif
65
66#include "GMapAreas.h"
67#include "GException.h"
68#include "debug.h"
69
70#include <math.h>
71#include <stdio.h>
72
73
74#ifdef HAVE_NAMESPACES
75namespace DJVU {
76# ifdef NOT_DEFINED // Just to fool emacs c++ mode
77}
78#endif
79#endif
80
81
82/****************************************************************************
83***************************** GMapArea definition ***************************
84****************************************************************************/
85
86const char GMapArea::MAPAREA_TAG[] =            "maparea";
87const char GMapArea::RECT_TAG[] =               "rect";
88const char GMapArea::POLY_TAG[] =               "poly";
89const char GMapArea::OVAL_TAG[] =               "oval";
90const char GMapArea::NO_BORDER_TAG[] =          "none";
91const char GMapArea::XOR_BORDER_TAG[] =         "xor";
92const char GMapArea::SOLID_BORDER_TAG[] =       "border";
93const char GMapArea::SHADOW_IN_BORDER_TAG[] =   "shadow_in";
94const char GMapArea::SHADOW_OUT_BORDER_TAG[] =  "shadow_out";
95const char GMapArea::SHADOW_EIN_BORDER_TAG[] =  "shadow_ein";
96const char GMapArea::SHADOW_EOUT_BORDER_TAG[] = "shadow_eout";
97const char GMapArea::BORDER_AVIS_TAG[] =        "border_avis";
98const char GMapArea::HILITE_TAG[] =             "hilite";
99const char GMapArea::URL_TAG[] =                "url";
100const char GMapArea::TARGET_SELF[] =            "_self";
101static const char zero_width[] = ERR_MSG("GMapAreas.zero_width");
102static const char zero_height[] = ERR_MSG("GMapAreas.zero_height");
103static const char width_1[] = ERR_MSG("GMapAreas.width_1");
104static const char width_3_32 [] = ERR_MSG("GMapAreas.width_3-32");
105static const char error_poly_border [] = ERR_MSG("GMapAreas.poly_border");
106static const char error_poly_hilite [] = ERR_MSG("GMapAreas.poly_hilite");
107static const char error_oval_border [] = ERR_MSG("GMapAreas.oval_border");
108static const char error_oval_hilite [] = ERR_MSG("GMapAreas.oval_hilite");
109static const char error_too_few_points [] = ERR_MSG("GMapAreas.too_few_points");
110static const char error_intersect [] = ERR_MSG("GMapAreas.intersect");
111
112GMapArea::~GMapArea() {}
113
114GMapRect::~GMapRect() {}
115
116GMapPoly::~GMapPoly() {}
117
118GMapOval::~GMapOval() {}
119
120void
121GMapArea::initialize_bounds(void)
122{
123   xmin=gma_get_xmin();
124   xmax=gma_get_xmax();
125   ymin=gma_get_ymin();
126   ymax=gma_get_ymax();
127   bounds_initialized=true;
128}
129
130int
131GMapArea::get_xmin(void) const
132{
133   if (!bounds_initialized)
134     const_cast<GMapArea *>(this)->initialize_bounds();
135   return xmin;
136}
137
138int
139GMapArea::get_ymin(void) const
140{
141   if (!bounds_initialized)
142     const_cast<GMapArea *>(this)->initialize_bounds();
143   return ymin;
144}
145
146int
147GMapArea::get_xmax(void) const
148{
149   if (!bounds_initialized)
150     const_cast<GMapArea *>(this)->initialize_bounds();
151   return xmax;
152}
153
154int
155GMapArea::get_ymax(void) const
156{
157   if (!bounds_initialized)
158     const_cast<GMapArea *>(this)->initialize_bounds();
159   return ymax;
160}
161
162GRect
163GMapArea::get_bound_rect(void) const
164{
165   return GRect(get_xmin(), get_ymin(), get_xmax()-get_xmin(),
166                get_ymax()-get_ymin());
167}
168
169void
170GMapArea::move(int dx, int dy)
171{
172   if (dx || dy)
173   {
174     if (bounds_initialized)
175     {
176        xmin+=dx;
177        ymin+=dy;
178        xmax+=dx;
179        ymax+=dy;
180     }
181     gma_move(dx, dy);
182   }
183}
184
185void
186GMapArea::resize(int new_width, int new_height)
187{
188   if (get_xmax()-get_xmin()!=new_width ||
189       get_ymax()-get_ymin()!=new_height)
190   {
191     gma_resize(new_width, new_height);
192     bounds_initialized=false;
193   }
194}
195
196void
197GMapArea::transform(const GRect & grect)
198{
199   if (grect.xmin!=get_xmin() || grect.ymin!=get_ymin() ||
200       grect.xmax!=get_xmax() || grect.ymax!=get_ymax())
201   {
202     gma_transform(grect);
203     bounds_initialized=false;
204   }
205}
206
207char const * const
208GMapArea::check_object(void)
209{
210   char const *retval;
211   if (get_xmax()==get_xmin())
212   {
213     retval=zero_width;
214   }
215   else if (get_ymax()==get_ymin())
216   {
217     retval=zero_height;
218   }
219   else if ((border_type==XOR_BORDER ||
220       border_type==SOLID_BORDER) && border_width!=1)
221   {
222     retval=width_1;
223   }
224   else if ((border_type==SHADOW_IN_BORDER ||
225       border_type==SHADOW_OUT_BORDER ||
226       border_type==SHADOW_EIN_BORDER ||
227       border_type==SHADOW_EOUT_BORDER)&&
228       (border_width<3 || border_width>32))
229   {
230     retval=width_3_32;
231   }else
232   {
233     retval=gma_check_object();
234   }
235   return retval;
236}
237
238bool
239GMapArea::is_point_inside(int x, int y) const
240{
241   if (!bounds_initialized)
242     const_cast<GMapArea *>(this)->initialize_bounds();
243   return (x>=xmin && x<xmax && y>=ymin && y<ymax) ?
244              gma_is_point_inside(x, y) : false;
245}
246
247GUTF8String
248GMapArea::print(void)
249{
250      // Make this hard check to make sure, that *no* illegal GMapArea
251      // can be stored into a file.
252   const char * const errors=check_object();
253   if (errors[0])
254   {
255     G_THROW(errors);
256   }
257   
258   int i;
259   GUTF8String tmp;
260   GUTF8String url1, target1, comment1;
261   const GUTF8String url_str=url;
262   for(i=0;i<(int) url_str.length();i++)
263   {
264      char ch=url_str[i];
265      if (ch=='"')
266        url1+='\\';
267      url1+=ch;
268   }
269   for(i=0;i<(int) target.length();i++)
270   {
271      char ch=target[i];
272      if (ch=='"')
273        target1+='\\';
274      target1+=ch;
275   }
276   for(i=0;i<(int) comment.length();i++)
277   {
278      char ch=comment[i];
279      if (ch=='"')
280        comment1+='\\';
281      comment1+=ch;
282   }
283   
284   GUTF8String border_color_str;
285   border_color_str.format("#%02X%02X%02X",
286           (border_color & 0xff0000) >> 16,
287           (border_color & 0xff00) >> 8,
288           (border_color & 0xff));
289
290   static const GUTF8String left('(');
291   static const GUTF8String right(')');
292   static const GUTF8String space(' ');
293   static const GUTF8String quote('"');
294   GUTF8String border_type_str;
295   switch(border_type)
296   {
297      case NO_BORDER:
298        border_type_str=left+NO_BORDER_TAG+right;
299        break;
300      case XOR_BORDER:
301        border_type_str=left+XOR_BORDER_TAG+right;
302        break;
303      case SOLID_BORDER:
304        border_type_str=left+SOLID_BORDER_TAG+space+border_color_str+right;
305        break;
306      case SHADOW_IN_BORDER:
307        border_type_str=left+SHADOW_IN_BORDER_TAG+space+GUTF8String(border_width)+right;
308        break;
309      case SHADOW_OUT_BORDER:
310        border_type_str=left+SHADOW_OUT_BORDER_TAG+space+GUTF8String(border_width)+right;
311        break;
312      case SHADOW_EIN_BORDER:
313        border_type_str=left+SHADOW_EIN_BORDER_TAG+space+GUTF8String(border_width)+right;
314        break;
315      case SHADOW_EOUT_BORDER:
316        border_type_str=left+SHADOW_EOUT_BORDER_TAG+space+GUTF8String(border_width)+right;
317        break;
318      default:
319        border_type_str=left+XOR_BORDER_TAG+right;
320        break;
321   }
322
323   GUTF8String hilite_str;
324   if (hilite_color!=0xffffffff)
325   {
326      hilite_str.format("(%s #%02X%02X%02X)",
327              HILITE_TAG, (hilite_color & 0xff0000) >> 16,
328              (hilite_color & 0xff00) >> 8,
329              (hilite_color & 0xff));
330   }
331   
332   GUTF8String URL;
333   if (target1==TARGET_SELF)
334   {
335      URL=quote+url1+quote;
336   }else
337   {
338      URL=left+URL_TAG+space+quote+url1+quote+space+quote+target1+quote+right;
339   }
340
341   GUTF8String total=left+MAPAREA_TAG+space+URL+space+quote+comment1+quote+space+gma_print()+border_type_str;
342   if (border_always_visible)
343     total+=space+left+BORDER_AVIS_TAG+right;
344   if ( hilite_str.length() > 0 )
345     total+=space+hilite_str;
346   total+=right;
347   return total;
348}
349
350/*
351void
352GMapArea::map(GRectMapper &mapper)
353{
354    get_bound_rect();
355    GRect rect = GRect(xmin, ymin, xmax, ymax);
356    mapper.map(rect);
357    xmin = rect.xmin;
358    ymin = rect.ymin;
359    xmax = rect.xmax;
360    ymax = rect.ymax;
361    clear_bounds();
362}
363void
364GMapArea::unmap(GRectMapper &mapper)
365{
366    get_bound_rect();
367    GRect rect = GRect(xmin, ymin, xmax, ymax);
368    mapper.unmap(rect);
369    xmin = rect.xmin;
370    ymin = rect.ymin;
371    xmax = rect.xmax;
372    ymax = rect.ymax;
373    clear_bounds();
374}
375*/
376
377
378/// Virtual function generating a list of defining coordinates
379/// (default are the opposite corners of the enclosing rectangle)
380void GMapArea::get_coords( GList<int> & CoordList ) const
381{
382  CoordList.append( get_xmin() );
383  CoordList.append( get_ymin() );
384  CoordList.append( get_xmax() );
385  CoordList.append( get_ymax() );
386}
387
388
389/****************************************************************************
390**************************** GMapRect definition ****************************
391****************************************************************************/
392
393void
394GMapRect::gma_resize(int new_width, int new_height)
395{
396   xmax=xmin+new_width;
397   ymax=ymin+new_height;
398}
399
400void
401GMapRect::gma_transform(const GRect & grect)
402{
403   xmin=grect.xmin; ymin=grect.ymin;
404   xmax=grect.xmax; ymax=grect.ymax;
405}
406
407GUTF8String
408GMapRect::gma_print(void)
409{
410   GUTF8String buffer;
411   return buffer.format("(%s %d %d %d %d) ",
412           RECT_TAG, xmin, ymin, xmax-xmin, ymax-ymin);
413}
414
415void 
416GMapRect::map(GRectMapper &mapper)
417{
418    get_bound_rect();
419    GRect rect;
420    rect.xmin = xmin;
421    rect.xmax = xmax;
422    rect.ymin = ymin;
423    rect.ymax = ymax;
424    mapper.map(rect);
425    xmin = rect.xmin;
426    ymin = rect.ymin;
427    xmax = rect.xmax;
428    ymax = rect.ymax;
429    clear_bounds();
430}
431void 
432GMapRect::unmap(GRectMapper &mapper)
433{
434    get_bound_rect();
435    GRect rect;
436    rect.xmin = xmin;
437    rect.xmax = xmax;
438    rect.ymin = ymin;
439    rect.ymax = ymax;
440    mapper.unmap(rect);
441    xmin = rect.xmin;
442    ymin = rect.ymin;
443    xmax = rect.xmax;
444    ymax = rect.ymax;
445    clear_bounds();
446}
447
448/****************************************************************************
449**************************** GMapPoly definition ****************************
450****************************************************************************/
451
452inline int
453GMapPoly::sign(int x) { return x<0 ? -1 : x>0 ? 1 : 0; }
454
455bool
456GMapPoly::does_side_cross_rect(const GRect & grect, int side)
457{
458   int x1=xx[side], x2=xx[(side+1)%points];
459   int y1=yy[side], y2=yy[(side+1)%points];
460   int xmin=x1<x2 ? x1 : x2;
461   int ymin=y1<y2 ? y1 : y2;
462   int xmax=x1+x2-xmin;
463   int ymax=y1+y2-ymin;
464
465   if (xmax<grect.xmin || xmin>grect.xmax ||
466       ymax<grect.ymin || ymin>grect.ymax)
467     return false;
468
469   return
470     (x1>=grect.xmin && x1<=grect.xmax && y1>=grect.ymin && y1<=grect.ymax) ||
471     (x2>=grect.xmin && x2<=grect.xmax && y2>=grect.ymin && y2<=grect.ymax) ||
472     do_segments_intersect(grect.xmin, grect.ymin, grect.xmax, grect.ymax,
473                           x1, y1, x2, y2) ||
474     do_segments_intersect(grect.xmax, grect.ymin, grect.xmin, grect.ymax,
475                           x1, y1, x2, y2);
476}
477
478bool
479GMapPoly::is_projection_on_segment(int x, int y, int x1, int y1, int x2, int y2)
480{
481   int res1=(x-x1)*(x2-x1)+(y-y1)*(y2-y1);
482   int res2=(x-x2)*(x2-x1)+(y-y2)*(y2-y1);
483   return sign(res1)*sign(res2)<=0;
484}
485
486bool
487GMapPoly::do_segments_intersect(int x11, int y11, int x12, int y12,
488                                int x21, int y21, int x22, int y22)
489{
490   int res11=(x11-x21)*(y22-y21)-(y11-y21)*(x22-x21);
491   int res12=(x12-x21)*(y22-y21)-(y12-y21)*(x22-x21);
492   int res21=(x21-x11)*(y12-y11)-(y21-y11)*(x12-x11);
493   int res22=(x22-x11)*(y12-y11)-(y22-y11)*(x12-x11);
494   if (!res11 && !res12)
495   {
496      // Segments are on the same line
497      return
498         is_projection_on_segment(x11, y11, x21, y21, x22, y22) ||
499         is_projection_on_segment(x12, y12, x21, y21, x22, y22) ||
500         is_projection_on_segment(x21, y21, x11, y11, x12, y12) ||
501         is_projection_on_segment(x22, y22, x11, y11, x12, y12);
502   }
503   int sign1=sign(res11)*sign(res12);
504   int sign2=sign(res21)*sign(res22);
505   return sign1<=0 && sign2<=0;
506}
507
508bool
509GMapPoly::are_segments_parallel(int x11, int y11, int x12, int y12,
510                                int x21, int y21, int x22, int y22)
511{
512   return (x12-x11)*(y22-y21)-(y12-y11)*(x22-x21)==0;
513}
514
515char const * const
516GMapPoly::check_data(void)
517{
518  if ((open && points<2) || (!open && points<3))
519    return error_too_few_points;
520  for(int i=0;i<sides;i++)
521    {
522      for(int j=i+2;j<sides;j++)
523        {
524          if (i != (j+1)%points )
525            if (do_segments_intersect(xx[i], yy[i], xx[i+1], yy[i+1],
526                                      xx[j], yy[j], xx[(j+1)%points], yy[(j+1)%points]))
527              return error_intersect;
528        }
529    }
530  return "";
531}
532
533void
534GMapPoly::optimize_data(void)
535{
536  // Removing segments of length zero
537  int i;
538  for(i=0;i<sides;i++)
539    {
540      while(xx[i]==xx[(i+1)%points] && yy[i]==yy[(i+1)%points])
541        {
542          for(int k=(i+1)%points;k<points-1;k++)
543            {
544              xx[k]=xx[k+1]; yy[k]=yy[k+1];
545            }
546          points--; sides--;
547          if (!points) return;
548        }
549    }
550  // Concatenating consequitive parallel segments
551  for(i=0;i<sides;i++)
552    {
553      while(((open && i+1<sides) || !open) &&
554            are_segments_parallel(xx[i], yy[i],
555                                  xx[(i+1)%points], yy[(i+1)%points],
556                                  xx[(i+1)%points], yy[(i+1)%points],
557                                  xx[(i+2)%points], yy[(i+2)%points]))
558        {
559          for(int k=(i+1)%points;k<points-1;k++)
560            {
561              xx[k]=xx[k+1]; yy[k]=yy[k+1];
562            }
563          points--; sides--;
564          if (!points) return;
565        }
566    }
567}
568
569bool
570GMapPoly::gma_is_point_inside(const int xin, const int yin) const
571{
572   if (open)
573     return false;
574
575   int xfar=get_xmax()+(get_xmax()-get_xmin());
576
577   int intersections=0;
578   for(int i=0;i<points;i++)
579   {
580      int res1=yy[i]-yin;
581      if (!res1) continue;
582      int res2, isaved=i;
583      while(!(res2=yy[(i+1)%points]-yin)) i++;
584      if (isaved!=i)
585      {
586         // Some points fell exactly on the line
587         if ((xx[(isaved+1)%points]-xin)*
588             (xx[i%points]-xin)<=0)
589         {
590            // Test point is exactly on the boundary
591            return true;
592         }
593      }
594      if ((res1<0 && res2>0) || (res1>0 && res2<0))
595      {
596         int x1=xx[i%points], y1=yy[i%points];
597         int x2=xx[(i+1)%points], y2=yy[(i+1)%points];
598         int _res1=(xin-x1)*(y2-y1)-(yin-y1)*(x2-x1);
599         int _res2=(xfar-x1)*(y2-y1)-(yin-y1)*(x2-x1);
600         if (!_res1 || !_res2)
601         {
602            // The point is on this boundary
603            return true;
604         }
605         if (sign(_res1)*sign(_res2)<0) intersections++;
606      }
607   }
608   return (intersections % 2)!=0;
609}
610
611int
612GMapPoly::gma_get_xmin(void) const
613{
614   int x=xx[0];
615   for(int i=1;i<points;i++)
616      if (x>xx[i]) x=xx[i];
617   return x;
618}
619
620int
621GMapPoly::gma_get_xmax(void) const
622{
623   int x=xx[0];
624   for(int i=1;i<points;i++)
625      if (x<xx[i]) x=xx[i];
626   return x+1;
627}
628
629int
630GMapPoly::gma_get_ymin(void) const
631{
632   int y=yy[0];
633   for(int i=1;i<points;i++)
634      if (y>yy[i]) y=yy[i];
635   return y;
636}
637
638int
639GMapPoly::gma_get_ymax(void) const
640{
641   int y=yy[0];
642   for(int i=1;i<points;i++)
643      if (y<yy[i]) y=yy[i];
644   return y+1;
645}
646
647void
648GMapPoly::gma_move(int dx, int dy)
649{
650   for(int i=0;i<points;i++)
651   {
652      xx[i]+=dx; yy[i]+=dy;
653   }
654}
655
656void
657GMapPoly::gma_resize(int new_width, int new_height)
658{
659   int width=get_xmax()-get_xmin();
660   int height=get_ymax()-get_ymin();
661   int xmin=get_xmin(), ymin=get_ymin();
662   for(int i=0;i<points;i++)
663   {
664      xx[i]=xmin+(xx[i]-xmin)*new_width/width;
665      yy[i]=ymin+(yy[i]-ymin)*new_height/height;
666   }
667}
668
669void
670GMapPoly::gma_transform(const GRect & grect)
671{
672   int width=get_xmax()-get_xmin();
673   int height=get_ymax()-get_ymin();
674   int xmin=get_xmin(), ymin=get_ymin();
675   for(int i=0;i<points;i++)
676   {
677      xx[i]=grect.xmin+(xx[i]-xmin)*grect.width()/width;
678      yy[i]=grect.ymin+(yy[i]-ymin)*grect.height()/height;
679   }
680}
681
682char const * const
683GMapPoly::gma_check_object(void) const
684{
685   const char * str;
686   str=(border_type!=NO_BORDER &&
687        border_type!=SOLID_BORDER &&
688        border_type!=XOR_BORDER) ? error_poly_border:
689       ((hilite_color!=0xffffffff) ? error_poly_hilite:"");
690   return str;
691}
692
693GMapPoly::GMapPoly(const int * _xx, const int * _yy, int _points, bool _open) :
694   open(_open), points(_points)
695{
696   sides=points-(open!=0);
697   
698   xx.resize(points-1); yy.resize(points-1);
699   for(int i=0;i<points;i++)
700   {
701      xx[i]=_xx[i]; yy[i]=_yy[i];
702   }
703   optimize_data();
704   char const * const res=check_data();
705   if (res[0])
706     G_THROW(res);
707}
708
709int     
710GMapPoly::add_vertex(int x, int y)
711{
712    points++;
713    sides=points-(open!=0);
714
715    xx.resize(points-1); yy.resize(points-1);
716    xx[points-1] = x;
717    yy[points-1] = y;
718
719    return points;
720}
721
722void
723GMapPoly::close_poly()
724{
725    open = false;
726    sides=points;
727}
728
729GUTF8String
730GMapPoly::gma_print(void)
731{
732   static const GUTF8String space(' ');
733   GUTF8String res=GUTF8String('(')+POLY_TAG+space;
734   for(int i=0;i<points;i++)
735   {
736      GUTF8String buffer;
737      res+=buffer.format("%d %d ", xx[i], yy[i]);
738   }
739   res.setat(res.length()-1, ')');
740   res+=space;
741   return res;
742}
743
744/// Virtual function generating a list of defining coordinates
745void GMapPoly::get_coords( GList<int> & CoordList ) const
746{
747  for(int i = 0 ; i < points ; i++)
748  {
749    CoordList.append( xx[i] );
750    CoordList.append( yy[i] );
751  }
752}
753
754void 
755GMapPoly::map(GRectMapper &mapper)
756{
757    get_bound_rect();
758    for(int i=0; i<points; i++)
759    {
760        mapper.map(xx[i], yy[i]);
761    }
762    clear_bounds();
763}
764
765void 
766GMapPoly::unmap(GRectMapper &mapper)
767{
768    get_bound_rect();
769    for(int i=0; i<points; i++)
770    {
771        mapper.unmap(xx[i], yy[i]);
772    }
773    clear_bounds();
774}
775
776
777
778/****************************************************************************
779**************************** GMapOval definition ****************************
780****************************************************************************/
781
782void
783GMapOval::gma_resize(int new_width, int new_height)
784{
785   xmax=xmin+new_width;
786   ymax=ymin+new_height;
787   initialize();
788}
789
790void
791GMapOval::gma_transform(const GRect & grect)
792{
793   xmin=grect.xmin; ymin=grect.ymin;
794   xmax=grect.xmax; ymax=grect.ymax;
795   initialize();
796}
797
798bool
799GMapOval::gma_is_point_inside(const int x, const int y) const
800{
801   return
802      sqrt((double)((x-xf1)*(x-xf1)+(y-yf1)*(y-yf1))) +
803      sqrt((double)((x-xf2)*(x-xf2)+(y-yf2)*(y-yf2))) <= 2*rmax;
804}
805
806char const * const
807GMapOval::gma_check_object(void) const
808{
809   return (border_type!=NO_BORDER &&
810       border_type!=SOLID_BORDER &&
811       border_type!=XOR_BORDER)?error_oval_border:
812      ((hilite_color!=0xffffffff) ? error_oval_hilite:"");
813}
814
815void
816GMapOval::initialize(void)
817{
818   int xc=(xmax+xmin)/2;
819   int yc=(ymax+ymin)/2;
820   int f;
821   
822   a=(xmax-xmin)/2;
823   b=(ymax-ymin)/2;
824   if (a>b)
825   {
826      rmin=b; rmax=a;
827      f=(int) sqrt((double)(rmax*rmax-rmin*rmin));
828      xf1=xc+f; xf2=xc-f; yf1=yf2=yc;
829   } else
830   {
831      rmin=a; rmax=b;
832      f=(int) sqrt((double)(rmax*rmax-rmin*rmin));
833      yf1=yc+f; yf2=yc-f; xf1=xf2=xc;
834   }
835}
836
837GMapOval::GMapOval(const GRect & rect) : xmin(rect.xmin), ymin(rect.ymin),
838   xmax(rect.xmax), ymax(rect.ymax)
839{
840   initialize();
841}
842
843GUTF8String
844GMapOval::gma_print(void)
845{
846   GUTF8String buffer;
847   return buffer.format("(%s %d %d %d %d) ",
848           OVAL_TAG, xmin, ymin, xmax-xmin, ymax-ymin);
849}
850
851void 
852GMapOval::map(GRectMapper &mapper)
853{
854    get_bound_rect();
855    GRect rect;
856    rect.xmin = xmin;
857    rect.xmax = xmax;
858    rect.ymin = ymin;
859    rect.ymax = ymax;
860    mapper.map(rect);
861    xmin = rect.xmin;
862    ymin = rect.ymin;
863    xmax = rect.xmax;
864    ymax = rect.ymax;
865    clear_bounds();
866    initialize();
867}
868
869void 
870GMapOval::unmap(GRectMapper &mapper)
871{
872    get_bound_rect();
873    GRect rect;
874    rect.xmin = xmin;
875    rect.xmax = xmax;
876    rect.ymin = ymin;
877    rect.ymax = ymax;
878    mapper.unmap(rect);
879    xmin = rect.xmin;
880    ymin = rect.ymin;
881    xmax = rect.xmax;
882    ymax = rect.ymax;
883    clear_bounds();
884    initialize();
885}
886
887GMapArea::GMapArea(void) : target("_self"), border_type(NO_BORDER),
888   border_always_visible(false), border_color(0xff), border_width(1),
889   hilite_color(0xffffffff), bounds_initialized(0) {}
890
891GMapRect::GMapRect(void) : xmin(0), ymin(0), xmax(0), ymax(0) {}
892
893GMapRect::GMapRect(const GRect & rect) : xmin(rect.xmin), ymin(rect.ymin),
894   xmax(rect.xmax), ymax(rect.ymax) {}
895
896GMapRect &
897GMapRect::operator=(const GRect & rect)
898{
899   xmin=rect.xmin;
900   xmax=rect.xmax;
901   ymin=rect.ymin;
902   ymax=rect.ymax;
903   return *this;
904}
905
906void
907GMapRect::gma_move(int dx, int dy)
908{
909   xmin+=dx;
910   xmax+=dx;
911   ymin+=dy;
912   ymax+=dy;
913}
914
915bool
916GMapRect::gma_is_point_inside(const int x, const int y) const
917{
918   return (x>=xmin)&&(x<xmax)&&(y>=ymin)&&(y<ymax);
919}
920
921GP<GMapArea>
922GMapRect::get_copy(void) const { return new GMapRect(*this); }
923
924GMapPoly::GMapPoly(void) : points(0), sides(0) {}
925
926void
927GMapPoly::move_vertex(int i, int x, int y)
928{
929   xx[i]=x; yy[i]=y;
930   clear_bounds();
931}
932
933GP<GMapArea>
934GMapPoly::get_copy(void) const { return new GMapPoly(*this); }
935
936GMapOval::GMapOval(void) : xmin(0), ymin(0), xmax(0), ymax(0) {}
937
938void
939GMapOval::gma_move(int dx, int dy)
940{
941   xmin+=dx; xmax+=dx; ymin+=dy; ymax+=dy;
942   xf1+=dx; yf1+=dy; xf2+=dx; yf2+=dy;
943}
944
945GP<GMapArea>
946GMapOval::get_copy(void) const
947{
948  return new GMapOval(*this);
949}
950
951static GUTF8String
952GMapArea2xmltag(const GMapArea &area,const GUTF8String &coords)
953{
954  GUTF8String retval("<AREA coords=\""
955    +coords+"\" shape=\""+area.get_shape_name()+"\" "
956    +"alt=\""+area.comment.toEscaped()+"\" ");
957  if(area.url.length())
958  {
959    retval+="href=\""+area.url+"\" ";
960  }else
961  {
962    retval+="nohref=\"nohref\" ";
963  }
964  if(area.target.length())
965  {
966    retval+="target=\""+area.target.toEscaped()+"\" ";
967  }
968  //  highlight
969  if( area.hilite_color != GMapArea::NO_HILITE &&
970      area.hilite_color != GMapArea::XOR_HILITE )
971  {
972    retval+=GUTF8String().format( "highlight=\"#%06X\" ", area.hilite_color );
973  }
974  const char *b_type="none";
975  switch( area.border_type )
976  {
977  case GMapArea::NO_BORDER:
978    b_type = "none";
979    break;
980  case GMapArea::XOR_BORDER:
981    b_type = "xor";
982    break;
983  case GMapArea::SOLID_BORDER:
984    b_type = "solid";
985    break;
986  case GMapArea::SHADOW_IN_BORDER:
987    b_type = "shadowin";
988    break;
989  case GMapArea::SHADOW_OUT_BORDER:
990    b_type = "shadowout";
991    break;
992  case GMapArea::SHADOW_EIN_BORDER:
993    b_type = "etchedin";
994    break;
995  case GMapArea::SHADOW_EOUT_BORDER:
996    b_type = "etchedout";
997    break;
998  }
999  retval=retval+"bordertype=\""+b_type+"\" ";
1000  if( area.border_type != GMapArea::NO_BORDER)
1001  {
1002    retval+="bordercolor=\""+GUTF8String().format("#%06X",area.border_color)
1003      +"\" border=\""+GUTF8String(area.border_width)+"\" ";
1004  }
1005  if(area.border_always_visible )
1006    retval=retval+"visible=\"visible\" ";
1007  return retval+"/>\n";
1008}
1009
1010GUTF8String
1011GMapRect::get_xmltag(const int height) const
1012{
1013  return GMapArea2xmltag( *this, GUTF8String(get_xmin())
1014    +","+GUTF8String(height-1-get_ymax())
1015    +","+GUTF8String(get_xmax())
1016    +","+GUTF8String(height-1-get_ymin()));
1017#if 0
1018  GUTF8String retval;
1019  return retval;
1020#endif
1021}
1022
1023GUTF8String
1024GMapOval::get_xmltag(const int height) const
1025{ 
1026  return GMapArea2xmltag( *this, GUTF8String(get_xmin())
1027    +","+GUTF8String(height-1-get_ymax())
1028    +","+GUTF8String(get_xmax())
1029    +","+GUTF8String(height-1-get_ymin()));
1030#if 0
1031  GUTF8String retval;
1032  return retval;
1033#endif
1034}
1035
1036GUTF8String
1037GMapPoly::get_xmltag(const int height) const
1038{
1039  GList<int> CoordList;
1040  get_coords(CoordList);
1041  GPosition pos=CoordList;
1042  GUTF8String retval;
1043  if(pos)
1044  {
1045    GUTF8String coords(CoordList[pos]);
1046    while(++pos)
1047    {
1048      coords+=","+GUTF8String(height-1-CoordList[pos]);
1049      if(! ++pos)
1050        break;
1051      coords+=","+GUTF8String(CoordList[pos]);
1052    }
1053    retval=GMapArea2xmltag( *this, coords);
1054  }
1055  return retval;
1056}
1057
1058
1059#ifdef HAVE_NAMESPACES
1060}
1061# ifndef NOT_USING_DJVU_NAMESPACE
1062using namespace DJVU;
1063# endif
1064#endif
1065
Note: See TracBrowser for help on using the repository browser.