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