[DEV] add cap of the line with corect display add bug more visible

This commit is contained in:
Edouard DUPIN 2015-11-27 22:35:10 +01:00
parent eca4520384
commit 9e5b150ec3
10 changed files with 336 additions and 90 deletions

View File

@ -6,6 +6,10 @@
* @license APACHE v2.0 (see license file) * @license APACHE v2.0 (see license file)
*/ */
#include <esvg/join.h>
#include <esvg/cap.h>
#ifndef __ESVG_BASE_H__ #ifndef __ESVG_BASE_H__
#define __ESVG_BASE_H__ #define __ESVG_BASE_H__
@ -38,18 +42,6 @@ namespace esvg {
spread_repead, //!< 'repead' spread. spread_repead, //!< 'repead' spread.
}; };
enum cap {
cap_butt,
cap_round,
cap_square
};
enum join {
join_miter,
join_round,
join_bevel
};
class PaintState { class PaintState {
public: public:
PaintState(); PaintState();

22
esvg/cap.h Normal file
View File

@ -0,0 +1,22 @@
/**
* @author Edouard DUPIN
*
* @copyright 2011, Edouard DUPIN, all right reserved
*
* @license APACHE v2.0 (see license file)
*/
#ifndef __ESVG_CAP_H__
#define __ESVG_CAP_H__
#include <etk/types.h>
namespace esvg {
enum cap {
cap_butt,
cap_round,
cap_square
};
}
#endif

23
esvg/join.h Normal file
View File

@ -0,0 +1,23 @@
/**
* @author Edouard DUPIN
*
* @copyright 2011, Edouard DUPIN, all right reserved
*
* @license APACHE v2.0 (see license file)
*/
#ifndef __ESVG_JOIN_H__
#define __ESVG_JOIN_H__
#include <etk/types.h>
namespace esvg {
enum join {
join_miter,
join_round,
join_bevel
};
}
#endif

View File

@ -8,6 +8,8 @@
#include <esvg/render/SegmentList.h> #include <esvg/render/SegmentList.h>
#include <esvg/debug.h> #include <esvg/debug.h>
#include <etk/math/Matrix2.h>
#undef __class__ #undef __class__
@ -145,9 +147,9 @@ void esvg::render::SegmentList::createSegmentListStroke(esvg::render::PointList&
} }
} }
// create segment list: // create segment list:
bool haveStartLine; bool haveStartLine = false;
vec2 leftPoint; vec2 leftPoint(0,0);
vec2 rightPoint; vec2 rightPoint(0,0);
if (itListPoint.size() > 0) { if (itListPoint.size() > 0) {
if (itListPoint.front().m_type == esvg::render::Point::type_join) { if (itListPoint.front().m_type == esvg::render::Point::type_join) {
// cyclic path... // cyclic path...
@ -173,85 +175,30 @@ void esvg::render::SegmentList::createSegmentListStroke(esvg::render::PointList&
SVG_VERBOSE("Find Single " << it.m_pos); SVG_VERBOSE("Find Single " << it.m_pos);
break; break;
case esvg::render::Point::type_start: case esvg::render::Point::type_start:
{ SVG_VERBOSE("Find Start " << it.m_pos);
SVG_VERBOSE("Find Start " << it.m_pos); if (haveStartLine == true) {
if (haveStartLine == true) { // close previous :
// close previous : SVG_WARNING(" find a non close path ...");
SVG_WARNING(" find a non close path ...");
addSegment(leftPoint, rightPoint);
}
haveStartLine = true;
leftPoint = it.m_pos
+ it.m_miterAxe*_width*0.5f;
rightPoint = it.m_pos
- it.m_miterAxe*_width*0.5f;
addSegment(leftPoint, rightPoint); addSegment(leftPoint, rightPoint);
SVG_VERBOSE(" segment :" << leftPoint << " -> " << rightPoint);
} }
haveStartLine = true;
startStopPoint(leftPoint, rightPoint, it, _cap, _width, true);
break; break;
case esvg::render::Point::type_stop: case esvg::render::Point::type_stop:
{ SVG_VERBOSE("Find Stop " << it.m_pos);
SVG_VERBOSE("Find Stop " << it.m_pos); if (haveStartLine == false) {
if (haveStartLine == false) { SVG_WARNING("find close path without start part ...");
SVG_WARNING("find close path without start part ..."); break;
break;
}
haveStartLine = false;
vec2 left = it.m_pos
+ it.m_miterAxe*_width*0.5f;
vec2 right = it.m_pos
- it.m_miterAxe*_width*0.5f;
//Draw from previous point:
addSegment(leftPoint, left);
SVG_VERBOSE(" segment :" << leftPoint << " -> " << left);
addSegment(right, rightPoint);
SVG_VERBOSE(" segment :" << right << " -> " << rightPoint);
leftPoint = left;
rightPoint = right;
// end line ...
if (rightPoint.y() <= leftPoint.y()) {
addSegment(leftPoint, rightPoint);
} else {
addSegment(rightPoint, leftPoint);
}
SVG_VERBOSE(" segment :" << rightPoint << " -> " << leftPoint);
} }
haveStartLine = false;
startStopPoint(leftPoint, rightPoint, it, _cap, _width, false);
break; break;
case esvg::render::Point::type_interpolation: case esvg::render::Point::type_interpolation:
{
SVG_VERBOSE("Find interpolation " << it.m_pos);
// TODO : Calculate intersection ... (now we do a simple fast test of path display ...)
#if 1
vec2 left = getIntersect(leftPoint, it.m_pos-it.m_posPrevious, it.m_pos, it.m_miterAxe);
vec2 right = getIntersect(rightPoint, it.m_pos-it.m_posPrevious, it.m_pos, it.m_miterAxe);
#else
vec2 left = it.m_pos
+ it.m_miterAxe*_width*0.5f;
vec2 right = it.m_pos
- it.m_miterAxe*_width*0.5f;
#endif
//Draw from previous point:
addSegment(leftPoint, left);
SVG_VERBOSE(" segment :" << leftPoint << " -> " << left);
addSegment(right, rightPoint);
SVG_VERBOSE(" segment :" << right << " -> " << rightPoint);
leftPoint = left;
rightPoint = right;
}
break;
case esvg::render::Point::type_join: case esvg::render::Point::type_join:
{ {
SVG_VERBOSE("Find Join " << it.m_pos); SVG_VERBOSE("Find interpolation/join " << it.m_pos);
// TODO : Calculate intersection ... (now we do a simple fast test of path display ...) vec2 left = getIntersect(leftPoint, it.m_pos-it.m_posPrevious, it.m_pos, it.m_miterAxe);
#if 1 vec2 right = getIntersect(rightPoint, it.m_pos-it.m_posPrevious, it.m_pos, it.m_miterAxe);
vec2 left = getIntersect(leftPoint, it.m_pos-it.m_posPrevious, it.m_pos, it.m_miterAxe);
vec2 right = getIntersect(rightPoint, it.m_pos-it.m_posPrevious, it.m_pos, it.m_miterAxe);
#else
vec2 left = it.m_pos
+ it.m_miterAxe*_width*0.5f;
vec2 right = it.m_pos
- it.m_miterAxe*_width*0.5f;
#endif
//Draw from previous point: //Draw from previous point:
addSegment(leftPoint, left); addSegment(leftPoint, left);
SVG_VERBOSE(" segment :" << leftPoint << " -> " << left); SVG_VERBOSE(" segment :" << leftPoint << " -> " << left);
@ -269,3 +216,134 @@ void esvg::render::SegmentList::createSegmentListStroke(esvg::render::PointList&
} }
void esvg::render::SegmentList::startStopPoint(vec2& _leftPoint,
vec2& _rightPoint,
const esvg::render::Point& _point,
enum esvg::cap _cap,
float _width,
bool _isStart) {
switch (_cap) {
case cap_butt:
{
vec2 left = _point.m_pos
+ _point.m_miterAxe*_width*0.5f;
vec2 right = _point.m_pos
- _point.m_miterAxe*_width*0.5f;
if (_isStart == false) {
//Draw from previous point:
addSegment(_leftPoint, left);
SVG_VERBOSE(" segment :" << _leftPoint << " -> " << left);
addSegment(right, _rightPoint);
SVG_VERBOSE(" segment :" << right << " -> " << _rightPoint);
}
_leftPoint = left;
_rightPoint = right;
}
if (_isStart == false) {
addSegment(_leftPoint, _rightPoint);
SVG_VERBOSE(" segment :" << _leftPoint << " -> " << _rightPoint);
} else {
addSegment(_rightPoint, _leftPoint);
SVG_VERBOSE(" segment :" << _rightPoint << " -> " << _leftPoint);
}
break;
case cap_round:
{
if (_isStart == false) {
vec2 left = _point.m_pos
+ _point.m_miterAxe*_width*0.5f;
vec2 right = _point.m_pos
- _point.m_miterAxe*_width*0.5f;
if (_isStart == false) {
//Draw from previous point:
addSegment(_leftPoint, left);
SVG_VERBOSE(" segment :" << _leftPoint << " -> " << left);
addSegment(right, _rightPoint);
SVG_VERBOSE(" segment :" << right << " -> " << _rightPoint);
}
_leftPoint = left;
_rightPoint = right;
}
int32_t nbDot = int32_t(_width);
if (nbDot <= 2) {
nbDot = 2;
}
float baseAngle = M_PI/float(nbDot);
float iii;
_rightPoint = _point.m_pos
- _point.m_miterAxe*_width*0.5f;
vec2 storeOld(_rightPoint);
for (iii=baseAngle; iii<M_PI; iii+=baseAngle) {
mat2 tmpMat;
if (_isStart == true) {
tmpMat = etk::mat2Rotate(iii);
} else {
tmpMat = etk::mat2Rotate(-iii);
}
vec2 miterRotate = tmpMat * _point.m_miterAxe;
_leftPoint = _point.m_pos
- miterRotate*_width*0.5f;
if (_isStart == false) {
addSegment(_leftPoint, _rightPoint);
SVG_VERBOSE(" segment :" << _leftPoint << " -> " << _rightPoint);
} else {
addSegment(_rightPoint, _leftPoint);
SVG_VERBOSE(" segment :" << _rightPoint << " -> " << _leftPoint);
}
_rightPoint = _leftPoint;
}
_leftPoint = _point.m_pos
+ _point.m_miterAxe*_width*0.5f;
if (_isStart == false) {
addSegment(_leftPoint, _rightPoint);
SVG_VERBOSE(" segment :" << _leftPoint << " -> " << _rightPoint);
} else {
addSegment(_rightPoint, _leftPoint);
SVG_VERBOSE(" segment :" << _rightPoint << " -> " << _leftPoint);
}
_rightPoint = storeOld;
}
break;
case cap_square:
{
vec2 nextAxe;
if (_isStart == true) {
nextAxe = _point.m_posNext - _point.m_pos;
} else {
nextAxe = _point.m_posPrevious - _point.m_pos;
}
vec2 left = _point.m_pos
+ _point.m_miterAxe*_width*0.5f;
vec2 right = _point.m_pos
- _point.m_miterAxe*_width*0.5f;
mat2 tmpMat = etk::mat2Translate(nextAxe.safeNormalize()*_width*-0.5f);
left = tmpMat*left;
right = tmpMat*right;
if (_isStart == false) {
if (_isStart == false) {
//Draw from previous point:
addSegment(_leftPoint, left);
SVG_VERBOSE(" segment :" << _leftPoint << " -> " << left);
addSegment(right, _rightPoint);
SVG_VERBOSE(" segment :" << right << " -> " << _rightPoint);
}
}
_leftPoint = left;
_rightPoint = right;
if (_isStart == false) {
addSegment(_leftPoint, _rightPoint);
SVG_VERBOSE(" segment :" << _leftPoint << " -> " << _rightPoint);
} else {
addSegment(_rightPoint, _leftPoint);
SVG_VERBOSE(" segment :" << _rightPoint << " -> " << _leftPoint);
}
SVG_VERBOSE(" segment :" << _leftPoint << " -> " << _rightPoint);
}
break;
default:
SVG_ERROR(" Undefined CAP TYPE");
break;
}
}

View File

@ -29,6 +29,13 @@ namespace esvg {
float _width, float _width,
enum esvg::cap _cap, enum esvg::cap _cap,
enum esvg::join _join); enum esvg::join _join);
private:
void startStopPoint(vec2& _leftPoint,
vec2& _rightPoint,
const esvg::render::Point& _point,
enum esvg::cap _cap,
float _width,
bool _isStart);
}; };
} }
} }

