You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
424 lines
8.2 KiB
C++
424 lines
8.2 KiB
C++
// XTPMarkupPathGeometryBuilder.cpp: implementation of the CXTPMarkupPathGeometryBuilder class.
|
|
//
|
|
// This file is a part of the XTREME TOOLKIT PRO MFC class library.
|
|
// (c)1998-2012 Codejock Software, All Rights Reserved.
|
|
//
|
|
// THIS SOURCE FILE IS THE PROPERTY OF CODEJOCK SOFTWARE AND IS NOT TO BE
|
|
// RE-DISTRIBUTED BY ANY MEANS WHATSOEVER WITHOUT THE EXPRESSED WRITTEN
|
|
// CONSENT OF CODEJOCK SOFTWARE.
|
|
//
|
|
// THIS SOURCE CODE CAN ONLY BE USED UNDER THE TERMS AND CONDITIONS OUTLINED
|
|
// IN THE XTREME TOOLKIT PRO LICENSE AGREEMENT. CODEJOCK SOFTWARE GRANTS TO
|
|
// YOU (ONE SOFTWARE DEVELOPER) THE LIMITED RIGHT TO USE THIS SOFTWARE ON A
|
|
// SINGLE COMPUTER.
|
|
//
|
|
// CONTACT INFORMATION:
|
|
// support@codejock.com
|
|
// http://www.codejock.com
|
|
//
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
#include "StdAfx.h"
|
|
#include <math.h>
|
|
|
|
#include <Common/XTPVC80Helpers.h>
|
|
|
|
#include <Markup/XTPMarkupObject.h>
|
|
#include <Markup/XTPMarkupInputElement.h>
|
|
#include <Markup/XTPMarkupUIElement.h>
|
|
#include <Markup/XTPMarkupFrameworkElement.h>
|
|
#include <Markup/XTPMarkupShape.h>
|
|
#include <Markup/XTPMarkupDrawingContext.h>
|
|
#include <Markup/XTPMarkupBuilder.h>
|
|
#include <Markup/XTPMarkupThickness.h>
|
|
#include <Markup/Path/XTPMarkupPathData.h>
|
|
|
|
#ifdef _DEBUG
|
|
#undef THIS_FILE
|
|
static char THIS_FILE[]=__FILE__;
|
|
#define new DEBUG_NEW
|
|
#endif
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// CXTPMarkupPathGeometryBuilder
|
|
|
|
CXTPMarkupPathGeometryBuilder::CXTPMarkupPathGeometryBuilder()
|
|
{
|
|
m_lpszValue = NULL;
|
|
m_nLength = 0;
|
|
m_nIndex = 0;
|
|
m_cToken = 0;
|
|
m_bFigureStarted = FALSE;
|
|
m_pBuilder = 0;
|
|
m_nFillRule = 0;
|
|
}
|
|
|
|
void CXTPMarkupPathGeometryBuilder::ThrowBadToken()
|
|
{
|
|
if (m_pBuilder)
|
|
{
|
|
CString strError;
|
|
strError.Format(_T("Unexpected token encountered at position '%i'"), m_nIndex);
|
|
m_pBuilder->ThrowBuilderException(strError);
|
|
}
|
|
else
|
|
{
|
|
AfxThrowMemoryException();
|
|
}
|
|
}
|
|
|
|
BOOL CXTPMarkupPathGeometryBuilder::SkipWhiteSpace(BOOL allowComma)
|
|
{
|
|
BOOL flag = FALSE;
|
|
|
|
while (More())
|
|
{
|
|
WCHAR c = m_lpszValue[m_nIndex];
|
|
|
|
switch (c)
|
|
{
|
|
case '\t':
|
|
case '\n':
|
|
case '\r':
|
|
case ' ':
|
|
break;
|
|
|
|
case ',':
|
|
if (allowComma)
|
|
{
|
|
flag = TRUE;
|
|
allowComma = FALSE;
|
|
}
|
|
else
|
|
{
|
|
ThrowBadToken();
|
|
}
|
|
break;
|
|
|
|
default:
|
|
return flag;
|
|
break;
|
|
}
|
|
m_nIndex++;
|
|
}
|
|
return flag;
|
|
}
|
|
|
|
BOOL CXTPMarkupPathGeometryBuilder::More() const
|
|
{
|
|
return m_nIndex < m_nLength;
|
|
}
|
|
|
|
BOOL CXTPMarkupPathGeometryBuilder::ReadToken()
|
|
{
|
|
SkipWhiteSpace(FALSE);
|
|
if (More())
|
|
{
|
|
m_cToken = m_lpszValue[m_nIndex++];
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
BOOL CXTPMarkupPathGeometryBuilder::IsNumber(BOOL allowComma)
|
|
{
|
|
BOOL flag = SkipWhiteSpace(allowComma);
|
|
if (More())
|
|
{
|
|
m_cToken = m_lpszValue[m_nIndex];
|
|
if ((m_cToken == '.') || (m_cToken == '-') || (m_cToken == '+') || ((m_cToken >= '0') && (m_cToken <= '9')))
|
|
{
|
|
return TRUE;
|
|
}
|
|
}
|
|
if (flag)
|
|
{
|
|
ThrowBadToken();
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
MARKUP_POINTF CXTPMarkupPathGeometryBuilder::ReadPoint(WCHAR cmd, BOOL allowcomma)
|
|
{
|
|
MARKUP_POINTF pt;
|
|
pt.x = ReadNumber(allowcomma);
|
|
pt.y = ReadNumber(TRUE);
|
|
if (cmd >= 'a')
|
|
{
|
|
pt.x += m_lastPoint.x;
|
|
pt.y += m_lastPoint.y;
|
|
}
|
|
return pt;
|
|
}
|
|
|
|
float CXTPMarkupPathGeometryBuilder::ReadNumber(BOOL allowComma)
|
|
{
|
|
if (!IsNumber(allowComma))
|
|
{
|
|
ThrowBadToken();
|
|
}
|
|
|
|
BOOL bSign = FALSE;
|
|
|
|
if (m_lpszValue[m_nIndex] == '+')
|
|
{
|
|
m_nIndex++;
|
|
}
|
|
else if (m_lpszValue[m_nIndex] == '-')
|
|
{
|
|
m_nIndex++;
|
|
bSign = TRUE;
|
|
}
|
|
|
|
float dValue = 0;
|
|
|
|
while (m_lpszValue[m_nIndex] >= '0' && m_lpszValue[m_nIndex] <= '9')
|
|
{
|
|
WCHAR c = m_lpszValue[m_nIndex];
|
|
dValue = 10 * dValue + (c - '0');
|
|
|
|
m_nIndex++;
|
|
}
|
|
if (m_lpszValue[m_nIndex] == '.')
|
|
{
|
|
float dDecimal = 1;
|
|
|
|
m_nIndex++;
|
|
while (m_lpszValue[m_nIndex] >= '0' && m_lpszValue[m_nIndex] <= '9')
|
|
{
|
|
WCHAR c = m_lpszValue[m_nIndex];
|
|
|
|
dDecimal /= 10;
|
|
dValue += dDecimal * float(c - '0');
|
|
|
|
m_nIndex++;
|
|
}
|
|
}
|
|
|
|
|
|
return bSign ? -dValue : dValue;
|
|
}
|
|
|
|
void CXTPMarkupPathGeometryBuilder::EnsureFigure()
|
|
{
|
|
if (!m_bFigureStarted)
|
|
{
|
|
BeginFigure(m_lastStart.x, m_lastStart.y);
|
|
m_bFigureStarted = TRUE;
|
|
}
|
|
}
|
|
|
|
MARKUP_POINTF CXTPMarkupPathGeometryBuilder::Reflect()
|
|
{
|
|
MARKUP_POINTF pt = {(2.0f * m_lastPoint.x) - m_secondLastPoint.x, (2.0f * m_lastPoint.y) - m_secondLastPoint.y};
|
|
return pt;
|
|
}
|
|
|
|
void CXTPMarkupPathGeometryBuilder::Parse(CXTPMarkupBuilder* pBuilder, LPCWSTR lpszValue, int nLength)
|
|
{
|
|
m_pBuilder = pBuilder;
|
|
m_lpszValue = lpszValue;
|
|
m_nLength = nLength;
|
|
|
|
m_arrPoints.RemoveAll();
|
|
m_arrTypes.RemoveAll();
|
|
|
|
MARKUP_POINTF ptZero = {0, 0};
|
|
m_secondLastPoint = ptZero;
|
|
m_lastPoint = ptZero;
|
|
m_lastStart = ptZero;
|
|
m_bFigureStarted = FALSE;
|
|
|
|
BOOL bFirstToken = TRUE;
|
|
WCHAR ch3 = ' ';
|
|
|
|
while (ReadToken())
|
|
{
|
|
WCHAR cmd = m_cToken;
|
|
if (bFirstToken)
|
|
{
|
|
if (cmd == 'F')
|
|
{
|
|
if (!IsNumber(FALSE))
|
|
ThrowBadToken();
|
|
|
|
if (m_lpszValue[m_nIndex] != '0' && m_lpszValue[m_nIndex] != '1')
|
|
ThrowBadToken();
|
|
|
|
m_nFillRule = m_lpszValue[m_nIndex] - '0';
|
|
m_nIndex++;
|
|
|
|
continue;
|
|
}
|
|
if ((cmd != 'M') && (cmd != 'm'))
|
|
{
|
|
ThrowBadToken();
|
|
}
|
|
bFirstToken = FALSE;
|
|
}
|
|
|
|
switch (cmd)
|
|
{
|
|
case 'L':
|
|
case 'V':
|
|
case 'H':
|
|
case 'h':
|
|
case 'l':
|
|
case 'v':
|
|
{
|
|
EnsureFigure();
|
|
do
|
|
{
|
|
switch (cmd)
|
|
{
|
|
case 'h':
|
|
m_lastPoint.x += ReadNumber(FALSE);
|
|
break;
|
|
|
|
case 'l':
|
|
m_lastPoint = ReadPoint(cmd, FALSE);
|
|
break;
|
|
|
|
case 'v':
|
|
m_lastPoint.y += ReadNumber(FALSE);
|
|
break;
|
|
|
|
case 'H':
|
|
m_lastPoint.x = ReadNumber(FALSE);
|
|
break;
|
|
|
|
case 'L':
|
|
m_lastPoint = ReadPoint(cmd, FALSE);
|
|
break;
|
|
|
|
case 'V':
|
|
m_lastPoint.y = ReadNumber(FALSE);
|
|
break;
|
|
}
|
|
LineTo(m_lastPoint.x, m_lastPoint.y);
|
|
}
|
|
while (IsNumber(TRUE));
|
|
ch3 = 'L';
|
|
continue;
|
|
}
|
|
|
|
case 'M':
|
|
case 'm':
|
|
{
|
|
m_lastPoint = ReadPoint(cmd, FALSE);
|
|
BeginFigure(m_lastPoint.x, m_lastPoint.y);
|
|
m_bFigureStarted = TRUE;
|
|
m_lastStart = m_lastPoint;
|
|
ch3 = 'M';
|
|
while (IsNumber(TRUE))
|
|
{
|
|
m_lastPoint = ReadPoint(cmd, FALSE);
|
|
LineTo(m_lastPoint.x, m_lastPoint.y);
|
|
ch3 = 'L';
|
|
}
|
|
continue;
|
|
}
|
|
|
|
case 'S':
|
|
case 'C':
|
|
case 'c':
|
|
case 's':
|
|
{
|
|
EnsureFigure();
|
|
do
|
|
{
|
|
MARKUP_POINTF point;
|
|
switch (cmd)
|
|
{
|
|
case 's':
|
|
case 'S':
|
|
if (ch3 == 'C')
|
|
{
|
|
point = Reflect();
|
|
}
|
|
else
|
|
{
|
|
point = m_lastPoint;
|
|
}
|
|
m_secondLastPoint = ReadPoint(cmd, FALSE);
|
|
break;
|
|
|
|
default:
|
|
point = ReadPoint(cmd, FALSE);
|
|
m_secondLastPoint = ReadPoint(cmd, TRUE);
|
|
break;
|
|
}
|
|
m_lastPoint = ReadPoint(cmd, TRUE);
|
|
BezierTo(point.x, point.y, m_secondLastPoint.x, m_secondLastPoint.y, m_lastPoint.x, m_lastPoint.y);
|
|
ch3 = 'C';
|
|
}
|
|
while (IsNumber(TRUE));
|
|
continue;
|
|
}
|
|
|
|
case 'Z':
|
|
case 'z':
|
|
{
|
|
EnsureFigure();
|
|
CloseFigure();
|
|
m_bFigureStarted = FALSE;
|
|
ch3 = 'Z';
|
|
m_lastPoint = m_lastStart;
|
|
continue;
|
|
}
|
|
|
|
default:
|
|
ThrowBadToken();
|
|
}
|
|
}
|
|
}
|
|
|
|
CXTPMarkupPathData* CXTPMarkupPathGeometryBuilder::CreateData() const
|
|
{
|
|
return new CXTPMarkupPathData(m_arrPoints.GetData(), m_arrTypes.GetData(), (int)m_arrTypes.GetSize());
|
|
}
|
|
|
|
void CXTPMarkupPathGeometryBuilder::BeginFigure(float x, float y)
|
|
{
|
|
MARKUP_POINTF startPoint = {x, y};
|
|
m_arrPoints.Add(startPoint);
|
|
m_arrTypes.Add(xtpMarkupPathPointTypeStart);
|
|
}
|
|
|
|
void CXTPMarkupPathGeometryBuilder::BezierTo(float x1, float y1, float x2, float y2, float x3, float y3)
|
|
{
|
|
MARKUP_POINTF point1 = {x1, y1};
|
|
MARKUP_POINTF point2 = {x2, y2};
|
|
MARKUP_POINTF point3 = {x3, y3};
|
|
|
|
m_arrPoints.Add(point1);
|
|
m_arrPoints.Add(point2);
|
|
m_arrPoints.Add(point3);
|
|
|
|
m_arrTypes.Add(xtpMarkupPathPointTypeBezier);
|
|
m_arrTypes.Add(xtpMarkupPathPointTypeBezier);
|
|
m_arrTypes.Add(xtpMarkupPathPointTypeBezier);
|
|
}
|
|
|
|
void CXTPMarkupPathGeometryBuilder::BezierTo(float x1, float y1, float x2, float y2)
|
|
{
|
|
BezierTo(x1, y1, x2, y2, x2, y2);
|
|
}
|
|
|
|
void CXTPMarkupPathGeometryBuilder::LineTo(float x, float y)
|
|
{
|
|
MARKUP_POINTF point = {x, y};
|
|
m_arrPoints.Add(point);
|
|
m_arrTypes.Add(xtpMarkupPathPointTypeLine);
|
|
}
|
|
|
|
void CXTPMarkupPathGeometryBuilder::CloseFigure()
|
|
{
|
|
if (m_arrTypes.GetSize() > 0)
|
|
{
|
|
m_arrTypes[m_arrTypes.GetSize() - 1] = BYTE(m_arrTypes[m_arrTypes.GetSize() - 1] | xtpMarkupPathPointTypeCloseSubpath);
|
|
}
|
|
}
|