source: trunk/libdjvu/GMapAreas.cpp @ 269

Last change on this file since 269 was 206, checked in by Eugene Romanenko, 14 years ago

DJVU plugin: djvulibre updated to version 3.5.19

File size: 25.7 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.10 2007/03/25 20:48:31 leonb Exp $
57// $Name: release_3_5_19 $
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) return false;
467
468   return
469      x1>=grect.xmin && x1<=grect.xmax && y1>=grect.ymin && y1<=grect.ymax ||
470      x2>=grect.xmin && x2<=grect.xmax && y2>=grect.ymin && y2<=grect.ymax ||
471      do_segments_intersect(grect.xmin, grect.ymin, grect.xmax, grect.ymax,
472                            x1, y1, x2, y2) ||
473      do_segments_intersect(grect.xmax, grect.ymin, grect.xmin, grect.ymax,
474                            x1, y1, x2, y2);
475}
476
477bool
478GMapPoly::is_projection_on_segment(int x, int y, int x1, int y1, int x2, int y2)
479{
480   int res1=(x-x1)*(x2-x1)+(y-y1)*(y2-y1);
481   int res2=(x-x2)*(x2-x1)+(y-y2)*(y2-y1);
482   return sign(res1)*sign(res2)<=0;
483}
484
485bool
486GMapPoly::do_segments_intersect(int x11, int y11, int x12, int y12,
487                                int x21, int y21, int x22, int y22)
488{
489   int res11=(x11-x21)*(y22-y21)-(y11-y21)*(x22-x21);
490   int res12=(x12-x21)*(y22-y21)-(y12-y21)*(x22-x21);
491   int res21=(x21-x11)*(y12-y11)-(y21-y11)*(x12-x11);
492   int res22=(x22-x11)*(y12-y11)-(y22-y11)*(x12-x11);
493   if (!res11 && !res12)
494   {
495      // Segments are on the same line
496      return
497         is_projection_on_segment(x11, y11, x21, y21, x22, y22) ||
498         is_projection_on_segment(x12, y12, x21, y21, x22, y22) ||
499         is_projection_on_segment(x21, y21, x11, y11, x12, y12) ||
500         is_projection_on_segment(x22, y22, x11, y11, x12, y12);
501   }
502   int sign1=sign(res11)*sign(res12);
503   int sign2=sign(res21)*sign(res22);
504   return sign1<=0 && sign2<=0;
505}
506
507bool
508GMapPoly::are_segments_parallel(int x11, int y11, int x12, int y12,
509                                int x21, int y21, int x22, int y22)
510{
511   return (x12-x11)*(y22-y21)-(y12-y11)*(x22-x21)==0;
512}
513
514char const * const
515GMapPoly::check_data(void)
516{
517  if (open && points<2 || !open && points<3) 
518    return error_too_few_points;
519  for(int i=0;i<sides;i++)
520  {
521    for(int j=i+2;j<sides;j++)
522    {
523      if (i != (j+1)%points )
524      {
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        {
528          return error_intersect;
529        }
530      }
531    }
532  }
533  return "";
534}
535
536void
537GMapPoly::optimize_data(void)
538{
539   // Removing segments of length zero
540   int i;
541   for(i=0;i<sides;i++)
542   {
543      while(xx[i]==xx[(i+1)%points] && yy[i]==yy[(i+1)%points])
544      {
545         for(int k=(i+1)%points;k<points-1;k++)
546         {
547            xx[k]=xx[k+1]; yy[k]=yy[k+1];
548         }
549         points--; sides--;
550         if (!points) return;
551      }
552   }
553   // Concatenating consequitive parallel segments
554   for(i=0;i<sides;i++)
555   {
556      while((open && i+1<sides || !open) &&
557            are_segments_parallel(xx[i], yy[i],
558                                  xx[(i+1)%points], yy[(i+1)%points],
559                                  xx[(i+1)%points], yy[(i+1)%points],
560                                  xx[(i+2)%points], yy[(i+2)%points]))
561      {
562         for(int k=(i+1)%points;k<points-1;k++)
563         {
564            xx[k]=xx[k+1]; yy[k]=yy[k+1];
565         }
566         points--; sides--;
567         if (!points) return;
568      }
569   }
570}
571
572bool
573GMapPoly::gma_is_point_inside(const int xin, const int yin) const
574{
575   if (open)
576     return false;
577   
578   int xfar=get_xmax()+(get_xmax()-get_xmin());
579   
580   int intersections=0;
581   for(int i=0;i<points;i++)
582   {
583      int res1=yy[i]-yin;
584      if (!res1) continue;
585      int res2, isaved=i;
586      while(!(res2=yy[(i+1)%points]-yin)) i++;
587      if (isaved!=i)
588      {
589         // Some points fell exactly on the line
590         if ((xx[(isaved+1)%points]-xin)*
591             (xx[i%points]-xin)<=0)
592         {
593            // Test point is exactly on the boundary
594            return true;
595         }
596      }
597      if (res1<0 && res2>0 || res1>0 && res2<0)
598      {
599         int x1=xx[i%points], y1=yy[i%points];
600         int x2=xx[(i+1)%points], y2=yy[(i+1)%points];
601         int _res1=(xin-x1)*(y2-y1)-(yin-y1)*(x2-x1);
602         int _res2=(xfar-x1)*(y2-y1)-(yin-y1)*(x2-x1);
603         if (!_res1 || !_res2)
604         {
605            // The point is on this boundary
606            return true;
607         }
608         if (sign(_res1)*sign(_res2)<0) intersections++;
609      }
610   }
611   return (intersections % 2)!=0;
612}
613
614int
615GMapPoly::gma_get_xmin(void) const
616{
617   int x=xx[0];
618   for(int i=1;i<points;i++)
619      if (x>xx[i]) x=xx[i];
620   return x;
621}
622
623int
624GMapPoly::gma_get_xmax(void) const
625{
626   int x=xx[0];
627   for(int i=1;i<points;i++)
628      if (x<xx[i]) x=xx[i];
629   return x+1;
630}
631
632int
633GMapPoly::gma_get_ymin(void) const
634{
635   int y=yy[0];
636   for(int i=1;i<points;i++)
637      if (y>yy[i]) y=yy[i];
638   return y;
639}
640
641int
642GMapPoly::gma_get_ymax(void) const
643{
644   int y=yy[0];
645   for(int i=1;i<points;i++)
646      if (y<yy[i]) y=yy[i];
647   return y+1;
648}
649
650void
651GMapPoly::gma_move(int dx, int dy)
652{
653   for(int i=0;i<points;i++)
654   {
655      xx[i]+=dx; yy[i]+=dy;
656   }
657}
658
659void
660GMapPoly::gma_resize(int new_width, int new_height)
661{
662   int width=get_xmax()-get_xmin();
663   int height=get_ymax()-get_ymin();
664   int xmin=get_xmin(), ymin=get_ymin();
665   for(int i=0;i<points;i++)
666   {
667      xx[i]=xmin+(xx[i]-xmin)*new_width/width;
668      yy[i]=ymin+(yy[i]-ymin)*new_height/height;
669   }
670}
671
672void
673GMapPoly::gma_transform(const GRect & grect)
674{
675   int width=get_xmax()-get_xmin();
676   int height=get_ymax()-get_ymin();
677   int xmin=get_xmin(), ymin=get_ymin();
678   for(int i=0;i<points;i++)
679   {
680      xx[i]=grect.xmin+(xx[i]-xmin)*grect.width()/width;
681      yy[i]=grect.ymin+(yy[i]-ymin)*grect.height()/height;
682   }
683}
684
685char const * const
686GMapPoly::gma_check_object(void) const
687{
688   const char * str;
689   str=(border_type!=NO_BORDER &&
690        border_type!=SOLID_BORDER &&
691        border_type!=XOR_BORDER) ? error_poly_border:
692       ((hilite_color!=0xffffffff) ? error_poly_hilite:"");
693   return str;
694}
695
696GMapPoly::GMapPoly(const int * _xx, const int * _yy, int _points, bool _open) :
697   open(_open), points(_points)
698{
699   sides=points-(open!=0);
700   
701   xx.resize(points-1); yy.resize(points-1);
702   for(int i=0;i<points;i++)
703   {
704      xx[i]=_xx[i]; yy[i]=_yy[i];
705   }
706   optimize_data();
707   char const * const res=check_data();
708   if (res[0])
709     G_THROW(res);
710}
711
712int     
713GMapPoly::add_vertex(int x, int y)
714{
715    points++;
716    sides=points-(open!=0);
717
718    xx.resize(points-1); yy.resize(points-1);
719    xx[points-1] = x;
720    yy[points-1] = y;
721
722    return points;
723}
724
725void
726GMapPoly::close_poly()
727{
728    open = false;
729    sides=points;
730}
731
732GUTF8String
733GMapPoly::gma_print(void)
734{
735   static const GUTF8String space(' ');
736   GUTF8String res=GUTF8String('(')+POLY_TAG+space;
737   for(int i=0;i<points;i++)
738   {
739      GUTF8String buffer;
740      res+=buffer.format("%d %d ", xx[i], yy[i]);
741   }
742   res.setat(res.length()-1, ')');
743   res+=space;
744   return res;
745}
746
747/// Virtual function generating a list of defining coordinates
748void GMapPoly::get_coords( GList<int> & CoordList ) const
749{
750  for(int i = 0 ; i < points ; i++)
751  {
752    CoordList.append( xx[i] );
753    CoordList.append( yy[i] );
754  }
755}
756
757void 
758GMapPoly::map(GRectMapper &mapper)
759{
760    get_bound_rect();
761    for(int i=0; i<points; i++)
762    {
763        mapper.map(xx[i], yy[i]);
764    }
765    clear_bounds();
766}
767
768void 
769GMapPoly::unmap(GRectMapper &mapper)
770{
771    get_bound_rect();
772    for(int i=0; i<points; i++)
773    {
774        mapper.unmap(xx[i], yy[i]);
775    }
776    clear_bounds();
777}
778
779
780
781/****************************************************************************
782**************************** GMapOval definition ****************************
783****************************************************************************/
784
785void
786GMapOval::gma_resize(int new_width, int new_height)
787{
788   xmax=xmin+new_width;
789   ymax=ymin+new_height;
790   initialize();
791}
792
793void
794GMapOval::gma_transform(const GRect & grect)
795{
796   xmin=grect.xmin; ymin=grect.ymin;
797   xmax=grect.xmax; ymax=grect.ymax;
798   initialize();
799}
800
801bool
802GMapOval::gma_is_point_inside(const int x, const int y) const
803{
804   return
805      sqrt((double)((x-xf1)*(x-xf1)+(y-yf1)*(y-yf1))) +
806      sqrt((double)((x-xf2)*(x-xf2)+(y-yf2)*(y-yf2))) <= 2*rmax;
807}
808
809char const * const
810GMapOval::gma_check_object(void) const
811{
812   return (border_type!=NO_BORDER &&
813       border_type!=SOLID_BORDER &&
814       border_type!=XOR_BORDER)?error_oval_border:
815      ((hilite_color!=0xffffffff) ? error_oval_hilite:"");
816}
817
818void
819GMapOval::initialize(void)
820{
821   int xc=(xmax+xmin)/2;
822   int yc=(ymax+ymin)/2;
823   int f;
824   
825   a=(xmax-xmin)/2;
826   b=(ymax-ymin)/2;
827   if (a>b)
828   {
829      rmin=b; rmax=a;
830      f=(int) sqrt((double)(rmax*rmax-rmin*rmin));
831      xf1=xc+f; xf2=xc-f; yf1=yf2=yc;
832   } else
833   {
834      rmin=a; rmax=b;
835      f=(int) sqrt((double)(rmax*rmax-rmin*rmin));
836      yf1=yc+f; yf2=yc-f; xf1=xf2=xc;
837   }
838}
839
840GMapOval::GMapOval(const GRect & rect) : xmin(rect.xmin), ymin(rect.ymin),
841   xmax(rect.xmax), ymax(rect.ymax)
842{
843   initialize();
844}
845
846GUTF8String
847GMapOval::gma_print(void)
848{
849   GUTF8String buffer;
850   return buffer.format("(%s %d %d %d %d) ",
851           OVAL_TAG, xmin, ymin, xmax-xmin, ymax-ymin);
852}
853
854void 
855GMapOval::map(GRectMapper &mapper)
856{
857    get_bound_rect();
858    GRect rect;
859    rect.xmin = xmin;
860    rect.xmax = xmax;
861    rect.ymin = ymin;
862    rect.ymax = ymax;
863    mapper.map(rect);
864    xmin = rect.xmin;
865    ymin = rect.ymin;
866    xmax = rect.xmax;
867    ymax = rect.ymax;
868    clear_bounds();
869    initialize();
870}
871
872void 
873GMapOval::unmap(GRectMapper &mapper)
874{
875    get_bound_rect();
876    GRect rect;
877    rect.xmin = xmin;
878    rect.xmax = xmax;
879    rect.ymin = ymin;
880    rect.ymax = ymax;
881    mapper.unmap(rect);
882    xmin = rect.xmin;
883    ymin = rect.ymin;
884    xmax = rect.xmax;
885    ymax = rect.ymax;
886    clear_bounds();
887    initialize();
888}
889
890GMapArea::GMapArea(void) : target("_self"), border_type(NO_BORDER),
891   border_always_visible(false), border_color(0xff), border_width(1),
892   hilite_color(0xffffffff), bounds_initialized(0) {}
893
894GMapRect::GMapRect(void) : xmin(0), ymin(0), xmax(0), ymax(0) {}
895
896GMapRect::GMapRect(const GRect & rect) : xmin(rect.xmin), ymin(rect.ymin),
897   xmax(rect.xmax), ymax(rect.ymax) {}
898
899GMapRect &
900GMapRect::operator=(const GRect & rect)
901{
902   xmin=rect.xmin;
903   xmax=rect.xmax;
904   ymin=rect.ymin;
905   ymax=rect.ymax;
906   return *this;
907}
908
909void
910GMapRect::gma_move(int dx, int dy)
911{
912   xmin+=dx;
913   xmax+=dx;
914   ymin+=dy;
915   ymax+=dy;
916}
917
918bool
919GMapRect::gma_is_point_inside(const int x, const int y) const
920{
921   return (x>=xmin)&&(x<xmax)&&(y>=ymin)&&(y<ymax);
922}
923
924GP<GMapArea>
925GMapRect::get_copy(void) const { return new GMapRect(*this); }
926
927GMapPoly::GMapPoly(void) : points(0), sides(0) {}
928
929void
930GMapPoly::move_vertex(int i, int x, int y)
931{
932   xx[i]=x; yy[i]=y;
933   clear_bounds();
934}
935
936GP<GMapArea>
937GMapPoly::get_copy(void) const { return new GMapPoly(*this); }
938
939GMapOval::GMapOval(void) : xmin(0), ymin(0), xmax(0), ymax(0) {}
940
941void
942GMapOval::gma_move(int dx, int dy)
943{
944   xmin+=dx; xmax+=dx; ymin+=dy; ymax+=dy;
945   xf1+=dx; yf1+=dy; xf2+=dx; yf2+=dy;
946}
947
948GP<GMapArea>
949GMapOval::get_copy(void) const
950{
951  return new GMapOval(*this);
952}
953
954static GUTF8String
955GMapArea2xmltag(const GMapArea &area,const GUTF8String &coords)
956{
957  GUTF8String retval("<AREA coords=\""
958    +coords+"\" shape=\""+area.get_shape_name()+"\" "
959    +"alt=\""+area.comment.toEscaped()+"\" ");
960  if(area.url.length())
961  {
962    retval+="href=\""+area.url+"\" ";
963  }else
964  {
965    retval+="nohref=\"nohref\" ";
966  }
967  if(area.target.length())
968  {
969    retval+="target=\""+area.target.toEscaped()+"\" ";
970  }
971  //  highlight
972  if( area.hilite_color != GMapArea::NO_HILITE &&
973      area.hilite_color != GMapArea::XOR_HILITE )
974  {
975    retval+=GUTF8String().format( "highlight=\"#%06X\" ", area.hilite_color );
976  }
977  const char *b_type="none";
978  switch( area.border_type )
979  {
980  case GMapArea::NO_BORDER:
981    b_type = "none";
982    break;
983  case GMapArea::XOR_BORDER:
984    b_type = "xor";
985    break;
986  case GMapArea::SOLID_BORDER:
987    b_type = "solid";
988    break;
989  case GMapArea::SHADOW_IN_BORDER:
990    b_type = "shadowin";
991    break;
992  case GMapArea::SHADOW_OUT_BORDER:
993    b_type = "shadowout";
994    break;
995  case GMapArea::SHADOW_EIN_BORDER:
996    b_type = "etchedin";
997    break;
998  case GMapArea::SHADOW_EOUT_BORDER:
999    b_type = "etchedout";
1000    break;
1001  }
1002  retval=retval+"bordertype=\""+b_type+"\" ";
1003  if( area.border_type != GMapArea::NO_BORDER)
1004  {
1005    retval+="bordercolor=\""+GUTF8String().format("#%06X",area.border_color)
1006      +"\" border=\""+GUTF8String(area.border_width)+"\" ";
1007  }
1008  if(area.border_always_visible )
1009    retval=retval+"visible=\"visible\" ";
1010  return retval+"/>\n";
1011}
1012
1013GUTF8String
1014GMapRect::get_xmltag(const int height) const
1015{
1016  return GMapArea2xmltag( *this, GUTF8String(get_xmin())
1017    +","+GUTF8String(height-1-get_ymax())
1018    +","+GUTF8String(get_xmax())
1019    +","+GUTF8String(height-1-get_ymin()));
1020#if 0
1021  GUTF8String retval;
1022  return retval;
1023#endif
1024}
1025
1026GUTF8String
1027GMapOval::get_xmltag(const int height) const
1028{ 
1029  return GMapArea2xmltag( *this, GUTF8String(get_xmin())
1030    +","+GUTF8String(height-1-get_ymax())
1031    +","+GUTF8String(get_xmax())
1032    +","+GUTF8String(height-1-get_ymin()));
1033#if 0
1034  GUTF8String retval;
1035  return retval;
1036#endif
1037}
1038
1039GUTF8String
1040GMapPoly::get_xmltag(const int height) const
1041{
1042  GList<int> CoordList;
1043  get_coords(CoordList);
1044  GPosition pos=CoordList;
1045  GUTF8String retval;
1046  if(pos)
1047  {
1048    GUTF8String coords(CoordList[pos]);
1049    while(++pos)
1050    {
1051      coords+=","+GUTF8String(height-1-CoordList[pos]);
1052      if(! ++pos)
1053        break;
1054      coords+=","+GUTF8String(CoordList[pos]);
1055    }
1056    retval=GMapArea2xmltag( *this, coords);
1057  }
1058  return retval;
1059}
1060
1061
1062#ifdef HAVE_NAMESPACES
1063}
1064# ifndef NOT_USING_DJVU_NAMESPACE
1065using namespace DJVU;
1066# endif
1067#endif
1068
Note: See TracBrowser for help on using the repository browser.