mirror of
https://github.com/ONLYOFFICE/core.git
synced 2026-07-11 14:00:32 +08:00
515 lines
12 KiB
C++
515 lines
12 KiB
C++
#pragma once
|
|
|
|
namespace ImageStudio {
|
|
namespace Serialize {
|
|
namespace Paint {
|
|
namespace Common {
|
|
class CWrapPolygon
|
|
{
|
|
private:
|
|
CArray<PointF> m_arPoints;
|
|
|
|
public:
|
|
CWrapPolygon() : m_arPoints()
|
|
{
|
|
}
|
|
CWrapPolygon(const CWrapPolygon& oSrc)
|
|
{
|
|
*this = oSrc;
|
|
}
|
|
CWrapPolygon& operator=(const CWrapPolygon& oSrc)
|
|
{
|
|
m_arPoints.Copy(oSrc.m_arPoints);
|
|
|
|
return *this;
|
|
}
|
|
~CWrapPolygon()
|
|
{
|
|
}
|
|
|
|
public:
|
|
void LoadFromXml(XmlUtils::CXmlNode& oNode)
|
|
{
|
|
|
|
}
|
|
void SetPoints(const CArray<PointF>& arrPoints)
|
|
{
|
|
m_arPoints.RemoveAll();
|
|
m_arPoints.Copy(arrPoints);
|
|
}
|
|
|
|
public:
|
|
RectF GetBounds()
|
|
{
|
|
}
|
|
|
|
void Calc(const RectF& oTextRect, CArray<RectF>& oArray)
|
|
{
|
|
oArray.RemoveAll();
|
|
|
|
REAL left = oTextRect.X;
|
|
REAL right = oTextRect.GetRight();
|
|
|
|
REAL top = oTextRect.Y;
|
|
REAL bottom = oTextRect.GetBottom();
|
|
|
|
CArray<REAL> oArray1;
|
|
CArray<REAL> oArray2;
|
|
|
|
Calc(left, right, top, oArray1);
|
|
Calc(left, right, bottom, oArray2);
|
|
|
|
size_t lMin = 0;
|
|
size_t lMax = 0;
|
|
CArray<REAL>* pArray = NULL;
|
|
|
|
if (oArray1.GetCount() >= oArray.GetCount())
|
|
{
|
|
lMin = oArray2.GetCount();
|
|
lMax = oArray1.GetCount();
|
|
|
|
pArray = &oArray1;
|
|
}
|
|
else
|
|
{
|
|
lMin = oArray.GetCount();
|
|
lMax = oArray.GetCount();
|
|
|
|
pArray = &oArray2;
|
|
}
|
|
|
|
BOOL bIsComplete = TRUE; // : bIsComplete = !IsInPolygon(m_arPoints);
|
|
|
|
REAL fStart = left;
|
|
REAL fEnd = right;
|
|
|
|
for (size_t lIndex = 0; lIndex < lMin; ++lIndex)
|
|
{
|
|
if (bIsComplete)
|
|
{
|
|
REAL fCurEnd = min(oArray1[lIndex], oArray2[lIndex]);
|
|
RectF oRect(fStart, top, fCurEnd - fStart, bottom - top);
|
|
|
|
oArray.Add(oRect);
|
|
}
|
|
else
|
|
{
|
|
fStart = max(oArray1[lIndex], oArray2[lIndex]);
|
|
}
|
|
bIsComplete = !bIsComplete;
|
|
}
|
|
for (size_t lIndex = lMin; lIndex < lMax; ++lIndex)
|
|
{
|
|
if (bIsComplete)
|
|
{
|
|
RectF oRect(fStart, top, (*pArray)[lIndex] - fStart, bottom - top);
|
|
|
|
oArray.Add(oRect);
|
|
}
|
|
else
|
|
{
|
|
fStart = (*pArray)[lIndex];
|
|
}
|
|
bIsComplete = !bIsComplete;
|
|
}
|
|
|
|
if (bIsComplete)
|
|
{
|
|
RectF oRect(fStart, top, right - fStart, bottom - top);
|
|
|
|
oArray.Add(oRect);
|
|
}
|
|
}
|
|
|
|
void Calc(const REAL& x1, const REAL& x2, const REAL& y, CArray<REAL>& oArray)
|
|
{
|
|
oArray.RemoveAll();
|
|
size_t lCount = m_arPoints.GetCount();
|
|
|
|
for (size_t i = 0; i < lCount; ++i)
|
|
{
|
|
size_t j = i + 1;
|
|
if (j == lCount)
|
|
--j;
|
|
|
|
REAL fCrossX = 0;
|
|
if (Cross(x1, x2, y, m_arPoints[i], m_arPoints[j], fCrossX))
|
|
{
|
|
oArray.Add(fCrossX);
|
|
}
|
|
}
|
|
|
|
oArray.Sort();
|
|
}
|
|
|
|
void Calculate(const RectF& oTextRect, CArray<RectF>& oArray)
|
|
{
|
|
oArray.RemoveAll();
|
|
|
|
REAL xLeft1 = 0, xRight1 = 0;
|
|
REAL xLeft2 = 0, xRight2 = 0;
|
|
|
|
REAL fVerticesMax = oTextRect.X;
|
|
REAL fVerticesMin = oTextRect.GetRight();
|
|
|
|
REAL yMin = oTextRect.Y;
|
|
REAL yMax = oTextRect.GetBottom();
|
|
|
|
size_t lCount = m_arPoints.GetCount();
|
|
for (size_t i = 0; i < lCount; ++i)
|
|
{
|
|
PointF& oPoint = m_arPoints[i];
|
|
|
|
if ((yMin < oPoint.Y) && (yMax > oPoint.Y))
|
|
{
|
|
if (fVerticesMin > oPoint.X)
|
|
fVerticesMin = oPoint.X;
|
|
if (fVerticesMax < oPoint.X)
|
|
fVerticesMax = oPoint.X;
|
|
}
|
|
}
|
|
|
|
REAL left = oTextRect.X;
|
|
REAL right = oTextRect.GetRight();
|
|
|
|
CalcCrosses(left, right, yMin, xLeft1, xRight1);
|
|
CalcCrosses(left, right, yMax, xLeft2, xRight2);
|
|
|
|
REAL __fRight = min(fVerticesMin, min(xLeft1, xLeft2));
|
|
REAL __fLeft = max(fVerticesMax, max(xRight1, xRight2));
|
|
|
|
if (__fRight > left && (!IsInPolygon(left, yMin) && !IsInPolygon(left, yMax)))
|
|
{
|
|
RectF oRectLeft(left, yMin, __fRight - left, yMax - yMin);
|
|
oArray.Add(oRectLeft);
|
|
}
|
|
if (__fLeft < right && (!IsInPolygon(right, yMin) && !IsInPolygon(right, yMax)))
|
|
{
|
|
RectF oRectRight(__fLeft, yMin, right - __fLeft, yMax - yMin);
|
|
oArray.Add(oRectRight);
|
|
}
|
|
}
|
|
|
|
void CalcCrosses(const REAL& left, const REAL& right, const REAL& y, REAL& fMin, REAL& fMax)
|
|
{
|
|
CArray<REAL> oArray;
|
|
size_t lCount = m_arPoints.GetCount();
|
|
|
|
for (size_t i = 0; i < lCount; ++i)
|
|
{
|
|
size_t j = i + 1;
|
|
if (j == lCount)
|
|
--j;
|
|
|
|
REAL fCrossX = 0;
|
|
if (Cross(left, right, y, m_arPoints[i], m_arPoints[j], fCrossX))
|
|
{
|
|
oArray.Add(fCrossX);
|
|
}
|
|
}
|
|
|
|
fMin = right;
|
|
fMax = left;
|
|
|
|
lCount = oArray.GetCount();
|
|
for (size_t i = 0; i < lCount; ++i)
|
|
{
|
|
if (oArray[i] < fMin)
|
|
fMin = oArray[i];
|
|
|
|
if (oArray[i] > fMax)
|
|
fMax = oArray[i];
|
|
}
|
|
}
|
|
|
|
BOOL IsInPolygon(const float& pointX, const float& pointY)
|
|
{
|
|
if (3 > m_arPoints.GetCount())
|
|
return FALSE;
|
|
|
|
int yflag0, yflag1, inside_flag;
|
|
float vtx0, vty0, vtx1, vty1;
|
|
|
|
int num_points = (int)m_arPoints.GetCount();
|
|
|
|
vtx0 = m_arPoints[num_points - 1].X;
|
|
vty0 = m_arPoints[num_points - 1].Y;
|
|
|
|
yflag0 = (vty0 >= pointY);
|
|
|
|
vtx1 = m_arPoints[0].X;
|
|
vty1 = m_arPoints[0].Y;
|
|
|
|
inside_flag = 0;
|
|
for (int j = 1; j <= num_points; ++j)
|
|
{
|
|
yflag1 = (vty1 >= pointY);
|
|
if (yflag0 != yflag1)
|
|
{
|
|
if ( ((vty1-pointY) * (vtx0-vtx1) >= (vtx1-pointX) * (vty0-vty1)) == yflag1 )
|
|
{
|
|
inside_flag ^= 1;
|
|
}
|
|
}
|
|
|
|
yflag0 = yflag1;
|
|
vtx0 = vtx1;
|
|
vty0 = vty1;
|
|
|
|
int k = (j >= num_points) ? j - num_points : j;
|
|
vtx1 = m_arPoints[k].X;
|
|
vty1 = m_arPoints[k].Y;
|
|
}
|
|
return inside_flag != 0;
|
|
}
|
|
|
|
BOOL Cross(const REAL& fX1, const REAL& fX2, const REAL& fY, const PointF& oPoint1, const PointF& oPoint2, REAL& fCrossX)
|
|
{
|
|
double x1 = (double)fX1;
|
|
double x2 = (double)fX2;
|
|
double y1 = (double)fY;
|
|
|
|
double x3 = (double)oPoint1.X;
|
|
double y3 = (double)oPoint1.Y;
|
|
double x4 = (double)oPoint2.X;
|
|
double y4 = (double)oPoint2.Y;
|
|
|
|
double dZnam = (y4 - y3) * (x2 - x1);// - (x4 - x3) * (y2 - y1);
|
|
|
|
if (0 == dZnam)
|
|
return FALSE;
|
|
|
|
double dCisl1 = (x4 - x3) * (y1 - y3) - (y4 - y3) * (x1 - x3);
|
|
double dCisl2 = (x2 - x1) * (y1 - y3);// - (y2 - y1) * (x1 - x3);
|
|
|
|
double dT1 = dCisl1 / dZnam;
|
|
double dT2 = dCisl2 / dZnam;
|
|
|
|
if ((0 >= dT1) || (dT1 >= 1) || (0 >= dT2) || (dT2 >= 1))
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
// ...
|
|
fCrossX = (REAL)(x1 + dT1 * (x2 - x1));
|
|
//double dY = y1 + dT1 * (y2 - y1);
|
|
|
|
return TRUE;
|
|
}
|
|
};
|
|
|
|
class CWrapRegion
|
|
{
|
|
public:
|
|
class CLinePoint
|
|
{
|
|
public:
|
|
REAL point;
|
|
bool bLeft;
|
|
|
|
public:
|
|
CLinePoint()
|
|
{
|
|
point = 0;
|
|
bLeft = true;
|
|
}
|
|
CLinePoint(REAL p, bool b)
|
|
{
|
|
point = p;
|
|
bLeft = b;
|
|
}
|
|
CLinePoint(const CLinePoint& oSrc)
|
|
{
|
|
*this = oSrc;
|
|
}
|
|
CLinePoint& operator=(const CLinePoint& oSrc)
|
|
{
|
|
point = oSrc.point;
|
|
bLeft = oSrc.bLeft;
|
|
|
|
return *this;
|
|
}
|
|
friend bool operator>(const CLinePoint& a, const CLinePoint& b)
|
|
{
|
|
return (a.point > b.point) ? true : false;
|
|
}
|
|
friend bool operator>=(const CLinePoint& a, const CLinePoint& b)
|
|
{
|
|
return (a.point >= b.point) ? true : false;
|
|
}
|
|
friend bool operator<(const CLinePoint& a, const CLinePoint& b)
|
|
{
|
|
return (a.point < b.point) ? true : false;
|
|
}
|
|
friend bool operator<=(const CLinePoint& a, const CLinePoint& b)
|
|
{
|
|
return (a.point <= b.point) ? true : false;
|
|
}
|
|
~CLinePoint()
|
|
{
|
|
}
|
|
};
|
|
|
|
private:
|
|
CArray<CWrapPolygon> m_arPolygons;
|
|
CAtlArray<REAL> m_arDistanceLeft;
|
|
CAtlArray<REAL> m_arDistanceRight;
|
|
|
|
public:
|
|
CWrapRegion()
|
|
: m_arPolygons(),
|
|
m_arDistanceLeft(), m_arDistanceRight()
|
|
{
|
|
}
|
|
CWrapRegion(const CWrapRegion& oSrc)
|
|
{
|
|
*this = oSrc;
|
|
}
|
|
CWrapRegion& operator=(const CWrapRegion& oSrc)
|
|
{
|
|
m_arPolygons.Copy(oSrc.m_arPolygons);
|
|
m_arDistanceLeft.Copy(oSrc.m_arDistanceLeft);
|
|
m_arDistanceRight.Copy(oSrc.m_arDistanceRight);
|
|
|
|
return *this;
|
|
}
|
|
~CWrapRegion()
|
|
{
|
|
}
|
|
|
|
public:
|
|
void Add(const CWrapPolygon& oSrc, const REAL& fDistanceLeft = 0.0f, const REAL& fDistanceRight = 0.0f)
|
|
{
|
|
m_arPolygons.Add(oSrc);
|
|
m_arDistanceLeft.Add(fDistanceLeft);
|
|
m_arDistanceRight.Add(fDistanceRight);
|
|
}
|
|
void RemoveAll()
|
|
{
|
|
m_arPolygons.RemoveAll();
|
|
}
|
|
void RemoveAt(size_t nIndex)
|
|
{
|
|
m_arPolygons.RemoveAt(nIndex);
|
|
}
|
|
|
|
public:
|
|
void Calculate(const RectF oLineRect, CArray<RectF>& oArray)
|
|
{
|
|
oArray.RemoveAll();
|
|
|
|
size_t lCount = m_arPolygons.GetCount();
|
|
if (0 == lCount)
|
|
{
|
|
oArray.Add(oLineRect);
|
|
return;
|
|
}
|
|
|
|
CArray<RectF>* pRects = new CArray<RectF>[lCount];
|
|
|
|
for (size_t i = 0; i < lCount; ++i)
|
|
{
|
|
m_arPolygons[i].Calculate(oLineRect, pRects[i]);
|
|
ApplyDistance(oLineRect, pRects[i], m_arDistanceLeft[i], m_arDistanceRight[i]);
|
|
}
|
|
|
|
CArray<CLinePoint> oLineBounds;
|
|
for (size_t lIndexPolygon = 0; lIndexPolygon < lCount; ++lIndexPolygon)
|
|
{
|
|
if (pRects[lIndexPolygon].GetCount() == 0)
|
|
{
|
|
RELEASEARRAYOBJECTS(pRects);
|
|
return;
|
|
}
|
|
for (size_t i = 0; i < pRects[lIndexPolygon].GetCount(); ++i)
|
|
{
|
|
CLinePoint oPointL(pRects[lIndexPolygon][i].X, true);
|
|
oLineBounds.Add(oPointL);
|
|
|
|
CLinePoint oPointR(pRects[lIndexPolygon][i].GetRight(), false);
|
|
oLineBounds.Add(oPointR);
|
|
}
|
|
}
|
|
|
|
oLineBounds.Sort();
|
|
|
|
RELEASEARRAYOBJECTS(pRects);
|
|
|
|
REAL fY = oLineRect.Y;
|
|
REAL fHeight = oLineRect.Height;
|
|
|
|
REAL fLeft = oLineRect.X;
|
|
REAL fRight = left;
|
|
|
|
size_t nCurIndex = 0;
|
|
size_t nCount = oLineBounds.GetCount();
|
|
|
|
bool bFoundLeft = false;
|
|
|
|
while (nCurIndex < nCount)
|
|
{
|
|
while (!oLineBounds[nCurIndex].bLeft)
|
|
{
|
|
++nCurIndex;
|
|
|
|
if (nCurIndex == nCount)
|
|
{
|
|
//
|
|
return;
|
|
}
|
|
|
|
continue;
|
|
}
|
|
|
|
while (oLineBounds[nCurIndex].bLeft)
|
|
{
|
|
++nCurIndex;
|
|
continue;
|
|
}
|
|
|
|
fLeft = oLineBounds[nCurIndex - 1].point;
|
|
fRight = oLineBounds[nCurIndex].point;
|
|
|
|
RectF oRect(fLeft, fY, fRight - fLeft, fHeight);
|
|
oArray.Add(oRect);
|
|
|
|
++nCurIndex;
|
|
}
|
|
}
|
|
void ApplyDistance(const RectF& oLineRect, CArray<RectF>& arrRects, const REAL& fDistanceLeft, const REAL& fDistanceRight)
|
|
{
|
|
if (arrRects.GetCount() == 0)
|
|
{
|
|
return;
|
|
}
|
|
BYTE nFirst = 0;
|
|
if ((fDistanceLeft != 0) && (arrRects[nFirst].GetRight() != oLineRect.GetRight()))
|
|
{
|
|
arrRects[nFirst].Width -= fDistanceLeft;
|
|
if (arrRects[nFirst].Width <= 0)
|
|
{
|
|
arrRects.RemoveAt(nFirst);
|
|
}
|
|
}
|
|
|
|
if (arrRects.GetCount() == 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
size_t nLast = arrRects.GetCount() - 1;
|
|
if ((fDistanceRight != 0) && (arrRects[nLast].X != oLineRect.X))
|
|
{
|
|
arrRects[nLast].Width -= fDistanceRight;
|
|
arrRects[nLast].X += fDistanceRight;
|
|
if (arrRects[nLast].Width <= 0)
|
|
{
|
|
arrRects.RemoveAt(nLast);
|
|
}
|
|
}
|
|
}
|
|
};
|
|
}
|
|
}
|
|
}
|
|
} |