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