View File

@ -169,6 +169,14 @@ void esvg::render::Weight::generate(ivec2 _size, int32_t _subSamplingCount, cons
scanline.set(currentPos, currentValue); scanline.set(currentPos, currentValue);
} }
} }
// if the counter is not at 0 ==> fill if to the end with full value ... 2.0
if (lastState != 0.0f) {
// just past the last state to the end of the image ...
SVG_ERROR("end of Path whith no end ... " << currentPos << " -> " << _size.x());
for (int32_t xxx=currentPos; xxx<_size.x(); ++xxx) {
scanline.set(xxx, 100.0);
}
}
append(yyy, scanline); append(yyy, scanline);
} }
} }

View File

@ -11,7 +11,6 @@
#include <etk/types.h> #include <etk/types.h>
#include <etk/math/Vector2D.h> #include <etk/math/Vector2D.h>
#include <esvg/Base.h>
#include <esvg/render/Scanline.h> #include <esvg/render/Scanline.h>
#include <esvg/render/SegmentList.h> #include <esvg/render/SegmentList.h>

View File

@ -77,6 +77,8 @@ def create(target, module_name):
'esvg/Renderer.h', 'esvg/Renderer.h',
'esvg/Stroking.h', 'esvg/Stroking.h',
'esvg/Text.h', 'esvg/Text.h',
'esvg/cap.h',
'esvg/join.h',
'esvg/render/Element.h', 'esvg/render/Element.h',
'esvg/render/ElementStop.h', 'esvg/render/ElementStop.h',
'esvg/render/ElementClose.h', 'esvg/render/ElementClose.h',

