/********************************************************************** * File: poutline.cpp (Formerly outline.c) * Description: Code for OUTLINE class. * Author: Ray Smith * Created: Wed Oct 23 10:52:04 BST 1991 * * (C) Copyright 1991, Hewlett-Packard Ltd. ** Licensed under the Apache License, Version 2.0 (the "License"); ** you may not use this file except in compliance with the License. ** You may obtain a copy of the License at ** http://www.apache.org/licenses/LICENSE-2.0 ** Unless required by applicable law or agreed to in writing, software ** distributed under the License is distributed on an "AS IS" BASIS, ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ** See the License for the specific language governing permissions and ** limitations under the License. * **********************************************************************/ #include "mfcpch.h" #include "poutline.h" ELISTIZE_S (OUTLINE) /********************************************************************** * OUTLINE::OUTLINE * * Constructor to build a OUTLINE from a compact LOOP. **********************************************************************/ OUTLINE::OUTLINE ( //constructor const ICOORD & startpt, //start position inT8 * compactloop, //from Tess format BOOL8 invert, //reverse it ICOORD bot_left, //bounding box ICOORD top_right): box (bot_left, top_right), start(startpt) { ICOORD pos; //current point ICOORD vec; //vector to next POLYPT *polypt; //new point inT8 *vector; //compact loop POLYPT_IT it = &outline; //iterator pos = startpt; vector = compactloop; do { //vector to next vec = ICOORD (*vector, *(vector + 1)); //make a new one polypt = new POLYPT (FCOORD (pos), FCOORD (vec)); //add to list it.add_after_then_move (polypt); pos += vec; //move to next vector += 2; } while (pos != startpt); if (invert) reverse(); //now reverse it } /********************************************************************** * OUTLINE::OUTLINE * * Constructor to build an OUTLINE from a list of POLYPTs. **********************************************************************/ OUTLINE::OUTLINE( //constructor POLYPT_IT *polypts //input list ) { POLYPT_IT other_it = *polypts; //end of list polypts->move_to_first (); other_it.move_to_last (); //put in outline outline.assign_to_sublist (polypts, &other_it); compute_bb(); } /********************************************************************** * OUTLINE::compute_bb * * Compute the bounding box from the outline points. **********************************************************************/ void OUTLINE::compute_bb() { //constructor ICOORD ibl, itr; //integer bb FCOORD botleft; //bounding box FCOORD topright; FCOORD pos; //current pos; POLYPT_IT polypts = &outline; //iterator botleft = polypts.data ()->pos; topright = botleft; start = ICOORD ((inT16) botleft.x (), (inT16) botleft.y ()); do { pos = polypts.data ()->pos; if (pos.x () < botleft.x ()) //get bounding box botleft = FCOORD (pos.x (), botleft.y ()); if (pos.y () < botleft.y ()) botleft = FCOORD (botleft.x (), pos.y ()); if (pos.x () > topright.x ()) topright = FCOORD (pos.x (), topright.y ()); if (pos.y () > topright.y ()) topright = FCOORD (topright.x (), pos.y ()); polypts.forward (); } while (!polypts.at_first ()); ibl = ICOORD ((inT16) botleft.x (), (inT16) botleft.y ()); itr = ICOORD ((inT16) topright.x () + 1, (inT16) topright.y () + 1); box = TBOX (ibl, itr); } /********************************************************************** * OUTLINE::area * * Compute the area from the outline points. **********************************************************************/ float OUTLINE::area() { //constructor FCOORD origin; //startpt FCOORD prev_vec; //previous value of vec FCOORD vec; //from start to current float total; //total area POLYPT_IT poly_it = polypts ();//iterator //child outline itertr OUTLINE_IT child_it(&children); origin = poly_it.data ()->pos; poly_it.forward (); vec = poly_it.data ()->pos - origin; poly_it.forward (); total = 0.0f; while (!poly_it.at_first ()) { prev_vec = vec; vec = poly_it.data ()->pos - origin; total += prev_vec * vec; poly_it.forward (); } total /= 2; for (child_it.mark_cycle_pt (); !child_it.cycled_list (); child_it.forward ()) { //add ares of childrein total += child_it.data ()->area (); } return total; } /********************************************************************** * OUTLINE::operator< * * Return TRUE if the left operand is inside the right one. **********************************************************************/ BOOL8 OUTLINE::operator< ( //winding number OUTLINE & other //other outline ) { inT16 count; //winding count POLYPT_IT it = &outline; //iterator if (!box.overlap (other.box)) return FALSE; //can't be contained do { count = other.winding_number (FCOORD (it.data ()->pos)); //get winding number if (count != INTERSECTING) return count != 0; it.forward (); } while (!it.at_first ()); //switch lists it.set_to_list (&other.outline); do { //try other way round count = winding_number (FCOORD (it.data ()->pos)); if (count != INTERSECTING) return count == 0; it.forward (); } while (!it.at_first ()); return TRUE; } /********************************************************************** * OUTLINE::winding_number * * Return the winding number of the outline around the given point. **********************************************************************/ inT16 OUTLINE::winding_number( //winding number const FCOORD &point //point to wind around ) { inT16 count; //winding count POLYPT *polypt; //current point FCOORD vec; //to current point float cross; //cross product POLYPT_IT it = &outline; //iterator count = 0; do { polypt = it.data (); vec = polypt->pos - point; //crossing the line if (vec.y () <= 0 && vec.y () + polypt->vec.y () > 0) { cross = vec * polypt->vec; //cross product if (cross > 0) count++; //crossing right half else if (cross == 0) return INTERSECTING; //going through point } else if (vec.y () > 0 && vec.y () + polypt->vec.y () <= 0) { cross = vec * polypt->vec; if (cross < 0) count--; //crossing back else if (cross == 0) return INTERSECTING; //illegal } it.forward (); } while (!it.at_first ()); return count; //winding number } /********************************************************************** * OUTLINE::reverse * * Reverse the direction of an outline. **********************************************************************/ void OUTLINE::reverse() { //reverse direction POLYPT_LIST back_list; //reversed list POLYPT_IT dest_it = &back_list;//destination POLYPT_IT src_it = &outline; //source list POLYPT *polypt; //current point do { polypt = src_it.extract (); //copy in reverse dest_it.add_after_then_move (polypt); src_it.backward (); } while (!src_it.empty ()); dest_it.move_to_first (); do { polypt = dest_it.data (); polypt->vec = dest_it.data_relative (1)->pos - polypt->pos; //vector to next dest_it.forward (); } while (!dest_it.at_first ()); dest_it.backward (); src_it.set_to_list (&back_list); //put it back outline.assign_to_sublist (&src_it, &dest_it); } /********************************************************************** * OUTLINE::move * * Move OUTLINE by vector **********************************************************************/ void OUTLINE::move( // reposition OUTLINE const FCOORD vec // by vector ) { //child outline itertr OUTLINE_IT child_it(&children); POLYPT_IT poly_it(&outline); //outline point itertr box.move (vec); start.set_x ((inT16) floor (start.x () + vec.x () + 0.5)); // ?? Why ICOORD? start.set_y ((inT16) floor (start.y () + vec.y () + 0.5)); // ?? Why ICOORD? for (poly_it.mark_cycle_pt (); !poly_it.cycled_list (); poly_it.forward ()) poly_it.data ()->pos += vec; for (child_it.mark_cycle_pt (); !child_it.cycled_list (); child_it.forward ()) child_it.data ()->move (vec); // move child outlines } /********************************************************************** * OUTLINE::scale * * Scale OUTLINE by vector **********************************************************************/ void OUTLINE::scale( // scale OUTLINE const float f // by multiplier ) { //child outline itertr OUTLINE_IT child_it(&children); POLYPT_IT poly_it(&outline); //outline point itertr POLYPT *pt; box.scale (f); // ?? Why ICOORD? start.set_x ((inT16) floor (start.x () * f + 0.5)); // ?? Why ICOORD? start.set_y ((inT16) floor (start.y () * f + 0.5)); for (poly_it.mark_cycle_pt (); !poly_it.cycled_list (); poly_it.forward ()) { pt = poly_it.data (); pt->pos *= f; pt->vec *= f; } for (child_it.mark_cycle_pt (); !child_it.cycled_list (); child_it.forward ()) child_it.data ()->scale (f); //scale child outlines } /********************************************************************** * OUTLINE::scale * * Scale OUTLINE by vector **********************************************************************/ void OUTLINE::scale( // scale OUTLINE const FCOORD vector //by fcoord ) { //child outline itertr OUTLINE_IT child_it(&children); POLYPT_IT poly_it(&outline); //outline point itertr POLYPT *pt; box.scale (vector); start.set_x ((inT16) floor (start.x () * vector.x () + 0.5)); // ?? Why ICOORD? start.set_y ((inT16) floor (start.y () * vector.y () + 0.5)); // ?? Why ICOORD? for (poly_it.mark_cycle_pt (); !poly_it.cycled_list (); poly_it.forward ()) { pt = poly_it.data (); pt->pos = FCOORD (pt->pos.x () * vector.x (), pt->pos.y () * vector.y ()); pt->vec = FCOORD (pt->vec.x () * vector.x (), pt->vec.y () * vector.y ()); } for (child_it.mark_cycle_pt (); !child_it.cycled_list (); child_it.forward ()) //scale child outlines child_it.data ()->scale (vector); } /********************************************************************** * OUTLINE::rotate * * Rotate OUTLINE by the given vector **********************************************************************/ void OUTLINE::rotate( const FCOORD vector //by fcoord ) { //child outline itertr OUTLINE_IT child_it(&children); POLYPT_IT poly_it(&outline); //outline point itertr POLYPT *pt; box.rotate(vector); start.rotate(vector); for (poly_it.mark_cycle_pt (); !poly_it.cycled_list (); poly_it.forward ()) { pt = poly_it.data (); pt->pos.rotate(vector); pt->vec.rotate(vector); } for (child_it.mark_cycle_pt (); !child_it.cycled_list (); child_it.forward ()) //scale child outlines child_it.data ()->rotate(vector); } /********************************************************************** * OUTLINE::plot * * Draw the outline in the given colour. **********************************************************************/ #ifndef GRAPHICS_DISABLED void OUTLINE::plot( //draw it ScrollView* window, //window to draw in ScrollView::Color colour //colour to draw in ) { POLYPT *polypt; //current point POLYPT_IT it = &outline; //iterator window->Pen(colour); polypt = it.data (); int startx = polypt->pos.x (); int starty = polypt->pos.y (); do { it.forward (); polypt = it.data (); window->Line(startx,starty,polypt->pos.x (),polypt->pos.y ()); startx = polypt->pos.x (); starty = polypt->pos.y (); } while (!it.at_first ()); } #endif /********************************************************************** * OUTLINE::operator= * * Assignment - deep copy data **********************************************************************/ OUTLINE & OUTLINE::operator= ( //assignment const OUTLINE & source //from this ) { box = source.box; start = source.start; if (!outline.empty()) outline.clear(); outline.deep_copy(&source.outline, &POLYPT::deep_copy); if (!children.empty()) children.clear(); children.deep_copy(&source.children, &OUTLINE::deep_copy); return *this; }