/********************************************************************** * File: polyblk.c (Formerly poly_block.c) * Description: Polygonal blocks * Author: Sheelagh Lloyd? * Created: * * (C) Copyright 1993, 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 #include #include #include "elst.h" #include "polyblk.h" #include "hpddef.h" //must be last (handpd.dll) #define PBLOCK_LABEL_SIZE 150 #define INTERSECTING MAX_INT16 int lessthan(const void *first, const void *second); POLY_BLOCK::POLY_BLOCK(ICOORDELT_LIST *points, POLY_TYPE t) { ICOORDELT_IT v = &vertices; vertices.clear (); v.move_to_first (); v.add_list_before (points); compute_bb(); type = t; } /********************************************************************** * POLY_BLOCK::compute_bb * * Compute the bounding box from the outline points. **********************************************************************/ void POLY_BLOCK::compute_bb() { //constructor ICOORD ibl, itr; //integer bb ICOORD botleft; //bounding box ICOORD topright; ICOORD pos; //current pos; ICOORDELT_IT pts = &vertices; //iterator botleft = *pts.data (); topright = botleft; do { pos = *pts.data (); if (pos.x () < botleft.x ()) //get bounding box botleft = ICOORD (pos.x (), botleft.y ()); if (pos.y () < botleft.y ()) botleft = ICOORD (botleft.x (), pos.y ()); if (pos.x () > topright.x ()) topright = ICOORD (pos.x (), topright.y ()); if (pos.y () > topright.y ()) topright = ICOORD (topright.x (), pos.y ()); pts.forward (); } while (!pts.at_first ()); ibl = ICOORD (botleft.x (), botleft.y ()); itr = ICOORD (topright.x (), topright.y ()); box = BOX (ibl, itr); } /********************************************************************** * POLY_BLOCK::winding_number * * Return the winding number of the outline around the given point. **********************************************************************/ INT16 POLY_BLOCK::winding_number( //winding number const ICOORD &point //point to wind around ) { INT16 count; //winding count ICOORD pt; //current point ICOORD vec; //point to current point ICOORD vvec; //current point to next point INT32 cross; //cross product ICOORDELT_IT it = &vertices; //iterator count = 0; do { pt = *it.data (); vec = pt - point; vvec = *it.data_relative (1) - pt; //crossing the line if (vec.y () <= 0 && vec.y () + vvec.y () > 0) { cross = vec * vvec; //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 () + vvec.y () <= 0) { cross = vec * vvec; if (cross < 0) count--; //crossing back else if (cross == 0) return INTERSECTING; //illegal } else if (vec.y () == 0 && vec.x () == 0) return INTERSECTING; it.forward (); } while (!it.at_first ()); return count; //winding number } /********************************************************************** * POLY_BLOCK::contains * * Is poly within poly **********************************************************************/ BOOL8 POLY_BLOCK::contains( //other outline POLY_BLOCK *other) { INT16 count; //winding count ICOORDELT_IT it = &vertices; //iterator ICOORD vertex; if (!box.overlap (*(other->bounding_box ()))) return FALSE; //can't be contained /* check that no vertex of this is inside other */ do { vertex = *it.data (); //get winding number count = other->winding_number (vertex); if (count != INTERSECTING) if (count != 0) return (FALSE); it.forward (); } while (!it.at_first ()); /* check that all vertices of other are inside this */ //switch lists it.set_to_list (other->points ()); do { vertex = *it.data (); //try other way round count = winding_number (vertex); if (count != INTERSECTING) if (count == 0) return (FALSE); it.forward (); } while (!it.at_first ()); return TRUE; } /********************************************************************** * POLY_BLOCK::rotate * * Rotate the POLY_BLOCK. **********************************************************************/ void POLY_BLOCK::rotate( //constructor FCOORD rotation //cos,sin of angle ) { FCOORD pos; //current pos; ICOORDELT *pt; //current point ICOORDELT_IT pts = &vertices; //iterator do { pt = pts.data (); pos.set_x (pt->x ()); pos.set_y (pt->y ()); pos.rotate (rotation); pt->set_x ((INT16) (floor (pos.x () + 0.5))); pt->set_y ((INT16) (floor (pos.y () + 0.5))); pts.forward (); } while (!pts.at_first ()); compute_bb(); } /********************************************************************** * POLY_BLOCK::move * * Move the POLY_BLOCK. **********************************************************************/ void POLY_BLOCK::move( //constructor ICOORD shift //cos,sin of angle ) { ICOORDELT *pt; //current point ICOORDELT_IT pts = &vertices; //iterator do { pt = pts.data (); *pt += shift; pts.forward (); } while (!pts.at_first ()); compute_bb(); } #ifndef GRAPHICS_DISABLED void POLY_BLOCK::plot(WINDOW window, COLOUR colour, INT32 num) { ICOORDELT_IT v = &vertices; line_color_index(window, colour); v.move_to_first (); if (num > 0) { text_color_index(window, colour); character_height (window, (float) 80); text_font_index (window, 6); char temp_buff[34]; #ifdef __UNIX__ sprintf(temp_buff, INT32FORMAT, num); #else ltoa (num, temp_buff, 10); #endif text2d (window, v.data ()->x (), v.data ()->y (), temp_buff, 0, FALSE); } move2d (window, v.data ()->x (), v.data ()->y ()); for (v.mark_cycle_pt (); !v.cycled_list (); v.forward ()) draw2d (window, v.data ()->x (), v.data ()->y ()); v.move_to_first (); draw2d (window, v.data ()->x (), v.data ()->y ()); } void POLY_BLOCK::fill(WINDOW window, COLOUR colour) { INT16 y; INT16 width; PB_LINE_IT *lines; ICOORDELT_LIST *segments; ICOORDELT_IT s_it; lines = new PB_LINE_IT (this); line_color_index(window, colour); for (y = this->bounding_box ()->bottom (); y <= this->bounding_box ()->top (); y++) { segments = lines->get_line (y); if (!segments->empty ()) { s_it.set_to_list (segments); for (s_it.mark_cycle_pt (); !s_it.cycled_list (); s_it.forward ()) { // Note different use of ICOORDELT, x coord is x coord of pixel // at the start of line segment, y coord is length of line segment // Last pixel is start pixel + length. width = s_it.data ()->y (); move2d (window, s_it.data ()->x (), y); draw2d (window, s_it.data ()->x () + (float) width, y); } } } } #endif BOOL8 POLY_BLOCK::overlap( // do polys overlap POLY_BLOCK *other) { INT16 count; //winding count ICOORDELT_IT it = &vertices; //iterator ICOORD vertex; if (!box.overlap (*(other->bounding_box ()))) return FALSE; //can't be any overlap /* see if a vertex of this is inside other */ do { vertex = *it.data (); //get winding number count = other->winding_number (vertex); if (count != INTERSECTING) if (count != 0) return (TRUE); it.forward (); } while (!it.at_first ()); /* see if a vertex of other is inside this */ //switch lists it.set_to_list (other->points ()); do { vertex = *it.data (); //try other way round count = winding_number (vertex); if (count != INTERSECTING) if (count != 0) return (TRUE); it.forward (); } while (!it.at_first ()); return FALSE; } ICOORDELT_LIST *PB_LINE_IT::get_line(INT16 y) { ICOORDELT_IT v, r; ICOORDELT_LIST *result; ICOORDELT *x, *current, *previous; float fy, fx; fy = (float) (y + 0.5); result = new ICOORDELT_LIST (); r.set_to_list (result); v.set_to_list (block->points ()); for (v.mark_cycle_pt (); !v.cycled_list (); v.forward ()) { if (((v.data_relative (-1)->y () > y) && (v.data ()->y () <= y)) || ((v.data_relative (-1)->y () <= y) && (v.data ()->y () > y))) { previous = v.data_relative (-1); current = v.data (); fx = (float) (0.5 + previous->x () + (current->x () - previous->x ()) * (fy - previous->y ()) / (current->y () - previous->y ())); x = new ICOORDELT ((INT16) fx, 0); r.add_to_end (x); } } if (!r.empty ()) { r.sort (lessthan); for (r.mark_cycle_pt (); !r.cycled_list (); r.forward ()) x = r.data (); for (r.mark_cycle_pt (); !r.cycled_list (); r.forward ()) { r.data ()->set_y (r.data_relative (1)->x () - r.data ()->x ()); r.forward (); delete (r.extract ()); } } return result; } int lessthan(const void *first, const void *second) { ICOORDELT *p1 = (*(ICOORDELT **) first); ICOORDELT *p2 = (*(ICOORDELT **) second); if (p1->x () < p2->x ()) return (-1); else if (p1->x () > p2->x ()) return (1); else return (0); } /********************************************************************** * POLY_BLOCK::serialise_asc * * Converto to ascii file. **********************************************************************/ void POLY_BLOCK::serialise_asc( //convert to ascii FILE *f //file to use ) { vertices.serialise_asc (f); box.serialise_asc (f); serialise_INT32(f, type); } /********************************************************************** * POLY_BLOCK::de_serialise_asc * * Converto from ascii file. **********************************************************************/ void POLY_BLOCK::de_serialise_asc( //convert from ascii FILE *f //file to use ) { vertices.de_serialise_asc (f); box.de_serialise_asc (f); type = (POLY_TYPE) de_serialise_INT32 (f); }