1 /*
2     Copyright (c) 2005-2020 Intel Corporation
3 
4     Licensed under the Apache License, Version 2.0 (the "License");
5     you may not use this file except in compliance with the License.
6     You may obtain a copy of the License at
7 
8         http://www.apache.org/licenses/LICENSE-2.0
9 
10     Unless required by applicable law or agreed to in writing, software
11     distributed under the License is distributed on an "AS IS" BASIS,
12     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13     See the License for the specific language governing permissions and
14     limitations under the License.
15 */
16 
17 // Polygon overlay
18 //
19 // Don't want warnings about deprecated sscanf, getenv
20 #ifndef _CRT_SECURE_NO_DEPRECATE
21 #define _CRT_SECURE_NO_DEPRECATE
22 #endif
23 #define _MAIN_C_ 1
24 #include <iostream>
25 #include <iomanip>
26 #include <algorithm>
27 #include <cstring>
28 
29 #include "tbb/tick_count.h"
30 #include "pover_global.h"
31 #include "polyover.h"
32 #include "pover_video.h"
33 #include "polymain.h"
34 
35 using namespace std;
36 
37 #if _DEBUG
38 const char *faceNames[] = { "North", "East", "South", "West" };
39 #endif
40 
41 /**
42 **/
main(int argc,char ** argv)43 int main( int argc, char **argv) {
44     pover_video poly;
45     poly.threaded = true;
46     gVideo = &poly;
47 
48     if(!initializeVideo(argc, argv)) {
49         return 1;
50     }
51 
52     gIsGraphicalVersion = poly.graphic_display();
53     if(argc > 1) {
54         if(!ParseCmdLine(argc, argv)) {
55             if(gIsGraphicalVersion) rt_sleep(10000);
56             // if graphical, we haven't opened the console window so all the error messages we
57             // so carefully wrote out disappeared into the ether.  :(
58             exit(1);
59         }
60     }
61 
62     if(gCsvFilename != NULL) {
63 #define BUFLEN 1000
64         std::string fname_buf = gCsvFilename;
65         fname_buf += ".csv";
66         gCsvFile.open(fname_buf.c_str());
67     }
68 
69     // we have gMapXSize and gMapYSize determining the number of "squares"
70     // we have g_xwinsize and g_ywinsize the total size of the window
71     // we also have BORDER_SIZE the size of the border between maps
72     // we need to determine
73     //      g_polyBoxSize -- the number of pixels on each size of each square
74 
75     if(gIsGraphicalVersion) {
76         int xpixelsPerMap = (g_xwinsize - 4*BORDER_SIZE) / 3;  // three maps, with borders between and outside
77         gMapXSize = xpixelsPerMap;   // make the boxes one per pixel
78         gPolyXBoxSize = xpixelsPerMap / gMapXSize;
79         int ypixelsPerMap = (g_ywinsize - 2*BORDER_SIZE);       // one map vertically
80         gMapYSize = ypixelsPerMap;   // one pixel per box, rather.
81 
82         gPolyYBoxSize = ypixelsPerMap / gMapYSize;
83         if((gPolyXBoxSize == 0) || (gPolyYBoxSize == 0)) {
84             cout << "The display window is not large enough to show the maps" << std::endl;
85             int minxSize = 4*BORDER_SIZE + 3*gMapXSize;
86             int minySize = 2*BORDER_SIZE + gMapYSize;
87             cout << "  Should be at least " << minxSize << " x " << minySize << "." << std::endl;
88             return 1;
89         }
90         map2XLoc = 2*BORDER_SIZE + gMapXSize * gPolyXBoxSize;
91         maprXLoc = 3*BORDER_SIZE + 2 * gMapXSize * gPolyXBoxSize;
92 
93     }
94     else {  // not gIsGraphicalVersion
95         // gMapXSize, gMapYSize, gNPolygons defined in pover_global.h
96     }
97 
98     // create two polygon maps
99     SetRandomSeed(gMyRandomSeed);  // for repeatability
100 
101     gVideo->main_loop();
102 }
103 
Usage(int argc,char ** argv)104 void Usage(int argc, char **argv) {
105     char *cmdTail = strrchr(*argv, '\\');
106     if(cmdTail == NULL)  {
107         cmdTail = *argv;
108     }
109     else {
110         cmdTail++;
111     }
112     cout << cmdTail << " [threads[:threads2]] [--polys npolys] [--size nnnxnnn] [--seed nnn]" << std::endl;
113     cout << "Create polygon maps and overlay them." << std::endl << std::endl;
114     cout << "Parameters:" << std::endl;
115     cout << "   threads[:threads2] - number of threads to run" << std::endl;
116     cout << "   --polys npolys - number of polygons in each map" << std::endl;
117     cout << "   --size nnnxnnn - size of each map (X x Y)" << std::endl;
118     cout << "   --seed nnn - initial value of random number generator" << std::endl;
119     cout << "   --csv filename - write timing data to CSV-format file" << std::endl;
120     cout << "   --grainsize n - set grainsize to n" << std::endl;
121     cout << "   --use_malloc - allocate polygons with malloc instead of scalable allocator" << std::endl;
122     cout << std::endl;
123     cout << "npolys must be smaller than the size of the map" << std::endl;
124     cout << std::endl;
125     exit(1);
126 }
127 
ParseCmdLine(int argc,char ** argv)128 bool ParseCmdLine(int argc, char **argv ) {
129     bool error_found = false;
130     bool nPolysSpecified = false;
131     bool nMapSizeSpecified = false;
132     bool nSeedSpecified = false;
133     bool csvSpecified = false;
134     bool grainsizeSpecified = false;
135     bool mallocSpecified = false;
136     int origArgc = argc;
137     char** origArgv = argv;
138     unsigned int newnPolygons = gNPolygons;
139     unsigned int newSeed = gMyRandomSeed;
140     unsigned int newX = gMapXSize;
141     unsigned int newY = gMapYSize;
142     unsigned int newGrainSize = gGrainSize;
143     argc--; argv++;
144     if(argc > 0 && isdigit((*argv)[0])) {
145         // first argument is one or two numbers, specifying how mny threads to run
146         char* end; gThreadsHigh = gThreadsLow = (int)strtol(argv[0],&end,0);
147         switch( *end) {
148             case ':': gThreadsHigh = (int)strtol(end+1,0,0); break;
149             case '\0': break;
150             default: cout << "Unexpected character in thread specifier: " << *end << std::endl; break;
151         }
152         if(gThreadsLow > gThreadsHigh) {
153             int t = gThreadsLow;
154             gThreadsLow = gThreadsHigh;
155             gThreadsHigh = t;
156         }
157         argv++; argc--;
158     }
159     while(argc > 0) {
160         // format 1: --size nnnxnnn, where nnn in {0 .. 9}+ -- size of map in "squares"
161         if(!strncmp("--size", *argv, (size_t)6)) {
162             if(nMapSizeSpecified) {
163                 cout << " Error: map size multiply specified" << std::endl;
164                 error_found = true;
165             }
166             else  {
167                 argv++; argc--;
168                 if(argc == 0) {
169                     error_found = true;
170                     cout << " Error: --size must have a value" << std::endl;
171                 }
172                 if(strchr(*argv, 'x') != strrchr(*argv,'x')) {
173                     // more than one 'x'
174                     cout << "Error: map size should be nnnxnnn (" << *argv << ")" << std::endl;
175                     error_found = true;
176                 }
177                 else {
178                     int rval;
179                     rval = sscanf(*argv, "%ux%u", &newX, &newY);
180                     if(rval != 2) {
181                         cout << "Error parsing map size (format should be nnnxnnn (" << *argv << ")" << std::endl;
182                         error_found = true;
183                     }
184                     if(newX == 0 || newY == 0) {
185                         cout << "Error: size of map should be greater than 0 (" << *argv << ")" << std::endl;
186                         error_found = true;
187                     }
188                 }
189             }
190             argc--; argv++;
191         }
192         // format 2: --seed nnn -- initial random number seed
193         else if(!strncmp("--seed", *argv, (size_t)6)) {
194             argv++; argc--;
195             if(nSeedSpecified) {
196                 cout << "Error: new seed multiply specified" << std::endl;
197                 error_found = true;
198             }
199             else {
200                 nSeedSpecified = true;
201                 int rtval = sscanf(*argv, "%u", &newSeed);
202                 if(rtval == 0) {
203                     cout << "Error: --seed should be an unsigned number (instead of " << *argv << ")" << std::endl;
204                     error_found = true;
205                 }
206             }
207             argv++; argc--;
208         }
209         // format 3: --polys n[n] -- number of polygons in each map
210         else if(!strncmp("--polys", *argv, (size_t)7)) {
211             //unsigned int newnPolygons;
212             argv++; argc--;
213             if(nPolysSpecified) {
214                 cout << "Error: number of polygons multiply-specified" << std::endl;
215                 error_found = true;
216             }else {
217                 int rtval = sscanf(*argv, "%u", &newnPolygons);
218                 if(newnPolygons == 0) {
219                     cout << "Error: number of polygons must be greater than 0 (" << *argv << ")" << std::endl;
220                 }
221             }
222             argv++; argc--;
223         }
224         // format 4: --csv <fileroot> -- name of CSV output file ("xxx" for "xxx.csv")
225         else if(!strncmp("--csv", *argv, (size_t)5)) {
226             argv++; argc--;
227             if(csvSpecified) {
228                 cout << "Error: Multiple specification of CSV file" << std::endl;
229                 error_found = true;
230             }
231             else {
232                 gCsvFilename = *argv;
233                 argv++; argc--;
234                 csvSpecified = true;
235             }
236         }
237         else if(!strncmp("--grainsize", *argv, (size_t)11)) {
238             argv++; argc--;
239             if(grainsizeSpecified) {
240                 cout << "Error: Multiple specification of grainsize" << std::endl;
241                 error_found = true;
242             }
243             else {
244                 int grval = sscanf(*argv, "%u", &newGrainSize);
245                 grainsizeSpecified = true;
246                 if(newGrainSize == 0) {
247                     cout << "Error: grainsize must be greater than 0" << std::endl;
248                     error_found = true;
249                 }
250             }
251             argv++; argc--;
252         }
253         else if(!strncmp("--use_malloc", *argv, (size_t)12)) {
254             argv++; argc--;
255             if(mallocSpecified) {
256                 cout << "Error: --use_malloc multiply-specified" << std::endl;
257                 error_found = true;
258             }
259             else {
260                 mallocSpecified = true;
261                 gMBehavior = UseMalloc;
262             }
263         }
264         else {
265             cout << "Error: unrecognized argument: " << *argv << std::endl;
266             error_found = true;
267             argv++; argc--;
268         }
269     }
270     if(!error_found) {
271         if(newX * newY < newnPolygons) {
272             error_found = true;
273             cout << "Error: map size should not be smaller than the number of polygons (gNPolygons = " << newnPolygons << ", map size " << newX << "x" << newY << ")" << std::endl;
274         }
275     }
276     if(!error_found) {
277         gMapXSize = newX;
278         gMapYSize = newY;
279         gNPolygons = newnPolygons;
280         gMyRandomSeed = newSeed;
281         gGrainSize = (int)newGrainSize;
282     }
283     else {
284         Usage(origArgc, origArgv);
285     }
286     return !error_found;
287 }
288 
289 // create a polygon map with at least gNPolygons polygons.
290 // Usually more than gNPolygons polygons will be generated, because the
291 // process of growing the polygons results in holes.
GenerateMap(Polygon_map_t ** newMap,int xSize,int ySize,int gNPolygons,colorcomp_t maxR,colorcomp_t maxG,colorcomp_t maxB)292 bool GenerateMap(Polygon_map_t **newMap, int xSize, int ySize, int gNPolygons, colorcomp_t maxR, colorcomp_t maxG, colorcomp_t maxB) {
293     bool error_found = false;
294     int  *validPolys;
295     int  *validSide;
296     int maxSides;
297     RPolygon *newPoly;
298 
299     if(xSize <= 0) {
300         cout << "xSize (" << xSize << ") should be > 0." << std::endl;
301         error_found = true;
302     }
303     if(ySize <= 0) {
304         cout << "ySize (" << ySize << ") should be > 0." << std::endl;
305         error_found = true;
306     }
307     if(gNPolygons > (xSize * ySize)) {
308         cout << "gNPolygons (" << gNPolygons << ") should be less than " << (xSize * ySize) << std::endl;
309         error_found = true;
310     }
311     if(error_found) return false;
312     // the whole map is [xSize x ySize] squares
313     // the way we create the map is to
314     //    1) pick nPolygon discrete squares on an [xSize x ySize] grid
315     //    2) while there are unused squares on the grid
316     //        3) pick a polygon with a side that has unused squares on a side
317     //        4) expand the polygon by 1 to occupy the unused squares
318     //
319     // Continue until every square on the grid is occupied by a polygon
320     int *tempMap;
321     tempMap = (int *)malloc(xSize * ySize * sizeof(int));
322     for(int i=0;i < xSize; i++) {
323         for(int j=0;j < ySize; j++) {
324             tempMap[i*ySize + j] = 0;
325         }
326     }
327 
328     // *newMap = new vector<RPolygon>;
329     *newMap = new Polygon_map_t;
330     (*newMap)->reserve(gNPolygons + 1);  // how much bigger does this need to be on average?
331     (*newMap)->push_back(RPolygon(0,0,xSize-1, ySize-1));
332     for(int i=0; i < gNPolygons; i++) {
333         int nX;
334         int nY;
335         do {    // look for an empty square.
336             nX = NextRan(xSize);
337             nY = NextRan(ySize);
338         } while(tempMap[nX * ySize + nY] != 0);
339         int nR = (maxR * NextRan(1000)) / 999;
340         int nG = (maxG * NextRan(1000)) / 999;
341         int nB = (maxB * NextRan(1000)) / 999;
342         (*newMap)->push_back(RPolygon(nX,nY,nX,nY,nR,nG,nB));
343         tempMap[nX * ySize + nY] = i+1;     // index of this polygon + 1
344     }
345     // now have to grow polygons to fill the space.
346     validPolys = (int *)malloc(4*gNPolygons * sizeof(int));
347     validSide = (int *)malloc(4*gNPolygons * sizeof(int));
348     for(int i=0;i<gNPolygons;i++) {
349         validPolys[4*i] = validPolys[4*i + 1] = validPolys[4*i + 2] = validPolys[4*i + 3] = i + 1;
350         validSide[4*i] = NORTH_SIDE;
351         validSide[4*i+1] = EAST_SIDE;
352         validSide[4*i+2] = SOUTH_SIDE;
353         validSide[4*i+3] = WEST_SIDE;
354     }
355     maxSides = 4*gNPolygons;
356     while(maxSides > 0) {
357         int indx = NextRan(maxSides);
358         int polyIndx = validPolys[indx];
359         int checkSide = validSide[indx];
360         int xlow, xhigh, ylow, yhigh;
361         int xlnew, xhnew, ylnew, yhnew;
362         (**newMap)[polyIndx].get(&xlow,&ylow,&xhigh,&yhigh);
363         xlnew = xlow;
364         xhnew = xhigh;
365         ylnew = ylow;
366         yhnew = yhigh;
367         // can this polygon be expanded along the chosen side?
368         switch(checkSide) {
369         case NORTH_SIDE:
370             // y-1 from xlow to xhigh
371             ylow = yhigh = (ylow - 1);
372             ylnew--;
373             break;
374         case EAST_SIDE:
375             // x+1 from ylow to yhigh
376             xlow = xhigh = (xhigh + 1);
377             xhnew++;
378             break;
379         case SOUTH_SIDE:
380             // y+1 from xlow to xhigh
381             ylow = yhigh = (yhigh+1);
382             yhnew++;
383             break;
384         case WEST_SIDE:
385             // x-1 from ylow to yhigh
386             xlow = xhigh = (xlow - 1);
387             xlnew--;
388             break;
389         }
390         bool okay_to_extend = !(((xlow < 0) || (xlow >= xSize)) || ((ylow < 0) || (ylow >= ySize)));
391         for(int ii = xlow; (ii <= xhigh) && okay_to_extend; ii++) {
392             for(int jj=ylow; (jj <= yhigh) && okay_to_extend; jj++) {
393                 okay_to_extend = tempMap[ii*ySize + jj] == 0;
394             }
395         }
396         if(okay_to_extend) {
397             (**newMap)[polyIndx].set(xlnew,ylnew,xhnew,yhnew);
398             for(int ii = xlow; ii <= xhigh; ii++) {
399                 for(int jj=ylow; jj <= yhigh && okay_to_extend; jj++) {
400                     tempMap[ii*ySize + jj] = polyIndx;
401                 }
402             }
403         }
404         else {
405             // once we cannot expand along a side, we will never be able to; remove from the list.
406             for(int i=indx + 1; i < maxSides; i++) {
407                 validPolys[i-1] = validPolys[i];
408                 validSide[i-1] = validSide[i];
409             }
410             maxSides--;
411         }
412     }
413 
414     // Once no polygons can be grown, look for unused squares, and fill them with polygons.
415     for(int j=0;j<ySize;j++) {
416         for(int i=0;i<xSize;i++) {
417             if(tempMap[i*ySize+j] == 0) {
418                 // try to grow in the x direction, then the y direction
419                 int ilen = i;
420                 int jlen = j;
421                 while(ilen < (xSize - 1) && tempMap[(ilen+1)*ySize + jlen] == 0) {
422                     ilen++;
423                 }
424                 bool yok = true;
425                 while(yok && jlen < (ySize - 1)) {
426                     for(int ii = i; ii <= ilen && yok; ii++) {
427                         yok = (tempMap[ii*ySize + jlen + 1] == 0);
428                     }
429                     if(yok) {
430                         jlen++;
431                     }
432                 }
433 
434                 // create new polygon and push it on our list.
435                 int nR = (maxR * NextRan(1000)) / 999;
436                 int nG = (maxG * NextRan(1000)) / 999;
437                 int nB = (maxB * NextRan(1000)) / 999;
438                 (*newMap)->push_back(RPolygon(i,j,ilen,jlen,nR,nG,nB));
439                 gNPolygons++;
440                 for(int ii=i; ii<=ilen;ii++) {
441                     for(int jj=j;jj<=jlen;jj++) {
442                         tempMap[ii*ySize + jj] = gNPolygons;
443                     }
444                 }
445             }
446         }
447     }
448 
449 #if _DEBUG
450     if(!gIsGraphicalVersion) {
451         cout << std::endl << "Final Map:" << std::endl;
452         for(int j=0; j < ySize; j++ ) {
453             cout << "Row " << setw(2) << j << ":";
454             for(int i=0;i<xSize;i++) {
455                 int it = tempMap[i*ySize + j];
456                 if(it<10) {
457                     cout << setw(2) << it;
458                 }
459                 else {
460                     char ct = (int)'a' + it - 10;
461                     cout << " " << ct;
462                 }
463             }
464             cout << std::endl;
465         }
466     }
467 #endif  // _DEBUG
468     free(tempMap);
469     free(validPolys);
470     free(validSide);
471     return true;
472 }
473 
CheckPolygonMap(Polygon_map_t * checkMap)474 void CheckPolygonMap(Polygon_map_t *checkMap) {
475 #define indx(i,j) (i*gMapYSize + j)
476 #define rangeCheck(str,n,limit) if(((n)<0)||((n)>=limit)) {cout << "checkMap error: " << str << " out of range (" << n << ")" << std::endl;anError=true;}
477 #define xRangeCheck(str,n) rangeCheck(str,n,gMapXSize)
478 #define yRangeCheck(str,n) rangeCheck(str,n,gMapYSize)
479     // The first polygon is the whole map.
480     bool anError = false;
481     int *cArray;
482     if(checkMap->size() <= 0) {
483         cout << "checkMap error: no polygons in map" << std::endl;
484         return;
485     }
486     // mapXhigh and mapYhigh are inclusive, that is, if the map is 5x5, those values would be 4.
487     int mapXhigh, mapYhigh, mapLowX, mapLowY;
488     int gMapXSize, gMapYSize;
489     (*checkMap)[0].get(&mapLowX, &mapLowY, &mapXhigh, &mapYhigh);
490     if((mapLowX !=0) || (mapLowY != 0)) {
491         cout << "checkMap error: map origin not (0,0) (X=" << mapLowX << ", Y=" << mapLowY << ")" << std::endl;
492         anError = true;
493     }
494     if((mapXhigh < 0) || (mapYhigh < 0)) {
495         cout << "checkMap error: no area in map (X=" << mapXhigh << ", Y=" << mapYhigh << ")" << std::endl;
496         anError = true;
497     }
498     if(anError) return;
499     // bounds for array.
500     gMapXSize = mapXhigh + 1;
501     gMapYSize = mapYhigh + 1;
502     cArray = (int *)malloc(sizeof(int)*(gMapXSize*gMapYSize));
503 
504     for(int i=0; i<gMapXSize; i++) {
505         for(int j=0; j< gMapYSize; j++) {
506             cArray[indx(i,j)] = 0;
507         }
508     }
509 
510     int xlow, xhigh, ylow, yhigh;
511     for(int p=1; p < int(checkMap->size()) && !anError; p++) {
512         (*checkMap)[p].get(&xlow, &ylow, &xhigh, &yhigh);
513         xRangeCheck("xlow", xlow);
514         yRangeCheck("ylow", ylow);
515         xRangeCheck("xhigh", xhigh);
516         yRangeCheck("yhigh", yhigh);
517         if(xlow>xhigh) {
518             cout << "checkMap error: xlow > xhigh (" << xlow << "," << xhigh << ")" << std::endl;
519             anError = true;
520         }
521         if(ylow>yhigh) {
522             cout << "checkMap error: ylow > yhigh (" << ylow << "," << yhigh << ")" << std::endl;
523             anError = true;
524         }
525         for(int ii = xlow; ii <= xhigh; ii++) {
526             for(int jj = ylow; jj <= yhigh; jj++) {
527                 if(cArray[indx(ii,jj)] != 0) {
528                     cout << "checkMap error: polygons " << cArray[indx(ii,jj)] << " and " << p << " intersect" << std::endl;
529                     anError = true;
530                 }
531                 cArray[indx(ii,jj)] = p;
532             }
533         }
534     }
535     for(int ii=0; ii < gMapXSize; ii++) {
536         for(int jj=0; jj < gMapYSize; jj++) {
537             if(cArray[indx(ii,jj)] == 0) {
538                 cout << "checkMap error: block(" << ii << ", " << jj << ") not in any polygon" << std::endl;
539                 anError = true;
540             }
541         }
542     }
543     free(cArray);
544 }
545 
CompOnePolygon(RPolygon & p1,RPolygon & p2)546 bool CompOnePolygon(RPolygon &p1, RPolygon &p2) {
547     int xl1, xh1, yl1, yh1;
548     int xl2, xh2, yl2, yh2;
549     p1.get(&xl1, &yl1, &xh1, &yh1);
550     p2.get(&xl2, &yl2, &xh2, &yh2);
551     if(yl1>yl2) return true;
552     if(yl1<yl2) return false;
553     return (xl1 > xl2);
554 }
555 
PolygonsEqual(RPolygon * p1,RPolygon * p2)556 bool PolygonsEqual(RPolygon *p1, RPolygon *p2) {
557     int xl1, xh1, yl1, yh1;
558     int xl2, xh2, yl2, yh2;
559     p1->get(&xl1, &yl1, &xh1, &yh1);
560     p2->get(&xl2, &yl2, &xh2, &yh2);
561     return ((xl1 == xl2) && (yl1==yl2) && (xh1 == xh2) && (yh1 == yh2));
562 }
563 
ComparePolygonMaps(Polygon_map_t * map1,Polygon_map_t * map2)564 bool ComparePolygonMaps(Polygon_map_t *map1, Polygon_map_t *map2) {
565     // create two new polygon maps, copy the pointers from the original to these.
566     // we have to skip the first polygon, which is the size of the whole map
567     Polygon_map_t *t1, *t2;
568     bool is_ok = true;
569     t1 = new Polygon_map_t;
570     t1->reserve(map1->size());
571     for(unsigned int i=1;i<map1->size(); i++) {
572         t1->push_back(map1->at(i));
573     }
574     t2 = new Polygon_map_t;
575     t2->reserve(map2->size());
576     for(unsigned int i=1;i<map2->size();i++) {
577         t2->push_back(map2->at(i));
578     }
579     // sort the two created maps by (xlow, ylow)
580     sort(t1->begin(), t1->end());
581     sort(t2->begin(), t2->end());
582     // compare each element of both maps.
583     if(t1->size() != t2->size()) {
584         cout << "Error: maps not the same size ( " << int(t1->size()) << " vs " << int(t2->size()) << ")." << std::endl;
585     }
586     int maxSize = (int)((t1->size() < t2->size()) ? t1->size() : t2->size());
587     for(int i=0; i < maxSize; i++) {
588         if(!PolygonsEqual(&((*t1)[i]), &((*t2)[i]))) {
589             cout << "Error: polygons unequal (" << (*t1)[i] << " vs " << (*t2)[i] << std::endl;
590             is_ok = false;
591         }
592     }
593     delete t1;
594     delete t2;
595     return is_ok;
596 }
597 
SetRandomSeed(int newSeed)598 void SetRandomSeed(int newSeed) {
599     srand((unsigned)newSeed);
600 }
601 
NextRan(int n)602 int NextRan(int n) {
603     // assert(n > 1);
604     // if we are given 1, we will just return 0
605     //assert(n < RAND_MAX);
606     int rrand = rand() << 15 | rand();
607     if(rrand < 0) rrand = -rrand;
608     return rrand % n;
609 }
610 
operator <<(std::ostream & s,const RPolygon & p)611 std::ostream& operator<<(std::ostream& s, const RPolygon &p) {
612     int xl, yl, xh, yh;
613     p.get(&xl, &yl, &xh, &yh);
614     return s << "[(" << xl << "," << yl << ")-(" << xh << "," << yh << ")] ";
615 }
616