00001
00020 #include "mfcpch.h"
00021 #include "poutline.h"
00022
00023 ELISTIZE_S (OUTLINE)
00027 OUTLINE::OUTLINE (
00028 const ICOORD & startpt,
00029 INT8 * compactloop,
00030 BOOL8 invert,
00031 ICOORD bot_left,
00032 ICOORD top_right):
00033 box (bot_left, top_right),
00034 start(startpt) {
00035 ICOORD pos;
00036 ICOORD vec;
00037 POLYPT *polypt;
00038 INT8 *vector;
00039 POLYPT_IT it = &outline;
00040
00041 pos = startpt;
00042 vector = compactloop;
00043 do {
00044
00045 vec = ICOORD (*vector, *(vector + 1));
00046
00047 polypt = new POLYPT (FCOORD (pos), FCOORD (vec));
00048
00049 it.add_after_then_move (polypt);
00050 pos += vec;
00051 vector += 2;
00052 }
00053 while (pos != startpt);
00054 if (invert)
00055 reverse();
00056 }
00057
00058
00062 OUTLINE::OUTLINE(
00063 POLYPT_IT *polypts
00064 ) {
00065 POLYPT_IT other_it = *polypts;
00066
00067 polypts->move_to_first ();
00068 other_it.move_to_last ();
00069
00070 outline.assign_to_sublist (polypts, &other_it);
00071 compute_bb();
00072 }
00073
00074
00078 void OUTLINE::compute_bb() {
00079 ICOORD ibl, itr;
00080 FCOORD botleft;
00081 FCOORD topright;
00082 FCOORD pos;
00083 POLYPT_IT polypts = &outline;
00084
00085 botleft = polypts.data ()->pos;
00086 topright = botleft;
00087 start = ICOORD ((INT16) botleft.x (), (INT16) botleft.y ());
00088 do {
00089 pos = polypts.data ()->pos;
00090 if (pos.x () < botleft.x ())
00091
00092 botleft = FCOORD (pos.x (), botleft.y ());
00093 if (pos.y () < botleft.y ())
00094 botleft = FCOORD (botleft.x (), pos.y ());
00095 if (pos.x () > topright.x ())
00096 topright = FCOORD (pos.x (), topright.y ());
00097 if (pos.y () > topright.y ())
00098 topright = FCOORD (topright.x (), pos.y ());
00099 polypts.forward ();
00100 }
00101 while (!polypts.at_first ());
00102 ibl = ICOORD ((INT16) botleft.x (), (INT16) botleft.y ());
00103 itr = ICOORD ((INT16) topright.x () + 1, (INT16) topright.y () + 1);
00104 box = BOX (ibl, itr);
00105 }
00106
00107
00112 float OUTLINE::area() {
00113 FCOORD origin;
00114 FCOORD prev_vec;
00115 FCOORD vec;
00116 float total;
00117 POLYPT_IT poly_it = polypts ();
00118
00119 OUTLINE_IT child_it(&children);
00120
00121 origin = poly_it.data ()->pos;
00122 poly_it.forward ();
00123 vec = poly_it.data ()->pos - origin;
00124 poly_it.forward ();
00125 total = 0.0f;
00126 while (!poly_it.at_first ()) {
00127 prev_vec = vec;
00128 vec = poly_it.data ()->pos - origin;
00129 total += prev_vec * vec;
00130 poly_it.forward ();
00131 }
00132 total /= 2;
00133 for (child_it.mark_cycle_pt (); !child_it.cycled_list ();
00134 child_it.forward ()) {
00135
00136 total += child_it.data ()->area ();
00137 }
00138 return total;
00139 }
00140
00141
00145 BOOL8
00146 OUTLINE::operator< (
00147 OUTLINE & other
00148 ) {
00149 INT16 count;
00150 POLYPT_IT it = &outline;
00151
00152 if (!box.overlap (other.box))
00153 return FALSE;
00154
00155 do {
00156 count = other.winding_number (FCOORD (it.data ()->pos));
00157
00158 if (count != INTERSECTING)
00159 return count != 0;
00160 it.forward ();
00161 }
00162 while (!it.at_first ());
00163
00164
00165 it.set_to_list (&other.outline);
00166 do {
00167
00168 count = winding_number (FCOORD (it.data ()->pos));
00169 if (count != INTERSECTING)
00170 return count == 0;
00171 it.forward ();
00172 }
00173 while (!it.at_first ());
00174 return TRUE;
00175 }
00176
00177
00181 INT16 OUTLINE::winding_number(
00182 const FCOORD &point
00183 ) {
00184 INT16 count;
00185 POLYPT *polypt;
00186 FCOORD vec;
00187 float cross;
00188 POLYPT_IT it = &outline;
00189
00190 count = 0;
00191 do {
00192 polypt = it.data ();
00193 vec = polypt->pos - point;
00194
00195 if (vec.y () <= 0 && vec.y () + polypt->vec.y () > 0) {
00196 cross = vec * polypt->vec;
00197 if (cross > 0)
00198 count++;
00199 else if (cross == 0)
00200 return INTERSECTING;
00201 }
00202 else if (vec.y () > 0 && vec.y () + polypt->vec.y () <= 0) {
00203 cross = vec * polypt->vec;
00204 if (cross < 0)
00205 count--;
00206 else if (cross == 0)
00207 return INTERSECTING;
00208 }
00209 it.forward ();
00210 }
00211 while (!it.at_first ());
00212 return count;
00213 }
00214
00215
00219 void OUTLINE::reverse() {
00220 POLYPT_LIST back_list;
00221 POLYPT_IT dest_it = &back_list;
00222 POLYPT_IT src_it = &outline;
00223 POLYPT *polypt;
00224
00225 do {
00226 polypt = src_it.extract ();
00227
00228 dest_it.add_after_then_move (polypt);
00229 src_it.backward ();
00230 }
00231 while (!src_it.empty ());
00232 dest_it.move_to_first ();
00233 do {
00234 polypt = dest_it.data ();
00235 polypt->vec = dest_it.data_relative (1)->pos - polypt->pos;
00236
00237 dest_it.forward ();
00238 }
00239 while (!dest_it.at_first ());
00240 dest_it.backward ();
00241 src_it.set_to_list (&back_list);
00242
00243 outline.assign_to_sublist (&src_it, &dest_it);
00244 }
00245
00249 void OUTLINE::move(
00250 const FCOORD vec
00251 ) {
00252
00253 OUTLINE_IT child_it(&children);
00254 POLYPT_IT poly_it(&outline);
00255
00256 box.move (vec);
00257
00258 start.set_x ((INT16) floor (start.x () + vec.x () + 0.5));
00259
00260 start.set_y ((INT16) floor (start.y () + vec.y () + 0.5));
00261
00262
00263 for (poly_it.mark_cycle_pt (); !poly_it.cycled_list (); poly_it.forward ())
00264 poly_it.data ()->pos += vec;
00265
00266 for (child_it.mark_cycle_pt (); !child_it.cycled_list ();
00267 child_it.forward ())
00268 child_it.data ()->move (vec);
00269 }
00270
00271
00275 void OUTLINE::scale(
00276 const float f
00277 ) {
00278
00279 OUTLINE_IT child_it(&children);
00280 POLYPT_IT poly_it(&outline);
00281 POLYPT *pt;
00282
00283 box.scale (f);
00284
00285
00286 start.set_x ((INT16) floor (start.x () * f + 0.5));
00287
00288 start.set_y ((INT16) floor (start.y () * f + 0.5));
00289
00290 for (poly_it.mark_cycle_pt (); !poly_it.cycled_list (); poly_it.forward ()) {
00291 pt = poly_it.data ();
00292 pt->pos *= f;
00293 pt->vec *= f;
00294 }
00295
00296 for (child_it.mark_cycle_pt (); !child_it.cycled_list ();
00297 child_it.forward ())
00298 child_it.data ()->scale (f);
00299 }
00300
00301
00305 void OUTLINE::scale(
00306 const FCOORD vector
00307 ) {
00308
00309 OUTLINE_IT child_it(&children);
00310 POLYPT_IT poly_it(&outline);
00311 POLYPT *pt;
00312
00313 box.scale (vector);
00314
00315 start.set_x ((INT16) floor (start.x () * vector.x () + 0.5));
00316
00317 start.set_y ((INT16) floor (start.y () * vector.y () + 0.5));
00318
00319
00320 for (poly_it.mark_cycle_pt (); !poly_it.cycled_list (); poly_it.forward ()) {
00321 pt = poly_it.data ();
00322 pt->pos =
00323 FCOORD (pt->pos.x () * vector.x (), pt->pos.y () * vector.y ());
00324 pt->vec =
00325 FCOORD (pt->vec.x () * vector.x (), pt->vec.y () * vector.y ());
00326 }
00327
00328 for (child_it.mark_cycle_pt (); !child_it.cycled_list ();
00329 child_it.forward ())
00330
00331 child_it.data ()->scale (vector);
00332 }
00333
00334
00338 #ifndef GRAPHICS_DISABLED
00339 void OUTLINE::plot(
00340 WINDOW window,
00341 COLOUR colour
00342 ) {
00343 POLYPT *polypt;
00344 POLYPT_IT it = &outline;
00345
00346 line_color_index(window, colour);
00347 polypt = it.data ();
00348 move2d (window, polypt->pos.x (), polypt->pos.y ());
00349 do {
00350 it.forward ();
00351 polypt = it.data ();
00352 draw2d (window, polypt->pos.x (), polypt->pos.y ());
00353 }
00354 while (!it.at_first ());
00355 }
00356
00357
00361 OUTLINE & OUTLINE::operator= (
00362 const OUTLINE & source
00363 ) {
00364 box = source.box;
00365 start = source.start;
00366 if (!outline.empty ())
00367 outline.clear ();
00368 outline.deep_copy (&source.outline);
00369 if (!children.empty ())
00370 children.clear ();
00371 children.deep_copy (&source.children);
00372 return *this;
00373 }
00374 #endif