source: trunk/libdjvu/GMapAreas.cpp @ 17

Last change on this file since 17 was 17, checked in by Eugene Romanenko, 15 years ago

update makefiles, remove absolute paths, update djvulibre to version 3.5.17

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