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