[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)
*/
#include <esvg/join.h>
#include <esvg/cap.h>
#ifndef __ESVG_BASE_H__
#define __ESVG_BASE_H__
@ -38,18 +42,6 @@ namespace esvg {
spread_repead, //!< 'repead' spread.
};
enum cap {
cap_butt,
cap_round,
cap_square
};
enum join {
join_miter,
join_round,
join_bevel
};
class PaintState {
public:
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/debug.h>
#include <etk/math/Matrix2.h>
#undef __class__
@ -145,9 +147,9 @@ void esvg::render::SegmentList::createSegmentListStroke(esvg::render::PointList&
}
}
// create segment list:
bool haveStartLine;
vec2 leftPoint;
vec2 rightPoint;
bool haveStartLine = false;
vec2 leftPoint(0,0);
vec2 rightPoint(0,0);
if (itListPoint.size() > 0) {
if (itListPoint.front().m_type == esvg::render::Point::type_join) {
// cyclic path...
@ -173,85 +175,30 @@ void esvg::render::SegmentList::createSegmentListStroke(esvg::render::PointList&
SVG_VERBOSE("Find Single " << it.m_pos);
break;
case esvg::render::Point::type_start:
{
SVG_VERBOSE("Find Start " << it.m_pos);
if (haveStartLine == true) {
// close previous :
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;
SVG_VERBOSE("Find Start " << it.m_pos);
if (haveStartLine == true) {
// close previous :
SVG_WARNING(" find a non close path ...");
addSegment(leftPoint, rightPoint);
SVG_VERBOSE(" segment :" << leftPoint << " -> " << rightPoint);
}
haveStartLine = true;
startStopPoint(leftPoint, rightPoint, it, _cap, _width, true);
break;
case esvg::render::Point::type_stop:
{
SVG_VERBOSE("Find Stop " << it.m_pos);
if (haveStartLine == false) {
SVG_WARNING("find close path without start part ...");
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);
SVG_VERBOSE("Find Stop " << it.m_pos);
if (haveStartLine == false) {
SVG_WARNING("find close path without start part ...");
break;
}
haveStartLine = false;
startStopPoint(leftPoint, rightPoint, it, _cap, _width, false);
break;
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:
{
SVG_VERBOSE("Find Join " << 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
SVG_VERBOSE("Find interpolation/join " << it.m_pos);
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);
//Draw from previous point:
addSegment(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,
enum esvg::cap _cap,
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);
}
}
// 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);
}
}

View File

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

View File

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

View File

@ -16,7 +16,8 @@
TEST(TestCap, butt) {
std::string data("<?xml version='1.0' encoding='UTF-8' standalone='no'?>"
"<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>");
esvg::Document doc;
doc.parse(data);
@ -27,7 +28,8 @@ TEST(TestCap, butt) {
TEST(TestCap, round) {
std::string data("<?xml version='1.0' encoding='UTF-8' standalone='no'?>"
"<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>");
esvg::Document doc;
doc.parse(data);
@ -38,7 +40,8 @@ TEST(TestCap, round) {
TEST(TestCap, square) {
std::string data("<?xml version='1.0' encoding='UTF-8' standalone='no'?>"
"<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>");
esvg::Document doc;
doc.parse(data);
@ -46,3 +49,115 @@ TEST(TestCap, square) {
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) {
std::string data("<?xml version='1.0' encoding='UTF-8' standalone='no'?>"
"<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' />"
"</svg>");
esvg::Document doc;