View File

@ -16,7 +16,8 @@
TEST(TestCap, butt) { TEST(TestCap, butt) {
std::string data("<?xml version='1.0' encoding='UTF-8' standalone='no'?>" std::string data("<?xml version='1.0' encoding='UTF-8' standalone='no'?>"
"<svg height='100' width='100'>" "<svg height='100' width='100'>"
" <polyline points='20,50 80,50' stroke='green' stroke-width='20' fill='none' stroke-linecap='butt'/>" " <polyline points='20,75 80,75' stroke='green' stroke-width='20' fill='none' stroke-linecap='butt'/>"
" <polyline points='80,25 20,25' stroke='orange' stroke-width='20' fill='none' stroke-linecap='butt'/>"
"</svg>"); "</svg>");
esvg::Document doc; esvg::Document doc;
doc.parse(data); doc.parse(data);
@ -27,7 +28,8 @@ TEST(TestCap, butt) {
TEST(TestCap, round) { TEST(TestCap, round) {
std::string data("<?xml version='1.0' encoding='UTF-8' standalone='no'?>" std::string data("<?xml version='1.0' encoding='UTF-8' standalone='no'?>"
"<svg height='100' width='100'>" "<svg height='100' width='100'>"
" <polyline points='20,50 80,50' stroke='green' stroke-width='20' fill='none' stroke-linecap='round'/>" " <polyline points='20,75 80,75' stroke='green' stroke-width='20' fill='none' stroke-linecap='round'/>"
" <polyline points='80,25 20,25' stroke='orange' stroke-width='20' fill='none' stroke-linecap='round'/>"
"</svg>"); "</svg>");
esvg::Document doc; esvg::Document doc;
doc.parse(data); doc.parse(data);
@ -38,7 +40,8 @@ TEST(TestCap, round) {
TEST(TestCap, square) { TEST(TestCap, square) {
std::string data("<?xml version='1.0' encoding='UTF-8' standalone='no'?>" std::string data("<?xml version='1.0' encoding='UTF-8' standalone='no'?>"
"<svg height='100' width='100'>" "<svg height='100' width='100'>"
" <polyline points='20,50 80,50' stroke='green' stroke-width='20' fill='none' stroke-linecap='square'/>" " <polyline points='20,75 80,75' stroke='green' stroke-width='20' fill='none' stroke-linecap='square'/>"
" <polyline points='80,25 20,25' stroke='orange' stroke-width='20' fill='none' stroke-linecap='square'/>"
"</svg>"); "</svg>");
esvg::Document doc; esvg::Document doc;
doc.parse(data); doc.parse(data);
@ -46,3 +49,115 @@ TEST(TestCap, square) {
doc.generateAnImage(ivec2(100, 100), "TestCap_square.bmp", g_visualDebug); doc.generateAnImage(ivec2(100, 100), "TestCap_square.bmp", g_visualDebug);
} }
TEST(TestCap, buttVert) {
std::string data("<?xml version='1.0' encoding='UTF-8' standalone='no'?>"
"<svg height='100' width='100'>"
" <polyline points='25,20 25,80' stroke='green' stroke-width='20' fill='none' stroke-linecap='butt'/>"
" <polyline points='75,80 75,20' stroke='orange' stroke-width='20' fill='none' stroke-linecap='butt'/>"
"</svg>");
esvg::Document doc;
doc.parse(data);
etk::FSNodeWriteAllData("TestCap_buttVert.svg", data);
doc.generateAnImage(ivec2(100, 100), "TestCap_buttVert.bmp", g_visualDebug);
}
TEST(TestCap, roundVert) {
std::string data("<?xml version='1.0' encoding='UTF-8' standalone='no'?>"
"<svg height='100' width='100'>"
" <polyline points='25,20 25,80' stroke='green' stroke-width='20' fill='none' stroke-linecap='round'/>"
" <polyline points='75,80 75,20' stroke='orange' stroke-width='20' fill='none' stroke-linecap='round'/>"
"</svg>");
esvg::Document doc;
doc.parse(data);
etk::FSNodeWriteAllData("TestCap_roundVert.svg", data);
doc.generateAnImage(ivec2(100, 100), "TestCap_roundVert.bmp", g_visualDebug);
}
TEST(TestCap, squareVert) {
std::string data("<?xml version='1.0' encoding='UTF-8' standalone='no'?>"
"<svg height='100' width='100'>"
" <polyline points='25,20 25,80' stroke='green' stroke-width='20' fill='none' stroke-linecap='square'/>"
" <polyline points='75,80 75,20' stroke='orange' stroke-width='20' fill='none' stroke-linecap='square'/>"
"</svg>");
esvg::Document doc;
doc.parse(data);
etk::FSNodeWriteAllData("TestCap_squareVert.svg", data);
doc.generateAnImage(ivec2(100, 100), "TestCap_squareVert.bmp", g_visualDebug);
}
TEST(TestCap, buttDiag1) {
std::string data("<?xml version='1.0' encoding='UTF-8' standalone='no'?>"
"<svg height='100' width='100'>"
" <polyline points='20,20 80,80' stroke='green' stroke-width='20' fill='none' stroke-linecap='butt'/>"
" <polyline points='80,20 20,80' stroke='orange' stroke-width='20' fill='none' stroke-linecap='butt'/>"
"</svg>");
esvg::Document doc;
doc.parse(data);
etk::FSNodeWriteAllData("TestCap_buttDiag1.svg", data);
doc.generateAnImage(ivec2(100, 100), "TestCap_buttDiag1.bmp", g_visualDebug);
}
TEST(TestCap, roundDiag1) {
std::string data("<?xml version='1.0' encoding='UTF-8' standalone='no'?>"
"<svg height='100' width='100'>"
" <polyline points='20,20 80,80' stroke='green' stroke-width='20' fill='none' stroke-linecap='round'/>"
" <polyline points='80,20 20,80' stroke='orange' stroke-width='20' fill='none' stroke-linecap='round'/>"
"</svg>");
esvg::Document doc;
doc.parse(data);
etk::FSNodeWriteAllData("TestCap_roundDiag1.svg", data);
doc.generateAnImage(ivec2(100, 100), "TestCap_roundDiag1.bmp", g_visualDebug);
}
TEST(TestCap, squareDiag1) {
std::string data("<?xml version='1.0' encoding='UTF-8' standalone='no'?>"
"<svg height='100' width='100'>"
" <polyline points='20,20 80,80' stroke='green' stroke-width='20' fill='none' stroke-linecap='square'/>"
" <polyline points='80,20 20,80' stroke='orange' stroke-width='20' fill='none' stroke-linecap='square'/>"
"</svg>");
esvg::Document doc;
doc.parse(data);
etk::FSNodeWriteAllData("TestCap_squareDiag1.svg", data);
doc.generateAnImage(ivec2(100, 100), "TestCap_squareDiag1.bmp", g_visualDebug);
}
TEST(TestCap, buttDiag2) {
std::string data("<?xml version='1.0' encoding='UTF-8' standalone='no'?>"
"<svg height='100' width='100'>"
" <polyline points='20,80 80,20' stroke='green' stroke-width='20' fill='none' stroke-linecap='butt'/>"
" <polyline points='80,80 20,20' stroke='orange' stroke-width='20' fill='none' stroke-linecap='butt'/>"
"</svg>");
esvg::Document doc;
doc.parse(data);
etk::FSNodeWriteAllData("TestCap_buttDiag2.svg", data);
doc.generateAnImage(ivec2(100, 100), "TestCap_buttDiag2.bmp", g_visualDebug);
}
TEST(TestCap, roundDiag2) {
std::string data("<?xml version='1.0' encoding='UTF-8' standalone='no'?>"
"<svg height='100' width='100'>"
" <polyline points='20,80 80,20' stroke='green' stroke-width='20' fill='none' stroke-linecap='round'/>"
" <polyline points='80,80 20,20' stroke='orange' stroke-width='20' fill='none' stroke-linecap='round'/>"
"</svg>");
esvg::Document doc;
doc.parse(data);
etk::FSNodeWriteAllData("TestCap_roundDiag2.svg", data);
doc.generateAnImage(ivec2(100, 100), "TestCap_roundDiag2.bmp", g_visualDebug);
}
TEST(TestCap, squareDiag2) {
std::string data("<?xml version='1.0' encoding='UTF-8' standalone='no'?>"
"<svg height='100' width='100'>"
" <polyline points='20,80 80,20' stroke='green' stroke-width='20' fill='none' stroke-linecap='square'/>"
" <polyline points='80,80 20,20' stroke='orange' stroke-width='20' fill='none' stroke-linecap='square'/>"
"</svg>");
esvg::Document doc;
doc.parse(data);
etk::FSNodeWriteAllData("TestCap_squareDiag2.svg", data);
doc.generateAnImage(ivec2(100, 100), "TestCap_squareDiag2.bmp", g_visualDebug);
}

View File

@ -94,7 +94,7 @@ TEST(TestPath, bezierCurveTo) {
TEST(TestPath, bezierSmoothCurveTo) { TEST(TestPath, bezierSmoothCurveTo) {
std::string data("<?xml version='1.0' encoding='UTF-8' standalone='no'?>" std::string data("<?xml version='1.0' encoding='UTF-8' standalone='no'?>"
"<svg height='100' width='100'>" "<svg height='100' width='100'>"
" <path d='m 50,50 t -20,20 z'" " <path d='m 50,50 t -20,30 t 30,-20 z'"
" fill='red' />" " fill='red' />"
"</svg>"); "</svg>");
esvg::Document doc; esvg::Document doc;