Files
core/ASCOfficePDFReader/SXPath.cpp

448 lines
12 KiB
C++

#include "stdafx.h"
#include <stdlib.h>
#include <string.h>
#include "MemoryUtils.h"
#include "SMathExt.h"
#include "SPath.h"
#include "SXPath.h"
//-------------------------------------------------------------------------------------------------------------------------------
struct SXPathAdjust
{
int nFirstPoint; // Äèàïàçîí òî÷åê
int nLastPoint; //
BOOL bVertical; // Âåðòèêàëüíûé ëè ñåãìåíò
double dX0a; //
double dX0b; //
double dXma; // Ãðàíèöû
double dXmb; //
double dX1a; //
double dX1b; //
double dX0; //
double dX1; //
double dXm; //
};
//-------------------------------------------------------------------------------------------------------------------------------
inline void SXPath::Transform(double *pMatrix, double dUserX, double dUserY, double *pdDeviceX, double *pdDeviceY)
{
*pdDeviceX = dUserX * pMatrix[0] + dUserY * pMatrix[2] + pMatrix[4];
*pdDeviceY = dUserX * pMatrix[1] + dUserY * pMatrix[3] + pMatrix[5];
}
//-------------------------------------------------------------------------------------------------------------------------------
// SXPath
//-------------------------------------------------------------------------------------------------------------------------------
SXPath::SXPath()
{
m_pSegments = NULL;
m_nSegmentsCount = m_nSize = 0;
}
SXPath::SXPath(SPath *pPath, double *pMatrix, double dFlatness, BOOL bCloseSubpaths)
{
double dX0, dY0, dX1, dY1, dX2, dY2, dX3, dY3, dXSp, dYSp;
SPathPoint *pPoints = (SPathPoint *)MemUtilsMallocArray( pPath->m_nPointsCount, sizeof(SPathPoint) );
// Ïðåîáðàçóåì òî÷êè
for ( int nIndex = 0; nIndex < pPath->m_nPointsCount; ++nIndex )
{
Transform( pMatrix, pPath->m_pPoints[nIndex].dX, pPath->m_pPoints[nIndex].dY, &pPoints[nIndex].dX, &pPoints[nIndex].dY );
}
SXPathAdjust *pAdjusts;
if ( pPath->m_pHints )
{
pAdjusts = (SXPathAdjust *)MemUtilsMallocArray( pPath->m_nHintsCount, sizeof(SXPathAdjust));
for ( int nIndex = 0; nIndex < pPath->m_nHintsCount; ++nIndex )
{
SPathHint *pHint = &pPath->m_pHints[nIndex];
dX0 = pPoints[pHint->nFirstControl ].dX; dY0 = pPoints[pHint->nFirstControl ].dY;
dX1 = pPoints[pHint->nFirstControl + 1].dX; dY1 = pPoints[pHint->nFirstControl + 1].dY;
dX2 = pPoints[pHint->nSecondControl ].dX; dY2 = pPoints[pHint->nSecondControl ].dY;
dX3 = pPoints[pHint->nSecondControl + 1].dX; dY3 = pPoints[pHint->nSecondControl + 1].dY;
double dAdj0 = 0, dAdj1 = 0;
if ( dX0 == dX1 && dX2 == dX3 )
{
pAdjusts[nIndex].bVertical = TRUE;
dAdj0 = dX0;
dAdj1 = dX2;
}
else if ( dY0 == dY1 && dY2 == dY3 )
{
pAdjusts[nIndex].bVertical = FALSE;
dAdj0 = dY0;
dAdj1 = dY2;
}
else
{
MemUtilsFree( pAdjusts );
pAdjusts = NULL;
break;
}
if ( dAdj0 > dAdj1 )
{
dX0 = dAdj0;
dAdj0 = dAdj1;
dAdj1 = dX0;
}
double dWidth = dAdj1 - dAdj0;
int nRoundWidth = round( dWidth );
if ( nRoundWidth == 0 )
{
nRoundWidth = 1;
}
pAdjusts[nIndex].dX0a = dAdj0 - 0.01;
pAdjusts[nIndex].dX0b = dAdj0 + 0.01;
pAdjusts[nIndex].dXma = (double)0.5 * ( dAdj0 + dAdj1 ) - 0.01;
pAdjusts[nIndex].dXmb = (double)0.5 * ( dAdj0 + dAdj1 ) + 0.01;
pAdjusts[nIndex].dX1a = dAdj1 - 0.01;
pAdjusts[nIndex].dX1b = dAdj1 + 0.01;
pAdjusts[nIndex].dX0 = (double)round( dAdj0 );
pAdjusts[nIndex].dX1 = pAdjusts[nIndex].dX0 + nRoundWidth - 0.01;
pAdjusts[nIndex].dXm = (double)0.5 * ( pAdjusts[nIndex].dX0 + pAdjusts[nIndex].dX1 );
pAdjusts[nIndex].nFirstPoint = pHint->nFirstPoint;
pAdjusts[nIndex].nLastPoint = pHint->nLastPoint;
}
}
else
{
pAdjusts = NULL;
}
// perform stroke adjustment
if ( pAdjusts )
{
int nIndex = 0;
SXPathAdjust *pCurAdjust;
for ( nIndex = 0, pCurAdjust = pAdjusts; nIndex < pPath->m_nHintsCount; ++nIndex, ++pCurAdjust )
{
for ( int nJ = pCurAdjust->nFirstPoint; nJ <= pCurAdjust->nLastPoint; ++nJ )
{
StrokeAdjust( pCurAdjust, &pPoints[nJ].dX, &pPoints[nJ].dY );
}
}
MemUtilsFree( pAdjusts );
}
m_pSegments = NULL;
m_nSegmentsCount = m_nSize = 0;
dX0 = dY0 = dXSp = dYSp = 0;
int nCurSubpath = 0;
int nCurSubpathX = 0;
int nCount = 0;
while ( nCount < pPath->m_nPointsCount )
{
// Ïðîïóñêàåì ïåðâóþ òî÷êó â SubPath
if ( pPath->m_pFlags[nCount] & SPathFirst )
{
dX0 = pPoints[nCount].dX;
dY0 = pPoints[nCount].dY;
dXSp = dX0;
dYSp = dY0;
nCurSubpath = nCount;
nCurSubpathX = m_nSegmentsCount;
++nCount;
}
else
{
// Ñåãìåíò - êðèâàÿ Áåçüå
if ( pPath->m_pFlags[nCount] & SPathCurve )
{
dX1 = pPoints[nCount + 0].dX;
dY1 = pPoints[nCount + 0].dY;
dX2 = pPoints[nCount + 1].dX;
dY2 = pPoints[nCount + 1].dY;
dX3 = pPoints[nCount + 2].dX;
dY3 = pPoints[nCount + 2].dY;
AddCurve( dX0, dY0, dX1, dY1, dX2, dY2, dX3, dY3, dFlatness, ( pPath->m_pFlags[nCount - 1] & SPathFirst) , ( pPath->m_pFlags[nCount + 2] & SPathLast ), !bCloseSubpaths && ( pPath->m_pFlags[nCount - 1] & SPathFirst ) && !( pPath->m_pFlags[nCount - 1] & SPathClosed ), !bCloseSubpaths && ( pPath->m_pFlags[nCount + 2] & SPathLast ) && !( pPath->m_pFlags[nCount + 2] & SPathClosed ) );
dX0 = dX3;
dY0 = dY3;
nCount += 3;
}
else // Ñåãìåíò - ïðÿìàÿ ëèíèÿ
{
dX1 = pPoints[nCount].dX;
dY1 = pPoints[nCount].dY;
AddSegment( dX0, dY0, dX1, dY1, pPath->m_pFlags[nCount - 1] & SPathFirst, pPath->m_pFlags[nCount] & SPathLast, !bCloseSubpaths && ( pPath->m_pFlags[nCount - 1] & SPathFirst ) && !( pPath->m_pFlags[nCount - 1] & SPathClosed ), !bCloseSubpaths && ( pPath->m_pFlags[nCount] & SPathLast ) && !( pPath->m_pFlags[nCount] & SPathClosed ) );
dX0 = dX1;
dY0 = dY1;
++nCount;
}
// Çàêðûâàåì SubPath
if ( bCloseSubpaths && ( pPath->m_pFlags[nCount - 1] & SPathLast ) && ( pPoints[nCount - 1].dX != pPoints[nCurSubpath].dX || pPoints[nCount - 1].dY != pPoints[nCurSubpath].dY ) )
{
AddSegment( dX0, dY0, dXSp, dYSp, FALSE, TRUE, FALSE, FALSE );
}
}
}
MemUtilsFree( pPoints );
}
void SXPath::StrokeAdjust(SXPathAdjust *pAdjust, double *pdX, double *pdY)
{
if ( pAdjust->bVertical )
{
double dX = *pdX;
if ( dX > pAdjust->dX0a && dX < pAdjust->dX0b )
{
*pdX = pAdjust->dX0;
}
else if ( dX > pAdjust->dXma && dX < pAdjust->dXmb )
{
*pdX = pAdjust->dXm;
}
else if ( dX > pAdjust->dX1a && dX < pAdjust->dX1b )
{
*pdX = pAdjust->dX1;
}
}
else
{
double dY = *pdY;
if ( dY > pAdjust->dX0a && dY < pAdjust->dX0b )
{
*pdY = pAdjust->dX0;
}
else if ( dY > pAdjust->dXma && dY < pAdjust->dXmb )
{
*pdY = pAdjust->dXm;
}
else if ( dY > pAdjust->dX1a && dY < pAdjust->dX1b )
{
*pdY = pAdjust->dX1;
}
}
}
SXPath::SXPath(SXPath *pXPath)
{
m_nSegmentsCount = pXPath->m_nSegmentsCount;
m_nSize = pXPath->m_nSize;
m_pSegments = (SXPathSegment *)MemUtilsMallocArray( m_nSize, sizeof(SXPathSegment) );
memcpy( m_pSegments, pXPath->m_pSegments, m_nSegmentsCount * sizeof(SXPathSegment) );
}
SXPath::~SXPath()
{
MemUtilsFree( m_pSegments );
}
void SXPath::Resize(int nSegmentsCount)
{
if ( m_nSegmentsCount + nSegmentsCount > m_nSize )
{
if ( m_nSize == 0 )
{
m_nSize = 32;
}
while ( m_nSize < m_nSegmentsCount + nSegmentsCount )
{
m_nSize *= 2;
}
m_pSegments = (SXPathSegment *)MemUtilsReallocArray( m_pSegments, m_nSize, sizeof(SXPathSegment) );
}
}
void SXPath::AddCurve(double dX0, double dY0, double dX1, double dY1, double dX2, double dY2, double dX3, double dY3, double dFlatness, BOOL bFirst, BOOL bLast, BOOL bEnd0, BOOL bEnd1)
{
double arrSegX[MaxCurveSplits + 1][3];
double arrSegY[MaxCurveSplits + 1][3];
int arrNext[MaxCurveSplits + 1];
double xl0, xl1, xl2, xr0, xr1, xr2, xr3, xx1, xx2, xh;
double yl0, yl1, yl2, yr0, yr1, yr2, yr3, yy1, yy2, yh;
double dx, dy, mx, my, d1, d2;
double dFlatness_2 = dFlatness * dFlatness;
// Íà÷àëüíûé ñåãìåíò
int nPart1 = 0, nPart2 = MaxCurveSplits;
arrSegX[nPart1][0] = dX0; arrSegY[nPart1][0] = dY0;
arrSegX[nPart1][1] = dX1; arrSegY[nPart1][1] = dY1;
arrSegX[nPart1][2] = dX2; arrSegY[nPart1][2] = dY2;
arrSegX[nPart2][0] = dX3; arrSegY[nPart2][0] = dY3;
arrNext[nPart1] = nPart2;
while ( nPart1 < MaxCurveSplits )
{
// Ñëåäóþùèé ñåãìåíò
xl0 = arrSegX[nPart1][0]; yl0 = arrSegY[nPart1][0];
xx1 = arrSegX[nPart1][1]; yy1 = arrSegY[nPart1][1];
xx2 = arrSegX[nPart1][2]; yy2 = arrSegY[nPart1][2];
nPart2 = arrNext[nPart1];
xr3 = arrSegX[nPart2][0]; yr3 = arrSegY[nPart2][0];
// Âû÷èñëÿåì ðàññòîÿíèå îò êîíòðîëüíûõ òî÷åê äî ñðåäíèõ òî÷åê ïðÿìîé ëèíèè. (Âû÷èñëåíèå íå ñîâñåì òî÷íîå, íî áûñòðîå)
mx = (xl0 + xr3) * 0.5;
my = (yl0 + yr3) * 0.5;
dx = xx1 - mx;
dy = yy1 - my;
d1 = dx*dx + dy*dy;
dx = xx2 - mx;
dy = yy2 - my;
d2 = dx*dx + dy*dy;
// Åñëè ñåãìåíò óæå äîñòàòî÷íî ïëîñêèé èëè áîëüøå äåëåíèé íåâîçîìæíî ñäåëàòü, äîáàâëÿåì ïðÿìóþ ëèíèþ
if ( nPart2 - nPart1 == 1 || ( d1 <= dFlatness_2 && d2 <= dFlatness_2 ) )
{
AddSegment( xl0, yl0, xr3, yr3, nPart1 == 0 && bFirst, nPart2 == MaxCurveSplits && bLast, nPart1 == 0 && bEnd0, nPart2 == MaxCurveSplits && bEnd1 );
nPart1 = nPart2;
}
else // â ïðîòèâíîì ñëó÷àå, ðàçäåëÿåì êðèâóþ íà ÷àñòè
{
xl1 = (xl0 + xx1) * 0.5;
yl1 = (yl0 + yy1) * 0.5;
xh = (xx1 + xx2) * 0.5;
yh = (yy1 + yy2) * 0.5;
xl2 = (xl1 + xh) * 0.5;
yl2 = (yl1 + yh) * 0.5;
xr2 = (xx2 + xr3) * 0.5;
yr2 = (yy2 + yr3) * 0.5;
xr1 = (xh + xr2) * 0.5;
yr1 = (yh + yr2) * 0.5;
xr0 = (xl2 + xr1) * 0.5;
yr0 = (yl2 + yr1) * 0.5;
int nPart3 = ( nPart1 + nPart2 ) / 2;
arrSegX[nPart1][1] = xl1; arrSegY[nPart1][1] = yl1;
arrSegX[nPart1][2] = xl2; arrSegY[nPart1][2] = yl2;
arrNext[nPart1] = nPart3;
arrSegX[nPart3][0] = xr0; arrSegY[nPart3][0] = yr0;
arrSegX[nPart3][1] = xr1; arrSegY[nPart3][1] = yr1;
arrSegX[nPart3][2] = xr2; arrSegY[nPart3][2] = yr2;
arrNext[nPart3] = nPart2;
}
}
}
void SXPath::AddSegment(double dX0, double dY0, double dX1, double dY1, BOOL bFirst, BOOL bLast, BOOL bEnd0, BOOL bEnd1)
{
Resize(1);
m_pSegments[m_nSegmentsCount].dFirstX = dX0;
m_pSegments[m_nSegmentsCount].dFirstY = dY0;
m_pSegments[m_nSegmentsCount].dSecondX = dX1;
m_pSegments[m_nSegmentsCount].dSecondY = dY1;
m_pSegments[m_nSegmentsCount].unFlags = 0;
if ( bFirst )
{
m_pSegments[m_nSegmentsCount].unFlags |= XPathFirst;
}
if ( bLast )
{
m_pSegments[m_nSegmentsCount].unFlags |= XPathLast;
}
if ( bEnd0 )
{
m_pSegments[m_nSegmentsCount].unFlags |= XPathEnd0;
}
if ( bEnd1 )
{
m_pSegments[m_nSegmentsCount].unFlags |= XPathEnd1;
}
if ( dY1 == dY0 )
{
m_pSegments[m_nSegmentsCount].dDxDy = m_pSegments[m_nSegmentsCount].dDyDx = 0;
m_pSegments[m_nSegmentsCount].unFlags |= XPathHoriz;
if ( dX1 == dX0 )
{
m_pSegments[m_nSegmentsCount].unFlags |= XPathVert;
}
}
else if ( dX1 == dX0 )
{
m_pSegments[m_nSegmentsCount].dDxDy = m_pSegments[m_nSegmentsCount].dDyDx = 0;
m_pSegments[m_nSegmentsCount].unFlags |= XPathVert;
}
else
{
m_pSegments[m_nSegmentsCount].dDxDy = ( dX1 - dX0 ) / ( dY1 - dY0 );
m_pSegments[m_nSegmentsCount].dDyDx = (double)1 / m_pSegments[m_nSegmentsCount].dDxDy;
}
if ( dY0 > dY1 )
{
m_pSegments[m_nSegmentsCount].unFlags |= XPathFlip;
}
++m_nSegmentsCount;
}
static int CompareXPathSegments(const void *pFirstSegment, const void *pSecondSegment)
{
SXPathSegment *pSegment0 = (SXPathSegment *)pFirstSegment;
SXPathSegment *pSegment1 = (SXPathSegment *)pSecondSegment;
double dX0, dY0, dX1, dY1;
if ( pSegment0->unFlags & XPathFlip )
{
dX0 = pSegment0->dSecondX;
dY0 = pSegment0->dSecondY;
}
else
{
dX0 = pSegment0->dFirstX;
dY0 = pSegment0->dFirstY;
}
if ( pSegment1->unFlags & XPathFlip )
{
dX1 = pSegment1->dSecondX;
dY1 = pSegment1->dSecondY;
}
else
{
dX1 = pSegment1->dFirstX;
dY1 = pSegment1->dFirstY;
}
if ( dY0 != dY1 )
{
return ( dY0 > dY1 ) ? 1 : -1;
}
if ( dX0 != dX1 )
{
return ( dX0 > dX1 ) ? 1 : -1;
}
return 0;
}
void SXPath::AntiAliasingScale()
{
SXPathSegment *pSegment = NULL;
int nIndex;
for ( nIndex = 0, pSegment = m_pSegments; nIndex < m_nSegmentsCount; ++nIndex, ++pSegment )
{
pSegment->dFirstX *= AntiAliasingSize;
pSegment->dFirstY *= AntiAliasingSize;
pSegment->dSecondX *= AntiAliasingSize;
pSegment->dSecondY *= AntiAliasingSize;
}
}
void SXPath::Sort()
{
qsort( m_pSegments, m_nSegmentsCount, sizeof(SXPathSegment), &CompareXPathSegments );
}