1d86ed7fbStbbdev /*
2*b15aabb3Stbbdev     Copyright (c) 2005-2021 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 #include <cstdlib>
20d86ed7fbStbbdev #include <cstring>
21d86ed7fbStbbdev #include <cassert>
22d86ed7fbStbbdev 
23d86ed7fbStbbdev #include <iostream>
24d86ed7fbStbbdev #include <algorithm>
25d86ed7fbStbbdev 
26d86ed7fbStbbdev #include "oneapi/tbb/tick_count.h"
27d86ed7fbStbbdev #include "oneapi/tbb/blocked_range.h"
28d86ed7fbStbbdev #include "oneapi/tbb/parallel_for.h"
29d86ed7fbStbbdev #include "oneapi/tbb/spin_mutex.h"
30d86ed7fbStbbdev #include "oneapi/tbb/global_control.h"
31d86ed7fbStbbdev 
32d86ed7fbStbbdev #include "common/utility/get_default_num_threads.hpp"
33d86ed7fbStbbdev 
34d86ed7fbStbbdev #include "polyover.hpp"
35d86ed7fbStbbdev #include "polymain.hpp"
36d86ed7fbStbbdev #include "pover_video.hpp"
37d86ed7fbStbbdev 
38d86ed7fbStbbdev /*!
39d86ed7fbStbbdev * @brief intersects a polygon with a map, adding any results to output map
40d86ed7fbStbbdev *
41d86ed7fbStbbdev * @param[out] resultMap output map (must be allocated)
42d86ed7fbStbbdev * @param[in] polygon to be intersected
43d86ed7fbStbbdev * @param[in] map intersected against
44d86ed7fbStbbdev * @param[in] lock to use when adding output polygons to result map
45d86ed7fbStbbdev *
46d86ed7fbStbbdev */
OverlayOnePolygonWithMap(Polygon_map_t * resultMap,RPolygon * myPoly,Polygon_map_t * map2,oneapi::tbb::spin_mutex * rMutex)47d86ed7fbStbbdev void OverlayOnePolygonWithMap(Polygon_map_t *resultMap,
48d86ed7fbStbbdev                               RPolygon *myPoly,
49d86ed7fbStbbdev                               Polygon_map_t *map2,
50d86ed7fbStbbdev                               oneapi::tbb::spin_mutex *rMutex) {
51d86ed7fbStbbdev     int r1, g1, b1, r2, g2, b2;
52d86ed7fbStbbdev     int myr = 0;
53d86ed7fbStbbdev     int myg = 0;
54d86ed7fbStbbdev     int myb = 0;
55d86ed7fbStbbdev     int p1Area = myPoly->area();
56d86ed7fbStbbdev     for (unsigned int j = 1; (j < map2->size()) && (p1Area > 0); j++) {
57d86ed7fbStbbdev         RPolygon *p2 = &((*map2)[j]);
58d86ed7fbStbbdev         RPolygon *pnew;
59d86ed7fbStbbdev         int newxMin, newxMax, newyMin, newyMax;
60d86ed7fbStbbdev         myPoly->getColor(&r1, &g1, &b1);
61d86ed7fbStbbdev         if (PolygonsOverlap(myPoly, p2, newxMin, newyMin, newxMax, newyMax)) {
62d86ed7fbStbbdev             p2->getColor(&r2, &g2, &b2);
63d86ed7fbStbbdev             myr = r1 + r2;
64d86ed7fbStbbdev             myg = g1 + g2;
65d86ed7fbStbbdev             myb = b1 + b2;
66d86ed7fbStbbdev             p1Area -= (newxMax - newxMin + 1) * (newyMax - newyMin + 1);
67d86ed7fbStbbdev             if (rMutex) {
68d86ed7fbStbbdev                 oneapi::tbb::spin_mutex::scoped_lock lock(*rMutex);
69d86ed7fbStbbdev                 resultMap->push_back(RPolygon(newxMin, newyMin, newxMax, newyMax, myr, myg, myb));
70d86ed7fbStbbdev             }
71d86ed7fbStbbdev             else {
72d86ed7fbStbbdev                 resultMap->push_back(RPolygon(newxMin, newyMin, newxMax, newyMax, myr, myg, myb));
73d86ed7fbStbbdev             }
74d86ed7fbStbbdev         }
75d86ed7fbStbbdev     }
76d86ed7fbStbbdev }
77d86ed7fbStbbdev 
78d86ed7fbStbbdev /*!
79d86ed7fbStbbdev * @brief Serial version of polygon overlay
80d86ed7fbStbbdev * @param[out] output map
81d86ed7fbStbbdev * @param[in]  first map (map that individual polygons are taken from)
82d86ed7fbStbbdev * @param[in]  second map (map passed to OverlayOnePolygonWithMap)
83d86ed7fbStbbdev */
SerialOverlayMaps(Polygon_map_t ** resultMap,Polygon_map_t * map1,Polygon_map_t * map2)84d86ed7fbStbbdev void SerialOverlayMaps(Polygon_map_t **resultMap, Polygon_map_t *map1, Polygon_map_t *map2) {
85d86ed7fbStbbdev     std::cout << "SerialOverlayMaps called"
86d86ed7fbStbbdev               << "\n";
87d86ed7fbStbbdev     *resultMap = new Polygon_map_t;
88d86ed7fbStbbdev 
89d86ed7fbStbbdev     RPolygon *p0 = &((*map1)[0]);
90d86ed7fbStbbdev     int mapxSize, mapySize, ignore1, ignore2;
91d86ed7fbStbbdev     p0->get(&ignore1, &ignore2, &mapxSize, &mapySize);
92d86ed7fbStbbdev     (*resultMap)->reserve(mapxSize * mapySize); // can't be any bigger than this
93d86ed7fbStbbdev     // push the map size as the first polygon,
94d86ed7fbStbbdev     (*resultMap)->push_back(RPolygon(0, 0, mapxSize, mapySize));
95d86ed7fbStbbdev     for (unsigned int i = 1; i < map1->size(); i++) {
96d86ed7fbStbbdev         RPolygon *p1 = &((*map1)[i]);
97d86ed7fbStbbdev         OverlayOnePolygonWithMap(*resultMap, p1, map2, nullptr);
98d86ed7fbStbbdev     }
99d86ed7fbStbbdev }
100d86ed7fbStbbdev 
101d86ed7fbStbbdev /*!
102d86ed7fbStbbdev * @class ApplyOverlay
103d86ed7fbStbbdev * @brief Simple version of parallel overlay (make parallel on polygons in map1)
104d86ed7fbStbbdev */
105d86ed7fbStbbdev class ApplyOverlay {
106d86ed7fbStbbdev     Polygon_map_t *m_map1, *m_map2, *m_resultMap;
107d86ed7fbStbbdev     oneapi::tbb::spin_mutex *m_rMutex;
108d86ed7fbStbbdev 
109d86ed7fbStbbdev public:
110d86ed7fbStbbdev     /*!
111d86ed7fbStbbdev     * @brief functor to apply
112d86ed7fbStbbdev     * @param[in] r range of polygons to intersect from map1
113d86ed7fbStbbdev     */
operator ()(const oneapi::tbb::blocked_range<int> & r) const114d86ed7fbStbbdev     void operator()(const oneapi::tbb::blocked_range<int> &r) const {
115d86ed7fbStbbdev         PRINT_DEBUG("From " << r.begin() << " to " << r.end());
116d86ed7fbStbbdev         for (int i = r.begin(); i != r.end(); i++) {
117d86ed7fbStbbdev             RPolygon *myPoly = &((*m_map1)[i]);
118d86ed7fbStbbdev             OverlayOnePolygonWithMap(m_resultMap, myPoly, m_map2, m_rMutex);
119d86ed7fbStbbdev         }
120d86ed7fbStbbdev     }
ApplyOverlay(Polygon_map_t * resultMap,Polygon_map_t * map1,Polygon_map_t * map2,oneapi::tbb::spin_mutex * rmutex)121d86ed7fbStbbdev     ApplyOverlay(Polygon_map_t *resultMap,
122d86ed7fbStbbdev                  Polygon_map_t *map1,
123d86ed7fbStbbdev                  Polygon_map_t *map2,
124d86ed7fbStbbdev                  oneapi::tbb::spin_mutex *rmutex)
125d86ed7fbStbbdev             : m_resultMap(resultMap),
126d86ed7fbStbbdev               m_map1(map1),
127d86ed7fbStbbdev               m_map2(map2),
128d86ed7fbStbbdev               m_rMutex(rmutex) {}
129d86ed7fbStbbdev };
130d86ed7fbStbbdev 
131d86ed7fbStbbdev /*!
132d86ed7fbStbbdev * @brief apply the parallel algorithm
133d86ed7fbStbbdev * @param[out] result_map generated map
134d86ed7fbStbbdev * @param[in] polymap1 first map to be applied (algorithm is parallel on this map)
135d86ed7fbStbbdev * @param[in] polymap2 second map.
136d86ed7fbStbbdev */
NaiveParallelOverlay(Polygon_map_t * & result_map,Polygon_map_t & polymap1,Polygon_map_t & polymap2)137d86ed7fbStbbdev void NaiveParallelOverlay(Polygon_map_t *&result_map,
138d86ed7fbStbbdev                           Polygon_map_t &polymap1,
139d86ed7fbStbbdev                           Polygon_map_t &polymap2) {
140d86ed7fbStbbdev     // -----------------------------------
141d86ed7fbStbbdev     bool automatic_threadcount = false;
142d86ed7fbStbbdev 
143d86ed7fbStbbdev     if (gThreadsLow == THREADS_UNSET || gThreadsLow == utility::get_default_num_threads()) {
144d86ed7fbStbbdev         gThreadsLow = gThreadsHigh = utility::get_default_num_threads();
145d86ed7fbStbbdev         automatic_threadcount = true;
146d86ed7fbStbbdev     }
147d86ed7fbStbbdev     result_map = new Polygon_map_t;
148d86ed7fbStbbdev 
149d86ed7fbStbbdev     RPolygon *p0 = &(polymap1[0]);
150d86ed7fbStbbdev     int mapxSize, mapySize, ignore1, ignore2;
151d86ed7fbStbbdev     p0->get(&ignore1, &ignore2, &mapxSize, &mapySize);
152d86ed7fbStbbdev     result_map->reserve(mapxSize * mapySize); // can't be any bigger than this
153d86ed7fbStbbdev     // push the map size as the first polygon,
154d86ed7fbStbbdev     oneapi::tbb::spin_mutex *resultMutex = new oneapi::tbb::spin_mutex();
155d86ed7fbStbbdev     int grain_size = gGrainSize;
156d86ed7fbStbbdev 
157d86ed7fbStbbdev     for (int nthreads = gThreadsLow; nthreads <= gThreadsHigh; nthreads++) {
158d86ed7fbStbbdev         oneapi::tbb::global_control c(oneapi::tbb::global_control::max_allowed_parallelism,
159d86ed7fbStbbdev                                       nthreads);
160d86ed7fbStbbdev         if (gIsGraphicalVersion) {
161d86ed7fbStbbdev             RPolygon *xp =
162d86ed7fbStbbdev                 new RPolygon(0, 0, gMapXSize - 1, gMapYSize - 1, 0, 0, 0); // Clear the output space
163d86ed7fbStbbdev             delete xp;
164d86ed7fbStbbdev         }
165d86ed7fbStbbdev         // put size polygon in result map
166d86ed7fbStbbdev         result_map->push_back(RPolygon(0, 0, mapxSize, mapySize));
167d86ed7fbStbbdev 
168d86ed7fbStbbdev         oneapi::tbb::tick_count t0 = oneapi::tbb::tick_count::now();
169d86ed7fbStbbdev         oneapi::tbb::parallel_for(
170d86ed7fbStbbdev             oneapi::tbb::blocked_range<int>(1, (int)(polymap1.size()), grain_size),
171d86ed7fbStbbdev             ApplyOverlay(result_map, &polymap1, &polymap2, resultMutex));
172d86ed7fbStbbdev         oneapi::tbb::tick_count t1 = oneapi::tbb::tick_count::now();
173d86ed7fbStbbdev 
174d86ed7fbStbbdev         double naiveParallelTime = (t1 - t0).seconds() * 1000;
175d86ed7fbStbbdev         std::cout << "Naive parallel with spin lock and ";
176d86ed7fbStbbdev         if (automatic_threadcount)
177d86ed7fbStbbdev             std::cout << "automatic";
178d86ed7fbStbbdev         else
179d86ed7fbStbbdev             std::cout << nthreads;
180d86ed7fbStbbdev         std::cout << ((nthreads == 1) ? " thread" : " threads");
181d86ed7fbStbbdev         std::cout << " took " << naiveParallelTime << " msec : speedup over serial "
182d86ed7fbStbbdev                   << (gSerialTime / naiveParallelTime) << "\n";
183d86ed7fbStbbdev         if (gCsvFile.is_open()) {
184d86ed7fbStbbdev             gCsvFile << "," << naiveParallelTime;
185d86ed7fbStbbdev         }
186d86ed7fbStbbdev #if _DEBUG
187d86ed7fbStbbdev         CheckPolygonMap(result_map);
188d86ed7fbStbbdev         ComparePolygonMaps(result_map, gResultMap);
189d86ed7fbStbbdev #endif
190d86ed7fbStbbdev         result_map->clear();
191d86ed7fbStbbdev     }
192d86ed7fbStbbdev     delete resultMutex;
193d86ed7fbStbbdev     if (gCsvFile.is_open()) {
194d86ed7fbStbbdev         gCsvFile << "\n";
195d86ed7fbStbbdev     }
196d86ed7fbStbbdev     // -----------------------------------
197d86ed7fbStbbdev }
198d86ed7fbStbbdev 
199d86ed7fbStbbdev template <typename T>
split_at(Flagged_map_t & in_map,Flagged_map_t & left_out,Flagged_map_t & right_out,const T median)200d86ed7fbStbbdev void split_at(Flagged_map_t &in_map,
201d86ed7fbStbbdev               Flagged_map_t &left_out,
202d86ed7fbStbbdev               Flagged_map_t &right_out,
203d86ed7fbStbbdev               const T median) {
204d86ed7fbStbbdev     left_out.reserve(in_map.size());
205d86ed7fbStbbdev     right_out.reserve(in_map.size());
206d86ed7fbStbbdev     for (Flagged_map_t::iterator i = in_map.begin(); i != in_map.end(); ++i) {
207d86ed7fbStbbdev         RPolygon *p = i->p();
208d86ed7fbStbbdev         if (p->xmax() < median) {
209d86ed7fbStbbdev             // in left map
210d86ed7fbStbbdev             left_out.push_back(*i);
211d86ed7fbStbbdev         }
212d86ed7fbStbbdev         else if (p->xmin() >= median) {
213d86ed7fbStbbdev             right_out.push_back(*i);
214d86ed7fbStbbdev             // in right map
215d86ed7fbStbbdev         }
216d86ed7fbStbbdev         else {
217d86ed7fbStbbdev             // in both maps.
218d86ed7fbStbbdev             left_out.push_back(*i);
219d86ed7fbStbbdev             right_out.push_back(RPolygon_flagged(p, true));
220d86ed7fbStbbdev         }
221d86ed7fbStbbdev     }
222d86ed7fbStbbdev }
223d86ed7fbStbbdev 
224d86ed7fbStbbdev // range that splits the maps as well as the range.  the flagged_map_t are
225d86ed7fbStbbdev // vectors of pointers, and each range owns its maps (has to free them on destruction.)
226d86ed7fbStbbdev template <typename T>
227d86ed7fbStbbdev class blocked_range_with_maps {
228d86ed7fbStbbdev     typedef oneapi::tbb::blocked_range<T> my_range_type;
229d86ed7fbStbbdev 
230d86ed7fbStbbdev private:
231d86ed7fbStbbdev     my_range_type my_range;
232d86ed7fbStbbdev     Flagged_map_t my_map1;
233d86ed7fbStbbdev     Flagged_map_t my_map2;
234d86ed7fbStbbdev 
235d86ed7fbStbbdev public:
blocked_range_with_maps(T begin,T end,typename my_range_type::size_type my_grainsize,Polygon_map_t * p1,Polygon_map_t * p2)236d86ed7fbStbbdev     blocked_range_with_maps(T begin,
237d86ed7fbStbbdev                             T end,
238d86ed7fbStbbdev                             typename my_range_type::size_type my_grainsize,
239d86ed7fbStbbdev                             Polygon_map_t *p1,
240d86ed7fbStbbdev                             Polygon_map_t *p2)
241d86ed7fbStbbdev             : my_range(begin, end, my_grainsize) {
242d86ed7fbStbbdev         my_map1.reserve(p1->size());
243d86ed7fbStbbdev         my_map2.reserve(p2->size());
244d86ed7fbStbbdev         for (int i = 1; i < p1->size(); ++i) {
245d86ed7fbStbbdev             my_map1.push_back(RPolygon_flagged(&((*p1)[i]), false));
246d86ed7fbStbbdev         }
247d86ed7fbStbbdev         for (int i = 1; i < p2->size(); ++i) {
248d86ed7fbStbbdev             my_map2.push_back(RPolygon_flagged(&(p2->at(i)), false));
249d86ed7fbStbbdev         }
250d86ed7fbStbbdev     }
251d86ed7fbStbbdev 
252d86ed7fbStbbdev     // copy-constructor required for deep copy of flagged maps.  One copy is done at the start of the
253d86ed7fbStbbdev     // parallel for.
blocked_range_with_maps(const blocked_range_with_maps & other)254d86ed7fbStbbdev     blocked_range_with_maps(const blocked_range_with_maps &other)
255d86ed7fbStbbdev             : my_range(other.my_range),
256d86ed7fbStbbdev               my_map1(other.my_map1),
257d86ed7fbStbbdev               my_map2(other.my_map2) {}
empty() const258d86ed7fbStbbdev     bool empty() const {
259d86ed7fbStbbdev         return my_range.empty();
260d86ed7fbStbbdev     }
is_divisible() const261d86ed7fbStbbdev     bool is_divisible() const {
262d86ed7fbStbbdev         return my_range.is_divisible();
263d86ed7fbStbbdev     }
264d86ed7fbStbbdev 
265d86ed7fbStbbdev #if _DEBUG
check_my_map()266d86ed7fbStbbdev     void check_my_map() {
267d86ed7fbStbbdev         assert(my_range.begin() <= my_range.end());
268d86ed7fbStbbdev         for (Flagged_map_t::iterator i = my_map1.begin(); i != my_map1.end(); ++i) {
269d86ed7fbStbbdev             RPolygon *rp = i->p();
270d86ed7fbStbbdev             assert(rp->xmax() >= my_range.begin());
271d86ed7fbStbbdev             assert(rp->xmin() < my_range.end());
272d86ed7fbStbbdev         }
273d86ed7fbStbbdev         for (Flagged_map_t::iterator i = my_map2.begin(); i != my_map2.end(); ++i) {
274d86ed7fbStbbdev             RPolygon *rp = i->p();
275d86ed7fbStbbdev             assert(rp->xmax() >= my_range.begin());
276d86ed7fbStbbdev             assert(rp->xmin() < my_range.end());
277d86ed7fbStbbdev         }
278d86ed7fbStbbdev     }
279d86ed7fbStbbdev 
dump_map(Flagged_map_t & mapx)280d86ed7fbStbbdev     void dump_map(Flagged_map_t &mapx) {
281d86ed7fbStbbdev         std::cout << " ** MAP **\n";
282d86ed7fbStbbdev         for (Flagged_map_t::iterator i = mapx.begin(); i != mapx.end(); ++i) {
283d86ed7fbStbbdev             std::cout << *(i->p());
284d86ed7fbStbbdev             if (i->isDuplicate()) {
285d86ed7fbStbbdev                 std::cout << " -- is_duplicate";
286d86ed7fbStbbdev             }
287d86ed7fbStbbdev             std::cout << "\n";
288d86ed7fbStbbdev         }
289d86ed7fbStbbdev         std::cout << "\n";
290d86ed7fbStbbdev     }
291d86ed7fbStbbdev #endif
292d86ed7fbStbbdev 
blocked_range_with_maps(blocked_range_with_maps & lhs_r,oneapi::tbb::split)293d86ed7fbStbbdev     blocked_range_with_maps(blocked_range_with_maps &lhs_r, oneapi::tbb::split)
294d86ed7fbStbbdev             : my_range(my_range_type(lhs_r.my_range, oneapi::tbb::split())) {
295d86ed7fbStbbdev         // lhs_r.my_range makes my_range from [median, high) and rhs_r.my_range from [low, median)
296d86ed7fbStbbdev         Flagged_map_t original_map1 = lhs_r.my_map1;
297d86ed7fbStbbdev         Flagged_map_t original_map2 = lhs_r.my_map2;
298d86ed7fbStbbdev         lhs_r.my_map1.clear();
299d86ed7fbStbbdev         lhs_r.my_map2.clear();
300d86ed7fbStbbdev         split_at(original_map1, lhs_r.my_map1, my_map1, my_range.begin());
301d86ed7fbStbbdev         split_at(original_map2, lhs_r.my_map2, my_map2, my_range.begin());
302d86ed7fbStbbdev #if _DEBUG
303d86ed7fbStbbdev         this->check_my_map();
304d86ed7fbStbbdev         lhs_r.check_my_map();
305d86ed7fbStbbdev #endif
306d86ed7fbStbbdev     }
307d86ed7fbStbbdev 
range() const308d86ed7fbStbbdev     const my_range_type &range() const {
309d86ed7fbStbbdev         return my_range;
310d86ed7fbStbbdev     }
map1()311d86ed7fbStbbdev     Flagged_map_t &map1() {
312d86ed7fbStbbdev         return my_map1;
313d86ed7fbStbbdev     }
map2()314d86ed7fbStbbdev     Flagged_map_t &map2() {
315d86ed7fbStbbdev         return my_map2;
316d86ed7fbStbbdev     }
317d86ed7fbStbbdev };
318d86ed7fbStbbdev 
319d86ed7fbStbbdev /*!
320d86ed7fbStbbdev * @class ApplySplitOverlay
321d86ed7fbStbbdev * @brief parallel by columnar strip
322d86ed7fbStbbdev */
323d86ed7fbStbbdev class ApplySplitOverlay {
324d86ed7fbStbbdev     Polygon_map_t *m_map1, *m_map2, *m_resultMap;
325d86ed7fbStbbdev     oneapi::tbb::spin_mutex *m_rMutex;
326d86ed7fbStbbdev 
327d86ed7fbStbbdev public:
328d86ed7fbStbbdev     /*!
329d86ed7fbStbbdev     * @brief functor for columnar parallel version
330d86ed7fbStbbdev     * @param[in] r range of map to be operated on
331d86ed7fbStbbdev     */
operator ()(blocked_range_with_maps<int> & r) const332d86ed7fbStbbdev     void operator()(/*const*/ blocked_range_with_maps<int> &r) const {
333d86ed7fbStbbdev #ifdef _DEBUG
334d86ed7fbStbbdev         // if we are debugging, serialize the method.  That way we can
335d86ed7fbStbbdev         // see what is happening in each strip without the interleaving
336d86ed7fbStbbdev         // confusing things.
337d86ed7fbStbbdev         oneapi::tbb::spin_mutex::scoped_lock lock(*m_rMutex);
338d86ed7fbStbbdev         std::cout << std::unitbuf << "From " << r.range().begin() << " to " << r.range().end() - 1
339d86ed7fbStbbdev                   << "\n";
340d86ed7fbStbbdev #endif
341d86ed7fbStbbdev         // get yMapSize
342d86ed7fbStbbdev         int r1, g1, b1, r2, g2, b2;
343d86ed7fbStbbdev         int myr = -1;
344d86ed7fbStbbdev         int myg = -1;
345d86ed7fbStbbdev         int myb = -1;
346d86ed7fbStbbdev         int i1, i2, i3, yMapSize;
347d86ed7fbStbbdev         (*m_map1)[0].get(&i1, &i2, &i3, &yMapSize);
348d86ed7fbStbbdev 
349d86ed7fbStbbdev         Flagged_map_t &fmap1 = r.map1();
350d86ed7fbStbbdev         Flagged_map_t &fmap2 = r.map2();
351d86ed7fbStbbdev 
352d86ed7fbStbbdev         // When intersecting polygons from fmap1 and fmap2, if BOTH are flagged
353d86ed7fbStbbdev         // as duplicate, don't add the result to the output map.  We can still
354d86ed7fbStbbdev         // intersect them, because we are keeping track of how much of the polygon
355d86ed7fbStbbdev         // is left over from intersecting, and quitting when the polygon is
356d86ed7fbStbbdev         // used up.
357d86ed7fbStbbdev 
358d86ed7fbStbbdev         for (unsigned int i = 0; i < fmap1.size(); i++) {
359d86ed7fbStbbdev             RPolygon *p1 = fmap1[i].p();
360d86ed7fbStbbdev             bool is_dup = fmap1[i].isDuplicate();
361d86ed7fbStbbdev             int parea = p1->area();
362d86ed7fbStbbdev             p1->getColor(&r1, &g1, &b1);
363d86ed7fbStbbdev             for (unsigned int j = 0; (j < fmap2.size()) && (parea > 0); j++) {
364d86ed7fbStbbdev                 int xl, yl, xh, yh;
365d86ed7fbStbbdev                 RPolygon *p2 = fmap2[j].p();
366d86ed7fbStbbdev                 if (PolygonsOverlap(p1, p2, xl, yl, xh, yh)) {
367d86ed7fbStbbdev                     if (!(is_dup && fmap2[j].isDuplicate())) {
368d86ed7fbStbbdev                         p2->getColor(&r2, &g2, &b2);
369d86ed7fbStbbdev                         myr = r1 + r2;
370d86ed7fbStbbdev                         myg = g1 + g2;
371d86ed7fbStbbdev                         myb = b1 + b2;
372d86ed7fbStbbdev #ifdef _DEBUG
373d86ed7fbStbbdev #else
374d86ed7fbStbbdev                         oneapi::tbb::spin_mutex::scoped_lock lock(*m_rMutex);
375d86ed7fbStbbdev #endif
376d86ed7fbStbbdev                         (*m_resultMap).push_back(RPolygon(xl, yl, xh, yh, myr, myg, myb));
377d86ed7fbStbbdev                     }
378d86ed7fbStbbdev                     parea -= (xh - xl + 1) * (yh - yl + 1);
379d86ed7fbStbbdev                 }
380d86ed7fbStbbdev             }
381d86ed7fbStbbdev         }
382d86ed7fbStbbdev     }
383d86ed7fbStbbdev 
ApplySplitOverlay(Polygon_map_t * resultMap,Polygon_map_t * map1,Polygon_map_t * map2,oneapi::tbb::spin_mutex * rmutex)384d86ed7fbStbbdev     ApplySplitOverlay(Polygon_map_t *resultMap,
385d86ed7fbStbbdev                       Polygon_map_t *map1,
386d86ed7fbStbbdev                       Polygon_map_t *map2,
387d86ed7fbStbbdev                       oneapi::tbb::spin_mutex *rmutex)
388d86ed7fbStbbdev             : m_resultMap(resultMap),
389d86ed7fbStbbdev               m_map1(map1),
390d86ed7fbStbbdev               m_map2(map2),
391d86ed7fbStbbdev               m_rMutex(rmutex) {}
392d86ed7fbStbbdev };
393d86ed7fbStbbdev 
394d86ed7fbStbbdev /*!
395d86ed7fbStbbdev * @brief intersects two maps strip-wise
396d86ed7fbStbbdev *
397d86ed7fbStbbdev * @param[out] resultMap output map (must be allocated)
398d86ed7fbStbbdev * @param[in] polymap1 map to be intersected
399d86ed7fbStbbdev * @param[in] polymap2 map to be intersected
400d86ed7fbStbbdev */
SplitParallelOverlay(Polygon_map_t ** result_map,Polygon_map_t * polymap1,Polygon_map_t * polymap2)401d86ed7fbStbbdev void SplitParallelOverlay(Polygon_map_t **result_map,
402d86ed7fbStbbdev                           Polygon_map_t *polymap1,
403d86ed7fbStbbdev                           Polygon_map_t *polymap2) {
404d86ed7fbStbbdev     int nthreads;
405d86ed7fbStbbdev     bool automatic_threadcount = false;
406d86ed7fbStbbdev     double domainSplitParallelTime;
407d86ed7fbStbbdev     oneapi::tbb::tick_count t0, t1;
408d86ed7fbStbbdev     oneapi::tbb::spin_mutex *resultMutex;
409d86ed7fbStbbdev     if (gThreadsLow == THREADS_UNSET || gThreadsLow == utility::get_default_num_threads()) {
410d86ed7fbStbbdev         gThreadsLow = gThreadsHigh = utility::get_default_num_threads();
411d86ed7fbStbbdev         automatic_threadcount = true;
412d86ed7fbStbbdev     }
413d86ed7fbStbbdev     *result_map = new Polygon_map_t;
414d86ed7fbStbbdev 
415d86ed7fbStbbdev     RPolygon *p0 = &((*polymap1)[0]);
416d86ed7fbStbbdev     int mapxSize, mapySize, ignore1, ignore2;
417d86ed7fbStbbdev     p0->get(&ignore1, &ignore2, &mapxSize, &mapySize);
418d86ed7fbStbbdev     (*result_map)->reserve(mapxSize * mapySize); // can't be any bigger than this
419d86ed7fbStbbdev     resultMutex = new oneapi::tbb::spin_mutex();
420d86ed7fbStbbdev 
421d86ed7fbStbbdev     int grain_size;
422d86ed7fbStbbdev #ifdef _DEBUG
423d86ed7fbStbbdev     grain_size = gMapXSize / 4;
424d86ed7fbStbbdev #else
425d86ed7fbStbbdev     grain_size = gGrainSize;
426d86ed7fbStbbdev #endif
427d86ed7fbStbbdev     for (nthreads = gThreadsLow; nthreads <= gThreadsHigh; nthreads++) {
428d86ed7fbStbbdev         oneapi::tbb::global_control c(oneapi::tbb::global_control::max_allowed_parallelism,
429d86ed7fbStbbdev                                       nthreads);
430d86ed7fbStbbdev         if (gIsGraphicalVersion) {
431d86ed7fbStbbdev             RPolygon *xp =
432d86ed7fbStbbdev                 new RPolygon(0, 0, gMapXSize - 1, gMapYSize - 1, 0, 0, 0); // Clear the output space
433d86ed7fbStbbdev             delete xp;
434d86ed7fbStbbdev         }
435d86ed7fbStbbdev         // push the map size as the first polygon,
436d86ed7fbStbbdev         (*result_map)->push_back(RPolygon(0, 0, mapxSize, mapySize));
437d86ed7fbStbbdev         t0 = oneapi::tbb::tick_count::now();
438d86ed7fbStbbdev         oneapi::tbb::parallel_for(
439d86ed7fbStbbdev             blocked_range_with_maps<int>(0, (int)(mapxSize + 1), grain_size, polymap1, polymap2),
440d86ed7fbStbbdev             ApplySplitOverlay((*result_map), polymap1, polymap2, resultMutex));
441d86ed7fbStbbdev         t1 = oneapi::tbb::tick_count::now();
442d86ed7fbStbbdev         domainSplitParallelTime = (t1 - t0).seconds() * 1000;
443d86ed7fbStbbdev         std::cout << "Splitting parallel with spin lock and ";
444d86ed7fbStbbdev         if (automatic_threadcount)
445d86ed7fbStbbdev             std::cout << "automatic";
446d86ed7fbStbbdev         else
447d86ed7fbStbbdev             std::cout << nthreads;
448d86ed7fbStbbdev         std::cout << ((nthreads == 1) ? " thread" : " threads");
449d86ed7fbStbbdev         std::cout << " took " << domainSplitParallelTime << " msec : speedup over serial "
450d86ed7fbStbbdev                   << (gSerialTime / domainSplitParallelTime) << "\n";
451d86ed7fbStbbdev         if (gCsvFile.is_open()) {
452d86ed7fbStbbdev             gCsvFile << "," << domainSplitParallelTime;
453d86ed7fbStbbdev         }
454d86ed7fbStbbdev #if _DEBUG
455d86ed7fbStbbdev         CheckPolygonMap(*result_map);
456d86ed7fbStbbdev         ComparePolygonMaps(*result_map, gResultMap);
457d86ed7fbStbbdev #endif
458d86ed7fbStbbdev         (*result_map)->clear();
459d86ed7fbStbbdev     }
460d86ed7fbStbbdev     delete resultMutex;
461d86ed7fbStbbdev     if (gCsvFile.is_open()) {
462d86ed7fbStbbdev         gCsvFile << "\n";
463d86ed7fbStbbdev     }
464d86ed7fbStbbdev }
465d86ed7fbStbbdev 
466d86ed7fbStbbdev class ApplySplitOverlayCV {
467d86ed7fbStbbdev     Polygon_map_t *m_map1, *m_map2;
468d86ed7fbStbbdev     concurrent_Polygon_map_t *m_resultMap;
469d86ed7fbStbbdev 
470d86ed7fbStbbdev public:
471d86ed7fbStbbdev     /*!
472d86ed7fbStbbdev     * @brief functor for columnar parallel version
473d86ed7fbStbbdev     * @param[in] r range of map to be operated on
474d86ed7fbStbbdev     */
operator ()(blocked_range_with_maps<int> & r) const475d86ed7fbStbbdev     void operator()(blocked_range_with_maps<int> &r) const {
476d86ed7fbStbbdev         // get yMapSize
477d86ed7fbStbbdev         int r1, g1, b1, r2, g2, b2;
478d86ed7fbStbbdev         int myr = -1;
479d86ed7fbStbbdev         int myg = -1;
480d86ed7fbStbbdev         int myb = -1;
481d86ed7fbStbbdev         int i1, i2, i3, yMapSize;
482d86ed7fbStbbdev         (*m_map1)[0].get(&i1, &i2, &i3, &yMapSize);
483d86ed7fbStbbdev 
484d86ed7fbStbbdev         Flagged_map_t &fmap1 = r.map1();
485d86ed7fbStbbdev         Flagged_map_t &fmap2 = r.map2();
486d86ed7fbStbbdev 
487d86ed7fbStbbdev         // When intersecting polygons from fmap1 and fmap2, if BOTH are flagged
488d86ed7fbStbbdev         // as duplicate, don't add the result to the output map.  We can still
489d86ed7fbStbbdev         // intersect them, because we are keeping track of how much of the polygon
490d86ed7fbStbbdev         // is left over from intersecting, and quitting when the polygon is
491d86ed7fbStbbdev         // used up.
492d86ed7fbStbbdev 
493d86ed7fbStbbdev         for (unsigned int i = 0; i < fmap1.size(); i++) {
494d86ed7fbStbbdev             RPolygon *p1 = fmap1[i].p();
495d86ed7fbStbbdev             bool is_dup = fmap1[i].isDuplicate();
496d86ed7fbStbbdev             int parea = p1->area();
497d86ed7fbStbbdev             p1->getColor(&r1, &g1, &b1);
498d86ed7fbStbbdev             for (unsigned int j = 0; (j < fmap2.size()) && (parea > 0); j++) {
499d86ed7fbStbbdev                 int xl, yl, xh, yh;
500d86ed7fbStbbdev                 RPolygon *p2 = fmap2[j].p();
501d86ed7fbStbbdev                 if (PolygonsOverlap(p1, p2, xl, yl, xh, yh)) {
502d86ed7fbStbbdev                     if (!(is_dup && fmap2[j].isDuplicate())) {
503d86ed7fbStbbdev                         p2->getColor(&r2, &g2, &b2);
504d86ed7fbStbbdev                         myr = r1 + r2;
505d86ed7fbStbbdev                         myg = g1 + g2;
506d86ed7fbStbbdev                         myb = b1 + b2;
507d86ed7fbStbbdev                         (*m_resultMap).push_back(RPolygon(xl, yl, xh, yh, myr, myg, myb));
508d86ed7fbStbbdev                     }
509d86ed7fbStbbdev                     parea -= (xh - xl + 1) * (yh - yl + 1);
510d86ed7fbStbbdev                 }
511d86ed7fbStbbdev             }
512d86ed7fbStbbdev         }
513d86ed7fbStbbdev     }
514d86ed7fbStbbdev 
ApplySplitOverlayCV(concurrent_Polygon_map_t * resultMap,Polygon_map_t * map1,Polygon_map_t * map2)515d86ed7fbStbbdev     ApplySplitOverlayCV(concurrent_Polygon_map_t *resultMap,
516d86ed7fbStbbdev                         Polygon_map_t *map1,
517d86ed7fbStbbdev                         Polygon_map_t *map2)
518d86ed7fbStbbdev             : m_resultMap(resultMap),
519d86ed7fbStbbdev               m_map1(map1),
520d86ed7fbStbbdev               m_map2(map2) {}
521d86ed7fbStbbdev };
522d86ed7fbStbbdev 
523d86ed7fbStbbdev /*!
524d86ed7fbStbbdev * @brief intersects two maps strip-wise, accumulating into a concurrent_vector
525d86ed7fbStbbdev *
526d86ed7fbStbbdev * @param[out] resultMap output map (must be allocated)
527d86ed7fbStbbdev * @param[in] polymap1 map to be intersected
528d86ed7fbStbbdev * @param[in] polymap2 map to be intersected
529d86ed7fbStbbdev */
SplitParallelOverlayCV(concurrent_Polygon_map_t ** result_map,Polygon_map_t * polymap1,Polygon_map_t * polymap2)530d86ed7fbStbbdev void SplitParallelOverlayCV(concurrent_Polygon_map_t **result_map,
531d86ed7fbStbbdev                             Polygon_map_t *polymap1,
532d86ed7fbStbbdev                             Polygon_map_t *polymap2) {
533d86ed7fbStbbdev     int nthreads;
534d86ed7fbStbbdev     bool automatic_threadcount = false;
535d86ed7fbStbbdev     double domainSplitParallelTime;
536d86ed7fbStbbdev     oneapi::tbb::tick_count t0, t1;
537d86ed7fbStbbdev     if (gThreadsLow == THREADS_UNSET || gThreadsLow == utility::get_default_num_threads()) {
538d86ed7fbStbbdev         gThreadsLow = gThreadsHigh = utility::get_default_num_threads();
539d86ed7fbStbbdev         automatic_threadcount = true;
540d86ed7fbStbbdev     }
541d86ed7fbStbbdev     *result_map = new concurrent_Polygon_map_t;
542d86ed7fbStbbdev 
543d86ed7fbStbbdev     RPolygon *p0 = &((*polymap1)[0]);
544d86ed7fbStbbdev     int mapxSize, mapySize, ignore1, ignore2;
545d86ed7fbStbbdev     p0->get(&ignore1, &ignore2, &mapxSize, &mapySize);
546d86ed7fbStbbdev     // (*result_map)->reserve(mapxSize*mapySize); // can't be any bigger than this
547d86ed7fbStbbdev 
548d86ed7fbStbbdev     int grain_size;
549d86ed7fbStbbdev #ifdef _DEBUG
550d86ed7fbStbbdev     grain_size = gMapXSize / 4;
551d86ed7fbStbbdev #else
552d86ed7fbStbbdev     grain_size = gGrainSize;
553d86ed7fbStbbdev #endif
554d86ed7fbStbbdev     for (nthreads = gThreadsLow; nthreads <= gThreadsHigh; nthreads++) {
555d86ed7fbStbbdev         oneapi::tbb::global_control c(oneapi::tbb::global_control::max_allowed_parallelism,
556d86ed7fbStbbdev                                       nthreads);
557d86ed7fbStbbdev         if (gIsGraphicalVersion) {
558d86ed7fbStbbdev             RPolygon *xp =
559d86ed7fbStbbdev                 new RPolygon(0, 0, gMapXSize - 1, gMapYSize - 1, 0, 0, 0); // Clear the output space
560d86ed7fbStbbdev             delete xp;
561d86ed7fbStbbdev         }
562d86ed7fbStbbdev         // push the map size as the first polygon,
563d86ed7fbStbbdev         (*result_map)->push_back(RPolygon(0, 0, mapxSize, mapySize));
564d86ed7fbStbbdev         t0 = oneapi::tbb::tick_count::now();
565d86ed7fbStbbdev         oneapi::tbb::parallel_for(
566d86ed7fbStbbdev             blocked_range_with_maps<int>(0, (int)(mapxSize + 1), grain_size, polymap1, polymap2),
567d86ed7fbStbbdev             ApplySplitOverlayCV((*result_map), polymap1, polymap2));
568d86ed7fbStbbdev         t1 = oneapi::tbb::tick_count::now();
569d86ed7fbStbbdev         domainSplitParallelTime = (t1 - t0).seconds() * 1000;
570d86ed7fbStbbdev         std::cout << "Splitting parallel with concurrent_vector and ";
571d86ed7fbStbbdev         if (automatic_threadcount)
572d86ed7fbStbbdev             std::cout << "automatic";
573d86ed7fbStbbdev         else
574d86ed7fbStbbdev             std::cout << nthreads;
575d86ed7fbStbbdev         std::cout << ((nthreads == 1) ? " thread" : " threads");
576d86ed7fbStbbdev         std::cout << " took " << domainSplitParallelTime << " msec : speedup over serial "
577d86ed7fbStbbdev                   << (gSerialTime / domainSplitParallelTime) << "\n";
578d86ed7fbStbbdev         if (gCsvFile.is_open()) {
579d86ed7fbStbbdev             gCsvFile << "," << domainSplitParallelTime;
580d86ed7fbStbbdev         }
581d86ed7fbStbbdev #if _DEBUG
582d86ed7fbStbbdev         {
583d86ed7fbStbbdev             Polygon_map_t s_result_map;
584d86ed7fbStbbdev             for (concurrent_Polygon_map_t::const_iterator i = (*result_map)->begin();
585d86ed7fbStbbdev                  i != (*result_map)->end();
586d86ed7fbStbbdev                  ++i) {
587d86ed7fbStbbdev                 s_result_map.push_back(*i);
588d86ed7fbStbbdev             }
589d86ed7fbStbbdev             CheckPolygonMap(&s_result_map);
590d86ed7fbStbbdev             ComparePolygonMaps(&s_result_map, gResultMap);
591d86ed7fbStbbdev         }
592d86ed7fbStbbdev #endif
593d86ed7fbStbbdev         (*result_map)->clear();
594d86ed7fbStbbdev     }
595d86ed7fbStbbdev 
596d86ed7fbStbbdev     if (gCsvFile.is_open()) {
597d86ed7fbStbbdev         gCsvFile << "\n";
598d86ed7fbStbbdev     }
599d86ed7fbStbbdev }
600d86ed7fbStbbdev 
601d86ed7fbStbbdev // ------------------------------------------------------
602d86ed7fbStbbdev 
603d86ed7fbStbbdev class ApplySplitOverlayETS {
604d86ed7fbStbbdev     Polygon_map_t *m_map1, *m_map2;
605d86ed7fbStbbdev     ETS_Polygon_map_t *m_resultMap;
606d86ed7fbStbbdev 
607d86ed7fbStbbdev public:
608d86ed7fbStbbdev     /*!
609d86ed7fbStbbdev     * @brief functor for columnar parallel version
610d86ed7fbStbbdev     * @param[in] r range of map to be operated on
611d86ed7fbStbbdev     */
operator ()(blocked_range_with_maps<int> & r) const612d86ed7fbStbbdev     void operator()(blocked_range_with_maps<int> &r) const {
613d86ed7fbStbbdev         // get yMapSize
614d86ed7fbStbbdev         int r1, g1, b1, r2, g2, b2;
615d86ed7fbStbbdev         int myr = -1;
616d86ed7fbStbbdev         int myg = -1;
617d86ed7fbStbbdev         int myb = -1;
618d86ed7fbStbbdev         int i1, i2, i3, yMapSize;
619d86ed7fbStbbdev         (*m_map1)[0].get(&i1, &i2, &i3, &yMapSize);
620d86ed7fbStbbdev 
621d86ed7fbStbbdev         Flagged_map_t &fmap1 = r.map1();
622d86ed7fbStbbdev         Flagged_map_t &fmap2 = r.map2();
623d86ed7fbStbbdev 
624d86ed7fbStbbdev         // When intersecting polygons from fmap1 and fmap2, if BOTH are flagged
625d86ed7fbStbbdev         // as duplicate, don't add the result to the output map.  We can still
626d86ed7fbStbbdev         // intersect them, because we are keeping track of how much of the polygon
627d86ed7fbStbbdev         // is left over from intersecting, and quitting when the polygon is
628d86ed7fbStbbdev         // used up.
629d86ed7fbStbbdev 
630d86ed7fbStbbdev         for (unsigned int i = 0; i < fmap1.size(); i++) {
631d86ed7fbStbbdev             RPolygon *p1 = fmap1[i].p();
632d86ed7fbStbbdev             bool is_dup = fmap1[i].isDuplicate();
633d86ed7fbStbbdev             int parea = p1->area();
634d86ed7fbStbbdev             p1->getColor(&r1, &g1, &b1);
635d86ed7fbStbbdev             for (unsigned int j = 0; (j < fmap2.size()) && (parea > 0); j++) {
636d86ed7fbStbbdev                 int xl, yl, xh, yh;
637d86ed7fbStbbdev                 RPolygon *p2 = fmap2[j].p();
638d86ed7fbStbbdev                 if (PolygonsOverlap(p1, p2, xl, yl, xh, yh)) {
639d86ed7fbStbbdev                     if (!(is_dup && fmap2[j].isDuplicate())) {
640d86ed7fbStbbdev                         p2->getColor(&r2, &g2, &b2);
641d86ed7fbStbbdev                         myr = r1 + r2;
642d86ed7fbStbbdev                         myg = g1 + g2;
643d86ed7fbStbbdev                         myb = b1 + b2;
644d86ed7fbStbbdev                         (*m_resultMap).local().push_back(RPolygon(xl, yl, xh, yh, myr, myg, myb));
645d86ed7fbStbbdev                     }
646d86ed7fbStbbdev                     parea -= (xh - xl + 1) * (yh - yl + 1);
647d86ed7fbStbbdev                 }
648d86ed7fbStbbdev             }
649d86ed7fbStbbdev         }
650d86ed7fbStbbdev     }
651d86ed7fbStbbdev 
ApplySplitOverlayETS(ETS_Polygon_map_t * resultMap,Polygon_map_t * map1,Polygon_map_t * map2)652d86ed7fbStbbdev     ApplySplitOverlayETS(ETS_Polygon_map_t *resultMap, Polygon_map_t *map1, Polygon_map_t *map2)
653d86ed7fbStbbdev             : m_resultMap(resultMap),
654d86ed7fbStbbdev               m_map1(map1),
655d86ed7fbStbbdev               m_map2(map2) {}
656d86ed7fbStbbdev };
657d86ed7fbStbbdev 
658d86ed7fbStbbdev /*!
659d86ed7fbStbbdev * @brief intersects two maps strip-wise, accumulating into an ets variable
660d86ed7fbStbbdev *
661d86ed7fbStbbdev * @param[out] resultMap output map (must be allocated)
662d86ed7fbStbbdev * @param[in] polymap1 map to be intersected
663d86ed7fbStbbdev * @param[in] polymap2 map to be intersected
664d86ed7fbStbbdev */
SplitParallelOverlayETS(ETS_Polygon_map_t ** result_map,Polygon_map_t * polymap1,Polygon_map_t * polymap2)665d86ed7fbStbbdev void SplitParallelOverlayETS(ETS_Polygon_map_t **result_map,
666d86ed7fbStbbdev                              Polygon_map_t *polymap1,
667d86ed7fbStbbdev                              Polygon_map_t *polymap2) {
668d86ed7fbStbbdev     int nthreads;
669d86ed7fbStbbdev     bool automatic_threadcount = false;
670d86ed7fbStbbdev     double domainSplitParallelTime;
671d86ed7fbStbbdev     oneapi::tbb::tick_count t0, t1;
672d86ed7fbStbbdev     if (gThreadsLow == THREADS_UNSET || gThreadsLow == utility::get_default_num_threads()) {
673d86ed7fbStbbdev         gThreadsLow = gThreadsHigh = utility::get_default_num_threads();
674d86ed7fbStbbdev         automatic_threadcount = true;
675d86ed7fbStbbdev     }
676d86ed7fbStbbdev     *result_map = new ETS_Polygon_map_t;
677d86ed7fbStbbdev 
678d86ed7fbStbbdev     RPolygon *p0 = &((*polymap1)[0]);
679d86ed7fbStbbdev     int mapxSize, mapySize, ignore1, ignore2;
680d86ed7fbStbbdev     p0->get(&ignore1, &ignore2, &mapxSize, &mapySize);
681d86ed7fbStbbdev     // (*result_map)->reserve(mapxSize*mapySize); // can't be any bigger than this
682d86ed7fbStbbdev 
683d86ed7fbStbbdev     int grain_size;
684d86ed7fbStbbdev #ifdef _DEBUG
685d86ed7fbStbbdev     grain_size = gMapXSize / 4;
686d86ed7fbStbbdev #else
687d86ed7fbStbbdev     grain_size = gGrainSize;
688d86ed7fbStbbdev #endif
689d86ed7fbStbbdev     for (nthreads = gThreadsLow; nthreads <= gThreadsHigh; nthreads++) {
690d86ed7fbStbbdev         oneapi::tbb::global_control c(oneapi::tbb::global_control::max_allowed_parallelism,
691d86ed7fbStbbdev                                       nthreads);
692d86ed7fbStbbdev         if (gIsGraphicalVersion) {
693d86ed7fbStbbdev             RPolygon *xp =
694d86ed7fbStbbdev                 new RPolygon(0, 0, gMapXSize - 1, gMapYSize - 1, 0, 0, 0); // Clear the output space
695d86ed7fbStbbdev             delete xp;
696d86ed7fbStbbdev         }
697d86ed7fbStbbdev         // push the map size as the first polygon,
698d86ed7fbStbbdev         // This polygon needs to be first, so we can push it at the start of a combine.
699d86ed7fbStbbdev         // (*result_map)->local.push_back(RPolygon(0,0,mapxSize, mapySize));
700d86ed7fbStbbdev         t0 = oneapi::tbb::tick_count::now();
701d86ed7fbStbbdev         oneapi::tbb::parallel_for(
702d86ed7fbStbbdev             blocked_range_with_maps<int>(0, (int)(mapxSize + 1), grain_size, polymap1, polymap2),
703d86ed7fbStbbdev             ApplySplitOverlayETS((*result_map), polymap1, polymap2));
704d86ed7fbStbbdev         t1 = oneapi::tbb::tick_count::now();
705d86ed7fbStbbdev         domainSplitParallelTime = (t1 - t0).seconds() * 1000;
706d86ed7fbStbbdev         std::cout << "Splitting parallel with ETS and ";
707d86ed7fbStbbdev         if (automatic_threadcount)
708d86ed7fbStbbdev             std::cout << "automatic";
709d86ed7fbStbbdev         else
710d86ed7fbStbbdev             std::cout << nthreads;
711d86ed7fbStbbdev         std::cout << ((nthreads == 1) ? " thread" : " threads");
712d86ed7fbStbbdev         std::cout << " took " << domainSplitParallelTime << " msec : speedup over serial "
713d86ed7fbStbbdev                   << (gSerialTime / domainSplitParallelTime) << "\n";
714d86ed7fbStbbdev         if (gCsvFile.is_open()) {
715d86ed7fbStbbdev             gCsvFile << "," << domainSplitParallelTime;
716d86ed7fbStbbdev         }
717d86ed7fbStbbdev #if _DEBUG
718d86ed7fbStbbdev         {
719d86ed7fbStbbdev             Polygon_map_t s_result_map;
720d86ed7fbStbbdev             oneapi::tbb::flattened2d<ETS_Polygon_map_t> psv = flatten2d(**result_map);
721d86ed7fbStbbdev             s_result_map.push_back(RPolygon(0, 0, mapxSize, mapySize));
722d86ed7fbStbbdev             for (oneapi::tbb::flattened2d<ETS_Polygon_map_t>::const_iterator ci = psv.begin();
723d86ed7fbStbbdev                  ci != psv.end();
724d86ed7fbStbbdev                  ++ci) {
725d86ed7fbStbbdev                 s_result_map.push_back(*ci);
726d86ed7fbStbbdev             }
727d86ed7fbStbbdev             CheckPolygonMap(&s_result_map);
728d86ed7fbStbbdev             ComparePolygonMaps(&s_result_map, gResultMap);
729d86ed7fbStbbdev         }
730d86ed7fbStbbdev #endif
731d86ed7fbStbbdev         (*result_map)->clear();
732d86ed7fbStbbdev     }
733d86ed7fbStbbdev 
734d86ed7fbStbbdev     if (gCsvFile.is_open()) {
735d86ed7fbStbbdev         gCsvFile << "\n";
736d86ed7fbStbbdev     }
737d86ed7fbStbbdev }
738