00001
00020 #include "mfcpch.h"
00021 #include <stdio.h>
00022 #include <ctype.h>
00023 #include <math.h>
00024 #include "elst.h"
00025 #include "polyblk.h"
00026
00027 #include "hpddef.h"
00028
00029 #define PBLOCK_LABEL_SIZE 150
00030 #define INTERSECTING MAX_INT16
00031
00032 int lessthan(const void *first, const void *second);
00033
00034
00038 POLY_BLOCK::POLY_BLOCK(ICOORDELT_LIST *points, POLY_TYPE t) {
00039 ICOORDELT_IT v = &vertices;
00040
00041 vertices.clear ();
00042 v.move_to_first ();
00043 v.add_list_before (points);
00044 compute_bb();
00045 type = t;
00046 }
00047
00048
00052 void POLY_BLOCK::compute_bb() {
00053 ICOORD ibl, itr;
00054 ICOORD botleft;
00055 ICOORD topright;
00056 ICOORD pos;
00057 ICOORDELT_IT pts = &vertices;
00058
00059 botleft = *pts.data ();
00060 topright = botleft;
00061 do {
00062 pos = *pts.data ();
00063 if (pos.x () < botleft.x ())
00064
00065 botleft = ICOORD (pos.x (), botleft.y ());
00066 if (pos.y () < botleft.y ())
00067 botleft = ICOORD (botleft.x (), pos.y ());
00068 if (pos.x () > topright.x ())
00069 topright = ICOORD (pos.x (), topright.y ());
00070 if (pos.y () > topright.y ())
00071 topright = ICOORD (topright.x (), pos.y ());
00072 pts.forward ();
00073 }
00074 while (!pts.at_first ());
00075 ibl = ICOORD (botleft.x (), botleft.y ());
00076 itr = ICOORD (topright.x (), topright.y ());
00077 box = BOX (ibl, itr);
00078 }
00079
00080
00081
00085 INT16 POLY_BLOCK::winding_number(
00086 const ICOORD &point
00087 ) {
00088 INT16 count;
00089 ICOORD pt;
00090 ICOORD vec;
00091 ICOORD vvec;
00092 INT32 cross;
00093 ICOORDELT_IT it = &vertices;
00094
00095 count = 0;
00096 do {
00097 pt = *it.data ();
00098 vec = pt - point;
00099 vvec = *it.data_relative (1) - pt;
00100
00101 if (vec.y () <= 0 && vec.y () + vvec.y () > 0) {
00102 cross = vec * vvec;
00103 if (cross > 0)
00104 count++;
00105 else if (cross == 0)
00106 return INTERSECTING;
00107 }
00108 else if (vec.y () > 0 && vec.y () + vvec.y () <= 0) {
00109 cross = vec * vvec;
00110 if (cross < 0)
00111 count--;
00112 else if (cross == 0)
00113 return INTERSECTING;
00114 }
00115 else if (vec.y () == 0 && vec.x () == 0)
00116 return INTERSECTING;
00117 it.forward ();
00118 }
00119 while (!it.at_first ());
00120 return count;
00121 }
00122
00123
00124
00128 BOOL8 POLY_BLOCK::contains(
00129 POLY_BLOCK *other) {
00130 INT16 count;
00131 ICOORDELT_IT it = &vertices;
00132 ICOORD vertex;
00133
00134 if (!box.overlap (*(other->bounding_box ())))
00135 return FALSE;
00136
00137
00138
00139 do {
00140 vertex = *it.data ();
00141
00142 count = other->winding_number (vertex);
00143 if (count != INTERSECTING)
00144 if (count != 0)
00145 return (FALSE);
00146 it.forward ();
00147 }
00148 while (!it.at_first ());
00149
00150
00151 it.set_to_list (other->points ());
00152 do {
00153 vertex = *it.data ();
00154
00155 count = winding_number (vertex);
00156 if (count != INTERSECTING)
00157 if (count == 0)
00158 return (FALSE);
00159 it.forward ();
00160 }
00161 while (!it.at_first ());
00162 return TRUE;
00163 }
00164
00165
00166
00170 void POLY_BLOCK::rotate(
00171 FCOORD rotation
00172 ) {
00173 FCOORD pos;
00174 ICOORDELT *pt;
00175 ICOORDELT_IT pts = &vertices;
00176
00177 do {
00178 pt = pts.data ();
00179 pos.set_x (pt->x ());
00180 pos.set_y (pt->y ());
00181 pos.rotate (rotation);
00182 pt->set_x ((INT16) (floor (pos.x () + 0.5)));
00183 pt->set_y ((INT16) (floor (pos.y () + 0.5)));
00184 pts.forward ();
00185 }
00186 while (!pts.at_first ());
00187 compute_bb();
00188 }
00189
00190
00191
00195 void POLY_BLOCK::move(
00196 ICOORD shift
00197 ) {
00198 ICOORDELT *pt;
00199 ICOORDELT_IT pts = &vertices;
00200
00201 do {
00202 pt = pts.data ();
00203 *pt += shift;
00204 pts.forward ();
00205 }
00206 while (!pts.at_first ());
00207 compute_bb();
00208 }
00209
00210
00211
00215 #ifndef GRAPHICS_DISABLED
00216 void POLY_BLOCK::plot(WINDOW window, COLOUR colour, INT32 num) {
00217 ICOORDELT_IT v = &vertices;
00218
00219 line_color_index(window, colour);
00220 v.move_to_first ();
00221
00222 if (num > 0) {
00223 text_color_index(window, colour);
00224 character_height (window, (float) 80);
00225 text_font_index (window, 6);
00226 char temp_buff[34];
00227 #ifdef __UNIX__
00228 sprintf(temp_buff, INT32FORMAT, num);
00229 #else
00230 ltoa (num, temp_buff, 10);
00231 #endif
00232 text2d (window, v.data ()->x (), v.data ()->y (), temp_buff, 0, FALSE);
00233 }
00234 move2d (window, v.data ()->x (), v.data ()->y ());
00235 for (v.mark_cycle_pt (); !v.cycled_list (); v.forward ())
00236 draw2d (window, v.data ()->x (), v.data ()->y ());
00237 v.move_to_first ();
00238 draw2d (window, v.data ()->x (), v.data ()->y ());
00239 }
00240
00241
00242
00246 void POLY_BLOCK::fill(WINDOW window, COLOUR colour) {
00247 INT16 y;
00248 INT16 width;
00249 PB_LINE_IT *lines;
00250 ICOORDELT_LIST *segments;
00251 ICOORDELT_IT s_it;
00252
00253 lines = new PB_LINE_IT (this);
00254
00255 line_color_index(window, colour);
00256
00257 for (y = this->bounding_box ()->bottom ();
00258 y <= this->bounding_box ()->top (); y++) {
00259 segments = lines->get_line (y);
00260 if (!segments->empty ()) {
00261 s_it.set_to_list (segments);
00262 for (s_it.mark_cycle_pt (); !s_it.cycled_list (); s_it.forward ()) {
00263
00264
00265
00266 width = s_it.data ()->y ();
00267 move2d (window, s_it.data ()->x (), y);
00268 draw2d (window, s_it.data ()->x () + (float) width, y);
00269 }
00270 }
00271 }
00272 }
00273 #endif
00274
00275
00276
00280 BOOL8 POLY_BLOCK::overlap(
00281 POLY_BLOCK *other) {
00282 INT16 count;
00283 ICOORDELT_IT it = &vertices;
00284 ICOORD vertex;
00285
00286 if (!box.overlap (*(other->bounding_box ())))
00287 return FALSE;
00288
00289
00290 do {
00291 vertex = *it.data ();
00292
00293 count = other->winding_number (vertex);
00294 if (count != INTERSECTING)
00295 if (count != 0)
00296 return (TRUE);
00297 it.forward ();
00298 }
00299 while (!it.at_first ());
00300
00301
00302
00303
00304 it.set_to_list (other->points ());
00305 do {
00306 vertex = *it.data ();
00307
00308 count = winding_number (vertex);
00309 if (count != INTERSECTING)
00310 if (count != 0)
00311 return (TRUE);
00312 it.forward ();
00313 }
00314 while (!it.at_first ());
00315 return FALSE;
00316 }
00317
00318
00319
00323 ICOORDELT_LIST *PB_LINE_IT::get_line(INT16 y) {
00324 ICOORDELT_IT v, r;
00325 ICOORDELT_LIST *result;
00326 ICOORDELT *x, *current, *previous;
00327 float fy, fx;
00328
00329 fy = (float) (y + 0.5);
00330 result = new ICOORDELT_LIST ();
00331 r.set_to_list (result);
00332 v.set_to_list (block->points ());
00333
00334 for (v.mark_cycle_pt (); !v.cycled_list (); v.forward ()) {
00335 if (((v.data_relative (-1)->y () > y) && (v.data ()->y () <= y))
00336 || ((v.data_relative (-1)->y () <= y) && (v.data ()->y () > y))) {
00337 previous = v.data_relative (-1);
00338 current = v.data ();
00339 fx = (float) (0.5 + previous->x () +
00340 (current->x () - previous->x ()) * (fy -
00341 previous->y ()) /
00342 (current->y () - previous->y ()));
00343 x = new ICOORDELT ((INT16) fx, 0);
00344 r.add_to_end (x);
00345 }
00346 }
00347
00348 if (!r.empty ()) {
00349 r.sort (lessthan);
00350 for (r.mark_cycle_pt (); !r.cycled_list (); r.forward ())
00351 x = r.data ();
00352 for (r.mark_cycle_pt (); !r.cycled_list (); r.forward ()) {
00353 r.data ()->set_y (r.data_relative (1)->x () - r.data ()->x ());
00354 r.forward ();
00355 delete (r.extract ());
00356 }
00357 }
00358
00359 return result;
00360 }
00361
00362
00363
00367 int lessthan(const void *first, const void *second) {
00368 ICOORDELT *p1 = (*(ICOORDELT **) first);
00369 ICOORDELT *p2 = (*(ICOORDELT **) second);
00370
00371 if (p1->x () < p2->x ())
00372 return (-1);
00373 else if (p1->x () > p2->x ())
00374 return (1);
00375 else
00376 return (0);
00377 }
00378
00379
00380
00384 void POLY_BLOCK::serialise_asc(
00385 FILE *f
00386 ) {
00387 vertices.serialise_asc (f);
00388 box.serialise_asc (f);
00389 serialise_INT32(f, type);
00390 }
00391
00392
00393
00397 void POLY_BLOCK::de_serialise_asc(
00398 FILE *f
00399 ) {
00400 vertices.de_serialise_asc (f);
00401 box.de_serialise_asc (f);
00402 type = (POLY_TYPE) de_serialise_INT32 (f);
00403 }