1 /**********************************************************************
2 * File: pdblock.c (Formerly pdblk.c)
3 * Description: PDBLK member functions and iterator functions.
4 * Author: Ray Smith
5 * Created: Fri Mar 15 09:41:28 GMT 1991
6 *
7 * (C) Copyright 1991, Hewlett-Packard Ltd.
8 ** Licensed under the Apache License, Version 2.0 (the "License");
9 ** you may not use this file except in compliance with the License.
10 ** You may obtain a copy of the License at
11 ** http://www.apache.org/licenses/LICENSE-2.0
12 ** Unless required by applicable law or agreed to in writing, software
13 ** distributed under the License is distributed on an "AS IS" BASIS,
14 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 ** See the License for the specific language governing permissions and
16 ** limitations under the License.
17 *
18 **********************************************************************/
19
20 #include "mfcpch.h"
21 #include <stdlib.h>
22 #include "blckerr.h"
23 #include "pdblock.h"
24 #include "svshowim.h"
25
26 #include "hpddef.h" //must be last (handpd.dll)
27
28 #define BLOCK_LABEL_HEIGHT 150 //char height of block id
29
CLISTIZE(PDBLK)30 CLISTIZE (PDBLK)
31 /**********************************************************************
32 * PDBLK::PDBLK
33 *
34 * Constructor for a simple rectangular block.
35 **********************************************************************/
36 PDBLK::PDBLK ( //rectangular block
37 inT16 xmin, //bottom left
38 inT16 ymin, inT16 xmax, //top right
39 inT16 ymax): box (ICOORD (xmin, ymin), ICOORD (xmax, ymax)) {
40 //boundaries
41 ICOORDELT_IT left_it = &leftside;
42 ICOORDELT_IT right_it = &rightside;
43
44 hand_poly = NULL;
45 left_it.set_to_list (&leftside);
46 right_it.set_to_list (&rightside);
47 //make default box
48 left_it.add_to_end (new ICOORDELT (xmin, ymin));
49 left_it.add_to_end (new ICOORDELT (xmin, ymax));
50 right_it.add_to_end (new ICOORDELT (xmax, ymin));
51 right_it.add_to_end (new ICOORDELT (xmax, ymax));
52 index_ = 0;
53 }
54
55
56 /**********************************************************************
57 * PDBLK::set_sides
58 *
59 * Sets left and right vertex lists
60 **********************************************************************/
61
set_sides(ICOORDELT_LIST * left,ICOORDELT_LIST * right)62 void PDBLK::set_sides( //set vertex lists
63 ICOORDELT_LIST *left, //left vertices
64 ICOORDELT_LIST *right //right vertices
65 ) {
66 //boundaries
67 ICOORDELT_IT left_it = &leftside;
68 ICOORDELT_IT right_it = &rightside;
69
70 leftside.clear ();
71 left_it.move_to_first ();
72 left_it.add_list_before (left);
73 rightside.clear ();
74 right_it.move_to_first ();
75 right_it.add_list_before (right);
76 }
77
78
79 /**********************************************************************
80 * PDBLK::contains
81 *
82 * Return TRUE if the given point is within the block.
83 **********************************************************************/
84
contains(ICOORD pt)85 BOOL8 PDBLK::contains( //test containment
86 ICOORD pt //point to test
87 ) {
88 BLOCK_RECT_IT it = this; //rectangle iterator
89 ICOORD bleft, tright; //corners of rectangle
90
91 for (it.start_block (); !it.cycled_rects (); it.forward ()) {
92 //get rectangle
93 it.bounding_box (bleft, tright);
94 //inside rect
95 if (pt.x () >= bleft.x () && pt.x () <= tright.x ()
96 && pt.y () >= bleft.y () && pt.y () <= tright.y ())
97 return TRUE; //is inside
98 }
99 return FALSE; //not inside
100 }
101
102
103 /**********************************************************************
104 * PDBLK::move
105 *
106 * Reposition block
107 **********************************************************************/
108
move(const ICOORD vec)109 void PDBLK::move( // reposition block
110 const ICOORD vec // by vector
111 ) {
112 ICOORDELT_IT it(&leftside);
113
114 for (it.mark_cycle_pt (); !it.cycled_list (); it.forward ())
115 *(it.data ()) += vec;
116
117 it.set_to_list (&rightside);
118
119 for (it.mark_cycle_pt (); !it.cycled_list (); it.forward ())
120 *(it.data ()) += vec;
121
122 box.move (vec);
123 }
124
125
126 /**********************************************************************
127 * PDBLK::plot
128 *
129 * Plot the outline of a block in the given colour.
130 **********************************************************************/
131
132 #ifndef GRAPHICS_DISABLED
plot(ScrollView * window,inT32 serial,ScrollView::Color colour)133 void PDBLK::plot( //draw outline
134 ScrollView* window, //window to draw in
135 inT32 serial, //serial number
136 ScrollView::Color colour //colour to draw in
137 ) {
138 ICOORD startpt; //start of outline
139 ICOORD endpt; //end of outline
140 ICOORD prevpt; //previous point
141 ICOORDELT_IT it = &leftside; //iterator
142
143 //set the colour
144 window->Pen(colour);
145 window->TextAttributes("Times", BLOCK_LABEL_HEIGHT, false, false, false);
146
147 if (hand_poly != NULL) {
148 hand_poly->plot(window, serial);
149 } else if (!leftside.empty ()) {
150 startpt = *(it.data ()); //bottom left corner
151 // tprintf("Block %d bottom left is (%d,%d)\n",
152 // serial,startpt.x(),startpt.y());
153 char temp_buff[34];
154 #ifdef __UNIX__
155 sprintf(temp_buff, INT32FORMAT, serial);
156 #else
157 ultoa (serial, temp_buff, 10);
158 #endif
159 window->Text(startpt.x (), startpt.y (), temp_buff);
160
161 window->SetCursor(startpt.x (), startpt.y ());
162 do {
163 prevpt = *(it.data ()); //previous point
164 it.forward (); //move to next point
165 //draw round corner
166 window->DrawTo(prevpt.x (), it.data ()->y ());
167 window->DrawTo(it.data ()->x (), it.data ()->y ());
168 }
169 while (!it.at_last ()); //until end of list
170 endpt = *(it.data ()); //end point
171
172 //other side of boundary
173 window->SetCursor(startpt.x (), startpt.y ());
174 it.set_to_list (&rightside);
175 prevpt = startpt;
176 for (it.mark_cycle_pt (); !it.cycled_list (); it.forward ()) {
177 //draw round corner
178 window->DrawTo(prevpt.x (), it.data ()->y ());
179 window->DrawTo(it.data ()->x (), it.data ()->y ());
180 prevpt = *(it.data ()); //previous point
181 }
182 //close boundary
183 window->DrawTo(endpt.x(), endpt.y());
184 }
185 }
186 #endif
187
188
189 /**********************************************************************
190 * PDBLK::show
191 *
192 * Show the image corresponding to a block as its set of rectangles.
193 **********************************************************************/
194
195 #ifndef GRAPHICS_DISABLED
show(IMAGE * image,ScrollView * window)196 void PDBLK::show( //show image block
197 IMAGE *image, //image to show
198 ScrollView* window //window to show in
199 ) {
200 BLOCK_RECT_IT it = this; //rectangle iterator
201 ICOORD bleft, tright; //corners of rectangle
202
203 for (it.start_block (); !it.cycled_rects (); it.forward ()) {
204 //get rectangle
205 it.bounding_box (bleft, tright);
206 // tprintf("Drawing a block with a bottom left of (%d,%d)\n",
207 // bleft.x(),bleft.y());
208 //show it
209 sv_show_sub_image (image, bleft.x (), bleft.y (), tright.x () - bleft.x (), tright.y () - bleft.y (), window, bleft.x (), bleft.y ());
210 }
211 }
212 #endif
213
214
215 /**********************************************************************
216 * PDBLK::operator=
217 *
218 * Assignment - duplicate the block structure, but with an EMPTY row list.
219 **********************************************************************/
220
operator =(const PDBLK & source)221 PDBLK & PDBLK::operator= ( //assignment
222 const PDBLK & source //from this
223 ) {
224 // this->ELIST_LINK::operator=(source);
225 if (!leftside.empty ())
226 leftside.clear ();
227 if (!rightside.empty ())
228 rightside.clear ();
229 leftside.deep_copy(&source.leftside, &ICOORDELT::deep_copy);
230 rightside.deep_copy(&source.rightside, &ICOORDELT::deep_copy);
231 box = source.box;
232 return *this;
233 }
234
235
236 /**********************************************************************
237 * BLOCK_RECT_IT::BLOCK_RECT_IT
238 *
239 * Construct a block rectangle iterator.
240 **********************************************************************/
241
BLOCK_RECT_IT(PDBLK * blkptr)242 BLOCK_RECT_IT::BLOCK_RECT_IT (
243 //iterate rectangles
244 PDBLK * blkptr //from block
245 ):left_it (&blkptr->leftside), right_it (&blkptr->rightside) {
246 block = blkptr; //remember block
247 //non empty list
248 if (!blkptr->leftside.empty ()) {
249 start_block(); //ready for iteration
250 }
251 }
252
253
254 /**********************************************************************
255 * BLOCK_RECT_IT::set_to_block
256 *
257 * Start a new block.
258 **********************************************************************/
259
set_to_block(PDBLK * blkptr)260 void BLOCK_RECT_IT::set_to_block( //start (new) block
261 PDBLK *blkptr) { //block to start
262 block = blkptr; //remember block
263 //set iterators
264 left_it.set_to_list (&blkptr->leftside);
265 right_it.set_to_list (&blkptr->rightside);
266 if (!blkptr->leftside.empty ())
267 start_block(); //ready for iteration
268 }
269
270
271 /**********************************************************************
272 * BLOCK_RECT_IT::start_block
273 *
274 * Restart a block.
275 **********************************************************************/
276
start_block()277 void BLOCK_RECT_IT::start_block() { //start (new) block
278 left_it.move_to_first ();
279 right_it.move_to_first ();
280 left_it.mark_cycle_pt ();
281 right_it.mark_cycle_pt ();
282 ymin = left_it.data ()->y (); //bottom of first box
283 ymax = left_it.data_relative (1)->y ();
284 if (right_it.data_relative (1)->y () < ymax)
285 //smallest step
286 ymax = right_it.data_relative (1)->y ();
287 }
288
289
290 /**********************************************************************
291 * BLOCK_RECT_IT::forward
292 *
293 * Move to the next rectangle in the block.
294 **********************************************************************/
295
forward()296 void BLOCK_RECT_IT::forward() { //next rectangle
297 if (!left_it.empty ()) { //non-empty list
298 if (left_it.data_relative (1)->y () == ymax)
299 left_it.forward (); //move to meet top
300 if (right_it.data_relative (1)->y () == ymax)
301 right_it.forward ();
302 //last is special
303 if (left_it.at_last () || right_it.at_last ()) {
304 left_it.move_to_first (); //restart
305 right_it.move_to_first ();
306 //now at bottom
307 ymin = left_it.data ()->y ();
308 }
309 else {
310 ymin = ymax; //new bottom
311 }
312 //next point
313 ymax = left_it.data_relative (1)->y ();
314 if (right_it.data_relative (1)->y () < ymax)
315 //least step forward
316 ymax = right_it.data_relative (1)->y ();
317 }
318 }
319
320
321 /**********************************************************************
322 * BLOCK_LINE_IT::get_line
323 *
324 * Get the the start and width of a line in the block.
325 **********************************************************************/
326
get_line(inT16 y,inT16 & xext)327 inT16 BLOCK_LINE_IT::get_line( //get a line
328 inT16 y, //line to get
329 inT16 &xext //output extent
330 ) {
331 ICOORD bleft; //bounding box
332 ICOORD tright; //of block & rect
333
334 //get block box
335 block->bounding_box (bleft, tright);
336 if (y < bleft.y () || y >= tright.y ()) {
337 // block->print(stderr,FALSE);
338 BADBLOCKLINE.error ("BLOCK_LINE_IT::get_line", ABORT, "Y=%d", y);
339 }
340
341 //get rectangle box
342 rect_it.bounding_box (bleft, tright);
343 //inside rectangle
344 if (y >= bleft.y () && y < tright.y ()) {
345 //width of line
346 xext = tright.x () - bleft.x ();
347 return bleft.x (); //start of line
348 }
349 for (rect_it.start_block (); !rect_it.cycled_rects (); rect_it.forward ()) {
350 //get rectangle box
351 rect_it.bounding_box (bleft, tright);
352 //inside rectangle
353 if (y >= bleft.y () && y < tright.y ()) {
354 //width of line
355 xext = tright.x () - bleft.x ();
356 return bleft.x (); //start of line
357 }
358 }
359 LOSTBLOCKLINE.error ("BLOCK_LINE_IT::get_line", ABORT, "Y=%d", y);
360 return 0; //dummy to stop warning
361 }
362