00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057 #ifdef HAVE_CONFIG_H
00058 # include "config.h"
00059 #endif
00060 #if NEED_GNUG_PRAGMAS
00061 # pragma implementation
00062 #endif
00063
00064 #include "GMapAreas.h"
00065 #include "GException.h"
00066 #include "debug.h"
00067
00068 #include <math.h>
00069 #include <stdio.h>
00070
00071
00072 #ifdef HAVE_NAMESPACES
00073 namespace DJVU {
00074 # ifdef NOT_DEFINED // Just to fool emacs c++ mode
00075 }
00076 #endif
00077 #endif
00078
00079
00080
00081
00082
00083
00084 const char GMapArea::MAPAREA_TAG[] = "maparea";
00085 const char GMapArea::RECT_TAG[] = "rect";
00086 const char GMapArea::POLY_TAG[] = "poly";
00087 const char GMapArea::OVAL_TAG[] = "oval";
00088 const char GMapArea::NO_BORDER_TAG[] = "none";
00089 const char GMapArea::XOR_BORDER_TAG[] = "xor";
00090 const char GMapArea::SOLID_BORDER_TAG[] = "border";
00091 const char GMapArea::SHADOW_IN_BORDER_TAG[] = "shadow_in";
00092 const char GMapArea::SHADOW_OUT_BORDER_TAG[] = "shadow_out";
00093 const char GMapArea::SHADOW_EIN_BORDER_TAG[] = "shadow_ein";
00094 const char GMapArea::SHADOW_EOUT_BORDER_TAG[] = "shadow_eout";
00095 const char GMapArea::BORDER_AVIS_TAG[] = "border_avis";
00096 const char GMapArea::HILITE_TAG[] = "hilite";
00097 const char GMapArea::URL_TAG[] = "url";
00098 const char GMapArea::TARGET_SELF[] = "_self";
00099 static const char zero_width[] = ERR_MSG("GMapAreas.zero_width");
00100 static const char zero_height[] = ERR_MSG("GMapAreas.zero_height");
00101 static const char width_1[] = ERR_MSG("GMapAreas.width_1");
00102 static const char width_3_32 [] = ERR_MSG("GMapAreas.width_3-32");
00103 static const char error_poly_border [] = ERR_MSG("GMapAreas.poly_border");
00104 static const char error_poly_hilite [] = ERR_MSG("GMapAreas.poly_hilite");
00105 static const char error_oval_border [] = ERR_MSG("GMapAreas.oval_border");
00106 static const char error_oval_hilite [] = ERR_MSG("GMapAreas.oval_hilite");
00107 static const char error_too_few_points [] = ERR_MSG("GMapAreas.too_few_points");
00108 static const char error_intersect [] = ERR_MSG("GMapAreas.intersect");
00109
00110 GMapArea::~GMapArea() {}
00111
00112 GMapRect::~GMapRect() {}
00113
00114 GMapPoly::~GMapPoly() {}
00115
00116 GMapOval::~GMapOval() {}
00117
00118 void
00119 GMapArea::initialize_bounds(void)
00120 {
00121 xmin=gma_get_xmin();
00122 xmax=gma_get_xmax();
00123 ymin=gma_get_ymin();
00124 ymax=gma_get_ymax();
00125 bounds_initialized=true;
00126 }
00127
00128 int
00129 GMapArea::get_xmin(void) const
00130 {
00131 if (!bounds_initialized)
00132 const_cast<GMapArea *>(this)->initialize_bounds();
00133 return xmin;
00134 }
00135
00136 int
00137 GMapArea::get_ymin(void) const
00138 {
00139 if (!bounds_initialized)
00140 const_cast<GMapArea *>(this)->initialize_bounds();
00141 return ymin;
00142 }
00143
00144 int
00145 GMapArea::get_xmax(void) const
00146 {
00147 if (!bounds_initialized)
00148 const_cast<GMapArea *>(this)->initialize_bounds();
00149 return xmax;
00150 }
00151
00152 int
00153 GMapArea::get_ymax(void) const
00154 {
00155 if (!bounds_initialized)
00156 const_cast<GMapArea *>(this)->initialize_bounds();
00157 return ymax;
00158 }
00159
00160 GRect
00161 GMapArea::get_bound_rect(void) const
00162 {
00163 return GRect(get_xmin(), get_ymin(), get_xmax()-get_xmin(),
00164 get_ymax()-get_ymin());
00165 }
00166
00167 void
00168 GMapArea::move(int dx, int dy)
00169 {
00170 if (dx || dy)
00171 {
00172 if (bounds_initialized)
00173 {
00174 xmin+=dx;
00175 ymin+=dy;
00176 xmax+=dx;
00177 ymax+=dy;
00178 }
00179 gma_move(dx, dy);
00180 }
00181 }
00182
00183 void
00184 GMapArea::resize(int new_width, int new_height)
00185 {
00186 if (get_xmax()-get_xmin()!=new_width ||
00187 get_ymax()-get_ymin()!=new_height)
00188 {
00189 gma_resize(new_width, new_height);
00190 bounds_initialized=false;
00191 }
00192 }
00193
00194 void
00195 GMapArea::transform(const GRect & grect)
00196 {
00197 if (grect.xmin!=get_xmin() || grect.ymin!=get_ymin() ||
00198 grect.xmax!=get_xmax() || grect.ymax!=get_ymax())
00199 {
00200 gma_transform(grect);
00201 bounds_initialized=false;
00202 }
00203 }
00204
00205 char const * const
00206 GMapArea::check_object(void)
00207 {
00208 char const *retval;
00209 if (get_xmax()==get_xmin())
00210 {
00211 retval=zero_width;
00212 }
00213 else if (get_ymax()==get_ymin())
00214 {
00215 retval=zero_height;
00216 }
00217 else if ((border_type==XOR_BORDER ||
00218 border_type==SOLID_BORDER) && border_width!=1)
00219 {
00220 retval=width_1;
00221 }
00222 else if ((border_type==SHADOW_IN_BORDER ||
00223 border_type==SHADOW_OUT_BORDER ||
00224 border_type==SHADOW_EIN_BORDER ||
00225 border_type==SHADOW_EOUT_BORDER)&&
00226 (border_width<3 || border_width>32))
00227 {
00228 retval=width_3_32;
00229 }else
00230 {
00231 retval=gma_check_object();
00232 }
00233 return retval;
00234 }
00235
00236 bool
00237 GMapArea::is_point_inside(int x, int y) const
00238 {
00239 if (!bounds_initialized)
00240 const_cast<GMapArea *>(this)->initialize_bounds();
00241 return (x>=xmin && x<xmax && y>=ymin && y<ymax) ?
00242 gma_is_point_inside(x, y) : false;
00243 }
00244
00245 GUTF8String
00246 GMapArea::print(void)
00247 {
00248
00249
00250 const char * const errors=check_object();
00251 if (errors[0])
00252 {
00253 G_THROW(errors);
00254 }
00255
00256 int i;
00257 GUTF8String tmp;
00258 GUTF8String url1, target1, comment1;
00259 const GUTF8String url_str=url;
00260 for(i=0;i<(int) url_str.length();i++)
00261 {
00262 char ch=url_str[i];
00263 if (ch=='"')
00264 url1+='\\';
00265 url1+=ch;
00266 }
00267 for(i=0;i<(int) target.length();i++)
00268 {
00269 char ch=target[i];
00270 if (ch=='"')
00271 target1+='\\';
00272 target1+=ch;
00273 }
00274 for(i=0;i<(int) comment.length();i++)
00275 {
00276 char ch=comment[i];
00277 if (ch=='"')
00278 comment1+='\\';
00279 comment1+=ch;
00280 }
00281
00282 GUTF8String border_color_str;
00283 border_color_str.format("#%02X%02X%02X",
00284 (border_color & 0xff0000) >> 16,
00285 (border_color & 0xff00) >> 8,
00286 (border_color & 0xff));
00287
00288 static const GUTF8String left('(');
00289 static const GUTF8String right(')');
00290 static const GUTF8String space(' ');
00291 static const GUTF8String quote('"');
00292 GUTF8String border_type_str;
00293 switch(border_type)
00294 {
00295 case NO_BORDER:
00296 border_type_str=left+NO_BORDER_TAG+right;
00297 break;
00298 case XOR_BORDER:
00299 border_type_str=left+XOR_BORDER_TAG+right;
00300 break;
00301 case SOLID_BORDER:
00302 border_type_str=left+SOLID_BORDER_TAG+space+border_color_str+right;
00303 break;
00304 case SHADOW_IN_BORDER:
00305 border_type_str=left+SHADOW_IN_BORDER_TAG+space+GUTF8String(border_width)+right;
00306 break;
00307 case SHADOW_OUT_BORDER:
00308 border_type_str=left+SHADOW_OUT_BORDER_TAG+space+GUTF8String(border_width)+right;
00309 break;
00310 case SHADOW_EIN_BORDER:
00311 border_type_str=left+SHADOW_EIN_BORDER_TAG+space+GUTF8String(border_width)+right;
00312 break;
00313 case SHADOW_EOUT_BORDER:
00314 border_type_str=left+SHADOW_EOUT_BORDER_TAG+space+GUTF8String(border_width)+right;
00315 break;
00316 default:
00317 border_type_str=left+XOR_BORDER_TAG+right;
00318 break;
00319 }
00320
00321 GUTF8String hilite_str;
00322 if (hilite_color!=0xffffffff)
00323 {
00324 hilite_str.format("(%s #%02X%02X%02X)",
00325 HILITE_TAG, (hilite_color & 0xff0000) >> 16,
00326 (hilite_color & 0xff00) >> 8,
00327 (hilite_color & 0xff));
00328 }
00329
00330 GUTF8String URL;
00331 if (target1==TARGET_SELF)
00332 {
00333 URL=quote+url1+quote;
00334 }else
00335 {
00336 URL=left+URL_TAG+space+quote+url1+quote+space+quote+target1+quote+right;
00337 }
00338
00339 GUTF8String total=left+MAPAREA_TAG+space+URL+space+quote+comment1+quote+space+gma_print()+border_type_str;
00340 if (border_always_visible)
00341 total+=space+left+BORDER_AVIS_TAG+right;
00342 if ( hilite_str.length() > 0 )
00343 total+=space+hilite_str;
00344 total+=right;
00345 return total;
00346 }
00347
00348
00349
00350
00351
00352
00353
00354
00355
00356
00357
00358
00359
00360
00361
00362
00363
00364
00365
00366
00367
00368
00369
00370
00371
00372
00373
00374
00375
00378 void GMapArea::get_coords( GList<int> & CoordList ) const
00379 {
00380 CoordList.append( get_xmin() );
00381 CoordList.append( get_ymin() );
00382 CoordList.append( get_xmax() );
00383 CoordList.append( get_ymax() );
00384 }
00385
00386
00387
00388
00389
00390
00391 void
00392 GMapRect::gma_resize(int new_width, int new_height)
00393 {
00394 xmax=xmin+new_width;
00395 ymax=ymin+new_height;
00396 }
00397
00398 void
00399 GMapRect::gma_transform(const GRect & grect)
00400 {
00401 xmin=grect.xmin; ymin=grect.ymin;
00402 xmax=grect.xmax; ymax=grect.ymax;
00403 }
00404
00405 GUTF8String
00406 GMapRect::gma_print(void)
00407 {
00408 GUTF8String buffer;
00409 return buffer.format("(%s %d %d %d %d) ",
00410 RECT_TAG, xmin, ymin, xmax-xmin, ymax-ymin);
00411 }
00412
00413 void
00414 GMapRect::map(GRectMapper &mapper)
00415 {
00416 get_bound_rect();
00417 GRect rect;
00418 rect.xmin = xmin;
00419 rect.xmax = xmax;
00420 rect.ymin = ymin;
00421 rect.ymax = ymax;
00422 mapper.map(rect);
00423 xmin = rect.xmin;
00424 ymin = rect.ymin;
00425 xmax = rect.xmax;
00426 ymax = rect.ymax;
00427 clear_bounds();
00428 }
00429 void
00430 GMapRect::unmap(GRectMapper &mapper)
00431 {
00432 get_bound_rect();
00433 GRect rect;
00434 rect.xmin = xmin;
00435 rect.xmax = xmax;
00436 rect.ymin = ymin;
00437 rect.ymax = ymax;
00438 mapper.unmap(rect);
00439 xmin = rect.xmin;
00440 ymin = rect.ymin;
00441 xmax = rect.xmax;
00442 ymax = rect.ymax;
00443 clear_bounds();
00444 }
00445
00446
00447
00448
00449
00450 inline int
00451 GMapPoly::sign(int x) { return x<0 ? -1 : x>0 ? 1 : 0; }
00452
00453 bool
00454 GMapPoly::does_side_cross_rect(const GRect & grect, int side)
00455 {
00456 int x1=xx[side], x2=xx[(side+1)%points];
00457 int y1=yy[side], y2=yy[(side+1)%points];
00458 int xmin=x1<x2 ? x1 : x2;
00459 int ymin=y1<y2 ? y1 : y2;
00460 int xmax=x1+x2-xmin;
00461 int ymax=y1+y2-ymin;
00462
00463 if (xmax<grect.xmin || xmin>grect.xmax ||
00464 ymax<grect.ymin || ymin>grect.ymax) return false;
00465
00466 return
00467 x1>=grect.xmin && x1<=grect.xmax && y1>=grect.ymin && y1<=grect.ymax ||
00468 x2>=grect.xmin && x2<=grect.xmax && y2>=grect.ymin && y2<=grect.ymax ||
00469 do_segments_intersect(grect.xmin, grect.ymin, grect.xmax, grect.ymax,
00470 x1, y1, x2, y2) ||
00471 do_segments_intersect(grect.xmax, grect.ymin, grect.xmin, grect.ymax,
00472 x1, y1, x2, y2);
00473 }
00474
00475 bool
00476 GMapPoly::is_projection_on_segment(int x, int y, int x1, int y1, int x2, int y2)
00477 {
00478 int res1=(x-x1)*(x2-x1)+(y-y1)*(y2-y1);
00479 int res2=(x-x2)*(x2-x1)+(y-y2)*(y2-y1);
00480 return sign(res1)*sign(res2)<=0;
00481 }
00482
00483 bool
00484 GMapPoly::do_segments_intersect(int x11, int y11, int x12, int y12,
00485 int x21, int y21, int x22, int y22)
00486 {
00487 int res11=(x11-x21)*(y22-y21)-(y11-y21)*(x22-x21);
00488 int res12=(x12-x21)*(y22-y21)-(y12-y21)*(x22-x21);
00489 int res21=(x21-x11)*(y12-y11)-(y21-y11)*(x12-x11);
00490 int res22=(x22-x11)*(y12-y11)-(y22-y11)*(x12-x11);
00491 if (!res11 && !res12)
00492 {
00493
00494 return
00495 is_projection_on_segment(x11, y11, x21, y21, x22, y22) ||
00496 is_projection_on_segment(x12, y12, x21, y21, x22, y22) ||
00497 is_projection_on_segment(x21, y21, x11, y11, x12, y12) ||
00498 is_projection_on_segment(x22, y22, x11, y11, x12, y12);
00499 }
00500 int sign1=sign(res11)*sign(res12);
00501 int sign2=sign(res21)*sign(res22);
00502 return sign1<=0 && sign2<=0;
00503 }
00504
00505 bool
00506 GMapPoly::are_segments_parallel(int x11, int y11, int x12, int y12,
00507 int x21, int y21, int x22, int y22)
00508 {
00509 return (x12-x11)*(y22-y21)-(y12-y11)*(x22-x21)==0;
00510 }
00511
00512 char const * const
00513 GMapPoly::check_data(void)
00514 {
00515 if (open && points<2 || !open && points<3)
00516 return error_too_few_points;
00517 for(int i=0;i<sides;i++)
00518 {
00519 for(int j=i+2;j<sides;j++)
00520 {
00521 if (i != (j+1)%points )
00522 {
00523 if (do_segments_intersect(xx[i], yy[i], xx[i+1], yy[i+1],
00524 xx[j], yy[j], xx[(j+1)%points], yy[(j+1)%points]))
00525 {
00526 return error_intersect;
00527 }
00528 }
00529 }
00530 }
00531 return "";
00532 }
00533
00534 void
00535 GMapPoly::optimize_data(void)
00536 {
00537
00538 int i;
00539 for(i=0;i<sides;i++)
00540 {
00541 while(xx[i]==xx[(i+1)%points] && yy[i]==yy[(i+1)%points])
00542 {
00543 for(int k=(i+1)%points;k<points-1;k++)
00544 {
00545 xx[k]=xx[k+1]; yy[k]=yy[k+1];
00546 }
00547 points--; sides--;
00548 if (!points) return;
00549 }
00550 }
00551
00552 for(i=0;i<sides;i++)
00553 {
00554 while((open && i+1<sides || !open) &&
00555 are_segments_parallel(xx[i], yy[i],
00556 xx[(i+1)%points], yy[(i+1)%points],
00557 xx[(i+1)%points], yy[(i+1)%points],
00558 xx[(i+2)%points], yy[(i+2)%points]))
00559 {
00560 for(int k=(i+1)%points;k<points-1;k++)
00561 {
00562 xx[k]=xx[k+1]; yy[k]=yy[k+1];
00563 }
00564 points--; sides--;
00565 if (!points) return;
00566 }
00567 }
00568 }
00569
00570 bool
00571 GMapPoly::gma_is_point_inside(const int xin, const int yin) const
00572 {
00573 if (open)
00574 return false;
00575
00576 int xfar=get_xmax()+(get_xmax()-get_xmin());
00577
00578 int intersections=0;
00579 for(int i=0;i<points;i++)
00580 {
00581 int res1=yy[i]-yin;
00582 if (!res1) continue;
00583 int res2, isaved=i;
00584 while(!(res2=yy[(i+1)%points]-yin)) i++;
00585 if (isaved!=i)
00586 {
00587
00588 if ((xx[(isaved+1)%points]-xin)*
00589 (xx[i%points]-xin)<=0)
00590 {
00591
00592 return true;
00593 }
00594 }
00595 if (res1<0 && res2>0 || res1>0 && res2<0)
00596 {
00597 int x1=xx[i%points], y1=yy[i%points];
00598 int x2=xx[(i+1)%points], y2=yy[(i+1)%points];
00599 int _res1=(xin-x1)*(y2-y1)-(yin-y1)*(x2-x1);
00600 int _res2=(xfar-x1)*(y2-y1)-(yin-y1)*(x2-x1);
00601 if (!_res1 || !_res2)
00602 {
00603
00604 return true;
00605 }
00606 if (sign(_res1)*sign(_res2)<0) intersections++;
00607 }
00608 }
00609 return (intersections % 2)!=0;
00610 }
00611
00612 int
00613 GMapPoly::gma_get_xmin(void) const
00614 {
00615 int x=xx[0];
00616 for(int i=1;i<points;i++)
00617 if (x>xx[i]) x=xx[i];
00618 return x;
00619 }
00620
00621 int
00622 GMapPoly::gma_get_xmax(void) const
00623 {
00624 int x=xx[0];
00625 for(int i=1;i<points;i++)
00626 if (x<xx[i]) x=xx[i];
00627 return x+1;
00628 }
00629
00630 int
00631 GMapPoly::gma_get_ymin(void) const
00632 {
00633 int y=yy[0];
00634 for(int i=1;i<points;i++)
00635 if (y>yy[i]) y=yy[i];
00636 return y;
00637 }
00638
00639 int
00640 GMapPoly::gma_get_ymax(void) const
00641 {
00642 int y=yy[0];
00643 for(int i=1;i<points;i++)
00644 if (y<yy[i]) y=yy[i];
00645 return y+1;
00646 }
00647
00648 void
00649 GMapPoly::gma_move(int dx, int dy)
00650 {
00651 for(int i=0;i<points;i++)
00652 {
00653 xx[i]+=dx; yy[i]+=dy;
00654 }
00655 }
00656
00657 void
00658 GMapPoly::gma_resize(int new_width, int new_height)
00659 {
00660 int width=get_xmax()-get_xmin();
00661 int height=get_ymax()-get_ymin();
00662 int xmin=get_xmin(), ymin=get_ymin();
00663 for(int i=0;i<points;i++)
00664 {
00665 xx[i]=xmin+(xx[i]-xmin)*new_width/width;
00666 yy[i]=ymin+(yy[i]-ymin)*new_height/height;
00667 }
00668 }
00669
00670 void
00671 GMapPoly::gma_transform(const GRect & grect)
00672 {
00673 int width=get_xmax()-get_xmin();
00674 int height=get_ymax()-get_ymin();
00675 int xmin=get_xmin(), ymin=get_ymin();
00676 for(int i=0;i<points;i++)
00677 {
00678 xx[i]=grect.xmin+(xx[i]-xmin)*grect.width()/width;
00679 yy[i]=grect.ymin+(yy[i]-ymin)*grect.height()/height;
00680 }
00681 }
00682
00683 char const * const
00684 GMapPoly::gma_check_object(void) const
00685 {
00686 const char * str;
00687 str=(border_type!=NO_BORDER &&
00688 border_type!=SOLID_BORDER &&
00689 border_type!=XOR_BORDER) ? error_poly_border:
00690 ((hilite_color!=0xffffffff) ? error_poly_hilite:"");
00691 return str;
00692 }
00693
00694 GMapPoly::GMapPoly(const int * _xx, const int * _yy, int _points, bool _open) :
00695 open(_open), points(_points)
00696 {
00697 sides=points-(open!=0);
00698
00699 xx.resize(points-1); yy.resize(points-1);
00700 for(int i=0;i<points;i++)
00701 {
00702 xx[i]=_xx[i]; yy[i]=_yy[i];
00703 }
00704 optimize_data();
00705 char const * const res=check_data();
00706 if (res[0])
00707 G_THROW(res);
00708 }
00709
00710 int
00711 GMapPoly::add_vertex(int x, int y)
00712 {
00713 points++;
00714 sides=points-(open!=0);
00715
00716 xx.resize(points-1); yy.resize(points-1);
00717 xx[points-1] = x;
00718 yy[points-1] = y;
00719
00720 return points;
00721 }
00722
00723 void
00724 GMapPoly::close_poly()
00725 {
00726 open = false;
00727 sides=points;
00728 }
00729
00730 GUTF8String
00731 GMapPoly::gma_print(void)
00732 {
00733 static const GUTF8String space(' ');
00734 GUTF8String res=GUTF8String('(')+POLY_TAG+space;
00735 for(int i=0;i<points;i++)
00736 {
00737 GUTF8String buffer;
00738 res+=buffer.format("%d %d ", xx[i], yy[i]);
00739 }
00740 res.setat(res.length()-1, ')');
00741 res+=space;
00742 return res;
00743 }
00744
00746 void GMapPoly::get_coords( GList<int> & CoordList ) const
00747 {
00748 for(int i = 0 ; i < points ; i++)
00749 {
00750 CoordList.append( xx[i] );
00751 CoordList.append( yy[i] );
00752 }
00753 }
00754
00755 void
00756 GMapPoly::map(GRectMapper &mapper)
00757 {
00758 get_bound_rect();
00759 for(int i=0; i<points; i++)
00760 {
00761 mapper.map(xx[i], yy[i]);
00762 }
00763 clear_bounds();
00764 }
00765
00766 void
00767 GMapPoly::unmap(GRectMapper &mapper)
00768 {
00769 get_bound_rect();
00770 for(int i=0; i<points; i++)
00771 {
00772 mapper.unmap(xx[i], yy[i]);
00773 }
00774 clear_bounds();
00775 }
00776
00777
00778
00779
00780
00781
00782
00783 void
00784 GMapOval::gma_resize(int new_width, int new_height)
00785 {
00786 xmax=xmin+new_width;
00787 ymax=ymin+new_height;
00788 initialize();
00789 }
00790
00791 void
00792 GMapOval::gma_transform(const GRect & grect)
00793 {
00794 xmin=grect.xmin; ymin=grect.ymin;
00795 xmax=grect.xmax; ymax=grect.ymax;
00796 initialize();
00797 }
00798
00799 bool
00800 GMapOval::gma_is_point_inside(const int x, const int y) const
00801 {
00802 return
00803 sqrt((double)((x-xf1)*(x-xf1)+(y-yf1)*(y-yf1))) +
00804 sqrt((double)((x-xf2)*(x-xf2)+(y-yf2)*(y-yf2))) <= 2*rmax;
00805 }
00806
00807 char const * const
00808 GMapOval::gma_check_object(void) const
00809 {
00810 return (border_type!=NO_BORDER &&
00811 border_type!=SOLID_BORDER &&
00812 border_type!=XOR_BORDER)?error_oval_border:
00813 ((hilite_color!=0xffffffff) ? error_oval_hilite:"");
00814 }
00815
00816 void
00817 GMapOval::initialize(void)
00818 {
00819 int xc=(xmax+xmin)/2;
00820 int yc=(ymax+ymin)/2;
00821 int f;
00822
00823 a=(xmax-xmin)/2;
00824 b=(ymax-ymin)/2;
00825 if (a>b)
00826 {
00827 rmin=b; rmax=a;
00828 f=(int) sqrt((double)(rmax*rmax-rmin*rmin));
00829 xf1=xc+f; xf2=xc-f; yf1=yf2=yc;
00830 } else
00831 {
00832 rmin=a; rmax=b;
00833 f=(int) sqrt((double)(rmax*rmax-rmin*rmin));
00834 yf1=yc+f; yf2=yc-f; xf1=xf2=xc;
00835 }
00836 }
00837
00838 GMapOval::GMapOval(const GRect & rect) : xmin(rect.xmin), ymin(rect.ymin),
00839 xmax(rect.xmax), ymax(rect.ymax)
00840 {
00841 initialize();
00842 }
00843
00844 GUTF8String
00845 GMapOval::gma_print(void)
00846 {
00847 GUTF8String buffer;
00848 return buffer.format("(%s %d %d %d %d) ",
00849 OVAL_TAG, xmin, ymin, xmax-xmin, ymax-ymin);
00850 }
00851
00852 void
00853 GMapOval::map(GRectMapper &mapper)
00854 {
00855 get_bound_rect();
00856 GRect rect;
00857 rect.xmin = xmin;
00858 rect.xmax = xmax;
00859 rect.ymin = ymin;
00860 rect.ymax = ymax;
00861 mapper.map(rect);
00862 xmin = rect.xmin;
00863 ymin = rect.ymin;
00864 xmax = rect.xmax;
00865 ymax = rect.ymax;
00866 clear_bounds();
00867 initialize();
00868 }
00869
00870 void
00871 GMapOval::unmap(GRectMapper &mapper)
00872 {
00873 get_bound_rect();
00874 GRect rect;
00875 rect.xmin = xmin;
00876 rect.xmax = xmax;
00877 rect.ymin = ymin;
00878 rect.ymax = ymax;
00879 mapper.unmap(rect);
00880 xmin = rect.xmin;
00881 ymin = rect.ymin;
00882 xmax = rect.xmax;
00883 ymax = rect.ymax;
00884 clear_bounds();
00885 initialize();
00886 }
00887
00888 GMapArea::GMapArea(void) : target("_self"), border_type(NO_BORDER),
00889 border_always_visible(false), border_color(0xff), border_width(1),
00890 hilite_color(0xffffffff), bounds_initialized(0) {}
00891
00892 GMapRect::GMapRect(void) : xmin(0), ymin(0), xmax(0), ymax(0) {}
00893
00894 GMapRect::GMapRect(const GRect & rect) : xmin(rect.xmin), ymin(rect.ymin),
00895 xmax(rect.xmax), ymax(rect.ymax) {}
00896
00897 GMapRect &
00898 GMapRect::operator=(const GRect & rect)
00899 {
00900 xmin=rect.xmin;
00901 xmax=rect.xmax;
00902 ymin=rect.ymin;
00903 ymax=rect.ymax;
00904 return *this;
00905 }
00906
00907 void
00908 GMapRect::gma_move(int dx, int dy)
00909 {
00910 xmin+=dx;
00911 xmax+=dx;
00912 ymin+=dy;
00913 ymax+=dy;
00914 }
00915
00916 bool
00917 GMapRect::gma_is_point_inside(const int x, const int y) const
00918 {
00919 return (x>=xmin)&&(x<xmax)&&(y>=ymin)&&(y<ymax);
00920 }
00921
00922 GP<GMapArea>
00923 GMapRect::get_copy(void) const { return new GMapRect(*this); }
00924
00925 GMapPoly::GMapPoly(void) : points(0), sides(0) {}
00926
00927 void
00928 GMapPoly::move_vertex(int i, int x, int y)
00929 {
00930 xx[i]=x; yy[i]=y;
00931 clear_bounds();
00932 }
00933
00934 GP<GMapArea>
00935 GMapPoly::get_copy(void) const { return new GMapPoly(*this); }
00936
00937 GMapOval::GMapOval(void) : xmin(0), ymin(0), xmax(0), ymax(0) {}
00938
00939 void
00940 GMapOval::gma_move(int dx, int dy)
00941 {
00942 xmin+=dx; xmax+=dx; ymin+=dy; ymax+=dy;
00943 xf1+=dx; yf1+=dy; xf2+=dx; yf2+=dy;
00944 }
00945
00946 GP<GMapArea>
00947 GMapOval::get_copy(void) const
00948 {
00949 return new GMapOval(*this);
00950 }
00951
00952 static GUTF8String
00953 GMapArea2xmltag(const GMapArea &area,const GUTF8String &coords)
00954 {
00955 GUTF8String retval("<AREA coords=\""
00956 +coords+"\" shape=\""+area.get_shape_name()+"\" "
00957 +"alt=\""+area.comment.toEscaped()+"\" ");
00958 if(area.url.length())
00959 {
00960 retval+="href=\""+area.url+"\" ";
00961 }else
00962 {
00963 retval+="nohref=\"nohref\" ";
00964 }
00965 if(area.target.length())
00966 {
00967 retval+="target=\""+area.target.toEscaped()+"\" ";
00968 }
00969
00970 if( area.hilite_color != GMapArea::NO_HILITE &&
00971 area.hilite_color != GMapArea::XOR_HILITE )
00972 {
00973 retval+=GUTF8String().format( "highlight=\"#%06X\" ", area.hilite_color );
00974 }
00975 const char *b_type="none";
00976 switch( area.border_type )
00977 {
00978 case GMapArea::NO_BORDER:
00979 b_type = "none";
00980 break;
00981 case GMapArea::XOR_BORDER:
00982 b_type = "xor";
00983 break;
00984 case GMapArea::SOLID_BORDER:
00985 b_type = "solid";
00986 break;
00987 case GMapArea::SHADOW_IN_BORDER:
00988 b_type = "shadowin";
00989 break;
00990 case GMapArea::SHADOW_OUT_BORDER:
00991 b_type = "shadowout";
00992 break;
00993 case GMapArea::SHADOW_EIN_BORDER:
00994 b_type = "etchedin";
00995 break;
00996 case GMapArea::SHADOW_EOUT_BORDER:
00997 b_type = "etchedout";
00998 break;
00999 }
01000 retval=retval+"bordertype=\""+b_type+"\" ";
01001 if( area.border_type != GMapArea::NO_BORDER)
01002 {
01003 retval+="bordercolor=\""+GUTF8String().format("#%06X",area.border_color)
01004 +"\" border=\""+GUTF8String(area.border_width)+"\" ";
01005 }
01006 if(area.border_always_visible )
01007 retval=retval+"visible=\"visible\" ";
01008 return retval+"/>\n";
01009 }
01010
01011 GUTF8String
01012 GMapRect::get_xmltag(const int height) const
01013 {
01014 return GMapArea2xmltag( *this, GUTF8String(get_xmin())
01015 +","+GUTF8String(height-1-get_ymax())
01016 +","+GUTF8String(get_xmax())
01017 +","+GUTF8String(height-1-get_ymin()));
01018 #if 0
01019 GUTF8String retval;
01020 return retval;
01021 #endif
01022 }
01023
01024 GUTF8String
01025 GMapOval::get_xmltag(const int height) const
01026 {
01027 return GMapArea2xmltag( *this, GUTF8String(get_xmin())
01028 +","+GUTF8String(height-1-get_ymax())
01029 +","+GUTF8String(get_xmax())
01030 +","+GUTF8String(height-1-get_ymin()));
01031 #if 0
01032 GUTF8String retval;
01033 return retval;
01034 #endif
01035 }
01036
01037 GUTF8String
01038 GMapPoly::get_xmltag(const int height) const
01039 {
01040 GList<int> CoordList;
01041 get_coords(CoordList);
01042 GPosition pos=CoordList;
01043 GUTF8String retval;
01044 if(pos)
01045 {
01046 GUTF8String coords(CoordList[pos]);
01047 while(++pos)
01048 {
01049 coords+=","+GUTF8String(height-1-CoordList[pos]);
01050 if(! ++pos)
01051 break;
01052 coords+=","+GUTF8String(CoordList[pos]);
01053 }
01054 retval=GMapArea2xmltag( *this, coords);
01055 }
01056 return retval;
01057 }
01058
01059
01060 #ifdef HAVE_NAMESPACES
01061 }
01062 # ifndef NOT_USING_DJVU_NAMESPACE
01063 using namespace DJVU;
01064 # endif
01065 #endif
01066