Shadowrun: Awakened 29 September 2011 - Build 871
polyover.cpp
Go to the documentation of this file.
00001 /*
00002     Copyright 2005-2010 Intel Corporation.  All Rights Reserved.
00003 
00004     This file is part of Threading Building Blocks.
00005 
00006     Threading Building Blocks is free software; you can redistribute it
00007     and/or modify it under the terms of the GNU General Public License
00008     version 2 as published by the Free Software Foundation.
00009 
00010     Threading Building Blocks is distributed in the hope that it will be
00011     useful, but WITHOUT ANY WARRANTY; without even the implied warranty
00012     of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013     GNU General Public License for more details.
00014 
00015     You should have received a copy of the GNU General Public License
00016     along with Threading Building Blocks; if not, write to the Free Software
00017     Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
00018 
00019     As a special exception, you may use this file as part of a free software
00020     library without restriction.  Specifically, if other files instantiate
00021     templates or use macros or inline functions from this file, or you compile
00022     this file and link it with other files to produce an executable, this
00023     file does not by itself cause the resulting executable to be covered by
00024     the GNU General Public License.  This exception does not however
00025     invalidate any other reasons why the executable file might be covered by
00026     the GNU General Public License.
00027 */
00028 
00029 // Polygon overlay
00030 //
00031 #include <iostream>
00032 #include <algorithm>
00033 #include <string.h>
00034 #include <cstdlib>
00035 #include <assert.h>
00036 #include "tbb/tick_count.h"
00037 #include "tbb/blocked_range.h"
00038 #include "tbb/task_scheduler_init.h"
00039 #include "tbb/parallel_for.h"
00040 #include "tbb/mutex.h"
00041 #include "tbb/spin_mutex.h"
00042 #include "polyover.h"
00043 #include "polymain.h"
00044 #include "pover_video.h"
00045 
00046 using namespace std;
00047 
00057 void OverlayOnePolygonWithMap(Polygon_map_t *resultMap, RPolygon *myPoly, Polygon_map_t *map2, tbb::spin_mutex *rMutex) {
00058     int r1, g1, b1, r2, g2, b2;
00059     int myr=0;
00060     int myg=0;
00061     int myb=0;
00062     int p1Area = myPoly->area();
00063     for(unsigned int j=1; (j < map2->size()) && (p1Area > 0); j++) {
00064         RPolygon *p2 = (*map2)[j];
00065         RPolygon *pnew;
00066         int newxMin, newxMax, newyMin, newyMax;
00067         myPoly->getColor(&r1, &g1, &b1);
00068         if(PolygonsOverlap(myPoly, p2, newxMin, newyMin, newxMax, newyMax)) {
00069             p2->getColor(&r2, &g2, &b2);
00070             myr = r1 + r2;
00071             myg = g1 + g2;
00072             myb = b1 + b2;
00073             pnew = RPolygon::alloc_RPolygon(newxMin, newyMin, newxMax, newyMax, myr, myg, myb);
00074             p1Area -= pnew->area(); // when all the area of the polygon is accounted for, we can quit.
00075             if(rMutex) {
00076                 tbb::spin_mutex::scoped_lock lock(*rMutex);
00077 #if _DEBUG
00078                 pnew->print(int(resultMap->size()));
00079 #endif
00080                 resultMap->push_back(pnew);
00081             }
00082             else {
00083 #ifdef _DEBUG
00084                 pnew->print(int(resultMap->size()));
00085 #endif
00086                 resultMap->push_back(pnew);
00087             }
00088         }
00089     }
00090 }
00091 
00098 void SerialOverlayMaps(Polygon_map_t **resultMap, Polygon_map_t *map1, Polygon_map_t *map2) {
00099     cout << "SerialOverlayMaps called" << std::endl;
00100     *resultMap = new Polygon_map_t;
00101 
00102     RPolygon *p0 = (*map1)[0];
00103     int mapxSize, mapySize, ignore1, ignore2;
00104     p0->get(&ignore1, &ignore2, &mapxSize, &mapySize);
00105     (*resultMap)->reserve(mapxSize*mapySize); // can't be any bigger than this
00106     // push the map size as the first polygon,
00107     p0 = RPolygon::alloc_RPolygon(0,0,mapxSize, mapySize);
00108     (*resultMap)->push_back(p0);
00109     for(unsigned int i=1; i < map1->size(); i++) {
00110         RPolygon *p1 = (*map1)[i];
00111         OverlayOnePolygonWithMap(*resultMap, p1, map2, NULL);
00112     }
00113 }
00114 
00119 class ApplyOverlay {
00120     Polygon_map_t *m_map1, *m_map2, *m_resultMap;
00121     tbb::spin_mutex *m_rMutex;
00122 public:
00127     void operator()( const tbb::blocked_range<int> & r) const {
00128         PRINT_DEBUG("From " << r.begin() << " to " << r.end());
00129         for(int i=r.begin(); i != r.end(); i++) {
00130             RPolygon *myPoly = (*m_map1)[i];
00131             OverlayOnePolygonWithMap(m_resultMap, myPoly, m_map2, m_rMutex);
00132         }
00133     }
00134     ApplyOverlay(Polygon_map_t *resultMap, Polygon_map_t *map1, Polygon_map_t *map2, tbb::spin_mutex *rmutex) :
00135     m_resultMap(resultMap), m_map1(map1), m_map2(map2), m_rMutex(rmutex) {}
00136 };
00137 
00144 void NaiveParallelOverlay(Polygon_map_t *&result_map, Polygon_map_t &polymap1, Polygon_map_t &polymap2) {
00145 // -----------------------------------
00146     bool automatic_threadcount = false;
00147 
00148     if(gThreadsLow == THREADS_UNSET || gThreadsLow == tbb::task_scheduler_init::automatic) {
00149         gThreadsLow = gThreadsHigh = tbb::task_scheduler_init::automatic;
00150         automatic_threadcount = true;
00151     }
00152     result_map = new Polygon_map_t;
00153 
00154     RPolygon *p0 = polymap1[0];
00155     int mapxSize, mapySize, ignore1, ignore2;
00156     p0->get(&ignore1, &ignore2, &mapxSize, &mapySize);
00157     result_map->reserve(mapxSize*mapySize); // can't be any bigger than this
00158     // push the map size as the first polygon,
00159     tbb::spin_mutex *resultMutex = new tbb::spin_mutex();
00160     int grain_size = gGrainSize;
00161 
00162     for(int nthreads = gThreadsLow; nthreads <= gThreadsHigh; nthreads++) {
00163         tbb::task_scheduler_init init(nthreads);
00164         if(gIsGraphicalVersion) {
00165             RPolygon *xp = RPolygon::alloc_RPolygon(0, 0, gMapXSize-1, gMapYSize-1, 0, 0, 0);  // Clear the output space
00166             RPolygon::free_RPolygon( xp );
00167         }
00168         // put size polygon in result map
00169         p0 = RPolygon::alloc_RPolygon(0,0,mapxSize, mapySize);
00170         result_map->push_back(p0);
00171 
00172         tbb::tick_count t0 = tbb::tick_count::now();
00173         tbb::parallel_for (tbb::blocked_range<int>(1,(int)(polymap1.size()),grain_size), ApplyOverlay(result_map, &polymap1, &polymap2, resultMutex));
00174         tbb::tick_count t1 = tbb::tick_count::now();
00175 
00176         double naiveParallelTime = (t1-t0).seconds() * 1000;
00177         cout << "Naive parallel with spin lock and ";
00178         if(automatic_threadcount) cout << "automatic";
00179         else cout << nthreads;
00180         cout << ((nthreads == 1) ? " thread" : " threads");
00181         cout << " took " << naiveParallelTime << " msec : speedup over serial " << (gSerialTime / naiveParallelTime) << std::endl;
00182         if(gCsvFile.is_open()) {
00183             gCsvFile << "," << naiveParallelTime;
00184         }
00185 #if _DEBUG
00186         CheckPolygonMap(result_map);
00187         ComparePolygonMaps(result_map, gResultMap);
00188 #endif
00189         for(int i=0; i<int(result_map->size());i++) {
00190             RPolygon::free_RPolygon(result_map->at(i));
00191         }
00192         result_map->clear();
00193     }
00194     delete resultMutex;
00195     if(gCsvFile.is_open()) {
00196         gCsvFile << std::endl;
00197     }
00198 // -----------------------------------
00199 }
00200 
00206 class ApplySplitOverlay {
00207     Polygon_map_t *m_map1, *m_map2, *m_resultMap;
00208     tbb::spin_mutex *m_rMutex;
00209 public:
00214     void operator()(const tbb::blocked_range<int> & r) const {
00215 #ifdef _DEBUG
00216         // if we are debugging, serialize the method.  That way we can
00217         // see what is happening in each strip without the interleaving
00218         // confusing things.
00219         tbb::spin_mutex::scoped_lock lock(*m_rMutex);
00220         cout << unitbuf << "From " << r.begin() << " to " << r.end()-1 << std::endl;
00221 #endif
00222         // instead of handing out subsets of polygons from map1 to intersect
00223         // with the polygons in map2, we are handed a strip of the map from
00224         // [(r.begin(),0)-(r.end()-1,yMapSize)].
00225         //
00226         // make a polygon with those values, and intersect with all the polygons
00227         // in map1 and map2, creating flagged polygon lists fmap1 and fmap2.
00228         // There are four possiblities:
00229         //
00230         //   1) a polygon is contained entirely within the strip.  We just
00231         //      add the polygon to our flagged map.
00232         //   2) the polygon will be partly contained in our strip, and partly
00233         //      in the strip to our right (higher x values).  Add the polygon
00234         //      to our flagged map.
00235         //   3) the polygon is partly contained in our map, and partly in the
00236         //      strip to our left.  Add the polygon to our map, but flag it as
00237         //      a duplicate.
00238         //   4) the polygons do not intersect. Don't add to flagged map.
00239         //
00240 
00241         // get yMapSize
00242         int r1, g1, b1, r2, g2, b2;
00243         int myr=-1;
00244         int myg=-1;
00245         int myb=-1;
00246         int i1, i2, i3, yMapSize;
00247         m_map1->at(0)->get(&i1, &i2, &i3, &yMapSize);
00248         RPolygon *slicePolygon = RPolygon::alloc_RPolygon(r.begin(), 0, r.end() - 1, yMapSize);
00249 
00250         Flagged_map_t *fmap1, *fmap2;
00251         fmap1 = new std::vector<RPolygon_flagged>;
00252         fmap1->reserve(m_map1->size());
00253         fmap2 = new Flagged_map_t;
00254         fmap2->reserve(m_map2->size());
00255 
00256         PRINT_DEBUG(std::endl << "Map1 -------------------");
00257         for(unsigned int i=1; i<m_map1->size(); i++) {
00258             int xl, yl, xh, yh;
00259             RPolygon *px = m_map1->at(i);
00260             if(PolygonsOverlap(slicePolygon, px, xl, yl, xh, yh)) {
00261                 bool is_duplicate = false;
00262                 int pxl, pyl, pxh, pyh;
00263                 int indx = (int)(fmap1->size());
00264                 fmap1->resize(indx+1);
00265                 fmap1->at(indx).setp(px);
00266                 px->get(&pxl, &pyl, &pxh, &pyh);
00267                 if(pxl < xl) {
00268                     is_duplicate = true;
00269                 }
00270                 //fmap1->at(indx).setp(px);
00271                 fmap1->at(indx).setDuplicate(is_duplicate);
00272                 PRINT_DEBUG(" Polygon " << *px << " is in map, is_duplicate=" << is_duplicate);
00273 
00274             }
00275         }
00276 
00277         PRINT_DEBUG(std::endl << "Map2 -------------------");
00278 
00279         for(unsigned int i=1; i<m_map2->size(); i++) {
00280             int xl, yl, xh, yh;
00281             RPolygon *px = m_map2->at(i);
00282 
00283             if(PolygonsOverlap(slicePolygon, px, xl, yl, xh, yh)) {
00284                 bool is_duplicate = false;
00285                 int pxl, pyl, pxh, pyh;
00286                 int indx = (int)(fmap2->size());
00287                 fmap2->resize(indx+1);
00288                 fmap2->at(indx).setp(px);
00289                 px->get(&pxl, &pyl, &pxh, &pyh);
00290                 if(pxl < xl) {
00291                     is_duplicate = true;
00292                 }
00293                 fmap2->at(indx).setDuplicate(is_duplicate);
00294                 PRINT_DEBUG(" Polygon " << *px << " is in map, is_duplicate=" << is_duplicate);
00295             }
00296         }
00297 
00298         // When intersecting polygons from fmap1 and fmap2, if BOTH are flagged
00299         // as duplicate, don't add the result to the output map.  We can still
00300         // intersect them, because we are keeping track of how much of the polygon
00301         // is left over from intersecting, and quitting when the polygon is
00302         // used up.
00303 
00304         for(unsigned int ii=0; ii < fmap1->size(); ii++) {
00305             RPolygon *p1 = fmap1->at(ii).p();
00306             bool is_dup = fmap1->at(ii).isDuplicate();
00307             int parea = p1->area();
00308             p1->getColor(&r1, &g1, &b1);
00309             for(unsigned int jj=0;(jj < fmap2->size()) && (parea > 0); jj++) {
00310                 int xl, yl, xh, yh;
00311                 RPolygon *p2 = fmap2->at(jj).p();
00312                 if(PolygonsOverlap(p1, p2, xl, yl, xh, yh)) {
00313                     if(!(is_dup && fmap2->at(jj).isDuplicate())) {
00314                         p2->getColor(&r2, &g2, &b2);
00315                         myr = r1 + r2;
00316                         myg = g1 + g2;
00317                         myb = b1 + b2;
00318                         RPolygon *pnew = RPolygon::alloc_RPolygon(xl, yl, xh, yh, myr, myg, myb);
00319 #ifdef _DEBUG
00320 #else
00321                         tbb::spin_mutex::scoped_lock lock(*m_rMutex);
00322 #endif
00323                         (*m_resultMap).push_back(pnew);
00324                     }
00325                     parea -= (xh-xl+1)*(yh-yl+1);
00326                 }
00327             }
00328         }
00329 
00330         delete fmap1;
00331         delete fmap2;
00332         RPolygon::free_RPolygon( slicePolygon );
00333     }
00334 
00335     ApplySplitOverlay(Polygon_map_t *resultMap, Polygon_map_t *map1, Polygon_map_t *map2, tbb::spin_mutex *rmutex) :
00336     m_resultMap(resultMap), m_map1(map1), m_map2(map2), m_rMutex(rmutex) {}
00337 };
00338 
00339 
00347 void SplitParallelOverlay(Polygon_map_t **result_map, Polygon_map_t *polymap1, Polygon_map_t *polymap2) {
00348     int nthreads;
00349     bool automatic_threadcount = false;
00350     double domainSplitParallelTime;
00351     tbb::tick_count t0, t1;
00352     tbb::spin_mutex *resultMutex;
00353     if(gThreadsLow == THREADS_UNSET || gThreadsLow == tbb::task_scheduler_init::automatic ) {
00354         gThreadsLow = gThreadsHigh = tbb::task_scheduler_init::automatic;
00355         automatic_threadcount = true;
00356     }
00357     *result_map = new Polygon_map_t;
00358 
00359     RPolygon *p0 = (*polymap1)[0];
00360     int mapxSize, mapySize, ignore1, ignore2;
00361     p0->get(&ignore1, &ignore2, &mapxSize, &mapySize);
00362     (*result_map)->reserve(mapxSize*mapySize); // can't be any bigger than this
00363     resultMutex = new tbb::spin_mutex();
00364 
00365     int grain_size;
00366 #ifdef _DEBUG
00367     grain_size = gMapXSize / 4;
00368 #else
00369     grain_size = gGrainSize;
00370 #endif
00371 
00372     for(nthreads = gThreadsLow; nthreads <= gThreadsHigh; nthreads++) {
00373         tbb::task_scheduler_init init(nthreads);
00374         if(gIsGraphicalVersion) {
00375             RPolygon *xp = RPolygon::alloc_RPolygon(0, 0, gMapXSize-1, gMapYSize-1, 0, 0, 0);  // Clear the output space
00376             RPolygon::free_RPolygon( xp );
00377         }
00378         // push the map size as the first polygon,
00379         p0 = RPolygon::alloc_RPolygon(0,0,mapxSize, mapySize);
00380         (*result_map)->push_back(p0);
00381         t0 = tbb::tick_count::now();
00382         tbb::parallel_for (tbb::blocked_range<int>(0,(int)(mapxSize+1),grain_size), ApplySplitOverlay((*result_map), polymap1, polymap2, resultMutex));
00383         t1 = tbb::tick_count::now();
00384         domainSplitParallelTime = (t1-t0).seconds()*1000;
00385         cout << "Splitting parallel with spin lock and ";
00386         if(automatic_threadcount) cout << "automatic";
00387         else cout << nthreads;
00388         cout << ((nthreads == 1) ? " thread" : " threads");
00389         cout << " took " << domainSplitParallelTime <<  " msec : speedup over serial " << (gSerialTime / domainSplitParallelTime) << std::endl;
00390         if(gCsvFile.is_open()) {
00391             gCsvFile << "," << domainSplitParallelTime;
00392         }
00393 #if _DEBUG
00394         CheckPolygonMap(*result_map);
00395         ComparePolygonMaps(*result_map, gResultMap);
00396 #endif
00397         for(int i=0; i<int((*result_map)->size());i++) {
00398             RPolygon::free_RPolygon((*result_map)->at(i));
00399         }
00400         (*result_map)->clear();
00401 
00402     }
00403     delete resultMutex;
00404     if(gCsvFile.is_open()) {
00405         gCsvFile << std::endl;
00406     }
00407 
00408 }

Copyright © 2007-2010 by The Shadowrun: Awakened Team. This work is licensed under the GNU Lesser General Public License 3.

GNU Lesser General Public License 3 Sourceforge.net