| /********************************************************************** |
| * 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); |
| if (!children.empty ()) |
| children.clear (); |
| children.deep_copy (&source.children); |
| return *this; |
| } |