1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_basegfx.hxx"
26 
27 #include <basegfx/polygon/b2dpolypolygonrasterconverter.hxx>
28 
29 #include <basegfx/numeric/ftools.hxx>
30 #include <basegfx/polygon/b2dpolygon.hxx>
31 #include <basegfx/polygon/b2dpolygontools.hxx>
32 #include <basegfx/polygon/b2dpolypolygontools.hxx>
33 
34 #include <boost/mem_fn.hpp>
35 
36 #include <algorithm>
37 
38 namespace basegfx
39 {
40 	class radixSort {
41 
42 		//! public interface
43 		public:
44 
45 			//! default constructor
46 			radixSort( void );
47 
48 			//! destructor
49 			~radixSort( void );
50 
51 			bool sort( const float *pInput, sal_uInt32 nNumElements, sal_uInt32 dwStride );
52 
indices(void) const53 			inline sal_uInt32 *indices( void ) const { return m_indices1; }
54 
55 		//! private attributes
56 		private:
57 
58 			// current size of index list
59 			sal_uInt32 m_current_size;
60 
61 			// last known size of index list
62 			sal_uInt32 m_previous_size;
63 
64 			// index lists
65 			sal_uInt32 *m_indices1;
66 			sal_uInt32 *m_indices2;
67 
68 			sal_uInt32 m_counter[256*4];
69 			sal_uInt32 m_offset[256];
70 
71 		//! private methods
72 		private:
73 
74 			bool resize( sal_uInt32 nNumElements );
75 			inline void reset_indices( void );
76 			bool prepareCounters( const float *pInput, sal_uInt32 nNumElements, sal_uInt32 dwStride );
77 	};
78 
radixSort(void)79 	inline radixSort::radixSort( void ) {
80 
81 		m_indices1 = NULL;
82 		m_indices2 = NULL;
83 		m_current_size = 0;
84 		m_previous_size = 0;
85 
86 		reset_indices();
87 	}
88 
~radixSort(void)89 	inline radixSort::~radixSort( void ) {
90 
91 		delete [] m_indices2;
92 		delete [] m_indices1;
93 	}
94 
resize(sal_uInt32 nNumElements)95 	bool radixSort::resize( sal_uInt32 nNumElements ) {
96 
97 		if(nNumElements==m_previous_size)
98 			return true;
99 
100 		if(nNumElements > m_current_size) {
101 
102 			// release index lists
103 			if(m_indices2)
104 				delete [] m_indices2;
105 			if(m_indices1)
106 				delete [] m_indices1;
107 
108 			// allocate new index lists
109 			m_indices1 = new sal_uInt32[nNumElements];
110 			m_indices2 = new sal_uInt32[nNumElements];
111 
112 			// check for out of memory situation
113             if(!m_indices1 || !m_indices2) {
114 				delete [] m_indices1;
115 				delete [] m_indices2;
116 				m_indices1 = NULL;
117 				m_indices2 = NULL;
118 				m_current_size = 0;
119 				return false;
120 			}
121 
122 			m_current_size = nNumElements;
123 		}
124 
125 		m_previous_size = nNumElements;
126 
127 		// initialize indices
128 		reset_indices();
129 
130 		return true;
131 	}
132 
reset_indices(void)133 	inline void radixSort::reset_indices( void ) {
134 
135 		for(sal_uInt32 i=0;i<m_current_size;i++)
136 			m_indices1[i] = i;
137 	}
138 
prepareCounters(const float * pInput,sal_uInt32 nNumElements,sal_uInt32 dwStride)139 	bool radixSort::prepareCounters( const float *pInput, sal_uInt32 nNumElements, sal_uInt32 dwStride ) {
140 
141 		// clear counters
142 		sal_uInt32 *ptr = m_counter;
143 		for(int i=0; i<64; ++i)
144         {
145 			*ptr++ = 0;
146 			*ptr++ = 0;
147 			*ptr++ = 0;
148 			*ptr++ = 0;
149 			*ptr++ = 0;
150 			*ptr++ = 0;
151 			*ptr++ = 0;
152 			*ptr++ = 0;
153 			*ptr++ = 0;
154 			*ptr++ = 0;
155 			*ptr++ = 0;
156 			*ptr++ = 0;
157 			*ptr++ = 0;
158 			*ptr++ = 0;
159 			*ptr++ = 0;
160 			*ptr++ = 0;
161 		}
162 
163 		// prepare pointers to relevant memory addresses
164 		sal_uInt8 *p = (sal_uInt8*)pInput;
165 		sal_uInt8 *pe = p+(nNumElements*dwStride);
166 		sal_uInt32 *h0= &m_counter[0];
167 		sal_uInt32 *h1= &m_counter[256];
168 		sal_uInt32 *h2= &m_counter[512];
169 		sal_uInt32 *h3= &m_counter[768];
170 
171 		sal_uInt32 *Indices = m_indices1;
172 		float previous_value = *(float *)(((sal_uInt8 *)pInput)+(m_indices1[0]*dwStride));
173 		bool bSorted = true;
174 		while(p!=pe) {
175 			float value = *(float *)(((sal_uInt8 *)pInput)+((*Indices++)*dwStride));
176 			if(value<previous_value)	{
177 				bSorted = false;
178 				break;
179 			}
180 			previous_value = value;
181 			h0[*p++]++;
182 			h1[*p++]++;
183 			h2[*p++]++;
184 			h3[*p++]++;
185 			p += dwStride-4;
186 		}
187 		if(bSorted)
188 			return true;
189 		while(p!=pe) {
190 			h0[*p++]++;
191 			h1[*p++]++;
192 			h2[*p++]++;
193 			h3[*p++]++;
194 			p += dwStride-4;
195 		}
196 		return false;
197 	}
198 
sort(const float * pInput,sal_uInt32 nNumElements,sal_uInt32 dwStride)199 	bool radixSort::sort( const float *pInput, sal_uInt32 nNumElements, sal_uInt32 dwStride ) {
200 
201 		if(!(pInput))
202 			return false;
203 		if(!(nNumElements))
204 			return false;
205 		if(!(resize(nNumElements)))
206 			return false;
207 
208 		// prepare radix counters, return if already sorted
209 		if(prepareCounters(pInput,nNumElements,dwStride))
210 			return true;
211 
212 		// count number of negative values
213 		sal_uInt32 num_negatives = 0;
214 		sal_uInt32 *h3= &m_counter[768];
215 		for(sal_uInt32 i=128;i<256;i++)
216 			num_negatives += h3[i];
217 
218 		// perform passes, one for each byte
219 		for(sal_uInt32 j=0;j<4;j++) {
220 
221 			// ignore this pass if all values have the same byte
222 			bool bRun = true;
223 			sal_uInt32 *current_counter = &m_counter[j<<8];
224 			sal_uInt8 unique_value = *(((sal_uInt8*)pInput)+j);
225 			if(current_counter[unique_value]==nNumElements)
226 				bRun=false;
227 
228 			// does the incoming byte contain the sign bit?
229 			sal_uInt32 i;
230 			if(j!=3) {
231 				if(bRun) {
232 					m_offset[0] = 0;
233 					for(i=1;i<256;i++)
234 						m_offset[i] = m_offset[i-1] + current_counter[i-1];
235 					sal_uInt8 *InputBytes = (sal_uInt8 *)pInput;
236 					sal_uInt32 *Indices = m_indices1;
237 					sal_uInt32 *IndicesEnd = &m_indices1[nNumElements];
238 					InputBytes += j;
239 					while(Indices!=IndicesEnd) {
240 						sal_uInt32 id = *Indices++;
241 						m_indices2[m_offset[InputBytes[id*dwStride]]++] = id;
242 					}
243 					sal_uInt32 *Tmp	= m_indices1;
244 					m_indices1 = m_indices2;
245 					m_indices2 = Tmp;
246 				}
247 			}
248 			else {
249 				if(bRun) {
250 					m_offset[0] = num_negatives;
251 					for(i=1;i<128;i++)
252 						m_offset[i] = m_offset[i-1] + current_counter[i-1];
253 					m_offset[255] = 0;
254 					for(i=0;i<127;i++)
255 						m_offset[254-i] = m_offset[255-i] + current_counter[255-i];
256 					for(i=128;i<256;i++)
257 						m_offset[i] += current_counter[i];
258 					for(i=0;i<nNumElements;i++) {
259 						sal_uInt32 Radix = (*(sal_uInt32 *)(((sal_uInt8 *)pInput)+(m_indices1[i]*dwStride)))>>24;
260 						if(Radix<128) m_indices2[m_offset[Radix]++] = m_indices1[i];
261 						else m_indices2[--m_offset[Radix]] = m_indices1[i];
262 					}
263 					sal_uInt32 *Tmp	= m_indices1;
264 					m_indices1 = m_indices2;
265 					m_indices2 = Tmp;
266 				}
267 				else {
268 					if(unique_value>=128) {
269 						for(i=0;i<nNumElements;i++)
270 							m_indices2[i] = m_indices1[nNumElements-i-1];
271 						sal_uInt32 *Tmp	= m_indices1;
272 						m_indices1 = m_indices2;
273 						m_indices2 = Tmp;
274 					}
275 				}
276 			}
277 		}
278 
279 		return true;
280 	}
281 
282 	//************************************************************
283 	// Internal vertex storage of B2DPolyPolygonRasterConverter
284 	//************************************************************
285 
Vertex()286     inline B2DPolyPolygonRasterConverter::Vertex::Vertex() :
287         aP1(),
288         aP2(),
289         bDownwards( true )
290     {
291     }
292 
Vertex(const B2DPoint & rP1,const B2DPoint & rP2,bool bDown)293     inline B2DPolyPolygonRasterConverter::Vertex::Vertex( const B2DPoint& rP1, const B2DPoint& rP2, bool bDown ) :
294         aP1( rP1 ),
295         aP2( rP2 ),
296         bDownwards( bDown )
297     {
298     }
299 
300 
301 	//************************************************************
302 	// Helper class for holding horizontal line segments during raster
303 	// conversion
304 	//************************************************************
305 
306 	namespace
307     {
308         class ImplLineNode
309         {
310 		public:
311             sal_Int32	mnYCounter;
312             float		mfXPos;
313             float		mfXDelta;
314             bool		mbDownwards;
315 
316         public:
317             /**rP1 and rP2 must not have equal y values, when rounded
318                to integer!
319             */
ImplLineNode(const B2DPoint & rP1,const B2DPoint & rP2,bool bDown)320             ImplLineNode(const B2DPoint& rP1, const B2DPoint& rP2, bool bDown) :
321                 mnYCounter( fround(rP2.getY()) - fround(rP1.getY()) ),
322                 mfXPos( (float)(rP1.getX()) ),
323                 mfXDelta((float) ((rP2.getX() - rP1.getX()) / mnYCounter) ),
324                 mbDownwards( bDown )
325             {
326             }
327 
328             /// get current x position
getXPos() const329             const float& getXPos() const
330             {
331                 return mfXPos;
332             }
333 
334             /// returns true, if line ends on this Y value
nextLine()335             float nextLine()
336             {
337                 if(mnYCounter>=0)
338                 {
339                     // go one step in Y
340                     mfXPos += mfXDelta;
341                     --mnYCounter;
342 					return mfXDelta;
343                 }
344 
345 				return 0.0f;
346             }
347 
isEnded()348             bool isEnded()
349             {
350                 return mnYCounter<=0;
351             }
352 
isDownwards()353             bool isDownwards()
354             {
355                 return mbDownwards;
356             }
357         };
358     }
359 
360     typedef ::std::vector<ImplLineNode> VectorOfLineNodes;
361 
362 
363 	//************************************************************
364 	//   Base2D PolyPolygon Raster Converter (Rasterizer)
365 	//************************************************************
366 
367     namespace
368     {
369         struct VertexComparator
370         {
operator ()basegfx::__anon48f8762a0211::VertexComparator371             bool operator()( const B2DPolyPolygonRasterConverter::Vertex& rLHS,
372                              const B2DPolyPolygonRasterConverter::Vertex& rRHS )
373             {
374                 return rLHS.aP1.getX() < rRHS.aP1.getX();
375             }
376         };
377     }
378 
init()379     void B2DPolyPolygonRasterConverter::init()
380     {
381         if(!maPolyPolyRectangle.isEmpty())
382         {
383             const sal_Int32	nMinY( fround(maPolyPolyRectangle.getMinY()) );
384             const sal_Int32 nScanlines(fround(maPolyPolyRectangle.getMaxY()) - nMinY);
385 
386             maScanlines.resize( nScanlines+1 );
387 
388             // add all polygons
389             for( sal_uInt32 i(0), nCount(maPolyPolygon.count());
390                  i < nCount;
391                  ++i )
392             {
393                 // add all vertices
394                 const B2DPolygon& rPoly( maPolyPolygon.getB2DPolygon(i) );
395                 for( sal_uInt32 k(0), nVertices(rPoly.count());
396                      k<nVertices;
397                      ++k )
398                 {
399                     const B2DPoint& rP1( rPoly.getB2DPoint(k) );
400                     const B2DPoint& rP2( rPoly.getB2DPoint( (k + 1) % nVertices ) );
401 
402                     const sal_Int32 nVertexYP1( fround(rP1.getY()) );
403                     const sal_Int32 nVertexYP2( fround(rP2.getY()) );
404 
405                     // insert only vertices which are not strictly
406                     // horizontal. Note that the ImplLineNode relies on
407                     // this.
408                     if(nVertexYP1 != nVertexYP2)
409                     {
410                         if( nVertexYP2 < nVertexYP1 )
411                         {
412                             const sal_Int32 nStartScanline(nVertexYP2 - nMinY);
413 
414                             // swap edges
415                             maScanlines[ nStartScanline ].push_back( Vertex(rP2, rP1, false) );
416                         }
417                         else
418                         {
419                             const sal_Int32 nStartScanline(nVertexYP1 - nMinY);
420 
421                             maScanlines[ nStartScanline ].push_back( Vertex(rP1, rP2, true) );
422                         }
423                     }
424                 }
425             }
426 
427             // now sort all scanlines, with increasing x coordinates
428             VectorOfVertexVectors::iterator aIter( maScanlines.begin() );
429             VectorOfVertexVectors::iterator aEnd( maScanlines.end() );
430             while( aIter != aEnd )
431             {
432                 ::std::sort( aIter->begin(),
433                              aIter->end(),
434                              VertexComparator() );
435                 ++aIter;
436             }
437         }
438     }
439 
B2DPolyPolygonRasterConverter(const B2DPolyPolygon & rPolyPoly)440     B2DPolyPolygonRasterConverter::B2DPolyPolygonRasterConverter( const B2DPolyPolygon& rPolyPoly ) :
441         maPolyPolygon( rPolyPoly ),
442         maPolyPolyRectangle( tools::getRange( rPolyPoly ) ),
443         maScanlines()
444     {
445         init();
446     }
447 
448     namespace
449     {
getCombinedBounds(const B2DPolyPolygon & rPolyPolyRaster,const B2DRectangle & rRasterArea)450         B2DRectangle getCombinedBounds( const B2DPolyPolygon& rPolyPolyRaster,
451                                         const B2DRectangle&   rRasterArea )
452         {
453             B2DRectangle aRect( tools::getRange( rPolyPolyRaster ) );
454             aRect.expand( rRasterArea );
455 
456             return aRect;
457         }
458     }
459 
B2DPolyPolygonRasterConverter(const B2DPolyPolygon & rPolyPolyRaster,const B2DRectangle & rRasterArea)460     B2DPolyPolygonRasterConverter::B2DPolyPolygonRasterConverter( const B2DPolyPolygon& rPolyPolyRaster,
461                                                                   const B2DRectangle&   rRasterArea ) :
462         maPolyPolygon( rPolyPolyRaster ),
463         maPolyPolyRectangle(
464             getCombinedBounds( rPolyPolyRaster,
465                                rRasterArea ) ),
466         maScanlines()
467     {
468         init();
469     }
470 
~B2DPolyPolygonRasterConverter()471     B2DPolyPolygonRasterConverter::~B2DPolyPolygonRasterConverter()
472     {
473     }
474 
475     namespace
476     {
477         class LineNodeGenerator
478         {
479         public:
LineNodeGenerator(VectorOfLineNodes & rActiveVertices)480             LineNodeGenerator( VectorOfLineNodes& rActiveVertices ) :
481                 mrActiveVertices( rActiveVertices )
482             {
483             }
484 
operator ()(const B2DPolyPolygonRasterConverter::Vertex & rVertex)485             void operator()( const B2DPolyPolygonRasterConverter::Vertex& rVertex )
486             {
487                 mrActiveVertices.push_back( ImplLineNode(rVertex.aP1,
488                                                          rVertex.aP2,
489                                                          rVertex.bDownwards) );
490             }
491 
492         private:
493             VectorOfLineNodes& mrActiveVertices;
494         };
495 
496         struct LineNodeComparator
497         {
operator ()basegfx::__anon48f8762a0411::LineNodeComparator498             bool operator()( const ImplLineNode& rLHS, const ImplLineNode& rRHS )
499             {
500                 return rLHS.getXPos() < rRHS.getXPos();
501             }
502         };
503     }
504 
rasterConvert(FillRule eFillRule)505     void B2DPolyPolygonRasterConverter::rasterConvert( FillRule eFillRule )
506     {
507         if( maScanlines.empty() )
508             return; // no scanlines at all -> bail out
509 
510         const sal_Int32	nMinY( fround(maPolyPolyRectangle.getMinY()) );
511         const sal_Int32 nScanlines(fround(maPolyPolyRectangle.getMaxY()) - nMinY);
512 
513         // Vector of currently active vertices. A vertex is active, if
514         // it crosses or touches the current scanline.
515         VectorOfLineNodes	aActiveVertices;
516 
517 		// mickey's optimized version...
518 		radixSort   rs;
519 		std::size_t nb(0);
520         std::size_t nb_previous(0);
521 		bool        bSort(false);
522 
523         // process each scanline
524         for( sal_Int32 y(0); y <= nScanlines; ++y )
525         {
526             // add vertices which start at current scanline into
527             // active vertex vector
528             ::std::for_each( maScanlines[y].begin(),
529                              maScanlines[y].end(),
530                              LineNodeGenerator( aActiveVertices ) );
531 			nb = aActiveVertices.size();
532 			if(nb != nb_previous)
533             {
534 				nb_previous = nb;
535 				bSort = true;
536 			}
537 
538             // sort with increasing X
539 			if(bSort)
540             {
541 				bSort = false;
542 
543                 if( nb )
544                 {
545                     rs.sort(&aActiveVertices[0].mfXPos,
546                             nb,
547                             sizeof(ImplLineNode));
548                 }
549 			}
550 
551             const std::size_t nLen( nb );
552             if( !nLen )
553             {
554                 // empty scanline - call derived with an 'off' span
555                 // for the full width
556                 span( maPolyPolyRectangle.getMinX(),
557                       maPolyPolyRectangle.getMaxX(),
558                       nMinY + y,
559                       false );
560             }
561             else
562             {
563                 const sal_Int32 nCurrY( nMinY + y );
564 
565                 // scanline not empty - forward all scans to derived,
566                 // according to selected fill rule
567 
568                 // TODO(P1): Maybe allow these 'off' span calls to be
569                 // switched off (or all 'on' span calls, depending on
570                 // use case scenario)
571 
572 				// sorting didn't change the order of the elements
573 				// in memory but prepared a list of indices in sorted order.
574 				// thus we now process the nodes with an additional indirection.
575 				sal_uInt32 *sorted = rs.indices();
576 
577                 // call derived with 'off' span for everything left of first active span
578                 if( aActiveVertices[sorted[0]].getXPos() > maPolyPolyRectangle.getMinX() )
579                 {
580                     span( maPolyPolyRectangle.getMinX(),
581                           aActiveVertices[sorted[0]].getXPos(),
582                           nCurrY,
583                           false );
584                 }
585 
586                 switch( eFillRule )
587                 {
588                     default:
589                         OSL_ENSURE(false,
590                                    "B2DPolyPolygonRasterConverter::rasterConvert(): Unexpected fill rule");
591                         return;
592 
593                     case FillRule_EVEN_ODD:
594                         // process each span in current scanline, with
595                         // even-odd fill rule
596                         for( ::std::size_t i(0), nLength(aActiveVertices.size());
597                              i+1 < nLength;
598                              ++i )
599                         {
600 							sal_uInt32 nIndex = sorted[i];
601 							sal_uInt32 nNextIndex = sorted[i+1];
602                             span( aActiveVertices[nIndex].getXPos(),
603                                   aActiveVertices[nNextIndex].getXPos(),
604                                   nCurrY,
605                                   i % 2 == 0 );
606 
607                             float delta = aActiveVertices[nIndex].nextLine();
608 							if(delta > 0.0f)
609                             {
610 								if(aActiveVertices[nIndex].getXPos() > aActiveVertices[nNextIndex].getXPos())
611 									bSort = true;
612 							}
613 							else if(delta < 0.0f)
614                             {
615 								if(i)
616                                 {
617 									sal_uInt32 nPrevIndex = sorted[i-1];
618 									if(aActiveVertices[nIndex].getXPos() < aActiveVertices[nPrevIndex].getXPos())
619 										bSort = true;
620 								}
621 							}
622                         }
623                         break;
624 
625                     case FillRule_NONZERO_WINDING_NUMBER:
626                         // process each span in current scanline, with
627                         // non-zero winding numbe fill rule
628                         sal_Int32 nWindingNumber(0);
629                         for( ::std::size_t i(0), nLength(aActiveVertices.size());
630                              i+1 < nLength;
631                              ++i )
632                         {
633 							sal_uInt32 nIndex = sorted[i];
634 							sal_uInt32 nNextIndex = sorted[i+1];
635                             nWindingNumber += -1 + 2*aActiveVertices[nIndex].isDownwards();
636 
637                             span( aActiveVertices[nIndex].getXPos(),
638                                   aActiveVertices[nNextIndex].getXPos(),
639                                   nCurrY,
640                                   nWindingNumber != 0 );
641 
642                             float delta = aActiveVertices[nIndex].nextLine();
643 							if(delta > 0.0f)
644                             {
645 								if(aActiveVertices[nIndex].getXPos() > aActiveVertices[nNextIndex].getXPos())
646 									bSort = true;
647 							}
648 							else if(delta < 0.0f)
649                             {
650 								if(i)
651                                 {
652 									sal_uInt32 nPrevIndex = sorted[i-1];
653 									if(aActiveVertices[nIndex].getXPos() < aActiveVertices[nPrevIndex].getXPos())
654 										bSort = true;
655 								}
656 							}
657                         }
658                         break;
659                 }
660 
661                 // call derived with 'off' span for everything right of last active span
662                 if( aActiveVertices[sorted[nb-1]].getXPos()+1.0 < maPolyPolyRectangle.getMaxX() )
663                 {
664                     span( aActiveVertices[sorted[nb-1]].getXPos()+1.0,
665                           maPolyPolyRectangle.getMaxX(),
666                           nCurrY,
667                           false );
668                 }
669 
670                 // also call nextLine on very last line node
671 				sal_uInt32 nIndex = sorted[nb-1];
672                 float delta = aActiveVertices[nIndex].nextLine();
673 				if(delta < 0.0f)
674                 {
675 					if(nb)
676                     {
677 						sal_uInt32 nPrevIndex = sorted[nb-2];
678 						if(aActiveVertices[nIndex].getXPos() < aActiveVertices[nPrevIndex].getXPos())
679 							bSort = true;
680 					}
681 				}
682             }
683 
684             // remove line nodes which have ended on the current scanline
685             aActiveVertices.erase( ::std::remove_if( aActiveVertices.begin(),
686                                                      aActiveVertices.end(),
687                                                      ::boost::mem_fn( &ImplLineNode::isEnded ) ),
688                                    aActiveVertices.end() );
689 			nb = aActiveVertices.size();
690 			if(nb != nb_previous)
691             {
692 				nb_previous = nb;
693 				bSort = true;
694 			}
695         }
696 	}
697 }
698 // eof
699