2016-03-19 06:57:51 +13:00
//#include "tsystem.h"
# include "tmachine.h"
# include "tcurves.h"
# include "tcommon.h"
# include "tregion.h"
//#include "tregionutil.h"
# include "tstopwatch.h"
# include "tstroke.h"
# include "tstrokeutil.h"
# include "tvectorimageP.h"
# include "tdebugmessage.h"
# include "tthreadmessage.h"
# include "tl2lautocloser.h"
# include <vector>
# include "tcurveutil.h"
# include <algorithm>
# if !defined(TNZ_LITTLE_ENDIAN)
TNZ_LITTLE_ENDIAN undefined ! !
# endif
//-----------------------------------------------------------------------------
# ifdef IS_DOTNET
# define NULL_ITER list<IntersectedStroke>::iterator()
# else
# define NULL_ITER 0
# endif
using namespace std ;
typedef TVectorImage : : IntersectionBranch IntersectionBranch ;
//-----------------------------------------------------------------------------
inline double myRound ( double x )
{
return ( 1.0 / REGION_COMPUTING_PRECISION ) * ( ( TINT32 ) ( x * REGION_COMPUTING_PRECISION ) ) ;
}
inline TThickPoint myRound ( const TThickPoint & p )
{
return TThickPoint ( myRound ( p . x ) , myRound ( p . y ) , p . thick ) ;
}
void roundStroke ( TStroke * s )
{
int size = s - > getControlPointCount ( ) ;
for ( int j = 0 ; j < ( int ) s - > getControlPointCount ( ) ; j + + ) {
TThickPoint p = s - > getControlPoint ( j ) ;
s - > setControlPoint ( j , myRound ( p ) ) ;
}
if ( size > 3 )
//! it can happen that a stroke has a first or last quadratic degenerated:(3 equal control points).
// in that case, if the stroke has an intersection in an endpoint, the resulting w could not be 0 or 1 as expected.
// since the w==0 and w==1 are used in the region computing to determine if the intersection is an endpoint,
//
{
if ( s - > getControlPoint ( 0 ) = = s - > getControlPoint ( 1 ) & & s - > getControlPoint ( 0 ) = = s - > getControlPoint ( 2 ) ) {
s - > setControlPoint ( 2 , s - > getControlPoint ( 3 ) ) ;
s - > setControlPoint ( 1 , s - > getControlPoint ( 3 ) ) ;
}
if ( s - > getControlPoint ( size - 1 ) = = s - > getControlPoint ( size - 2 ) & & s - > getControlPoint ( size - 1 ) = = s - > getControlPoint ( size - 3 ) ) {
s - > setControlPoint ( size - 2 , s - > getControlPoint ( size - 4 ) ) ;
s - > setControlPoint ( size - 3 , s - > getControlPoint ( size - 4 ) ) ;
}
}
}
//-----------------------------------------------------------------------------
class VIListElem
{
public :
VIListElem * m_prev ;
VIListElem * m_next ;
VIListElem ( ) : m_prev ( 0 ) , m_next ( 0 ) { }
inline VIListElem * next ( ) { return m_next ; }
inline VIListElem * prev ( ) { return m_prev ; }
} ;
template < class T >
class VIList
{
int m_size ;
T * m_begin , * m_end ;
public :
VIList ( ) : m_begin ( 0 ) , m_end ( 0 ) , m_size ( 0 ) { }
inline T * first ( ) const { return m_begin ; } ;
inline T * last ( ) const { return m_end ; } ;
void clear ( ) ;
void pushBack ( T * elem ) ;
void insert ( T * before , T * elem ) ;
T * erase ( T * element ) ;
T * getElemAt ( int pos ) ;
int getPosOf ( T * elem ) ;
inline int size ( ) { return m_size ; }
inline bool empty ( ) { return size ( ) = = 0 ; }
} ;
class Intersection : public VIListElem
{
public :
//Intersection* m_prev, *m_next;
TPointD m_intersection ;
int m_numInter ;
//bool m_isNotErasable;
VIList < IntersectedStroke > m_strokeList ;
Intersection ( ) : m_numInter ( 0 ) , m_strokeList ( ) { }
inline Intersection * next ( ) { return ( Intersection * ) VIListElem : : next ( ) ; } ;
inline Intersection * prev ( ) { return ( Intersection * ) VIListElem : : prev ( ) ; } ;
//inline Intersection* operator++() {return next();}
} ;
class IntersectedStrokeEdges
{
public :
int m_index ;
list < TEdge * > m_edgeList ;
IntersectedStrokeEdges ( int index ) : m_index ( index ) , m_edgeList ( ) { }
~ IntersectedStrokeEdges ( )
{
assert ( m_index > = 0 ) ; /*clearPointerContainer(m_edgeList);*/
m_edgeList . clear ( ) ;
m_index = - 1 ;
}
} ;
class IntersectionData
{
public :
UINT maxAutocloseId ;
VIList < Intersection > m_intList ;
map < int , VIStroke * > m_autocloseMap ;
vector < IntersectedStrokeEdges > m_intersectedStrokeArray ;
IntersectionData ( )
: maxAutocloseId ( 1 ) , m_intList ( )
{
}
~ IntersectionData ( ) ;
} ;
//-----------------------------------------------------------------------------
class IntersectedStroke : public VIListElem
{
/*double m_w;
TStroke * m_s ;
UINT m_index ; */
//IntersectedStroke* m_prev, *m_next;
public :
TEdge m_edge ;
Intersection * m_nextIntersection ;
IntersectedStroke * m_nextStroke ;
bool m_visited , m_gettingOut ; //, m_dead;
IntersectedStroke ( )
: m_visited ( false ) , m_nextIntersection ( 0 ) , m_nextStroke ( 0 ) { } ;
IntersectedStroke ( Intersection * nextIntersection ,
IntersectedStroke * nextStroke )
/*: m_w(-1.0)
, m_s ( NULL )
, m_index ( 0 ) */
: m_edge ( ) ,
m_nextIntersection ( nextIntersection ) ,
m_nextStroke ( nextStroke ) ,
m_visited ( false )
//, m_dead(false)
{
}
IntersectedStroke ( const IntersectedStroke & s )
: m_edge ( s . m_edge , false ) , m_nextIntersection ( s . m_nextIntersection ) , m_nextStroke ( s . m_nextStroke ) , m_visited ( s . m_visited ) , m_gettingOut ( s . m_gettingOut )
//, m_dead(s.m_dead)
{
}
inline IntersectedStroke * next ( ) { return ( IntersectedStroke * ) VIListElem : : next ( ) ; } ;
} ;
//=============================================================================
template < class T >
void VIList < T > : : clear ( )
{
while ( m_begin ) {
T * aux = m_begin ;
m_begin = m_begin - > next ( ) ;
delete aux ;
}
m_end = 0 ;
m_size = 0 ;
}
template < class T >
void VIList < T > : : pushBack ( T * elem )
{
if ( ! m_begin ) {
assert ( ! m_end ) ;
elem - > m_next = elem - > m_prev = 0 ;
m_begin = m_end = elem ;
} else {
assert ( m_end ) ;
assert ( m_end - > m_next = = 0 ) ;
m_end - > m_next = elem ;
elem - > m_prev = m_end ;
elem - > m_next = 0 ;
m_end = elem ;
}
m_size + + ;
}
template < class T >
void VIList < T > : : insert ( T * before , T * elem )
{
assert ( before & & elem ) ;
elem - > m_prev = before - > m_prev ;
elem - > m_next = before ;
if ( ! before - > m_prev )
before - > m_prev = m_begin = elem ;
else {
before - > m_prev - > m_next = elem ;
before - > m_prev = elem ;
}
m_size + + ;
}
template < class T >
T * VIList < T > : : erase ( T * element )
{
T * ret ;
assert ( m_size > 0 ) ;
if ( ! element - > m_prev ) {
assert ( m_begin = = element ) ;
if ( ! element - > m_next )
ret = m_begin = m_end = 0 ;
else {
m_begin = ( T * ) m_begin - > m_next ;
m_begin - > m_prev = 0 ;
ret = m_begin ;
}
} else if ( ! element - > m_next ) {
assert ( m_end = = element ) ;
m_end = ( T * ) m_end - > m_prev ;
m_end - > m_next = 0 ;
ret = 0 ;
} else {
element - > m_prev - > m_next = element - > m_next ;
element - > m_next - > m_prev = element - > m_prev ;
ret = ( T * ) element - > m_next ;
}
m_size - - ;
delete element ;
return ret ;
}
template < class T >
T * VIList < T > : : getElemAt ( int pos )
{
assert ( pos < m_size ) ;
T * p = m_begin ;
while ( pos - - )
p = p - > next ( ) ;
return p ;
}
template < class T >
int VIList < T > : : getPosOf ( T * elem )
{
int count = 0 ;
T * p = m_begin ;
while ( p & & p ! = elem ) {
count + + ;
p = p - > next ( ) ;
}
assert ( p = = elem ) ;
return count ;
}
//-------------------------------------------------------------
//-----------------------------------------------------------------------------
# ifdef LEVO
void print ( list < Intersection > & intersectionList , char * str )
{
ofstream of ( str ) ;
of < < " *************************** " < < endl ;
list < Intersection > : : const_iterator it ;
list < IntersectedStroke > : : const_iterator it1 ;
int i , j ;
for ( i = 0 , it = intersectionList . begin ( ) ; it ! = intersectionList . end ( ) ; it + + , i + + ) {
of < < " *************************** " < < endl ;
of < < " Intersection# " < < i < < " : " < < it - > m_intersection < < " numBranches: " < < it - > m_numInter < < endl ;
of < < endl ;
for ( j = 0 , it1 = it - > m_strokeList . begin ( ) ; it1 ! = it - > m_strokeList . end ( ) ; it1 + + , j + + ) {
of < < " ----Branch # " < < j ;
if ( it1 - > m_edge . m_index < 0 )
of < < " (AUTOCLOSE) " ;
of < < " Intersection at " < < it1 - > m_edge . m_w0 < < " : "
< < " : " < < endl ;
of < < " ColorId: " < < it1 - > m_edge . m_styleId < < endl ;
/*
TColorStyle * fs = it1 - > m_edge . m_fillStyle ;
if ( fs = = 0 )
of < < " NO color: " < < endl ;
else
{
TFillStyleP fp = fs - > getFillStyle ( ) ;
if ( fp )
{
fp - >
assert ( false ) ;
else
of < < " Color: ( " < < colorStyle - > getColor ( ) . r < < " , " < < colorStyle - > getColor ( ) . g < < " , " < < colorStyle - > getColor ( ) . b < < " ) " < < endl ;
*/
of < < " ----Stroke " < < ( it1 - > m_gettingOut ? " OUT " : " IN " ) < < " # " < < it1 - > m_edge . m_index < < " : " < < endl ;
//if (it1->m_dead)
//of<<"---- DEAD Intersection.";
//else
{
of < < " ---- NEXT Intersection: " ;
if ( it1 - > m_nextIntersection ! = intersectionList . end ( ) ) {
int dist = std : : distance ( intersectionList . begin ( ) , it1 - > m_nextIntersection ) ;
of < < dist ;
list < Intersection > : : iterator iit = intersectionList . begin ( ) ;
std : : advance ( iit , dist ) ;
of < < " " < < std : : distance ( iit - > m_strokeList . begin ( ) , it1 - > m_nextStroke ) ;
}
else
of < < " NULL!! " ;
of < < " ---- NEXT Stroke: " ;
if ( it1 - > m_nextIntersection ! = intersectionList . end ( ) )
of < < it1 - > m_nextStroke - > m_edge . m_index ;
else
of < < " NULL!! " ;
}
of < < endl
< < endl ;
}
}
}
# endif
void findNearestIntersection ( list < Intersection > & interList ,
const list < Intersection > : : iterator & i1 ,
const list < IntersectedStroke > : : iterator & i2 ) ;
//-----------------------------------------------------------------------------
# ifdef _TOLGO
void checkInterList ( list < Intersection > & intersectionList )
{
list < Intersection > : : iterator it ;
list < IntersectedStroke > : : iterator it1 ;
for ( it = intersectionList . begin ( ) ; it ! = intersectionList . end ( ) ; it + + ) {
int count = 0 ;
for ( it1 = it - > m_strokeList . begin ( ) ; it1 ! = it - > m_strokeList . end ( ) ; it1 + + ) {
int val ;
if ( it1 - > m_nextIntersection ! = intersectionList . end ( ) ) {
count + + ;
//assert (it1->m_nextIntersection!=intersectionList.end());
assert ( it1 - > m_nextStroke - > m_nextIntersection = = it ) ;
assert ( it1 - > m_nextStroke - > m_nextStroke = = it1 ) ;
//int k = it1->m_edge.m_index;
val = std : : distance ( intersectionList . begin ( ) , it1 - > m_nextIntersection ) ;
}
//else
// assert(it1->m_nextIntersection==intersectionList.end());
}
assert ( count = = it - > m_numInter ) ;
}
}
# else
# define checkInterList
# endif
//-----------------------------------------------------------------------------
//void addFakeIntersection(list<Intersection>& intersectionList,TStroke* s, UINT ii, double w);
void addIntersections ( IntersectionData & intersectionData ,
const vector < VIStroke * > & s , int ii , int jj , const vector < DoublePair > & intersections , int numStrokes , bool isVectorized ) ;
void addIntersection ( IntersectionData & intData ,
const vector < VIStroke * > & s , int ii , int jj ,
DoublePair intersections , int strokeSize , bool isVectorized ) ;
//-----------------------------------------------------------------------------
bool sortBBox ( const TStroke * s1 , const TStroke * s2 )
{
return s1 - > getBBox ( ) . x0 < s2 - > getBBox ( ) . x0 ;
}
//-----------------------------------------------------------------------------
void cleanIntersectionMarks ( const VIList < Intersection > & interList )
{
Intersection * p ;
IntersectedStroke * q ;
for ( p = interList . first ( ) ; p ; p = p - > next ( ) )
for ( q = p - > m_strokeList . first ( ) ; q ; q = q - > next ( ) ) {
q - > m_visited = false ; // Ogni ramo della lista viene messo nella condizione
// di poter essere visitato
if ( q - > m_nextIntersection ) {
q - > m_nextIntersection = 0 ;
p - > m_numInter - - ;
}
}
}
//-----------------------------------------------------------------------------
void cleanNextIntersection ( const VIList < Intersection > & interList , TStroke * s )
{
Intersection * p ;
IntersectedStroke * q ;
for ( p = interList . first ( ) ; p ; p = p - > next ( ) )
for ( q = p - > m_strokeList . first ( ) ; q ; q = q - > next ( ) )
if ( q - > m_edge . m_s = = s ) {
//if (it2->m_nextIntersection==NULL)
// return; //gia' ripulita prima
if ( q - > m_nextIntersection ) {
q - > m_nextIntersection = 0 ;
p - > m_numInter - - ;
}
q - > m_nextStroke = 0 ;
}
}
//-----------------------------------------------------------------------------
void TVectorImage : : Imp : : eraseEdgeFromStroke ( IntersectedStroke * is )
{
if ( is - > m_edge . m_index > = 0 ) //elimino il puntatore all'edge nella lista della VIStroke
{
VIStroke * s ;
s = m_strokes [ is - > m_edge . m_index ] ;
assert ( s - > m_s = = is - > m_edge . m_s ) ;
list < TEdge * > : : iterator iit = s - > m_edgeList . begin ( ) , it_e = s - > m_edgeList . end ( ) ;
for ( ; iit ! = it_e ; + + iit )
if ( ( * iit ) - > m_w0 = = is - > m_edge . m_w0 & & ( * iit ) - > m_w1 = = is - > m_edge . m_w1 ) {
assert ( ( * iit ) - > m_toBeDeleted = = false ) ;
s - > m_edgeList . erase ( iit ) ;
return ;
}
}
}
//-----------------------------------------------------------------------------
IntersectedStroke * TVectorImage : : Imp : : eraseBranch ( Intersection * in ,
IntersectedStroke * is )
{
if ( is - > m_nextIntersection ) {
Intersection * nextInt = is - > m_nextIntersection ;
IntersectedStroke * nextStroke = is - > m_nextStroke ;
assert ( nextStroke - > m_nextIntersection = = in ) ;
assert ( nextStroke - > m_nextStroke = = is ) ;
assert ( nextStroke ! = is ) ;
//nextStroke->m_nextIntersection = intList.end();
//nextStroke->m_nextStroke = nextInt->m_strokeList.end();
if ( nextStroke - > m_nextIntersection ) {
nextStroke - > m_nextIntersection = 0 ;
nextInt - > m_numInter - - ;
}
//nextInt->m_strokeList.erase(nextStroke);//non posso cancellarla, puo' servire in futuro!
}
if ( is - > m_nextIntersection )
in - > m_numInter - - ;
eraseEdgeFromStroke ( is ) ;
is - > m_edge . m_w0 = is - > m_edge . m_w1 = - 3 ;
is - > m_edge . m_index = - 3 ;
is - > m_edge . m_s = 0 ;
is - > m_edge . m_styleId = - 3 ;
return in - > m_strokeList . erase ( is ) ;
}
//-----------------------------------------------------------------------------
void TVectorImage : : Imp : : eraseDeadIntersections ( )
{
Intersection * p = m_intersectionData - > m_intList . first ( ) ;
while ( p ) //la faccio qui, e non nella eraseIntersection. vedi commento li'.
{
//Intersection* &intList = m_intersectionData->m_intList;
if ( p - > m_strokeList . size ( ) = = 1 ) {
eraseBranch ( p , p - > m_strokeList . first ( ) ) ;
assert ( p - > m_strokeList . size ( ) = = 0 ) ;
p = m_intersectionData - > m_intList . erase ( p ) ;
} else if ( p - > m_strokeList . size ( ) = = 2 & &
( p - > m_strokeList . first ( ) - > m_edge . m_s = = p - > m_strokeList . last ( ) - > m_edge . m_s & &
p - > m_strokeList . first ( ) - > m_edge . m_w0 = = p - > m_strokeList . last ( ) - > m_edge . m_w0 ) ) //intersezione finta
{
IntersectedStroke * it1 = p - > m_strokeList . first ( ) , * iit1 , * iit2 ;
IntersectedStroke * it2 = it1 - > next ( ) ;
eraseEdgeFromStroke ( p - > m_strokeList . first ( ) ) ;
eraseEdgeFromStroke ( p - > m_strokeList . first ( ) - > next ( ) ) ;
iit1 = ( it1 - > m_nextIntersection ) ? it1 - > m_nextStroke : 0 ;
iit2 = ( it2 - > m_nextIntersection ) ? it2 - > m_nextStroke : 0 ;
if ( iit1 & & iit2 ) {
iit1 - > m_edge . m_w1 = iit2 - > m_edge . m_w0 ;
iit2 - > m_edge . m_w1 = iit1 - > m_edge . m_w0 ;
}
if ( iit1 ) {
iit1 - > m_nextStroke = iit2 ;
iit1 - > m_nextIntersection = it2 - > m_nextIntersection ;
if ( ! iit1 - > m_nextIntersection )
it1 - > m_nextIntersection - > m_numInter - - ;
}
if ( iit2 ) {
iit2 - > m_nextStroke = iit1 ;
iit2 - > m_nextIntersection = it1 - > m_nextIntersection ;
if ( ! iit2 - > m_nextIntersection )
it2 - > m_nextIntersection - > m_numInter - - ;
}
p - > m_strokeList . clear ( ) ;
p - > m_numInter = 0 ;
p = m_intersectionData - > m_intList . erase ( p ) ;
} else
p = p - > next ( ) ;
}
}
//-----------------------------------------------------------------------------
void TVectorImage : : Imp : : doEraseIntersection ( int index , vector < int > * toBeDeleted )
{
Intersection * p1 = m_intersectionData - > m_intList . first ( ) ;
TStroke * deleteIt = 0 ;
while ( p1 ) {
bool removeAutocloses = false ;
IntersectedStroke * p2 = p1 - > m_strokeList . first ( ) ;
while ( p2 ) {
IntersectedStroke & is = * p2 ;
if ( is . m_edge . m_index = = index ) {
if ( is . m_edge . m_index > = 0 )
//if (!is.m_autoclose && (is.m_edge.m_w0==1 || is.m_edge.m_w0==0))
removeAutocloses = true ;
else
deleteIt = is . m_edge . m_s ;
p2 = eraseBranch ( p1 , p2 ) ;
} else
p2 = p2 - > next ( ) ;
//checkInterList(interList);
}
if ( removeAutocloses ) //se ho tolto una stroke dall'inter corrente, tolgo tutti le stroke di autclose che partono da qui
{
assert ( toBeDeleted ) ;
for ( p2 = p1 - > m_strokeList . first ( ) ; p2 ; p2 = p2 - > next ( ) )
if ( p2 - > m_edge . m_index < 0 & & ( p2 - > m_edge . m_w0 = = 1 | | p2 - > m_edge . m_w0 = = 0 ) )
toBeDeleted - > push_back ( p2 - > m_edge . m_index ) ;
}
if ( p1 - > m_strokeList . empty ( ) )
p1 = m_intersectionData - > m_intList . erase ( p1 ) ;
else
p1 = p1 - > next ( ) ;
}
if ( deleteIt )
delete deleteIt ;
}
//-----------------------------------------------------------------------------
2016-04-15 19:44:40 +12:00
UINT TVectorImage : : Imp : : getFillData ( std : : unique_ptr < IntersectionBranch [ ] > & v )
2016-03-19 06:57:51 +13:00
{
//print(m_intersectionData->m_intList, "C:\\temp\\intersectionPrimaSave.txt");
//Intersection* intList = m_intersectionData->m_intList;
if ( m_intersectionData - > m_intList . empty ( ) )
return 0 ;
Intersection * p1 ;
IntersectedStroke * p2 ;
UINT currInt = 0 ;
vector < UINT > branchesBefore ( m_intersectionData - > m_intList . size ( ) + 1 ) ;
branchesBefore [ 0 ] = 0 ;
UINT count = 0 , size = 0 ;
p1 = m_intersectionData - > m_intList . first ( ) ;
for ( ; p1 ; p1 = p1 - > next ( ) , currInt + + ) {
UINT strokeListSize = p1 - > m_strokeList . size ( ) ;
size + = strokeListSize ;
branchesBefore [ currInt + 1 ] = branchesBefore [ currInt ] + strokeListSize ;
}
2016-04-15 19:44:40 +12:00
v . reset ( new IntersectionBranch [ size ] ) ;
2016-03-19 06:57:51 +13:00
currInt = 0 ;
p1 = m_intersectionData - > m_intList . first ( ) ;
for ( ; p1 ; p1 = p1 - > next ( ) , currInt + + ) {
UINT currBranch = 0 ;
for ( p2 = p1 - > m_strokeList . first ( ) ; p2 ; p2 = p2 - > next ( ) , currBranch + + ) {
IntersectionBranch & b = v [ count ] ;
b . m_currInter = currInt ;
b . m_strokeIndex = p2 - > m_edge . m_index ;
b . m_w = p2 - > m_edge . m_w0 ;
b . m_style = p2 - > m_edge . m_styleId ;
//assert(b.m_style<100);
b . m_gettingOut = p2 - > m_gettingOut ;
if ( ! p2 - > m_nextIntersection )
b . m_nextBranch = count ;
else {
UINT distInt = m_intersectionData - > m_intList . getPosOf ( p2 - > m_nextIntersection ) ;
UINT distBranch = p2 - > m_nextIntersection - > m_strokeList . getPosOf ( p2 - > m_nextStroke ) ;
if ( ( distInt < currInt ) | |
( distInt = = currInt & & distBranch < currBranch ) ) {
UINT posNext = branchesBefore [ distInt ] + distBranch ;
assert ( posNext < count ) ;
b . m_nextBranch = posNext ;
assert ( v [ posNext ] . m_nextBranch = = ( std : : numeric_limits < UINT > : : max ) ( ) ) ;
v [ posNext ] . m_nextBranch = count ;
} else
b . m_nextBranch = ( std : : numeric_limits < UINT > : : max ) ( ) ;
}
count + + ;
}
}
//for (UINT i=0; i<count; i++)
// assert(v[i].m_nextBranch != std::numeric_limits<UINT>::max());
# ifdef _DEBUG
/*ofstream of("C:\\temp\\fillDataOut.txt");
for ( UINT ii = 0 ; ii < size ; ii + + )
{
of < < ii < < " ---------------------- " < < endl ;
of < < " index: " < < v [ ii ] . m_strokeIndex < < endl ;
of < < " w: " < < v [ ii ] . m_w < < endl ;
of < < " curr inter: " < < v [ ii ] . m_currInter < < endl ;
of < < " next inter: " < < v [ ii ] . m_nextBranch < < endl ;
of < < " gettingOut: " < < ( ( v [ ii ] . m_gettingOut ) ? " TRUE " : " FALSE " ) < < endl ;
of < < " colorId: " < < v [ ii ] . m_style < < endl ;
} */
# endif
return size ;
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
namespace
{
TStroke * reconstructAutocloseStroke ( Intersection * p1 ,
IntersectedStroke * p2 )
{
bool found = false ;
Intersection * pp1 = p1 - > next ( ) ;
IntersectedStroke * pp2 ;
//vector<TEdge*> vapp;
for ( ; ! found & & pp1 ; pp1 = pp1 - > next ( ) ) {
for ( pp2 = pp1 - > m_strokeList . first ( ) ; ! found & & pp2 ; pp2 = pp2 - > next ( ) ) {
if ( p2 - > m_edge . m_index = = pp2 - > m_edge . m_index ) {
if ( ( pp2 - > m_edge . m_w0 = = 1 & & p2 - > m_edge . m_w0 = = 0 ) | |
( pp2 - > m_edge . m_w0 = = 0 & & p2 - > m_edge . m_w0 = = 1 ) ) {
found = true ;
vector < TPointD > v ;
if ( p2 - > m_edge . m_w0 = = 0 ) {
v . push_back ( p1 - > m_intersection ) ;
v . push_back ( pp1 - > m_intersection ) ;
} else {
v . push_back ( pp1 - > m_intersection ) ;
v . push_back ( p1 - > m_intersection ) ;
}
p2 - > m_edge . m_s = pp2 - > m_edge . m_s = new TStroke ( v ) ;
//for (UINT ii=0; ii<vapp.size(); ii++)
// vapp[ii]->m_s = it2->m_edge.m_s;
}
//else if (iit2->m_edge.m_w0!=0 && iit2->m_edge.m_w0!=1)
// vapp.push_back(&(iit2->m_edge));
}
}
}
assert ( found ) ;
if ( ! found )
p2 - > m_edge . m_s = 0 ;
return p2 - > m_edge . m_s ;
}
} //namespace
//-----------------------------------------------------------------------------
2016-04-15 19:44:40 +12:00
void TVectorImage : : Imp : : setFillData ( std : : unique_ptr < IntersectionBranch [ ] > const & v , UINT branchCount , bool doComputeRegions )
2016-03-19 06:57:51 +13:00
{
# ifdef _DEBUG
/*ofstream of("C:\\temp\\fillDataIn.txt");
for ( UINT ii = 0 ; ii < branchCount ; ii + + )
{
of < < ii < < " ---------------------- " < < endl ;
of < < " index: " < < v [ ii ] . m_strokeIndex < < endl ;
of < < " w: " < < v [ ii ] . m_w < < endl ;
of < < " curr inter: " < < v [ ii ] . m_currInter < < endl ;
of < < " next inter: " < < v [ ii ] . m_nextBranch < < endl ;
of < < " gettingOut: " < < ( ( v [ ii ] . m_gettingOut ) ? " TRUE " : " FALSE " ) < < endl ;
of < < " colorId: " < < v [ ii ] . m_style < < endl ;
} */
# endif
if ( branchCount = = 0 )
return ;
//{
//QMutexLocker sl(m_mutex);
VIList < Intersection > & intList = m_intersectionData - > m_intList ;
clearPointerContainer ( m_regions ) ;
m_regions . clear ( ) ;
intList . clear ( ) ;
Intersection * currInt ;
IntersectedStroke * currBranch ;
UINT size = v [ branchCount - 1 ] . m_currInter + 1 ;
vector < UINT > branchesBefore ( size ) ;
UINT i = 0 ;
for ( ; i < branchCount ; i + + ) {
const IntersectionBranch & b = v [ i ] ;
if ( i = = 0 | | v [ i ] . m_currInter ! = v [ i - 1 ] . m_currInter ) {
if ( v [ i ] . m_currInter > = size ) //pezza per immagine corrotte...evito crash
{
intList . clear ( ) ;
return ;
}
branchesBefore [ v [ i ] . m_currInter ] = i ;
currInt = new Intersection ( ) ;
intList . pushBack ( currInt ) ;
}
currBranch = new IntersectedStroke ( ) ;
currInt - > m_strokeList . pushBack ( currBranch ) ;
currBranch - > m_edge . m_styleId = b . m_style ;
//assert(b.m_style<100);
currBranch - > m_edge . m_index = b . m_strokeIndex ;
if ( b . m_strokeIndex > = 0 )
currBranch - > m_edge . m_s = m_strokes [ b . m_strokeIndex ] - > m_s ;
else
currBranch - > m_edge . m_s = 0 ;
currBranch - > m_gettingOut = b . m_gettingOut ;
currBranch - > m_edge . m_w0 = b . m_w ;
if ( b . m_nextBranch < branchCount )
currBranch - > m_edge . m_w1 = v [ b . m_nextBranch ] . m_w ;
else
currBranch - > m_edge . m_w1 = 1.0 ;
assert ( currBranch - > m_edge . m_w0 > = - 1e-8 & & currBranch - > m_edge . m_w0 < = 1 + 1e-8 ) ;
assert ( currBranch - > m_edge . m_w1 > = - 1e-8 & & currBranch - > m_edge . m_w1 < = 1 + 1e-8 ) ;
if ( b . m_nextBranch < i ) {
Intersection * p1 ;
IntersectedStroke * p2 ;
p1 = intList . getElemAt ( v [ b . m_nextBranch ] . m_currInter ) ;
assert ( b . m_nextBranch - branchesBefore [ v [ b . m_nextBranch ] . m_currInter ] > = 0 ) ;
p2 = p1 - > m_strokeList . getElemAt ( b . m_nextBranch - branchesBefore [ v [ b . m_nextBranch ] . m_currInter ] ) ;
currBranch - > m_nextIntersection = p1 ;
currBranch - > m_nextStroke = p2 ;
p2 - > m_nextIntersection = currInt ;
p2 - > m_nextStroke = currBranch ;
//if (currBranch == currInt->m_strokeList.begin())
// currInt->m_intersection = currBranch->m_edge.m_s->getPoint(currBranch->m_edge.m_w0);
currInt - > m_numInter + + ;
p1 - > m_numInter + + ;
} else if ( b . m_nextBranch = = i )
currBranch - > m_nextIntersection = 0 ;
else if ( b . m_nextBranch = = ( std : : numeric_limits < UINT > : : max ) ( ) ) {
currBranch - > m_nextIntersection = 0 ;
currBranch - > m_nextStroke = 0 ;
}
/* {
assert ( b . m_nextBranch < branchCount ) ;
assert ( v [ b . m_nextBranch ] . m_nextBranch = = i ) ;
} */
if ( i = = branchCount - 1 | | v [ i ] . m_currInter ! = v [ i + 1 ] . m_currInter ) {
int j = i ;
while ( v [ j ] . m_strokeIndex < 0 & & ( ( j > 0 & & v [ j ] . m_currInter = = v [ j - 1 ] . m_currInter ) | | j = = 0 ) )
j - - ;
if ( v [ j ] . m_strokeIndex > = 0 )
currInt - > m_intersection = m_strokes [ v [ j ] . m_strokeIndex ] - > m_s - > getPoint ( v [ j ] . m_w ) ;
}
}
for ( i = 0 ; i < m_strokes . size ( ) ; i + + )
m_strokes [ i ] - > m_isNewForFill = false ;
//computeRegions();
Intersection * p1 ;
IntersectedStroke * p2 ;
vector < UINT > toBeDeleted ;
for ( p1 = intList . first ( ) ; p1 ; p1 = p1 - > next ( ) )
for ( p2 = p1 - > m_strokeList . first ( ) ; p2 ; p2 = p2 - > next ( ) ) {
if ( p2 - > m_edge . m_index < 0 & & ! p2 - > m_edge . m_s & &
( p2 - > m_edge . m_w0 = = 0 | | p2 - > m_edge . m_w0 = = 1 ) ) {
p2 - > m_edge . m_s = reconstructAutocloseStroke ( p1 , p2 ) ;
if ( p2 - > m_edge . m_s )
m_intersectionData - > m_autocloseMap [ p2 - > m_edge . m_index ] = new VIStroke ( p2 - > m_edge . m_s , TGroupId ( ) ) ;
else
toBeDeleted . push_back ( p2 - > m_edge . m_index ) ;
}
}
for ( p1 = intList . first ( ) ; p1 ; p1 = p1 - > next ( ) )
for ( p2 = p1 - > m_strokeList . first ( ) ; p2 ; p2 = p2 - > next ( ) ) {
if ( ! p2 - > m_edge . m_s & & p2 - > m_edge . m_index < 0 ) {
VIStroke * vs = m_intersectionData - > m_autocloseMap [ p2 - > m_edge . m_index ] ;
if ( vs ) {
p2 - > m_edge . m_s = m_intersectionData - > m_autocloseMap [ p2 - > m_edge . m_index ] - > m_s ;
//TEdge& e = it2->m_edge;
if ( ! p2 - > m_edge . m_s )
toBeDeleted . push_back ( p2 - > m_edge . m_index ) ;
}
}
}
for ( i = 0 ; i < toBeDeleted . size ( ) ; i + + )
eraseIntersection ( toBeDeleted [ i ] ) ;
m_areValidRegions = false ;
//}
if ( doComputeRegions )
computeRegions ( ) ;
//print(m_intersectionData->m_intList, "C:\\temp\\intersectionDopoLoad.txt");
}
//-----------------------------------------------------------------------------
void TVectorImage : : Imp : : eraseIntersection ( int index )
{
vector < int > autocloseStrokes ;
doEraseIntersection ( index , & autocloseStrokes ) ;
for ( UINT i = 0 ; i < autocloseStrokes . size ( ) ; i + + ) {
doEraseIntersection ( autocloseStrokes [ i ] ) ;
assert ( autocloseStrokes [ i ] < 0 ) ;
m_intersectionData - > m_autocloseMap . erase ( autocloseStrokes [ i ] ) ;
}
}
//-----------------------------------------------------------------------------
void findNearestIntersection ( VIList < Intersection > & interList )
{
Intersection * p1 ;
IntersectedStroke * p2 ;
for ( p1 = interList . first ( ) ; p1 ; p1 = p1 - > next ( ) ) {
for ( p2 = p1 - > m_strokeList . first ( ) ; p2 ; p2 = p2 - > next ( ) ) {
if ( p2 - > m_nextIntersection ) //already set
continue ;
int versus = ( p2 - > m_gettingOut ) ? 1 : - 1 ;
double minDelta = ( std : : numeric_limits < double > : : max ) ( ) ;
Intersection * pp1 , * p1Res ;
IntersectedStroke * pp2 , * p2Res ;
for ( pp1 = p1 ; pp1 ; pp1 = pp1 - > next ( ) ) {
if ( pp1 = = p1 )
pp2 = p2 , pp2 = pp2 - > next ( ) ;
else
pp2 = pp1 - > m_strokeList . first ( ) ;
for ( ; pp2 ; pp2 = pp2 - > next ( ) ) {
if ( pp2 - > m_edge . m_index = = p2 - > m_edge . m_index & &
pp2 - > m_gettingOut = = ! p2 - > m_gettingOut ) {
double delta = versus * ( pp2 - > m_edge . m_w0 - p2 - > m_edge . m_w0 ) ;
if ( delta > 0 & & delta < minDelta ) {
p1Res = pp1 ;
p2Res = pp2 ;
minDelta = delta ;
}
}
}
}
if ( minDelta ! = ( std : : numeric_limits < double > : : max ) ( ) ) {
p2Res - > m_nextIntersection = p1 ;
p2Res - > m_nextStroke = p2 ;
p2Res - > m_edge . m_w1 = p2 - > m_edge . m_w0 ;
p2 - > m_nextIntersection = p1Res ;
p2 - > m_nextStroke = p2Res ;
p2 - > m_edge . m_w1 = p2Res - > m_edge . m_w0 ;
p1 - > m_numInter + + ;
p1Res - > m_numInter + + ;
}
}
}
}
//-----------------------------------------------------------------------------
void markDeadIntersections ( VIList < Intersection > & intList , Intersection * p ) ;
//questa funzione "cuscinetto" serve perche crashava il compilatore in release!!!
void inline markDeadIntersectionsRic ( VIList < Intersection > & intList , Intersection * p )
{
markDeadIntersections ( intList , p ) ;
}
//-----------------------------------------------------------------------------
void markDeadIntersections ( VIList < Intersection > & intList , Intersection * p )
{
IntersectedStroke * p1 = p - > m_strokeList . first ( ) ;
if ( ! p1 )
return ;
if ( p - > m_numInter = = 1 ) {
while ( p1 & & ! ! p1 - > m_nextIntersection )
p1 = p1 - > next ( ) ;
assert ( p1 ) ;
if ( ! p1 )
return ;
Intersection * nextInt = p1 - > m_nextIntersection ;
IntersectedStroke * nextStroke = p1 - > m_nextStroke ;
p - > m_numInter = 0 ;
p1 - > m_nextIntersection = 0 ;
if ( nextInt /*&& !nextStroke->m_dead*/ ) {
nextInt - > m_numInter - - ;
nextStroke - > m_nextIntersection = 0 ;
markDeadIntersectionsRic ( intList , nextInt ) ;
}
} else if ( p - > m_numInter = = 2 ) //intersezione finta (forse)
{
while ( p1 & & ! p1 - > m_nextIntersection )
p1 = p1 - > next ( ) ;
assert ( p1 ) ;
if ( ! p1 )
return ;
IntersectedStroke * p2 = p1 - > next ( ) ;
while ( p2 & & ! p2 - > m_nextIntersection )
p2 = p2 - > next ( ) ;
assert ( p2 ) ;
if ( ! p2 )
return ;
if ( p1 - > m_edge . m_s = = p2 - > m_edge . m_s & & p1 - > m_edge . m_w0 = = p2 - > m_edge . m_w0 ) //intersezione finta
{
IntersectedStroke * pp1 , * pp2 ;
assert ( p1 - > m_nextIntersection & & p2 - > m_nextIntersection ) ;
pp1 = p1 - > m_nextStroke ;
pp2 = p2 - > m_nextStroke ;
pp2 - > m_edge . m_w1 = pp1 - > m_edge . m_w0 ;
pp1 - > m_edge . m_w1 = pp2 - > m_edge . m_w0 ;
//if (iit1!=0)
pp1 - > m_nextStroke = pp2 ;
//if (iit2!=0)
pp2 - > m_nextStroke = pp1 ;
//if (iit1!=0)
pp1 - > m_nextIntersection = p2 - > m_nextIntersection ;
//if (iit2!=0)
pp2 - > m_nextIntersection = p1 - > m_nextIntersection ;
p - > m_numInter = 0 ;
p1 - > m_nextIntersection = p2 - > m_nextIntersection = 0 ;
}
}
}
//-----------------------------------------------------------------------------
//se cross val era 0, cerco di spostarmi un po' su w per vedere come sono orientate le tangenti agli stroke...
double nearCrossVal ( TStroke * s0 , double w0 , TStroke * s1 , double w1 )
{
double ltot0 = s0 - > getLength ( ) ;
double ltot1 = s1 - > getLength ( ) ;
double dl = tmin ( ltot1 , ltot0 ) / 1000 ;
double crossVal , dl0 = dl , dl1 = dl ;
TPointD p0 , p1 ;
int count = 0 ;
if ( w0 = = 1.0 )
dl0 = - dl0 ;
if ( w1 = = 1.0 )
dl1 = - dl1 ;
double l0 = s0 - > getLength ( w0 ) + dl0 ;
double l1 = s1 - > getLength ( w1 ) + dl1 ;
do {
p0 = s0 - > getSpeed ( s0 - > getParameterAtLength ( l0 ) ) ;
p1 = s1 - > getSpeed ( s1 - > getParameterAtLength ( l1 ) ) ;
crossVal = cross ( p0 , p1 ) ;
l0 + = dl0 , l1 + = dl1 ;
count + + ;
} while ( areAlmostEqual ( crossVal , 0.0 ) & &
( ( dl0 > 0 & & l0 < ltot0 ) | | ( dl0 < 0 & & l0 > 0 ) ) & &
( ( dl1 > 0 & & l1 < ltot1 ) | | ( dl1 < 0 & & l1 > 0 ) ) ) ;
return crossVal ;
}
//-----------------------------------------------------------------------------
inline void insertBranch ( Intersection & in , IntersectedStroke & item , bool gettingOut )
{
if ( item . m_edge . m_w0 ! = ( gettingOut ? 1.0 : 0.0 ) ) {
item . m_gettingOut = gettingOut ;
in . m_strokeList . pushBack ( new IntersectedStroke ( item ) ) ;
}
}
//-----------------------------------------------------------------------------
double getAngle ( const TPointD & p0 , const TPointD & p1 )
{
double angle1 = 180 * atan2 ( p0 . x , p0 . y ) / TConsts : : pi ;
double angle2 = 180 * atan2 ( p1 . x , p1 . y ) / TConsts : : pi ;
if ( angle1 < 0 )
angle1 = 360 + angle1 ;
if ( angle2 < 0 )
angle2 = 360 + angle2 ;
return ( angle2 - angle1 ) < 0 ? 360 + angle2 - angle1 : angle2 - angle1 ;
}
//-----------------------------------------------------------------------------
//nel caso l'angolo tra due stroke in un certo w sia nullo,
// si va un po' avanti per vedere come sono orientate....
double getNearAngle ( const TStroke * s1 , double w1 , bool out1 , const TStroke * s2 , double w2 , bool out2 )
{
bool verse1 = ( out1 & & w1 < 1 ) | | ( ! out1 & & w1 = = 0 ) ;
bool verse2 = ( out2 & & w2 < 1 ) | | ( ! out2 & & w2 = = 0 ) ;
double ltot1 = s1 - > getLength ( ) ;
double ltot2 = s2 - > getLength ( ) ;
double l1 = s1 - > getLength ( w1 ) ;
double l2 = s2 - > getLength ( w2 ) ;
double dl = min ( ltot1 , ltot2 ) / 1000 ;
double dl1 = verse1 ? dl : - dl ;
double dl2 = verse2 ? dl : - dl ;
while ( ( ( verse1 & & l1 < ltot1 ) | | ( ! verse1 & & l1 > 0 ) ) & & ( ( verse2 & & l2 < ltot2 ) | | ( ! verse2 & & l2 > 0 ) ) ) {
l1 + = dl1 ;
l2 + = dl2 ;
TPointD p1 = ( out1 ? 1 : - 1 ) * s1 - > getSpeed ( s1 - > getParameterAtLength ( l1 ) ) ;
TPointD p2 = ( out2 ? 1 : - 1 ) * s2 - > getSpeed ( s2 - > getParameterAtLength ( l2 ) ) ;
double angle = getAngle ( p1 , p2 ) ;
if ( ! areAlmostEqual ( angle , 0 , 1e-9 ) )
return angle ;
}
return 0 ;
}
//-----------------------------------------------------------------------------
bool makeEdgeIntersection ( Intersection & interList , IntersectedStroke & item1 , IntersectedStroke & item2 ,
const TPointD & p1a , const TPointD & p1b , const TPointD & p2a , const TPointD & p2b )
{
double angle1 = getAngle ( p1a , p1b ) ;
double angle2 = getAngle ( p1a , p2a ) ;
double angle3 = getAngle ( p1a , p2b ) ;
double angle ;
bool eraseP1b = false , eraseP2a = false , eraseP2b = false ;
if ( areAlmostEqual ( angle1 , 0 , 1e-9 ) ) {
angle1 = getNearAngle ( item1 . m_edge . m_s , item1 . m_edge . m_w0 , true , item1 . m_edge . m_s , item1 . m_edge . m_w0 , false ) ;
if ( areAlmostEqual ( angle1 , 1e-9 ) )
eraseP1b = true ;
}
if ( areAlmostEqual ( angle2 , 0 , 1e-9 ) ) {
angle2 = getNearAngle ( item1 . m_edge . m_s , item1 . m_edge . m_w0 , true , item2 . m_edge . m_s , item2 . m_edge . m_w0 , true ) ;
if ( areAlmostEqual ( angle2 , 1e-9 ) )
eraseP2a = true ;
}
if ( areAlmostEqual ( angle3 , 0 , 1e-9 ) ) {
angle3 = getNearAngle ( item1 . m_edge . m_s , item1 . m_edge . m_w0 , true , item2 . m_edge . m_s , item2 . m_edge . m_w0 , false ) ;
if ( areAlmostEqual ( angle3 , 1e-9 ) )
eraseP2b = true ;
}
if ( areAlmostEqual ( angle1 , angle2 , 1e-9 ) ) {
angle = getNearAngle ( item1 . m_edge . m_s , item1 . m_edge . m_w0 , false , item2 . m_edge . m_s , item2 . m_edge . m_w0 , true ) ;
if ( angle ! = 0 ) {
angle2 + = angle ;
if ( angle2 > 360 )
angle2 - = 360 ;
} else
eraseP2a = true ;
}
if ( areAlmostEqual ( angle1 , angle3 , 1e-9 ) ) {
angle = getNearAngle ( item1 . m_edge . m_s , item1 . m_edge . m_w0 , false , item2 . m_edge . m_s , item2 . m_edge . m_w0 , false ) ;
if ( angle ! = 0 ) {
angle3 + = angle ;
if ( angle3 > 360 )
angle3 - = 360 ;
} else
eraseP2b = true ;
}
if ( areAlmostEqual ( angle2 , angle3 , 1e-9 ) ) {
angle = getNearAngle ( item1 . m_edge . m_s , item1 . m_edge . m_w0 , false , item2 . m_edge . m_s , item2 . m_edge . m_w0 , true ) ;
if ( angle ! = 0 ) {
angle3 + = angle ;
if ( angle3 > 360 )
angle3 - = 360 ;
} else
eraseP2b = true ;
}
int fac = ( angle1 < angle2 ) | ( ( angle1 < angle3 ) < < 1 ) | ( ( angle2 < angle3 ) < < 2 ) ;
switch ( fac ) {
CASE 0 : //p1a p2b p2a p1b
insertBranch ( interList , item1 , true ) ;
if ( ! eraseP2b )
insertBranch ( interList , item2 , false ) ;
if ( ! eraseP2a )
insertBranch ( interList , item2 , true ) ;
if ( ! eraseP1b )
insertBranch ( interList , item1 , false ) ;
CASE 1 : //p1a p2b p1b p2a
insertBranch ( interList , item1 , true ) ;
if ( ! eraseP2b )
insertBranch ( interList , item2 , false ) ;
if ( ! eraseP1b )
insertBranch ( interList , item1 , false ) ;
if ( ! eraseP2a )
insertBranch ( interList , item2 , true ) ;
CASE 2 : assert ( false ) ;
CASE 3 : //p1a p1b p2b p2a
insertBranch ( interList , item1 , true ) ;
if ( ! eraseP1b )
insertBranch ( interList , item1 , false ) ;
if ( ! eraseP2b )
insertBranch ( interList , item2 , false ) ;
if ( ! eraseP2a )
insertBranch ( interList , item2 , true ) ;
CASE 4 : //p1a p2a p2b p1b
insertBranch ( interList , item1 , true ) ;
if ( ! eraseP2a )
insertBranch ( interList , item2 , true ) ;
if ( ! eraseP2b )
insertBranch ( interList , item2 , false ) ;
if ( ! eraseP1b )
insertBranch ( interList , item1 , false ) ;
CASE 5 : assert ( false ) ;
CASE 6 : //p1a p2a p1b p2b
insertBranch ( interList , item1 , true ) ;
if ( ! eraseP2a )
insertBranch ( interList , item2 , true ) ;
if ( ! eraseP1b )
insertBranch ( interList , item1 , false ) ;
if ( ! eraseP2b )
insertBranch ( interList , item2 , false ) ;
CASE 7 : //p1a p1b p2a p2b
insertBranch ( interList , item1 , true ) ;
if ( ! eraseP1b )
insertBranch ( interList , item1 , false ) ;
if ( ! eraseP2a )
insertBranch ( interList , item2 , true ) ;
if ( ! eraseP2b )
insertBranch ( interList , item2 , false ) ;
DEFAULT :
assert ( false ) ;
}
return true ;
}
//-----------------------------------------------------------------------------
bool makeIntersection ( IntersectionData & intData , const vector < VIStroke * > & s , int ii , int jj ,
DoublePair inter , int strokeSize , Intersection & interList )
{
IntersectedStroke item1 , item2 ;
interList . m_intersection = s [ ii ] - > m_s - > getPoint ( inter . first ) ;
item1 . m_edge . m_w0 = inter . first ;
item2 . m_edge . m_w0 = inter . second ;
if ( ii > = 0 & & ii < strokeSize ) {
item1 . m_edge . m_s = s [ ii ] - > m_s ;
item1 . m_edge . m_index = ii ;
} else {
if ( ii < 0 ) {
item1 . m_edge . m_s = intData . m_autocloseMap [ ii ] - > m_s ;
item1 . m_edge . m_index = ii ;
} else {
item1 . m_edge . m_s = s [ ii ] - > m_s ;
item1 . m_edge . m_index = - ( ii + intData . maxAutocloseId * 100000 ) ;
intData . m_autocloseMap [ item1 . m_edge . m_index ] = s [ ii ] ;
}
}
if ( jj > = 0 & & jj < strokeSize ) {
item2 . m_edge . m_s = s [ jj ] - > m_s ;
item2 . m_edge . m_index = jj ;
} else {
if ( jj < 0 ) {
item2 . m_edge . m_s = intData . m_autocloseMap [ jj ] - > m_s ;
item2 . m_edge . m_index = jj ;
} else {
item2 . m_edge . m_s = s [ jj ] - > m_s ;
item2 . m_edge . m_index = - ( jj + intData . maxAutocloseId * 100000 ) ;
intData . m_autocloseMap [ item2 . m_edge . m_index ] = s [ jj ] ;
}
}
bool reversed = false ;
TPointD p0 , p0b , p1 , p1b ;
bool ret1 = item1 . m_edge . m_s - > getSpeedTwoValues ( item1 . m_edge . m_w0 , p0 , p0b ) ;
bool ret2 = item2 . m_edge . m_s - > getSpeedTwoValues ( item2 . m_edge . m_w0 , p1 , p1b ) ;
if ( ret1 | | ret2 ) //punto angoloso!!!!
return makeEdgeIntersection ( interList , item1 , item2 , p0 , p0b , p1 , p1b ) ;
double crossVal = cross ( p0 , p1 ) ;
//crossVal = cross(p0, p1);
if ( areAlmostEqual ( crossVal , 0.0 ) ) {
bool endpoint1 = ( item1 . m_edge . m_w0 = = 0.0 | | item1 . m_edge . m_w0 = = 1.0 ) ;
bool endpoint2 = ( item2 . m_edge . m_w0 = = 0.0 | | item2 . m_edge . m_w0 = = 1.0 ) ;
if ( endpoint1 & &
endpoint2 & &
( ( p0 . x * p1 . x > = 0 & & p0 . y * p1 . y > = 0 & & item1 . m_edge . m_w0 ! = item2 . m_edge . m_w0 ) | |
( p0 . x * p1 . x < = 0 & & p0 . y * p1 . y < = 0 & & item1 . m_edge . m_w0 = = item2 . m_edge . m_w0 ) ) )
//due endpoint a 180 gradi;metto
{
item1 . m_gettingOut = ( item1 . m_edge . m_w0 = = 0.0 ) ;
interList . m_strokeList . pushBack ( new IntersectedStroke ( item1 ) ) ;
item2 . m_gettingOut = ( item2 . m_edge . m_w0 = = 0.0 ) ;
interList . m_strokeList . pushBack ( new IntersectedStroke ( item2 ) ) ;
return true ;
}
//crossVal = nearCrossVal(item1.m_edge.m_s, item1.m_edge.m_w0, item2.m_edge.m_s, item2.m_edge.m_w0);
//if (areAlmostEqual(crossVal, 0.0))
// return false;
return makeEdgeIntersection ( interList , item1 , item2 , p0 , p0b , p1 , p1b ) ;
}
if ( crossVal > 0 )
reversed = true ; //std::reverse(interList.m_strokeList.begin(), interList.m_strokeList.end());
if ( item1 . m_edge . m_w0 ! = 1.0 ) {
item1 . m_gettingOut = true ;
interList . m_strokeList . pushBack ( new IntersectedStroke ( item1 ) ) ;
}
if ( item2 . m_edge . m_w0 ! = ( reversed ? 0.0 : 1.0 ) ) {
item2 . m_gettingOut = ! reversed ;
interList . m_strokeList . pushBack ( new IntersectedStroke ( item2 ) ) ;
}
if ( item1 . m_edge . m_w0 ! = 0.0 ) {
item1 . m_gettingOut = false ;
interList . m_strokeList . pushBack ( new IntersectedStroke ( item1 ) ) ;
}
if ( item2 . m_edge . m_w0 ! = ( reversed ? 1.0 : 0.0 ) ) {
item2 . m_gettingOut = reversed ;
interList . m_strokeList . pushBack ( new IntersectedStroke ( item2 ) ) ;
}
return true ;
}
//-----------------------------------------------------------------------------
/*
void checkAuto ( const vector < VIStroke * > & s )
{
for ( int i = 0 ; i < ( int ) s . size ( ) ; i + + )
for ( int j = i + 1 ; j < ( int ) s . size ( ) ; j + + )
if ( s [ i ] - > m_s - > getChunkCount ( ) = = 1 & & s [ j ] - > m_s - > getChunkCount ( ) = = 1 ) //se ha una sola quadratica, probabilmente e' un autoclose.
{
const TThickQuadratic * q = s [ i ] - > m_s - > getChunk ( 0 ) ;
const TThickQuadratic * p = s [ j ] - > m_s - > getChunk ( 0 ) ;
if ( areAlmostEqual ( q - > getP0 ( ) , p - > getP0 ( ) , 1e-2 ) & & areAlmostEqual ( q - > getP2 ( ) , p - > getP2 ( ) , 1e-2 ) )
assert ( ! " eccolo! " ) ;
if ( areAlmostEqual ( q - > getP0 ( ) , p - > getP2 ( ) , 1e-2 ) & & areAlmostEqual ( q - > getP2 ( ) , p - > getP0 ( ) , 1e-2 ) )
assert ( ! " eccolo! " ) ;
}
}
*/
//-----------------------------------------------------------------------------
bool addAutocloseIntersection ( IntersectionData & intData , vector < VIStroke * > & s ,
int ii , int jj , double w0 , double w1 , int strokeSize , bool isVectorized )
{
assert ( s [ ii ] - > m_groupId = = s [ jj ] - > m_groupId ) ;
Intersection * rp = intData . m_intList . last ( ) ;
assert ( w0 > = 0.0 & & w0 < = 1.0 ) ;
assert ( w1 > = 0.0 & & w1 < = 1.0 ) ;
for ( ; rp ; rp = rp - > prev ( ) ) // evito di fare la connessione, se gia' ce
// ne e' una simile tra le stesse due stroke
{
if ( rp - > m_strokeList . size ( ) < 2 )
continue ;
IntersectedStroke * ps = rp - > m_strokeList . first ( ) ;
int s0 = ps - > m_edge . m_index ;
if ( s0 < 0 )
continue ;
double ww0 = ps - > m_edge . m_w0 ;
ps = ps - > next ( ) ;
if ( ps - > m_edge . m_index = = s0 & & ps - > m_edge . m_w0 = = ww0 ) {
ps = ps - > next ( ) ;
if ( ! ps )
continue ;
}
int s1 = ps - > m_edge . m_index ;
if ( s1 < 0 )
continue ;
double ww1 = ps - > m_edge . m_w0 ;
if ( ! ( ( s0 = = ii & & s1 = = jj ) | | ( s0 = = jj & & s1 = = ii ) ) )
continue ;
if ( s0 = = ii & & areAlmostEqual ( w0 , ww0 , 0.1 ) & & areAlmostEqual ( w1 , ww1 , 0.1 ) )
return false ;
else if ( s1 = = ii & & areAlmostEqual ( w0 , ww1 , 0.1 ) & & areAlmostEqual ( w1 , ww0 , 0.1 ) )
return false ;
}
vector < TPointD > v ;
v . push_back ( s [ ii ] - > m_s - > getPoint ( w0 ) ) ;
v . push_back ( s [ jj ] - > m_s - > getPoint ( w1 ) ) ;
if ( v [ 0 ] = = v [ 1 ] ) //le stroke si intersecano , ma la fottuta funzione intersect non ha trovato l'intersezione(tipicamente, questo accade agli estremi)!!!
{
addIntersection ( intData , s , ii , jj , DoublePair ( w0 , w1 ) , strokeSize , isVectorized ) ;
return true ;
}
//se gia e' stato messo questo autoclose, evito
for ( int i = 0 ; i < ( int ) s . size ( ) ; i + + )
if ( s [ i ] - > m_s - > getChunkCount ( ) = = 1 ) //se ha una sola quadratica, probabilmente e' un autoclose.
{
const TThickQuadratic * q = s [ i ] - > m_s - > getChunk ( 0 ) ;
if ( areAlmostEqual ( q - > getP0 ( ) , v [ 0 ] , 1e-2 ) & & areAlmostEqual ( q - > getP2 ( ) , v [ 1 ] , 1e-2 ) | |
areAlmostEqual ( q - > getP0 ( ) , v [ 1 ] , 1e-2 ) & & areAlmostEqual ( q - > getP2 ( ) , v [ 0 ] , 1e-2 ) ) {
return true ;
addIntersection ( intData , s , i , ii , DoublePair ( 0.0 , w0 ) , strokeSize , isVectorized ) ;
addIntersection ( intData , s , i , jj , DoublePair ( 1.0 , w1 ) , strokeSize , isVectorized ) ;
return true ;
}
}
assert ( s [ ii ] - > m_groupId = = s [ jj ] - > m_groupId ) ;
s . push_back ( new VIStroke ( new TStroke ( v ) , s [ ii ] - > m_groupId ) ) ;
addIntersection ( intData , s , s . size ( ) - 1 , ii , DoublePair ( 0.0 , w0 ) , strokeSize , isVectorized ) ;
addIntersection ( intData , s , s . size ( ) - 1 , jj , DoublePair ( 1.0 , w1 ) , strokeSize , isVectorized ) ;
return true ;
}
//-----------------------------------------------------------------------------
//double g_autocloseTolerance = c_newAutocloseTolerance;
bool isCloseEnoughP2P ( double facMin , double facMax , TStroke * s1 , double w0 , TStroke * s2 , double w1 )
{
double autoDistMin , autoDistMax ;
TThickPoint p0 = s1 - > getThickPoint ( w0 ) ;
TThickPoint p1 = s2 - > getThickPoint ( w1 ) ;
double dist2 ;
dist2 = tdistance2 ( p0 , p1 ) ;
/*!when closing beetween a normal stroke and a 0-thickness stroke (very typical) the thin one is assumed to have same thickness of the other*/
if ( p0 . thick = = 0 )
p0 . thick = p1 . thick ;
else if ( p1 . thick = = 0 )
p1 . thick = p0 . thick ;
if ( facMin = = 0 ) {
autoDistMin = 0 ;
autoDistMax = tmax ( - 2.0 , facMax * ( p0 . thick + p1 . thick ) * ( p0 . thick + p1 . thick ) ) ;
if ( autoDistMax < 0.0000001 ) //! for strokes without thickness, I connect for distances less than min between 2.5 and half of the length of the stroke)
{
double len1 = s1 - > getLength ( ) ;
double len2 = s2 - > getLength ( ) ;
autoDistMax = facMax * tmin ( 2.5 , len1 * len1 / ( 2 * 2 ) , len2 * len2 / ( 2 * 2 ) , 100.0 /*dummyVal*/ ) ;
}
} else {
autoDistMin = tmax ( - 2.0 , facMin * ( p0 . thick + p1 . thick ) * ( p0 . thick + p1 . thick ) ) ;
if ( autoDistMin < 0.0000001 ) //! for strokes without thickness, I connect for distances less than min between 2.5 and half of the length of the stroke)
{
double len1 = s1 - > getLength ( ) ;
double len2 = s2 - > getLength ( ) ;
autoDistMin = facMax * tmin ( 2.5 , len1 * len1 / ( 2 * 2 ) , len2 * len2 / ( 2 * 2 ) , 100.0 /*dummyVal*/ ) ;
}
autoDistMax = autoDistMin + ( facMax - facMin ) * ( facMax - facMin ) ;
}
if ( dist2 < autoDistMin | | dist2 > autoDistMax )
return false ;
//if (dist2<=tmax(2.0, g_autocloseTolerance*(p0.thick+p1.thick)*(p0.thick+p1.thick))) //0.01 tiene conto di quando thick==0
if ( s1 = = s2 ) {
TRectD r = s1 - > getBBox ( ) ; //se e' un autoclose su una stroke piccolissima, creerebbe uan area trascurabile, ignoro
if ( fabs ( r . x1 - r . x0 ) < 2 & & fabs ( r . y1 - r . y0 ) < 2 )
return false ;
}
return true ;
}
//---------------------------------------------------------------------------------------------------------------------
/*
bool makePoint2PointConnections ( double factor , vector < VIStroke * > & s ,
int ii , bool isIStartPoint ,
int jj , bool isJStartPoint , IntersectionData & intData ,
int strokeSize )
{
double w0 = ( isIStartPoint ? 0.0 : 1.0 ) ;
double w1 = ( isJStartPoint ? 0.0 : 1.0 ) ;
if ( isCloseEnoughP2P ( factor , s [ ii ] - > m_s , w0 , s [ jj ] - > m_s , w1 ) )
return addAutocloseIntersection ( intData , s , ii , jj , w0 , w1 , strokeSize ) ;
return false ;
}
*/
//-----------------------------------------------------------------------------
double getCurlW ( TStroke * s , bool isBegin ) / / trova il punto di split su una stroke , in prossimita di un ricciolo ;
// un ricciolo c'e' se la curva ha un min o max relativo su x seguito da uno su y, o viceversa.
{
int numChunks = s - > getChunkCount ( ) ;
double dx2 , dx1 = 0 , dy2 , dy1 = 0 ;
int i = 0 ;
for ( i = 0 ; i < numChunks ; i + + ) {
const TQuadratic * q = s - > getChunk ( isBegin ? i : numChunks - 1 - i ) ;
dy2 = q - > getP1 ( ) . y - q - > getP0 ( ) . y ;
if ( dy1 * dy2 < 0 )
break ;
dy1 = dy2 ;
dy2 = q - > getP2 ( ) . y - q - > getP1 ( ) . y ;
if ( dy1 * dy2 < 0 )
break ;
dy1 = dy2 ;
}
if ( i = = numChunks )
return - 1 ;
int maxMin0 = isBegin ? i : numChunks - 1 - i ;
int j = 0 ;
for ( j = 0 ; j < numChunks ; j + + ) {
const TQuadratic * q = s - > getChunk ( isBegin ? j : numChunks - 1 - j ) ;
dx2 = q - > getP1 ( ) . x - q - > getP0 ( ) . x ;
if ( dx1 * dx2 < 0 )
break ;
dx1 = dx2 ;
dx2 = q - > getP2 ( ) . x - q - > getP1 ( ) . x ;
if ( dx1 * dx2 < 0 )
break ;
dx1 = dx2 ;
}
if ( j = = numChunks )
return - 1 ;
int maxMin1 = isBegin ? j : numChunks - 1 - j ;
return getWfromChunkAndT ( s , isBegin ? tmax ( maxMin0 , maxMin1 ) : tmin ( maxMin0 , maxMin1 ) , isBegin ? 1.0 : 0.0 ) ;
}
# ifdef Levo
bool lastIsX = false , lastIsY = false ;
for ( int i = 0 ; i < numChunks ; i + + ) {
const TThickQuadratic * q = s - > getChunk ( isBegin ? i : numChunks - 1 - i ) ;
if ( ( q - > getP0 ( ) . y < q - > getP1 ( ) . y & & q - > getP2 ( ) . y < q - > getP1 ( ) . y ) | | //la quadratica ha un minimo o massimo relativo
( q - > getP0 ( ) . y > q - > getP1 ( ) . y & & q - > getP2 ( ) . y > q - > getP1 ( ) . y ) ) {
double w = getWfromChunkAndT ( s , isBegin ? i : numChunks - 1 - i , isBegin ? 1.0 : 0.0 ) ;
if ( lastIsX ) //e' il secondo min o max relativo
return w ;
lastIsX = false ;
lastIsY = true ;
} else if ( ( q - > getP0 ( ) . x < q - > getP1 ( ) . x & & q - > getP2 ( ) . x < q - > getP1 ( ) . x ) | | //la quadratica ha un minimo o massimo relativo
( q - > getP0 ( ) . x > q - > getP1 ( ) . x & & q - > getP2 ( ) . x > q - > getP1 ( ) . x ) ) {
double w = getWfromChunkAndT ( s , isBegin ? i : numChunks - 1 - i , isBegin ? 1.0 : 0.0 ) ;
if ( lastIsY ) //e' il secondo min o max relativo
return w ;
lastIsX = true ;
lastIsY = false ;
}
}
return - 1 ;
}
# endif
//-----------------------------------------------------------------------------
bool isCloseEnoughP2L ( double facMin , double facMax , TStroke * s1 , double w1 , TStroke * s2 , double & w )
{
if ( s1 - > isSelfLoop ( ) )
return false ;
TThickPoint p0 = s1 - > getThickPoint ( w1 ) ;
double t , dist2 ;
int index ;
TStroke sAux , * sComp ;
if ( s1 = = s2 ) //per trovare le intersezioni con una stroke e se stessa, si toglie il
//pezzo di stroke di cui si cercano vicinanze fino alla prima curva
{
double w = getCurlW ( s1 , w1 = = 0.0 ) ;
if ( w = = - 1 )
return false ;
split < TStroke > ( * s1 , tmin ( 1 - w1 , w ) , tmax ( 1 - w1 , w ) , sAux ) ;
sComp = & sAux ;
} else
sComp = s2 ;
if ( sComp - > getNearestChunk ( p0 , t , index , dist2 ) & & dist2 > 0 ) {
if ( s1 = = s2 ) {
double dummy ;
s2 - > getNearestChunk ( sComp - > getChunk ( index ) - > getPoint ( t ) , t , index , dummy ) ;
}
//if (areAlmostEqual(w, 0.0, 0.05) || areAlmostEqual(w, 1.0, 0.05))
// return; //se w e' vicino ad un estremo, rientra nell'autoclose point to point
//if (s[jj]->m_s->getLength(w)<=s[jj]->m_s->getThickPoint(0).thick ||
// s[jj]->m_s->getLength(w, 1)<=s[jj]->m_s->getThickPoint(1).thick)
// return;
TThickPoint p1 = s2 - > getChunk ( index ) - > getThickPoint ( t ) ;
/*!when closing beetween a normal stroke and a 0-thickness stroke (very typical) the thin one is assumed to have same thickness of the other*/
if ( p0 . thick = = 0 )
p0 . thick = p1 . thick ;
else if ( p1 . thick = = 0 )
p1 . thick = p0 . thick ;
double autoDistMin , autoDistMax ;
if ( facMin = = 0 ) {
autoDistMin = 0 ;
autoDistMax = tmax ( - 2.0 , ( facMax + 0.7 ) * ( p0 . thick + p1 . thick ) * ( p0 . thick + p1 . thick ) ) ;
if ( autoDistMax < 0.0000001 ) //! for strokes without thickness, I connect for distances less than min between 2.5 and half of the length of the pointing stroke)
{
double len1 = s1 - > getLength ( ) ;
autoDistMax = facMax * tmin ( 2.5 , len1 * len1 / ( 2 * 2 ) ) ;
}
} else {
autoDistMin = tmax ( - 2.0 , ( facMin + 0.7 ) * ( p0 . thick + p1 . thick ) * ( p0 . thick + p1 . thick ) ) ;
if ( autoDistMin < 0.0000001 ) //! for strokes without thickness, I connect for distances less than min between 2.5 and half of the length of the pointing stroke)
{
double len1 = s1 - > getLength ( ) ;
autoDistMin = facMax * tmin ( 2.5 , len1 * len1 / ( 2 * 2 ) ) ;
}
autoDistMax = autoDistMin + ( facMax - facMin + 0.7 ) * ( facMax - facMin + 0.7 ) ;
}
//double autoDistMin = tmax(-2.0, facMin==0?0:(facMin+0.7)*(p0.thick+p1.thick)*(p0.thick+p1.thick));
//double autoDistMax = tmax(-2.0, (facMax+0.7)*(p0.thick+p1.thick)*(p0.thick+p1.thick));
if ( dist2 < autoDistMin | | dist2 > autoDistMax )
return false ;
//if (dist2<=(tmax(2.0, (g_autocloseTolerance+0.7)*(p0.thick+p1.thick)*(p0.thick+p1.thick)))) //0.01 tiene conto di quando thick==0
w = getWfromChunkAndT ( s2 , index , t ) ;
return true ;
}
return false ;
}
//-------------------------------------------------------------
/*
void makePoint2LineConnection ( double factor , vector < VIStroke * > & s , int ii , int jj , bool isBegin , IntersectionData & intData ,
int strokeSize )
{
double w1 = isBegin ? 0.0 : 1.0 ;
TStroke * s1 = s [ ii ] - > m_s ;
TStroke * s2 = s [ jj ] - > m_s ;
double w ;
if ( isCloseEnoughP2L ( factor , s1 , w1 , s2 , w ) )
addAutocloseIntersection ( intData , s , ii , jj , w1 , w , strokeSize ) ;
}
*/
//-----------------------------------------------------------------------------
namespace
{
inline bool isSegment ( const TStroke & s )
{
vector < TThickPoint > v ;
s . getControlPoints ( v ) ;
UINT n = v . size ( ) ;
if ( areAlmostEqual ( v [ n - 1 ] . x , v [ 0 ] . x , 1e-4 ) ) {
for ( UINT i = 1 ; i < n - 1 ; i + + )
if ( ! areAlmostEqual ( v [ i ] . x , v [ 0 ] . x , 1e-4 ) )
return false ;
} else if ( areAlmostEqual ( v [ n - 1 ] . y , v [ 0 ] . y , 1e-4 ) ) {
for ( UINT i = 1 ; i < n - 1 ; i + + )
if ( ! areAlmostEqual ( v [ i ] . y , v [ 0 ] . y , 1e-4 ) )
return false ;
} else {
double fac = ( v [ n - 1 ] . y - v [ 0 ] . y ) / ( v [ n - 1 ] . x - v [ 0 ] . x ) ;
for ( UINT i = 1 ; i < n - 1 ; i + + )
if ( ! areAlmostEqual ( ( v [ i ] . y - v [ 0 ] . y ) / ( v [ i ] . x - v [ 0 ] . x ) , fac , 1e-4 ) )
return false ;
}
return true ;
}
//---------------------------------------------------------------------------------
/*
bool segmentAlreadyExist ( const TVectorImageP & vi , const TPointD & p1 , const TPointD & p2 )
{
for ( UINT i = 0 ; i < vi - > getStrokeCount ( ) ; i + + )
{
TStroke * s = vi - > getStroke ( i ) ;
if ( ! s - > getBBox ( ) . contains ( p1 ) | | ! s - > getBBox ( ) . contains ( p2 ) )
continue ;
if ( ( ( areAlmostEqual ( s - > getPoint ( 0.0 ) , p1 , 1e-4 ) & & areAlmostEqual ( s - > getPoint ( 1.0 ) , p2 , 1e-4 ) ) | |
( areAlmostEqual ( s - > getPoint ( 0.0 ) , p2 , 1e-4 ) & & areAlmostEqual ( s - > getPoint ( 1.0 ) , p1 , 1e-4 ) ) ) & &
isSegment ( * s ) )
return true ;
}
return false ;
}
*/
//----------------------------------------------------------------------------------
bool segmentAlreadyPresent ( const TVectorImageP & vi , const TPointD & p1 , const TPointD & p2 )
{
for ( UINT i = 0 ; i < vi - > getStrokeCount ( ) ; i + + ) {
TStroke * s = vi - > getStroke ( i ) ;
if ( ( ( areAlmostEqual ( s - > getPoint ( 0.0 ) , p1 , 1e-4 ) & & areAlmostEqual ( s - > getPoint ( 1.0 ) , p2 , 1e-4 ) ) | |
( areAlmostEqual ( s - > getPoint ( 0.0 ) , p2 , 1e-4 ) & & areAlmostEqual ( s - > getPoint ( 1.0 ) , p1 , 1e-4 ) ) ) & &
isSegment ( * s ) )
return true ;
}
return false ;
/*
for ( UINT i = 0 ; i < vi - > getStrokeCount ( ) ; i + + )
{
TStroke * s = vi - > getStroke ( i ) ;
if ( s - > getChunkCount ( ) ! = 1 )
continue ;
if ( areAlmostEqual ( ( TPointD ) s - > getControlPoint ( 0 ) , p1 , 1e-2 ) & &
areAlmostEqual ( ( TPointD ) s - > getControlPoint ( s - > getControlPointCount ( ) - 1 ) , p2 , 1e-2 ) )
return true ;
}
return false ;
*/
}
void getClosingSegments ( TL2LAutocloser & l2lautocloser , double facMin , double facMax , TStroke * s1 , TStroke * s2 ,
vector < DoublePair > * intersections , vector < std : : pair < double , double > > & segments )
{
bool ret1 = false , ret2 = false , ret3 = false , ret4 = false ;
# define L2LAUTOCLOSE
# ifdef L2LAUTOCLOSE
double thickmax2 = s1 - > getMaxThickness ( ) + s2 - > getMaxThickness ( ) ;
thickmax2 * = thickmax2 ;
if ( facMin = = 0 )
l2lautocloser . setMaxDistance2 ( ( facMax + 0.7 ) * thickmax2 ) ;
else
l2lautocloser . setMaxDistance2 ( ( facMax + 0.7 ) * thickmax2 + ( facMax - facMin + 0.7 ) * ( facMax - facMin + 0.7 ) ) ;
std : : vector < TL2LAutocloser : : Segment > l2lSegments ;
if ( intersections )
l2lautocloser . search ( l2lSegments , s1 , s2 , * intersections ) ;
else
l2lautocloser . search ( l2lSegments , s1 , s2 ) ;
for ( UINT i = 0 ; i < l2lSegments . size ( ) ; i + + ) {
TL2LAutocloser : : Segment & seg = l2lSegments [ i ] ;
double autoDistMin , autoDistMax ;
if ( facMin = = 0 ) {
autoDistMin = 0 ;
autoDistMax = ( facMax + 0.7 ) * ( seg . p0 . thick + seg . p1 . thick ) * ( seg . p0 . thick + seg . p1 . thick ) ;
} else {
autoDistMin = ( facMin + 0.7 ) * ( seg . p0 . thick + seg . p1 . thick ) * ( seg . p0 . thick + seg . p1 . thick ) ;
autoDistMax = autoDistMin + ( facMax - facMin + 0.7 ) * ( facMax - facMin + 0.7 ) ;
}
if ( seg . dist2 > autoDistMin & & seg . dist2 < autoDistMax )
segments . push_back ( std : : pair < double , double > ( seg . w0 , seg . w1 ) ) ;
}
# endif
if ( s1 - > isSelfLoop ( ) & & s2 - > isSelfLoop ( ) )
return ;
if ( ! s1 - > isSelfLoop ( ) & & ! s2 - > isSelfLoop ( ) ) {
if ( ret1 = isCloseEnoughP2P ( facMin , facMax , s1 , 0.0 , s2 , 1.0 ) )
segments . push_back ( std : : pair < double , double > ( 0.0 , 1.0 ) ) ;
if ( s1 ! = s2 ) {
if ( ret2 = isCloseEnoughP2P ( facMin , facMax , s1 , 0.0 , s2 , 0.0 ) )
segments . push_back ( std : : pair < double , double > ( 0.0 , 0.0 ) ) ;
if ( ret3 = isCloseEnoughP2P ( facMin , facMax , s1 , 1.0 , s2 , 0.0 ) )
segments . push_back ( std : : pair < double , double > ( 1.0 , 0.0 ) ) ;
if ( ret4 = isCloseEnoughP2P ( facMin , facMax , s1 , 1.0 , s2 , 1.0 ) )
segments . push_back ( std : : pair < double , double > ( 1.0 , 1.0 ) ) ;
}
}
double w ;
if ( ! ret1 & & ! ret2 & & isCloseEnoughP2L ( facMin , facMax , s1 , 0.0 , s2 , w ) )
segments . push_back ( std : : pair < double , double > ( 0.0 , w ) ) ;
if ( ! ret1 & & ! ret4 & & isCloseEnoughP2L ( facMin , facMax , s2 , 1.0 , s1 , w ) )
segments . push_back ( std : : pair < double , double > ( w , 1.0 ) ) ;
if ( s1 ! = s2 ) {
if ( ! ret2 & & ! ret3 & & isCloseEnoughP2L ( facMin , facMax , s2 , 0.0 , s1 , w ) )
segments . push_back ( std : : pair < double , double > ( w , 0.0 ) ) ;
if ( ! ret3 & & ! ret4 & & isCloseEnoughP2L ( facMin , facMax , s1 , 1.0 , s2 , w ) )
segments . push_back ( std : : pair < double , double > ( 1.0 , w ) ) ;
}
}
} //namaspace
//---------------------------------------------------------------------------------
void getClosingPoints ( const TRectD & rect , double fac , const TVectorImageP & vi ,
vector < pair < int , double > > & startPoints , vector < pair < int , double > > & endPoints )
{
UINT strokeCount = vi - > getStrokeCount ( ) ;
TL2LAutocloser l2lautocloser ;
for ( UINT i = 0 ; i < strokeCount ; i + + ) {
TStroke * s1 = vi - > getStroke ( i ) ;
if ( ! rect . overlaps ( s1 - > getBBox ( ) ) )
continue ;
if ( s1 - > getChunkCount ( ) = = 1 )
continue ;
for ( UINT j = i ; j < strokeCount ; j + + ) {
TStroke * s2 = vi - > getStroke ( j ) ;
if ( ! rect . overlaps ( s1 - > getBBox ( ) ) )
continue ;
if ( s2 - > getChunkCount ( ) = = 1 )
continue ;
2016-04-27 03:11:57 +12:00
# ifdef NEW_REGION_FILL
double autoTol = 0 ;
# else
2016-03-19 06:57:51 +13:00
double autoTol = vi - > getAutocloseTolerance ( ) ;
2016-04-27 03:11:57 +12:00
# endif
2016-03-19 06:57:51 +13:00
double enlarge1 = ( autoTol + 0.7 ) * ( s1 - > getMaxThickness ( ) > 0 ? s1 - > getMaxThickness ( ) : 2.5 ) + fac ;
double enlarge2 = ( autoTol + 0.7 ) * ( s2 - > getMaxThickness ( ) > 0 ? s2 - > getMaxThickness ( ) : 2.5 ) + fac ;
if ( i ! = j & & ! s1 - > getBBox ( ) . enlarge ( enlarge1 ) . overlaps ( s2 - > getBBox ( ) . enlarge ( enlarge2 ) ) )
continue ;
vector < std : : pair < double , double > > segments ;
getClosingSegments ( l2lautocloser , autoTol , autoTol + fac , s1 , s2 , 0 , segments ) ;
for ( UINT k = 0 ; k < segments . size ( ) ; k + + ) {
TPointD p1 = s1 - > getPoint ( segments [ k ] . first ) ;
TPointD p2 = s2 - > getPoint ( segments [ k ] . second ) ;
if ( rect . contains ( p1 ) & & rect . contains ( p2 ) ) {
if ( segmentAlreadyPresent ( vi , p1 , p2 ) )
continue ;
startPoints . push_back ( pair < int , double > ( i , segments [ k ] . first ) ) ;
endPoints . push_back ( pair < int , double > ( j , segments [ k ] . second ) ) ;
}
}
}
}
}
//-------------------------------------------------------------------------------------------------------
void autoclose ( double factor , vector < VIStroke * > & s , int ii , int jj , IntersectionData & IntData ,
int strokeSize , TL2LAutocloser & l2lautocloser , vector < DoublePair > * intersections , bool isVectorized )
{
vector < std : : pair < double , double > > segments ;
getClosingSegments ( l2lautocloser , 0 , factor , s [ ii ] - > m_s , s [ jj ] - > m_s , intersections , segments ) ;
for ( UINT i = 0 ; i < segments . size ( ) ; i + + )
addAutocloseIntersection ( IntData , s , ii , jj , segments [ i ] . first , segments [ i ] . second , strokeSize , isVectorized ) ;
}
//------------------------------------------------------------------------------------------------------
# ifdef LEVO
void autoclose ( double factor , vector < VIStroke * > & s , int ii , int jj , IntersectionData & IntData ,
int strokeSize )
{
bool ret1 = false , ret2 = false , ret3 = false , ret4 = false ;
if ( s [ ii ] - > m_s - > isSelfLoop ( ) & & s [ jj ] - > m_s - > isSelfLoop ( ) )
return ;
if ( ! s [ ii ] - > m_s - > isSelfLoop ( ) & & ! s [ jj ] - > m_s - > isSelfLoop ( ) ) {
ret1 = makePoint2PointConnections ( factor , s , ii , true , jj , false , IntData , strokeSize ) ;
if ( ii ! = jj ) {
ret2 = makePoint2PointConnections ( factor , s , ii , true , jj , true , IntData , strokeSize ) ;
ret3 = makePoint2PointConnections ( factor , s , ii , false , jj , true , IntData , strokeSize ) ;
ret4 = makePoint2PointConnections ( factor , s , ii , false , jj , false , IntData , strokeSize ) ;
}
}
if ( ! ret1 & & ! ret2 )
makePoint2LineConnection ( factor , s , ii , jj , true , IntData , strokeSize ) ;
if ( ! ret1 & & ! ret4 )
makePoint2LineConnection ( factor , s , jj , ii , false , IntData , strokeSize ) ;
if ( ii ! = jj ) {
if ( ! ret2 & & ! ret3 )
makePoint2LineConnection ( factor , s , jj , ii , true , IntData , strokeSize ) ;
if ( ! ret3 & & ! ret4 )
makePoint2LineConnection ( factor , s , ii , jj , false , IntData , strokeSize ) ;
}
}
# endif
//-----------------------------------------------------------------------------
TPointD inline getTangent ( const IntersectedStroke & item )
{
return ( item . m_gettingOut ? 1 : - 1 ) * item . m_edge . m_s - > getSpeed ( item . m_edge . m_w0 , item . m_gettingOut ) ;
}
//-----------------------------------------------------------------------------
void addBranch ( IntersectionData & intData , VIList < IntersectedStroke > & strokeList ,
const vector < VIStroke * > & s , int ii , double w , int strokeSize , bool gettingOut )
{
IntersectedStroke * p1 , * p2 ;
TPointD tanRef , lastTan ;
IntersectedStroke * item = new IntersectedStroke ( ) ;
if ( ii < 0 ) {
item - > m_edge . m_s = intData . m_autocloseMap [ ii ] - > m_s ;
item - > m_edge . m_index = ii ;
} else {
item - > m_edge . m_s = s [ ii ] - > m_s ;
if ( ii < strokeSize )
item - > m_edge . m_index = ii ;
else {
item - > m_edge . m_index = - ( ii + intData . maxAutocloseId * 100000 ) ;
intData . m_autocloseMap [ item - > m_edge . m_index ] = s [ ii ] ;
}
}
item - > m_edge . m_w0 = w ;
item - > m_gettingOut = gettingOut ;
/*
if ( strokeList . size ( ) = = 2 ) //potrebbero essere orientati male; due branch possono stare come vogliono, ma col terzo no.
{
TPointD tan2 = getTangent ( strokeList . back ( ) ) ;
TPointD aux = getTangent ( * ( strokeList . begin ( ) ) ) ;
double crossVal = cross ( aux , tan2 ) ;
if ( areAlmostEqual ( aux , tan2 , 1e-3 ) )
return ;
if ( crossVal > 0 )
{
std : : reverse ( strokeList . begin ( ) , strokeList . end ( ) ) ;
//tan2 = getTangent(strokeList.back());
}
}
*/
/*
if ( areAlmostEqual ( lastCross , 0.0 ) & & tan1 . x * tan2 . x > = 0 & & tan1 . y * tan2 . y > = 0 ) //significa angolo tra tangenti nullo
{
crossVal = nearCrossVal ( item . m_edge . m_s , item . m_edge . m_w0 , strokeList . back ( ) . m_edge . m_s , strokeList . back ( ) . m_edge . m_w0 ) ;
if ( areAlmostEqual ( crossVal , 0.0 ) )
return ;
if ( ! strokeList . back ( ) . m_gettingOut )
crossVal = - crossVal ;
}
*/
tanRef = getTangent ( * item ) ;
lastTan = getTangent ( * strokeList . last ( ) ) ;
/*
for ( it = strokeList . begin ( ) ; it ! = strokeList . end ( ) ; + + it )
{
TPointD curTan = getTangent ( * it ) ;
double angle0 = getAngle ( lastTan , curTan ) ;
double angle1 = getAngle ( lastTan , tanRef ) ;
if ( areAlmostEqual ( angle0 , angle1 , 1e-8 ) )
{
double angle = getNearAngle ( it - > m_edge . m_s , it - > m_edge . m_w0 , it - > m_gettingOut ,
item . m_edge . m_s , item . m_edge . m_w0 , item . m_gettingOut ) ;
angle1 + = angle ; if ( angle1 > 360 ) angle1 - = 360 ;
}
if ( angle1 < angle0 )
{
strokeList . insert ( it , item ) ;
return ;
}
lastTan = curTan ;
} */
p2 = strokeList . last ( ) ;
for ( p1 = strokeList . first ( ) ; p1 ; p1 = p1 - > next ( ) ) {
TPointD curTan = getTangent ( * p1 ) ;
double angle0 = getAngle ( lastTan , curTan ) ;
double angle1 = getAngle ( lastTan , tanRef ) ;
if ( areAlmostEqual ( angle1 , 0 , 1e-8 ) ) {
double angle = getNearAngle ( p2 - > m_edge . m_s , p2 - > m_edge . m_w0 , p2 - > m_gettingOut ,
item - > m_edge . m_s , item - > m_edge . m_w0 , item - > m_gettingOut ) ;
angle1 + = angle ;
if ( angle1 > 360 )
angle1 - = 360 ;
}
if ( areAlmostEqual ( angle0 , angle1 , 1e-8 ) ) {
double angle = getNearAngle ( p1 - > m_edge . m_s , p1 - > m_edge . m_w0 , p1 - > m_gettingOut ,
item - > m_edge . m_s , item - > m_edge . m_w0 , item - > m_gettingOut ) ;
angle1 + = angle ;
if ( angle1 > 360 )
angle1 - = 360 ;
}
if ( angle1 < angle0 ) {
strokeList . insert ( p1 , item ) ;
return ;
}
lastTan = curTan ;
p2 = p1 ;
}
//assert(!"add branch: can't find where to insert!");
strokeList . pushBack ( item ) ;
}
//-----------------------------------------------------------------------------
void addBranches ( IntersectionData & intData , Intersection & intersection , const vector < VIStroke * > & s , int ii , int jj ,
DoublePair intersectionPair , int strokeSize )
{
bool foundS1 = false , foundS2 = false ;
IntersectedStroke * p ;
assert ( ! intersection . m_strokeList . empty ( ) ) ;
for ( p = intersection . m_strokeList . first ( ) ; p ; p = p - > next ( ) ) {
if ( ( ii > = 0 & & p - > m_edge . m_s = = s [ ii ] - > m_s & & p - > m_edge . m_w0 = = intersectionPair . first ) | |
( ii < 0 & & p - > m_edge . m_index = = ii & & p - > m_edge . m_w0 = = intersectionPair . first ) )
foundS1 = true ;
if ( ( jj > = 0 & & p - > m_edge . m_s = = s [ jj ] - > m_s & & p - > m_edge . m_w0 = = intersectionPair . second ) | |
( jj < 0 & & p - > m_edge . m_index = = jj & & p - > m_edge . m_w0 = = intersectionPair . second ) )
foundS2 = true ;
}
if ( foundS1 & & foundS2 ) {
/*
//errore!(vedi commento sotto) possono essere un sacco di intersezioni coincidenti se passano per l'estremo di una quad
//significa che ci sono due intersezioni coincidenti. cioe' due stroke tangenti. quindi devo invertire l'ordine di due branch enlla rosa dei branch.
list < IntersectedStroke > : : iterator it1 , it2 ;
it1 = intersection . m_strokeList . begin ( ) ;
it2 = it1 ; it2 + + ;
for ( ; it2 ! = intersection . m_strokeList . end ( ) ; + + it1 , + + it2 )
{
if ( ( * it1 ) . m_gettingOut ! = ( * it2 ) . m_gettingOut & & ( ( * it1 ) . m_edge . m_index = = jj & & ( * it2 ) . m_edge . m_index = = ii ) | |
( ( * it1 ) . m_edge . m_index = = ii & & ( * it2 ) . m_edge . m_index = = jj ) )
{
IntersectedStroke & el1 = ( * it1 ) ;
IntersectedStroke & el2 = ( * it2 ) ;
IntersectedStroke app ;
app = el1 ;
el1 = el2 ;
el2 = app ;
break ;
}
}
*/
return ;
}
if ( ! foundS1 ) {
if ( intersectionPair . first ! = 1 )
addBranch ( intData , intersection . m_strokeList , s , ii , intersectionPair . first , strokeSize , true ) ;
if ( intersectionPair . first ! = 0 )
addBranch ( intData , intersection . m_strokeList , s , ii , intersectionPair . first , strokeSize , false ) ;
//assert(intersection.m_strokeList.size()-size>0);
}
if ( ! foundS2 ) {
if ( intersectionPair . second ! = 1 )
addBranch ( intData , intersection . m_strokeList , s , jj , intersectionPair . second , strokeSize , true ) ;
if ( intersectionPair . second ! = 0 )
addBranch ( intData , intersection . m_strokeList , s , jj , intersectionPair . second , strokeSize , false ) ;
//intersection.m_numInter+=intersection.m_strokeList.size()-size;
//assert(intersection.m_strokeList.size()-size>0);
}
}
//-----------------------------------------------------------------------------
void addIntersections ( IntersectionData & intData ,
const vector < VIStroke * > & s , int ii , int jj ,
vector < DoublePair > & intersections , int strokeSize , bool isVectorized )
{
for ( int k = 0 ; k < ( int ) intersections . size ( ) ; k + + ) {
if ( ii > = strokeSize & &
( areAlmostEqual ( intersections [ k ] . first , 0.0 ) | | areAlmostEqual ( intersections [ k ] . first , 1.0 ) ) )
continue ;
if ( jj > = strokeSize & &
( areAlmostEqual ( intersections [ k ] . second , 0.0 ) | | areAlmostEqual ( intersections [ k ] . second , 1.0 ) ) )
continue ;
addIntersection ( intData , s , ii , jj , intersections [ k ] , strokeSize , isVectorized ) ;
}
}
//-----------------------------------------------------------------------------
inline double truncate ( double x )
{
x + = 1.0 ;
TUINT32 * l = ( TUINT32 * ) & x ;
# if TNZ_LITTLE_ENDIAN
l [ 0 ] & = 0xFFE00000 ;
# else
l [ 1 ] & = 0xFFE00000 ;
# endif
return x - 1.0 ;
}
//-----------------------------------------------------------------------------
void addIntersection ( IntersectionData & intData ,
const vector < VIStroke * > & s , int ii , int jj ,
DoublePair intersection , int strokeSize , bool isVectorized )
{
Intersection * p ;
TPointD point ;
assert ( ii < 0 | | jj < 0 | | s [ ii ] - > m_groupId = = s [ jj ] - > m_groupId ) ;
//UINT iw;
//iw = ((UINT)(intersection.first*0x3fffffff));
//intersection.first = truncate(intersection.first);
//iw = (UINT)(intersection.second*0x3fffffff);
//intersection.second = truncate(intersection.second);
if ( areAlmostEqual ( intersection . first , 0.0 , 1e-5 ) )
intersection . first = 0.0 ;
else if ( areAlmostEqual ( intersection . first , 1.0 , 1e-5 ) )
intersection . first = 1.0 ;
if ( areAlmostEqual ( intersection . second , 0.0 , 1e-5 ) )
intersection . second = 0.0 ;
else if ( areAlmostEqual ( intersection . second , 1.0 , 1e-5 ) )
intersection . second = 1.0 ;
point = s [ ii ] - > m_s - > getPoint ( intersection . first ) ;
for ( p = intData . m_intList . first ( ) ; p ; p = p - > next ( ) )
if ( p - > m_intersection = = point | |
( isVectorized & & areAlmostEqual ( p - > m_intersection , point , 1e-2 ) ) ) //devono essere rigorosamente uguali, altrimenti
// il calcolo dell'ordine dei rami con le tangenti sballa
{
addBranches ( intData , * p , s , ii , jj , intersection , strokeSize ) ;
return ;
}
intData . m_intList . pushBack ( new Intersection ) ;
if ( ! makeIntersection ( intData , s , ii , jj , intersection , strokeSize , * intData . m_intList . last ( ) ) )
intData . m_intList . erase ( intData . m_intList . last ( ) ) ;
}
//-----------------------------------------------------------------------------
void TVectorImage : : Imp : : findIntersections ( )
{
vector < VIStroke * > & strokeArray = m_strokes ;
IntersectionData & intData = * m_intersectionData ;
int strokeSize = ( int ) strokeArray . size ( ) ;
int i , j ;
bool isVectorized = ( m_autocloseTolerance < 0 ) ;
assert ( intData . m_intersectedStrokeArray . empty ( ) ) ;
# define AUTOCLOSE_ATTIVO
# ifdef AUTOCLOSE_ATTIVO
intData . maxAutocloseId + + ;
map < int , VIStroke * > : : iterator it , it_b = intData . m_autocloseMap . begin ( ) ;
map < int , VIStroke * > : : iterator it_e = intData . m_autocloseMap . end ( ) ;
//prima cerco le intersezioni tra nuove strokes e vecchi autoclose
for ( i = 0 ; i < strokeSize ; i + + ) {
TStroke * s1 = strokeArray [ i ] - > m_s ;
if ( ! strokeArray [ i ] - > m_isNewForFill | | strokeArray [ i ] - > m_isPoint )
continue ;
TRectD bBox = s1 - > getBBox ( ) ;
double thick2 = s1 - > getThickPoint ( 0 ) . thick * 2.1 ; //2.1 instead of 2.0, for usual problems of approx...
if ( bBox . getLx ( ) < = thick2 & & bBox . getLy ( ) < = thick2 ) {
strokeArray [ i ] - > m_isPoint = true ;
continue ;
}
roundStroke ( s1 ) ;
for ( it = it_b ; it ! = it_e ; + + it ) {
if ( ! it - > second | | it - > second - > m_groupId ! = strokeArray [ i ] - > m_groupId )
continue ;
TStroke * s2 = it - > second - > m_s ;
vector < DoublePair > parIntersections ;
if ( intersect ( s1 , s2 , parIntersections , true ) )
addIntersections ( intData , strokeArray , i , it - > first , parIntersections , strokeSize , isVectorized ) ;
}
}
# endif
//poi, intersezioni tra stroke, in cui almeno uno dei due deve essere nuovo
map < pair < int , int > , vector < DoublePair > > intersectionMap ;
for ( i = 0 ; i < strokeSize ; i + + ) {
TStroke * s1 = strokeArray [ i ] - > m_s ;
if ( strokeArray [ i ] - > m_isPoint )
continue ;
for ( j = i ; j < strokeSize /*&& (strokeArray[i]->getBBox().x1>= strokeArray[j]->getBBox().x0)*/ ; j + + ) {
TStroke * s2 = strokeArray [ j ] - > m_s ;
if ( strokeArray [ j ] - > m_isPoint | | ! ( strokeArray [ i ] - > m_isNewForFill | | strokeArray [ j ] - > m_isNewForFill ) )
continue ;
if ( strokeArray [ i ] - > m_groupId ! = strokeArray [ j ] - > m_groupId )
continue ;
vector < DoublePair > parIntersections ;
if ( s1 - > getBBox ( ) . overlaps ( s2 - > getBBox ( ) ) ) {
UINT size = intData . m_intList . size ( ) ;
if ( intersect ( s1 , s2 , parIntersections , false ) ) {
//if (i==0 && j==1) parIntersections.erase(parIntersections.begin());
intersectionMap [ pair < int , int > ( i , j ) ] = parIntersections ;
addIntersections ( intData , strokeArray , i , j , parIntersections , strokeSize , isVectorized ) ;
} else
intersectionMap [ pair < int , int > ( i , j ) ] = vector < DoublePair > ( ) ;
if ( ! strokeArray [ i ] - > m_isNewForFill & & size ! = intData . m_intList . size ( ) & & ! strokeArray [ i ] - > m_edgeList . empty ( ) ) //aggiunte nuove intersezioni
{
intData . m_intersectedStrokeArray . push_back ( IntersectedStrokeEdges ( i ) ) ;
list < TEdge * > & _list = intData . m_intersectedStrokeArray . back ( ) . m_edgeList ;
list < TEdge * > : : const_iterator it ;
for ( it = strokeArray [ i ] - > m_edgeList . begin ( ) ; it ! = strokeArray [ i ] - > m_edgeList . end ( ) ; + + it )
_list . push_back ( new TEdge ( * * it , false ) ) ;
}
}
}
}
# ifdef AUTOCLOSE_ATTIVO
TL2LAutocloser l2lautocloser ;
for ( i = 0 ; i < strokeSize ; i + + ) {
TStroke * s1 = strokeArray [ i ] - > m_s ;
if ( strokeArray [ i ] - > m_isPoint )
continue ;
for ( j = i ; j < strokeSize ; j + + ) {
if ( strokeArray [ i ] - > m_groupId ! = strokeArray [ j ] - > m_groupId )
continue ;
TStroke * s2 = strokeArray [ j ] - > m_s ;
if ( strokeArray [ j ] - > m_isPoint )
continue ;
if ( ! ( strokeArray [ i ] - > m_isNewForFill | | strokeArray [ j ] - > m_isNewForFill ) )
continue ;
double enlarge1 = ( m_autocloseTolerance + 0.7 ) * ( s1 - > getMaxThickness ( ) > 0 ? s1 - > getMaxThickness ( ) : 2.5 ) ;
double enlarge2 = ( m_autocloseTolerance + 0.7 ) * ( s2 - > getMaxThickness ( ) > 0 ? s2 - > getMaxThickness ( ) : 2.5 ) ;
if ( s1 - > getBBox ( ) . enlarge ( enlarge1 ) . overlaps ( s2 - > getBBox ( ) . enlarge ( enlarge2 ) ) ) {
map < pair < int , int > , vector < DoublePair > > : : iterator it = intersectionMap . find ( pair < int , int > ( i , j ) ) ;
if ( it = = intersectionMap . end ( ) )
autoclose ( m_autocloseTolerance , strokeArray , i , j , intData , strokeSize , l2lautocloser , 0 , isVectorized ) ;
else
autoclose ( m_autocloseTolerance , strokeArray , i , j , intData , strokeSize , l2lautocloser , & ( it - > second ) , isVectorized ) ;
}
}
strokeArray [ i ] - > m_isNewForFill = false ;
}
# endif
for ( i = 0 ; i < strokeSize ; i + + ) {
list < TEdge * > : : iterator it , it_b = strokeArray [ i ] - > m_edgeList . begin ( ) , it_e = strokeArray [ i ] - > m_edgeList . end ( ) ;
for ( it = it_b ; it ! = it_e ; + + it )
if ( ( * it ) - > m_toBeDeleted = = 1 )
delete * it ;
strokeArray [ i ] - > m_edgeList . clear ( ) ;
}
//si devono cercare le intersezioni con i segmenti aggiunti per l'autoclose
for ( i = strokeSize ; i < ( int ) strokeArray . size ( ) ; + + i ) {
TStroke * s1 = strokeArray [ i ] - > m_s ;
for ( j = i + 1 ; j < ( int ) strokeArray . size ( ) ; + + j ) //intersezione segmento-segmento
{
if ( strokeArray [ i ] - > m_groupId ! = strokeArray [ j ] - > m_groupId )
continue ;
TStroke * s2 = strokeArray [ j ] - > m_s ;
vector < DoublePair > parIntersections ;
if ( intersect ( s1 , s2 , parIntersections , true ) )
addIntersections ( intData , strokeArray , i , j , parIntersections , strokeSize , isVectorized ) ;
}
for ( j = 0 ; j < strokeSize ; + + j ) //intersezione segmento-curva
{
if ( strokeArray [ j ] - > m_isPoint )
continue ;
if ( strokeArray [ i ] - > m_groupId ! = strokeArray [ j ] - > m_groupId )
continue ;
TStroke * s2 = strokeArray [ j ] - > m_s ;
vector < DoublePair > parIntersections ;
if ( intersect ( s1 , s2 , parIntersections , true ) )
addIntersections ( intData , strokeArray , i , j , parIntersections , strokeSize , isVectorized ) ;
}
}
}
//la struttura delle intersezioni viene poi visitata per trovare
// i link tra un'intersezione e la successiva
//-----------------------------------------------------------------------------
void TVectorImage : : Imp : : deleteRegionsData ( )
{
clearPointerContainer ( m_strokes ) ;
clearPointerContainer ( m_regions ) ;
Intersection * p1 ;
for ( p1 = m_intersectionData - > m_intList . first ( ) ; p1 ; p1 = p1 - > next ( ) )
p1 - > m_strokeList . clear ( ) ;
m_intersectionData - > m_intList . clear ( ) ;
delete m_intersectionData ;
m_intersectionData = 0 ;
}
void TVectorImage : : Imp : : initRegionsData ( )
{
m_intersectionData = new IntersectionData ( ) ;
}
//-----------------------------------------------------------------------------
int TVectorImage : : Imp : : computeIntersections ( )
{
Intersection * p1 ;
IntersectionData & intData = * m_intersectionData ;
int strokeSize = ( int ) m_strokes . size ( ) ;
findIntersections ( ) ;
findNearestIntersection ( intData . m_intList ) ;
//for (it1=intData.m_intList.begin(); it1!=intData.m_intList.end();) //la faccio qui, e non nella eraseIntersection. vedi commento li'.
eraseDeadIntersections ( ) ;
for ( p1 = intData . m_intList . first ( ) ; p1 ; p1 = p1 - > next ( ) )
markDeadIntersections ( intData . m_intList , p1 ) ;
//checkInterList(intData.m_intList);
return strokeSize ;
}
//-----------------------------------------------------------------------------
/*
void endPointIntersect ( const TStroke * s0 , const TStroke * s1 , vector < DoublePair > & parIntersections )
{
TPointD p00 = s0 - > getPoint ( 0 ) ;
TPointD p11 = s1 - > getPoint ( 1 ) ;
if ( tdistance2 ( p00 , p11 ) < 2 * 0.06 * 0.06 )
parIntersections . push_back ( DoublePair ( 0 , 1 ) ) ;
if ( s0 = = s1 )
return ;
TPointD p01 = s0 - > getPoint ( 1 ) ;
TPointD p10 = s1 - > getPoint ( 0 ) ;
if ( tdistance2 ( p00 , p10 ) < 2 * 0.06 * 0.06 )
parIntersections . push_back ( DoublePair ( 0 , 0 ) ) ;
if ( tdistance2 ( p01 , p10 ) < 2 * 0.06 * 0.06 )
parIntersections . push_back ( DoublePair ( 1 , 0 ) ) ;
if ( tdistance2 ( p01 , p11 ) < 2 * 0.06 * 0.06 )
parIntersections . push_back ( DoublePair ( 1 , 1 ) ) ;
}
*/
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// Trova una possibile regione data una lista di punti di intersezione
TRegion * findRegion (
VIList < Intersection > & intList ,
Intersection * p1 ,
IntersectedStroke * p2 ,
bool minimizeEdges )
{
TRegion * r = new TRegion ( ) ;
int currStyle = 0 ;
IntersectedStroke * pStart = p2 ;
Intersection * nextp1 ;
IntersectedStroke * nextp2 ;
//Cicla finche' t2 non punta ad uno stroke gia' visitato
while ( ! p2 - > m_visited ) {
p2 - > m_visited = true ;
// Ciclo finche' lo stroke puntato da it2 non ha un successivo punto di intersezione
do {
p2 = p2 - > next ( ) ;
if ( ! p2 ) // uso la lista come se fosse circolare
p2 = p1 - > m_strokeList . first ( ) ;
if ( ! p2 ) {
delete r ;
return 0 ;
}
} while ( ! p2 - > m_nextIntersection ) ;
nextp1 = p2 - > m_nextIntersection ;
nextp2 = p2 - > m_nextStroke ;
// Viene controllato e sistemato lo stile degli stroke
if ( p2 - > m_edge . m_styleId ! = 0 ) {
if ( currStyle = = 0 )
currStyle = p2 - > m_edge . m_styleId ;
else if ( p2 - > m_edge . m_styleId ! = currStyle ) {
currStyle = p2 - > m_edge . m_styleId ;
for ( UINT i = 0 ; i < r - > getEdgeCount ( ) ; i + + )
r - > getEdge ( i ) - > m_styleId = currStyle ;
}
} else
p2 - > m_edge . m_styleId = currStyle ;
//Aggiunge lo stroke puntato da p2 alla regione
r - > addEdge ( & p2 - > m_edge , minimizeEdges ) ;
if ( nextp2 = = pStart )
return r ;
p1 = nextp1 ;
p2 = nextp2 ;
}
delete r ;
return 0 ;
}
//-----------------------------------------------------------------------------
/*
bool areEqualRegions ( const TRegion & r1 , const TRegion & r2 )
{
if ( r1 . getBBox ( ) ! = r2 . getBBox ( ) )
return false ;
if ( r1 . getEdgeCount ( ) ! = r2 . getEdgeCount ( ) )
return false ;
for ( UINT i = 0 ; i < r1 . getEdgeCount ( ) ; i + + )
{
TEdge * e1 = r1 . getEdge ( i ) ;
for ( j = 0 ; j < r2 . getEdgeCount ( ) ; j + + )
{
TEdge * e2 = r2 . getEdge ( j ) ;
if ( e1 - > m_s = = e2 - > m_s & &
tmin ( e1 - > m_w0 , e1 - > m_w1 ) = = tmin ( e2 - > m_w0 , e2 - > m_w1 ) & &
tmax ( e1 - > m_w0 , e1 - > m_w1 ) = = tmax ( e2 - > m_w0 , e2 - > m_w1 ) )
{
if ( e1 - > m_styleId & & ! e2 - > m_styleId )
e2 - > m_styleId = e1 - > m_styleId ;
else if ( e2 - > m_styleId & & ! e1 - > m_styleId )
e1 - > m_styleId = e2 - > m_styleId ;
break ;
}
}
if ( j = = r2 . getEdgeCount ( ) ) //e1 non e' uguale a nessun edge di r2
return false ;
}
return true ;
}
*/
//-----------------------------------------------------------------------------
/*
bool isMetaRegion ( const TRegion & r1 , const TRegion & r2 )
{
if ( areEqualRegions ( r1 , r2 ) )
return true ;
for ( UINT i = 0 ; i < r1 . getRegionCount ( ) ; i + + )
{
if ( isMetaRegion ( * r1 . getRegion ( i ) , r2 ) )
return true ;
}
return false ;
}
//-----------------------------------------------------------------------------
bool isMetaRegion ( const vector < TRegion * > & m_regions , const TRegion & r )
{
for ( UINT i = 0 ; i < m_regions . size ( ) ; i + + )
if ( isMetaRegion ( * ( m_regions [ i ] ) , r ) )
return true ;
return false ;
}
//-----------------------------------------------------------------------------
*/
class TRegionClockWiseFormula : public TRegionFeatureFormula
{
private :
double m_quasiArea ;
public :
TRegionClockWiseFormula ( ) : m_quasiArea ( 0 ) { }
void inline update ( const TPointD & p1 , const TPointD & p2 )
{
m_quasiArea + = ( p2 . y + p1 . y ) * ( p1 . x - p2 . x ) ;
}
bool inline isClockwise ( ) { return m_quasiArea > 0.5 ; }
} ;
//----------------------------------------------------------------------------------------------
void computeRegionFeature ( const TRegion & r , TRegionFeatureFormula & formula )
{
TPointD p , pOld /*, pAux*/ ;
int pointAdded = 0 ;
int size = r . getEdgeCount ( ) ;
if ( size = = 0 )
return ;
//if (size<2)
// return !isMetaRegion(regions, r);
int firstControlPoint ;
int lastControlPoint ;
TEdge * e = r . getEdge ( size - 1 ) ;
pOld = e - > m_s - > getPoint ( e - > m_w1 ) ;
for ( int i = 0 ; i < size ; i + + ) {
TEdge * e = r . getEdge ( i ) ;
TStroke * s = e - > m_s ;
firstControlPoint = s - > getControlPointIndexAfterParameter ( e - > m_w0 ) ;
lastControlPoint = s - > getControlPointIndexAfterParameter ( e - > m_w1 ) ;
p = s - > getPoint ( e - > m_w0 ) ;
formula . update ( pOld , p ) ;
pOld = p ;
pointAdded + + ;
if ( firstControlPoint < = lastControlPoint ) {
if ( firstControlPoint & 0x1 )
firstControlPoint + + ;
if ( lastControlPoint - firstControlPoint < = 2 ) ///per evitare di avere troppi pochi punti....
{
p = s - > getPoint ( 0.333333 * e - > m_w0 + 0.666666 * e - > m_w1 ) ;
formula . update ( pOld , p ) ;
pOld = p ;
pointAdded + + ;
p = s - > getPoint ( 0.666666 * e - > m_w0 + 0.333333 * e - > m_w1 ) ;
formula . update ( pOld , p ) ;
pOld = p ;
pointAdded + + ;
} else
for ( int j = firstControlPoint ; j < lastControlPoint ; j + = 2 ) {
p = s - > getControlPoint ( j ) ;
formula . update ( pOld , p ) ;
pOld = p ;
pointAdded + + ;
}
} else {
firstControlPoint - - ; //this case, getControlPointIndexBEFOREParameter
lastControlPoint - - ;
if ( firstControlPoint & 0x1 )
firstControlPoint - - ;
if ( firstControlPoint - lastControlPoint < = 2 ) ///per evitare di avere troppi pochi punti....
{
p = s - > getPoint ( 0.333333 * e - > m_w0 + 0.666666 * e - > m_w1 ) ;
formula . update ( pOld , p ) ;
pOld = p ;
pointAdded + + ;
p = s - > getPoint ( 0.666666 * e - > m_w0 + 0.333333 * e - > m_w1 ) ;
formula . update ( pOld , p ) ;
pOld = p ;
pointAdded + + ;
} else
for ( int j = firstControlPoint ; j > lastControlPoint ; j - = 2 ) {
p = s - > getControlPoint ( j ) ;
formula . update ( pOld , p ) ;
pOld = p ;
pointAdded + + ;
}
}
p = s - > getPoint ( e - > m_w1 ) ;
formula . update ( pOld , p ) ;
pOld = p ;
pointAdded + + ;
}
assert ( pointAdded > = 4 ) ;
}
//----------------------------------------------------------------------------------
bool isValidArea ( const TRegion & r )
{
TRegionClockWiseFormula formula ;
computeRegionFeature ( r , formula ) ;
return formula . isClockwise ( ) ;
}
# ifdef LEVO
bool isValidArea ( const vector < TRegion * > & regions , const TRegion & r )
{
double area = 0.0 ;
TPointD p , pOld /*, pAux*/ ;
int pointAdded = 0 ;
int size = r . getEdgeCount ( ) ;
if ( size = = 0 )
return false ;
//if (size<2)
// return !isMetaRegion(regions, r);
int firstControlPoint ;
int lastControlPoint ;
TEdge * e = r . getEdge ( size - 1 ) ;
pOld = e - > m_s - > getPoint ( e - > m_w1 ) ;
for ( int i = 0 ; i < size ; i + + ) {
TEdge * e = r . getEdge ( i ) ;
TStroke * s = e - > m_s ;
firstControlPoint = s - > getControlPointIndexAfterParameter ( e - > m_w0 ) ;
lastControlPoint = s - > getControlPointIndexAfterParameter ( e - > m_w1 ) ;
p = s - > getPoint ( e - > m_w0 ) ;
area + = ( p . y + pOld . y ) * ( pOld . x - p . x ) ;
pOld = p ;
pointAdded + + ;
if ( firstControlPoint < = lastControlPoint ) {
if ( firstControlPoint & 0x1 )
firstControlPoint + + ;
if ( lastControlPoint - firstControlPoint < = 2 ) ///per evitare di avere troppi pochi punti....
{
p = s - > getPoint ( 0.333333 * e - > m_w0 + 0.666666 * e - > m_w1 ) ;
area + = ( p . y + pOld . y ) * ( pOld . x - p . x ) ;
pOld = p ;
pointAdded + + ;
p = s - > getPoint ( 0.666666 * e - > m_w0 + 0.333333 * e - > m_w1 ) ;
area + = ( p . y + pOld . y ) * ( pOld . x - p . x ) ;
pOld = p ;
pointAdded + + ;
} else
for ( int j = firstControlPoint ; j < lastControlPoint ; j + = 2 ) {
p = s - > getControlPoint ( j ) ;
area + = ( p . y + pOld . y ) * ( pOld . x - p . x ) ;
pOld = p ;
pointAdded + + ;
}
} else {
firstControlPoint - - ; //this case, getControlPointIndexBEFOREParameter
lastControlPoint - - ;
if ( firstControlPoint & 0x1 )
firstControlPoint - - ;
if ( firstControlPoint - lastControlPoint < = 2 ) ///per evitare di avere troppi pochi punti....
{
p = s - > getPoint ( 0.333333 * e - > m_w0 + 0.666666 * e - > m_w1 ) ;
area + = ( p . y + pOld . y ) * ( pOld . x - p . x ) ;
pOld = p ;
pointAdded + + ;
p = s - > getPoint ( 0.666666 * e - > m_w0 + 0.333333 * e - > m_w1 ) ;
area + = ( p . y + pOld . y ) * ( pOld . x - p . x ) ;
pOld = p ;
pointAdded + + ;
} else
for ( int j = firstControlPoint ; j > lastControlPoint ; j - = 2 ) {
p = s - > getControlPoint ( j ) ;
area + = ( p . y + pOld . y ) * ( pOld . x - p . x ) ;
pOld = p ;
pointAdded + + ;
}
}
p = s - > getPoint ( e - > m_w1 ) ;
area + = ( p . y + pOld . y ) * ( pOld . x - p . x ) ;
pOld = p ;
pointAdded + + ;
}
assert ( pointAdded > = 4 ) ;
return area > 0.5 ;
}
# endif
//-----------------------------------------------------------------------------
void transferColors ( const list < TEdge * > & oldList , const list < TEdge * > & newList , bool isStrokeChanged , bool isFlipped , bool overwriteColor ) ;
//-----------------------------------------------------------------------------
void printStrokes1 ( vector < VIStroke * > & v , int size )
{
UINT i = 0 ;
ofstream of ( " C: \\ temp \\ strokes.txt " ) ;
for ( i = 0 ; i < ( UINT ) size ; i + + ) {
TStroke * s = v [ i ] - > m_s ;
of < < " ***stroke " < < i < < endl ;
for ( UINT j = 0 ; j < ( UINT ) s - > getChunkCount ( ) ; j + + ) {
const TThickQuadratic * q = s - > getChunk ( j ) ;
of < < " s0 " < < q - > getP0 ( ) < < endl ;
of < < " s1 " < < q - > getP1 ( ) < < endl ;
of < < " s2 " < < q - > getP2 ( ) < < endl ;
of < < " ****** " < < endl ;
}
of < < endl ;
}
for ( i = size ; i < v . size ( ) ; i + + ) {
TStroke * s = v [ i ] - > m_s ;
of < < " ***Autostroke " < < i < < endl ;
of < < " s0 " < < s - > getPoint ( 0.0 ) < < endl ;
of < < " s1 " < < s - > getPoint ( 1.0 ) < < endl ;
of < < endl ;
}
}
//-----------------------------------------------------------------------------
# ifdef _DEBUG
static void printTime ( TStopWatch & sw , string name )
{
2016-04-19 01:16:18 +12:00
ostrstream ss ;
2016-03-19 06:57:51 +13:00
ss < < name < < " : " ;
sw . print ( ss ) ;
ss < < ' \n ' < < ' \0 ' ;
string s = ss . str ( ) ;
ss . freeze ( false ) ;
//TSystem::outputDebug(s);
}
# endif
//-----------------------------------------------------------------------------
void printStrokes1 ( vector < VIStroke * > & v , int size ) ;
//void testHistory();
// Trova le regioni in una TVectorImage
int TVectorImage : : Imp : : computeRegions ( )
{
2016-04-27 03:11:57 +12:00
# ifdef NEW_REGION_FILL
return 0 ;
# endif
2016-03-19 06:57:51 +13:00
# if defined(_DEBUG) && !defined(MACOSX)
TStopWatch stopWatch ;
stopWatch . start ( true ) ;
# endif
//testHistory();
if ( ! m_computeRegions )
return 0 ;
QMutexLocker sl ( m_mutex ) ;
/*if (m_intersectionData->m_computedAlmostOnce)
{
UINT i , n = m_strokes . size ( ) ;
vector < int > vv ( n ) ;
for ( i = 0 ; i < n ; + + i ) vv [ i ] = i ;
m_intersectionData - > m_computedAlmostOnce = true ;
notifyChangedStrokes ( vv , vector < TStroke * > ( ) , false ) ;
return true ;
} */
//g_autocloseTolerance = m_autocloseTolerance;
//Cancella le regioni gia' esistenti per ricalcolarle
clearPointerContainer ( m_regions ) ;
m_regions . clear ( ) ;
// Controlla che ci siano degli stroke
if ( m_strokes . empty ( ) ) {
# if defined(_DEBUG) && !defined(MACOSX)
stopWatch . stop ( ) ;
# endif
return 0 ;
}
//Inizializza la lista di intersezioni intList
m_computedAlmostOnce = true ;
VIList < Intersection > & intList = m_intersectionData - > m_intList ;
cleanIntersectionMarks ( intList ) ;
//calcolo struttura delle intersezioni
int added = 0 , notAdded = 0 ;
int strokeSize ;
strokeSize = computeIntersections ( ) ;
Intersection * p1 ;
IntersectedStroke * p2 ;
for ( p1 = intList . first ( ) ; p1 ; p1 = p1 - > next ( ) )
for ( p2 = p1 - > m_strokeList . first ( ) ; p2 ; p2 = p2 - > next ( ) )
p2 - > m_edge . m_r = 0 ;
for ( p1 = intList . first ( ) ; p1 ; p1 = p1 - > next ( ) ) {
// Controlla che il punto in questione non sia isolato
if ( p1 - > m_numInter = = 0 )
continue ;
for ( p2 = p1 - > m_strokeList . first ( ) ; p2 ; p2 = p2 - > next ( ) ) {
TRegion * region ;
// se lo stroke non unisce due punti di intersezione
// non lo considero e vado avanti con un altro stroke
if ( ! p2 - > m_nextIntersection )
continue ;
//Se lo stroke puntato da t2 non e' stato ancora visitato, trova una regione
if ( ! p2 - > m_visited & & ( region = : : findRegion ( intList , p1 , p2 , m_minimizeEdges ) ) ) {
// Se la regione e' valida la aggiunge al vettore delle regioni
if ( isValidArea ( * region ) ) {
added + + ;
addRegion ( region ) ;
//Lega ogni ramo della regione alla regione di appartenenza
for ( UINT i = 0 ; i < region - > getEdgeCount ( ) ; i + + ) {
TEdge * e = region - > getEdge ( i ) ;
e - > m_r = region ;
if ( e - > m_index > = 0 )
m_strokes [ e - > m_index ] - > addEdge ( e ) ;
}
} else // Se la regione non e' valida viene scartata
{
notAdded + + ;
delete region ;
}
}
}
}
if ( ! m_notIntersectingStrokes ) {
UINT i ;
for ( i = 0 ; i < m_intersectionData - > m_intersectedStrokeArray . size ( ) ; i + + ) {
if ( ! m_strokes [ m_intersectionData - > m_intersectedStrokeArray [ i ] . m_index ] - > m_edgeList . empty ( ) )
transferColors ( m_intersectionData - > m_intersectedStrokeArray [ i ] . m_edgeList ,
m_strokes [ m_intersectionData - > m_intersectedStrokeArray [ i ] . m_index ] - > m_edgeList , false , false , true ) ;
clearPointerContainer ( m_intersectionData - > m_intersectedStrokeArray [ i ] . m_edgeList ) ;
m_intersectionData - > m_intersectedStrokeArray [ i ] . m_edgeList . clear ( ) ;
}
m_intersectionData - > m_intersectedStrokeArray . clear ( ) ;
}
assert ( m_intersectionData - > m_intersectedStrokeArray . empty ( ) ) ;
//tolgo i segmenti aggiunti con l'autoclose
vector < VIStroke * > : : iterator it = m_strokes . begin ( ) ;
advance ( it , strokeSize ) ;
m_strokes . erase ( it , m_strokes . end ( ) ) ;
m_areValidRegions = true ;
# if defined(_DEBUG)
checkRegions ( m_regions ) ;
# endif
return 0 ;
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
/*
class Branch
{
TEdge m_edge ;
bool m_out , m_visited ;
Branch * m_next ;
Branch * m_nextBranch ;
Intersection * m_intersection ;
public :
Branch * next ( )
{
assert ( m_intersection ) ;
return m_next ? m_next : m_intersection - > m_branchList ;
}
}
class Intersection
{
private :
TPointD m_intersectionPoint ;
int m_intersectionCount ;
Branch * m_branchList ;
Intersection * m_next ;
list < IntersectedStroke > m_strokeList ;
public :
AddIntersection ( int index0 , int index1 , DoublePair intersectionValues ) ;
}
*/
# ifdef _DEBUG
2016-04-19 19:32:17 +12:00
void TVectorImage : : Imp : : checkRegions ( const std : : vector < TRegion * > & regions )
2016-03-19 06:57:51 +13:00
{
for ( UINT i = 0 ; i < regions . size ( ) ; i + + ) {
TRegion * r = regions [ i ] ;
UINT j = 0 ;
for ( j = 0 ; j < r - > getEdgeCount ( ) ; j + + ) {
TEdge * e = r - > getEdge ( j ) ;
//assert(areSameGroup(e->m_index, false, ==m_strokes[r->getEdge(0)->m_index]->m_groupId);
assert ( e - > m_r = = r ) ;
//if (e->m_s->isSelfLoop())
// {
// assert(r->getEdgeCount()==1);
//assert(r->getSubregionCount()==0);
// }
//if (j>0)
// assert(!e->m_s->isSelfLoop());
}
if ( r - > getSubregionCount ( ) > 0 ) {
2016-04-19 19:32:17 +12:00
std : : vector < TRegion * > aux ( r - > getSubregionCount ( ) ) ;
2016-03-19 06:57:51 +13:00
for ( j = 0 ; j < r - > getSubregionCount ( ) ; j + + )
aux [ j ] = r - > getSubregion ( j ) ;
checkRegions ( aux ) ;
}
}
}
# endif
namespace
{
2016-04-19 19:32:17 +12:00
inline TGroupId getGroupId ( TRegion * r , const std : : vector < VIStroke * > & strokes )
2016-03-19 06:57:51 +13:00
{
for ( UINT i = 0 ; i < r - > getEdgeCount ( ) ; i + + )
if ( r - > getEdge ( i ) - > m_index > = 0 )
return strokes [ r - > getEdge ( i ) - > m_index ] - > m_groupId ;
return TGroupId ( ) ;
}
}
//------------------------------------------------------------
TRegion * TVectorImage : : findRegion ( const TRegion & region ) const
{
TRegion * ret = 0 ;
2016-04-19 19:32:17 +12:00
for ( std : : vector < TRegion * > : : iterator it = m_imp - > m_regions . begin ( ) ; it ! = m_imp - > m_regions . end ( ) ; + + it )
2016-03-19 06:57:51 +13:00
if ( ( ret = ( * it ) - > findRegion ( region ) ) ! = 0 )
return ret ;
return 0 ;
}
//------------------------------------------------------------
void TVectorImage : : Imp : : addRegion ( TRegion * region )
{
2016-04-19 19:32:17 +12:00
for ( std : : vector < TRegion * > : : iterator it = m_regions . begin ( ) ; it ! = m_regions . end ( ) ; + + it ) {
2016-03-19 06:57:51 +13:00
if ( getGroupId ( region , m_strokes ) ! = getGroupId ( * it , m_strokes ) )
continue ;
if ( region - > contains ( * * it ) ) {
//region->addSubregion(*it);
region - > addSubregion ( * it ) ;
it = m_regions . erase ( it ) ;
while ( it ! = m_regions . end ( ) ) {
if ( region - > contains ( * * it ) ) {
region - > addSubregion ( * it ) ;
//region->addSubregion(*it);
it = m_regions . erase ( it ) ;
} else
it + + ;
}
m_regions . push_back ( region ) ;
return ;
} else if ( ( * it ) - > contains ( * region ) ) {
( * it ) - > addSubregion ( region ) ;
//(*it)->addSubregion(region);
return ;
}
}
m_regions . push_back ( region ) ;
}
//-----------------------------------------------------------------------------
void TVectorImage : : replaceStroke ( int index , TStroke * newStroke )
{
if ( ( int ) m_imp - > m_strokes . size ( ) < = index )
return ;
delete m_imp - > m_strokes [ index ] - > m_s ;
m_imp - > m_strokes [ index ] - > m_s = newStroke ;
Intersection * p1 ;
IntersectedStroke * p2 ;
for ( p1 = m_imp - > m_intersectionData - > m_intList . first ( ) ; p1 ; p1 = p1 - > next ( ) )
for ( p2 = ( * p1 ) . m_strokeList . first ( ) ; p2 ; p2 = p2 - > next ( ) )
if ( p2 - > m_edge . m_index = = index )
p2 - > m_edge . m_s = newStroke ;
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void TVectorImage : : Imp : : moveStroke ( int fromIndex , int moveBefore )
{
assert ( ( int ) m_strokes . size ( ) > fromIndex ) ;
assert ( ( int ) m_strokes . size ( ) > = moveBefore ) ;
# ifdef _DEBUG
checkIntersections ( ) ;
# endif
VIStroke * vi = m_strokes [ fromIndex ] ;
m_strokes . erase ( m_strokes . begin ( ) + fromIndex ) ;
2016-04-19 19:32:17 +12:00
std : : vector < VIStroke * > : : iterator it = m_strokes . begin ( ) ;
2016-03-19 06:57:51 +13:00
if ( fromIndex < moveBefore )
advance ( it , moveBefore - 1 ) ;
else
advance ( it , moveBefore ) ;
m_strokes . insert ( it , vi ) ;
Intersection * p1 ;
IntersectedStroke * p2 ;
for ( p1 = m_intersectionData - > m_intList . first ( ) ; p1 ; p1 = p1 - > next ( ) )
for ( p2 = p1 - > m_strokeList . first ( ) ; p2 ; p2 = p2 - > next ( ) ) {
if ( fromIndex < moveBefore ) {
if ( p2 - > m_edge . m_index = = fromIndex )
p2 - > m_edge . m_index = moveBefore - 1 ;
else if ( p2 - > m_edge . m_index > fromIndex & & p2 - > m_edge . m_index < moveBefore )
p2 - > m_edge . m_index - - ;
} else //(fromIndex>moveBefore)
{
if ( p2 - > m_edge . m_index = = fromIndex )
p2 - > m_edge . m_index = moveBefore ;
else if ( p2 - > m_edge . m_index > = moveBefore & & p2 - > m_edge . m_index < fromIndex )
p2 - > m_edge . m_index + + ;
}
}
# ifdef _DEBUG
checkIntersections ( ) ;
# endif
}
//-----------------------------------------------------------------------------
void TVectorImage : : Imp : : reindexEdges ( UINT strokeIndex )
{
Intersection * p1 ;
IntersectedStroke * p2 ;
for ( p1 = m_intersectionData - > m_intList . first ( ) ; p1 ; p1 = p1 - > next ( ) )
for ( p2 = ( * p1 ) . m_strokeList . first ( ) ; p2 ; p2 = p2 - > next ( ) ) {
assert ( p2 - > m_edge . m_index ! = ( int ) strokeIndex | | p2 - > m_edge . m_index < 0 ) ;
if ( p2 - > m_edge . m_index > ( int ) strokeIndex )
p2 - > m_edge . m_index - - ;
}
}
//-----------------------------------------------------------------------------
void TVectorImage : : Imp : : reindexEdges ( const vector < int > & indexes , bool areAdded )
{
int i ;
int size = indexes . size ( ) ;
if ( size = = 0 )
return ;
# ifdef _DEBUG
for ( i = 0 ; i < size ; i + + )
assert ( i = = 0 | | indexes [ i - 1 ] < indexes [ i ] ) ;
# endif
int min = ( int ) indexes [ 0 ] ;
Intersection * p1 ;
IntersectedStroke * p2 ;
for ( p1 = m_intersectionData - > m_intList . first ( ) ; p1 ; p1 = p1 - > next ( ) )
for ( p2 = p1 - > m_strokeList . first ( ) ; p2 ; p2 = p2 - > next ( ) ) {
if ( areAdded ) {
if ( p2 - > m_edge . m_index < min )
continue ;
else
for ( i = size - 1 ; i > = 0 ; i - - )
if ( p2 - > m_edge . m_index > = ( int ) indexes [ i ] - i ) {
p2 - > m_edge . m_index + = i + 1 ;
break ;
}
} else {
if ( p2 - > m_edge . m_index < min )
continue ;
else
for ( i = size - 1 ; i > = 0 ; i - - )
if ( p2 - > m_edge . m_index > ( int ) indexes [ i ] ) {
p2 - > m_edge . m_index - = i + 1 ;
break ;
}
}
//assert(it2->m_edge.m_index!=1369);
}
}
//-----------------------------------------------------------------------------
void TVectorImage : : Imp : : insertStrokeAt ( VIStroke * vs , int strokeIndex , bool recomputeRegions )
{
list < TEdge * > oldEdgeList , emptyList ;
if ( m_computedAlmostOnce & & recomputeRegions ) {
oldEdgeList = vs - > m_edgeList ;
vs - > m_edgeList . clear ( ) ;
}
assert ( strokeIndex > = 0 & & strokeIndex < = ( int ) m_strokes . size ( ) ) ;
vector < VIStroke * > : : iterator it = m_strokes . begin ( ) ;
advance ( it , strokeIndex ) ;
vs - > m_isNewForFill = true ;
m_strokes . insert ( it , vs ) ;
if ( ! m_computedAlmostOnce )
return ;
Intersection * p1 ;
IntersectedStroke * p2 ;
for ( p1 = m_intersectionData - > m_intList . first ( ) ; p1 ; p1 = p1 - > next ( ) )
for ( p2 = ( * p1 ) . m_strokeList . first ( ) ; p2 ; p2 = p2 - > next ( ) )
if ( p2 - > m_edge . m_index > = ( int ) strokeIndex )
p2 - > m_edge . m_index + + ;
if ( ! recomputeRegions )
return ;
computeRegions ( ) ;
transferColors ( oldEdgeList , m_strokes [ strokeIndex ] - > m_edgeList , true , false , true ) ;
/*
# ifdef _DEBUG
checkIntersections ( ) ;
# endif
*/
}
//-----------------------------------------------------------------------------
void invalidateRegionPropAndBBox ( TRegion * reg )
{
for ( UINT regId = 0 ; regId ! = reg - > getSubregionCount ( ) ; regId + + ) {
invalidateRegionPropAndBBox ( reg - > getSubregion ( regId ) ) ;
}
reg - > invalidateProp ( ) ;
reg - > invalidateBBox ( ) ;
}
void TVectorImage : : transform ( const TAffine & aff , bool doChangeThickness )
{
UINT i ;
for ( i = 0 ; i < m_imp - > m_strokes . size ( ) ; + + i )
m_imp - > m_strokes [ i ] - > m_s - > transform ( aff , doChangeThickness ) ;
map < int , VIStroke * > : : iterator it = m_imp - > m_intersectionData - > m_autocloseMap . begin ( ) ;
for ( ; it ! = m_imp - > m_intersectionData - > m_autocloseMap . end ( ) ; + + it )
it - > second - > m_s - > transform ( aff , false ) ;
for ( i = 0 ; i < m_imp - > m_regions . size ( ) ; + + i )
invalidateRegionPropAndBBox ( m_imp - > m_regions [ i ] ) ;
}
//-----------------------------------------------------------------------------
# ifdef _DEBUG
# include "tvectorrenderdata.h"
# include "tgl.h"
void TVectorImage : : drawAutocloses ( const TVectorRenderData & rd ) const
{
float width ;
glPushMatrix ( ) ;
tglMultMatrix ( rd . m_aff ) ;
glGetFloatv ( GL_LINE_WIDTH , & width ) ;
tglColor ( TPixel ( 0 , 255 , 0 , 255 ) ) ;
glLineWidth ( 1.5 ) ;
glBegin ( GL_LINES ) ;
Intersection * p1 ;
IntersectedStroke * p2 ;
for ( p1 = m_imp - > m_intersectionData - > m_intList . first ( ) ; p1 ; p1 = p1 - > next ( ) )
for ( p2 = ( * p1 ) . m_strokeList . first ( ) ; p2 ; p2 = p2 - > next ( ) ) {
if ( p2 - > m_edge . m_index < 0 & & p2 - > m_edge . m_w0 = = 0.0 ) {
TStroke * s = p2 - > m_edge . m_s ;
TPointD p0 = s - > getPoint ( 0.0 ) ;
TPointD p1 = s - > getPoint ( 1.0 ) ;
glVertex2d ( p0 . x , p0 . y ) ;
glVertex2d ( p1 . x , p1 . y ) ;
}
}
glEnd ( ) ;
glLineWidth ( width ) ;
glPopMatrix ( ) ;
}
# endif
//-----------------------------------------------------------------------------
void TVectorImage : : reassignStyles ( map < int , int > & table )
{
UINT i ;
UINT strokeCount = getStrokeCount ( ) ;
//UINT regionCount = getRegionCount();
for ( i = 0 ; i < strokeCount ; + + i ) {
TStroke * stroke = getStroke ( i ) ;
int styleId = stroke - > getStyle ( ) ;
if ( styleId ! = 0 ) {
map < int , int > : : iterator it = table . find ( styleId ) ;
if ( it ! = table . end ( ) )
stroke - > setStyle ( it - > second ) ;
}
}
Intersection * p1 ;
IntersectedStroke * p2 ;
for ( p1 = m_imp - > m_intersectionData - > m_intList . first ( ) ; p1 ; p1 = p1 - > next ( ) )
for ( p2 = ( * p1 ) . m_strokeList . first ( ) ; p2 ; p2 = p2 - > next ( ) )
if ( p2 - > m_edge . m_styleId ! = 0 ) {
map < int , int > : : iterator it = table . find ( p2 - > m_edge . m_styleId ) ;
if ( it ! = table . end ( ) )
p2 - > m_edge . m_styleId = it - > second ;
//assert(it->second<100);
}
}
//-----------------------------------------------------------------------------
struct TDeleteMapFunctor {
void operator ( ) ( pair < int , VIStroke * > ptr )
{
delete ptr . second ;
}
} ;
IntersectionData : : ~ IntersectionData ( )
{
std : : for_each ( m_autocloseMap . begin ( ) , m_autocloseMap . end ( ) , TDeleteMapFunctor ( ) ) ;
}
//-----------------------------------------------------------------------------
# ifdef _DEBUG
void TVectorImage : : Imp : : checkIntersections ( )
{
//return;
UINT i , j ;
Intersection * p1 ;
IntersectedStroke * p2 ;
for ( i = 0 , p1 = m_intersectionData - > m_intList . first ( ) ; p1 ; p1 = p1 - > next ( ) , i + + )
for ( j = 0 , p2 = ( * p1 ) . m_strokeList . first ( ) ; p2 ; p2 = p2 - > next ( ) , j + + ) {
IntersectedStroke & is = * p2 ;
assert ( is . m_edge . m_styleId > = 0 & & is . m_edge . m_styleId < = 1000 ) ;
assert ( is . m_edge . m_w0 > = 0 & & is . m_edge . m_w0 < = 1 ) ;
assert ( is . m_edge . m_index < ( int ) m_strokes . size ( ) ) ;
if ( is . m_edge . m_index > = 0 ) {
assert ( is . m_edge . m_s - > getChunkCount ( ) > = 0 & & is . m_edge . m_s - > getChunkCount ( ) < = 10000 ) ;
assert ( m_strokes [ is . m_edge . m_index ] - > m_s = = is . m_edge . m_s ) ;
} else
assert ( m_intersectionData - > m_autocloseMap [ is . m_edge . m_index ] ) ;
if ( p2 - > m_nextIntersection ) {
IntersectedStroke * nextStroke = p2 - > m_nextStroke ;
assert ( nextStroke - > m_nextIntersection = = p1 ) ;
assert ( nextStroke - > m_nextStroke = = p2 ) ;
}
}
for ( i = 0 ; i < m_strokes . size ( ) ; i + + ) {
VIStroke * vs = m_strokes [ i ] ;
list < TEdge * > : : const_iterator it = vs - > m_edgeList . begin ( ) , it_e = vs - > m_edgeList . end ( ) ;
for ( ; it ! = it_e ; + + it ) {
TEdge * e = * it ;
assert ( e - > getStyle ( ) > = 0 & & e - > getStyle ( ) < = 1000 ) ;
assert ( e - > m_w0 > = 0 & & e - > m_w1 < = 1 ) ;
assert ( e - > m_s = = vs - > m_s ) ;
assert ( e - > m_s - > getChunkCount ( ) > = 0 & & e - > m_s - > getChunkCount ( ) < = 10000 ) ;
//assert(e->m_index<(int)m_strokes.size()); l'indice nella stroke potrebbe essere non valido, non importa.
//assert(m_strokes[e->m_index]->m_s==e->m_s); deve essere buono nella intersectionData
}
}
for ( i = 0 ; i < m_regions . size ( ) ; i + + ) {
m_regions [ i ] - > checkRegion ( ) ;
}
}
# endif
//-----------------------------------------------------------------------------
TStroke * TVectorImage : : Imp : : removeEndpoints ( int strokeIndex )
{
# ifdef _DEBUG
checkIntersections ( ) ;
# endif
VIStroke * vs = m_strokes [ strokeIndex ] ;
if ( vs - > m_s - > isSelfLoop ( ) )
return 0 ;
if ( vs - > m_edgeList . empty ( ) )
return 0 ;
list < TEdge * > : : iterator it = vs - > m_edgeList . begin ( ) ;
double minW = 1.0 ;
double maxW = 0.0 ;
for ( ; it ! = vs - > m_edgeList . end ( ) ; + + it ) {
minW = tmin ( minW - 0.00002 , ( * it ) - > m_w0 , ( * it ) - > m_w1 ) ;
maxW = tmax ( maxW + 0.00002 , ( * it ) - > m_w0 , ( * it ) - > m_w1 ) ;
}
if ( areAlmostEqual ( minW , 0.0 , 0.001 ) & & areAlmostEqual ( maxW , 1.0 , 0.001 ) )
return 0 ;
TStroke * oldS = vs - > m_s ;
TStroke * s = new TStroke ( * ( vs - > m_s ) ) ;
double offs = s - > getLength ( minW ) ;
TStroke s0 , s1 , final ;
if ( ! areAlmostEqual ( maxW , 1.0 , 0.001 ) ) {
s - > split ( maxW , s0 , s1 ) ;
} else
s0 = * s ;
if ( ! areAlmostEqual ( minW , 0.0 , 0.001 ) ) {
double newW = ( maxW = = 1.0 ) ? minW : s0 . getParameterAtLength ( offs ) ;
s0 . split ( newW , s1 , final ) ;
} else
final = s0 ;
vs - > m_s = new TStroke ( final ) ;
vs - > m_s - > setStyle ( oldS - > getStyle ( ) ) ;
for ( it = vs - > m_edgeList . begin ( ) ; it ! = vs - > m_edgeList . end ( ) ; + + it ) {
( * it ) - > m_w0 = vs - > m_s - > getParameterAtLength ( s - > getLength ( ( * it ) - > m_w0 ) - offs ) ;
( * it ) - > m_w1 = vs - > m_s - > getParameterAtLength ( s - > getLength ( ( * it ) - > m_w1 ) - offs ) ;
( * it ) - > m_s = vs - > m_s ;
}
Intersection * p1 ;
IntersectedStroke * p2 ;
for ( p1 = m_intersectionData - > m_intList . first ( ) ; p1 ; p1 = p1 - > next ( ) )
for ( p2 = ( * p1 ) . m_strokeList . first ( ) ; p2 ; p2 = p2 - > next ( ) ) {
if ( p2 - > m_edge . m_s = = oldS ) {
p2 - > m_edge . m_w0 = vs - > m_s - > getParameterAtLength ( s - > getLength ( p2 - > m_edge . m_w0 ) - offs ) ;
p2 - > m_edge . m_w1 = vs - > m_s - > getParameterAtLength ( s - > getLength ( p2 - > m_edge . m_w1 ) - offs ) ;
p2 - > m_edge . m_s = vs - > m_s ;
}
}
# ifdef _DEBUG
checkIntersections ( ) ;
# endif
return oldS ;
}
//-----------------------------------------------------------------------------
void TVectorImage : : Imp : : restoreEndpoints ( int index , TStroke * oldStroke )
{
# ifdef _DEBUG
checkIntersections ( ) ;
# endif
VIStroke * vs = m_strokes [ index ] ;
TStroke * s = vs - > m_s ;
TPointD p = s - > getPoint ( 0.0 ) ;
double offs = oldStroke - > getLength ( oldStroke - > getW ( p ) ) ;
vs - > m_s = oldStroke ;
list < TEdge * > : : iterator it = vs - > m_edgeList . begin ( ) ;
for ( ; it ! = vs - > m_edgeList . end ( ) ; + + it ) {
( * it ) - > m_w0 = vs - > m_s - > getParameterAtLength ( s - > getLength ( ( * it ) - > m_w0 ) + offs ) ;
( * it ) - > m_w1 = vs - > m_s - > getParameterAtLength ( s - > getLength ( ( * it ) - > m_w1 ) + offs ) ;
( * it ) - > m_s = vs - > m_s ;
}
Intersection * p1 ;
IntersectedStroke * p2 ;
for ( p1 = m_intersectionData - > m_intList . first ( ) ; p1 ; p1 = p1 - > next ( ) )
for ( p2 = ( * p1 ) . m_strokeList . first ( ) ; p2 ; p2 = p2 - > next ( ) ) {
if ( p2 - > m_edge . m_s = = s ) {
p2 - > m_edge . m_w0 = vs - > m_s - > getParameterAtLength ( s - > getLength ( p2 - > m_edge . m_w0 ) + offs ) ;
p2 - > m_edge . m_w1 = vs - > m_s - > getParameterAtLength ( s - > getLength ( p2 - > m_edge . m_w1 ) + offs ) ;
p2 - > m_edge . m_s = vs - > m_s ;
}
}
delete s ;
# ifdef _DEBUG
checkIntersections ( ) ;
# endif
}