[DEV] radial gradient correct the non center focal position
This commit is contained in:
parent
dbbd996850
commit
83f0a8128f
@ -13,7 +13,7 @@
|
||||
#include <esvg/esvg.h>
|
||||
|
||||
#undef __class__
|
||||
#define __class__ "render:DynamicColorSpecial"
|
||||
#define __class__ "render::DynamicColorSpecial"
|
||||
|
||||
esvg::render::DynamicColorSpecial::DynamicColorSpecial(const std::string& _link, const mat2& _mtx) :
|
||||
m_linear(true),
|
||||
@ -155,35 +155,98 @@ etk::Color<float,4> esvg::render::DynamicColorSpecial::getColorLinear(const ivec
|
||||
}
|
||||
return etk::color::green;
|
||||
}
|
||||
static std::pair<vec2,vec2> intersectLineToCircle(const vec2& _pos1,
|
||||
const vec2& _pos2,
|
||||
const vec2& _center = vec2(0.0f, 0.0f),
|
||||
float _radius = 1.0f) {
|
||||
vec2 v1;
|
||||
vec2 v2;
|
||||
//vector2D from point 1 to point 2
|
||||
v1 = _pos2 - _pos1;
|
||||
//vector2D from point 1 to the circle's center
|
||||
v2 = _center - _pos1;
|
||||
|
||||
float dot = v1.dot(v2);
|
||||
vec2 proj1 = vec2(((dot / (v1.length2())) * v1.x()),
|
||||
((dot / (v1.length2())) * v1.y()));
|
||||
vec2 midpt = _pos1 + proj1;
|
||||
|
||||
float distToCenter = (midpt - _center).length2();
|
||||
if (distToCenter > _radius * _radius) {
|
||||
return std::pair<vec2,vec2>(vec2(0.0,0.0), vec2(0.0,0.0));
|
||||
}
|
||||
if (distToCenter == _radius * _radius) {
|
||||
return std::pair<vec2,vec2>(midpt, midpt);
|
||||
}
|
||||
float distToIntersection;
|
||||
if (distToCenter == 0.0f) {
|
||||
distToIntersection = _radius;
|
||||
} else {
|
||||
distToCenter = std::sqrt(distToCenter);
|
||||
distToIntersection = std::sqrt(_radius * _radius - distToCenter * distToCenter);
|
||||
}
|
||||
// normalize...
|
||||
v1.safeNormalize();
|
||||
v1 *= distToIntersection;
|
||||
return std::pair<vec2,vec2>(midpt + v1, midpt - v1);
|
||||
}
|
||||
|
||||
etk::Color<float,4> esvg::render::DynamicColorSpecial::getColorRadial(const ivec2& _pos) {
|
||||
float ratio = 0.0f;
|
||||
// in the basic vertion of the gradient the color is calculated with the ration in X and Y in the bonding box associated (it is rotate with the object..
|
||||
vec2 intersecX = getIntersect(m_pos1, m_axeX,
|
||||
// in the basic vertion of the gradient the color is calculated with the ration in X and Y in the bonding box associated (it is rotate with the object)..
|
||||
vec2 intersecX = getIntersect(m_pos1, m_axeX,
|
||||
vec2(_pos.x(), _pos.y()), m_axeY);
|
||||
vec2 intersecY = getIntersect(m_pos1, m_axeY,
|
||||
vec2 intersecY = getIntersect(m_pos1, m_axeY,
|
||||
vec2(_pos.x(), _pos.y()), m_axeX);
|
||||
vec2 vectorBaseDrawX = intersecX - m_pos1;
|
||||
vec2 vectorBaseDrawY = intersecY - m_pos1;
|
||||
float baseDrawX = vectorBaseDrawX.length();
|
||||
float baseDrawY = vectorBaseDrawY.length();
|
||||
ratio = vec2(baseDrawX, baseDrawY).length();
|
||||
if (m_baseSize.x()+m_baseSize.y() != 0.0f) {
|
||||
ratio /= 100.0f;//(m_baseSize.x()*m_baseSize.y());
|
||||
} else {
|
||||
ratio = 1.0f;
|
||||
}
|
||||
if (m_baseSize.x()+m_baseSize.y() != 0.0f) {
|
||||
if ( m_baseSize.x() != 0.0f
|
||||
&& m_baseSize.y() != 0.0f) {
|
||||
ratio = vec2(baseDrawX/m_baseSize.x(), baseDrawY/m_baseSize.y()).length();
|
||||
} else if (m_baseSize.x() != 0.0f) {
|
||||
ratio = baseDrawX/m_baseSize.x();
|
||||
// specal case when focal == center (this is faster ...)
|
||||
if (m_centerIsFocal == true) {
|
||||
ratio = vec2(baseDrawX, baseDrawY).length();
|
||||
if (m_baseSize.x()+m_baseSize.y() != 0.0f) {
|
||||
if ( m_baseSize.x() != 0.0f
|
||||
&& m_baseSize.y() != 0.0f) {
|
||||
ratio = vec2(baseDrawX/m_baseSize.x(), baseDrawY/m_baseSize.y()).length();
|
||||
} else if (m_baseSize.x() != 0.0f) {
|
||||
ratio = baseDrawX/m_baseSize.x();
|
||||
} else {
|
||||
ratio = baseDrawY/m_baseSize.y();
|
||||
}
|
||||
} else {
|
||||
ratio = baseDrawY/m_baseSize.y();
|
||||
ratio = 1.0f;
|
||||
}
|
||||
} else {
|
||||
ratio = 1.0f;
|
||||
// set the sense of the elements:
|
||||
if (m_axeX.dot(vectorBaseDrawX) < 0) {
|
||||
baseDrawX *= -1.0f;
|
||||
}
|
||||
if (m_axeY.dot(vectorBaseDrawY) < 0) {
|
||||
baseDrawY *= -1.0f;
|
||||
}
|
||||
if (m_baseSize.y() != 0.0f) {
|
||||
baseDrawY /= m_baseSize.y();
|
||||
}
|
||||
// normalize to 1.0f
|
||||
baseDrawX /= m_baseSize.x();
|
||||
if ( m_clipOut == true
|
||||
&& baseDrawX <= -1.0f) {
|
||||
ratio = 1.0f;
|
||||
} else {
|
||||
float tmpLength = -m_focalLength/m_baseSize.x();
|
||||
vec2 focalCenter = vec2(tmpLength, 0.0f);
|
||||
vec2 currentPoint = vec2(baseDrawX, baseDrawY);
|
||||
if (focalCenter == currentPoint) {
|
||||
ratio = 0.0f;
|
||||
} else {
|
||||
std::pair<vec2,vec2> positions = intersectLineToCircle(focalCenter, currentPoint);
|
||||
float lenghtBase = (currentPoint - focalCenter).length();
|
||||
float lenghtBorder1 = (positions.first - focalCenter).length();
|
||||
float lenghtBorder2 = (positions.second - focalCenter).length();
|
||||
ratio = lenghtBase/lenghtBorder1;
|
||||
}
|
||||
}
|
||||
}
|
||||
switch(m_spread) {
|
||||
case spreadMethod_pad:
|
||||
@ -236,11 +299,11 @@ void esvg::render::DynamicColorSpecial::generate(esvg::Document* _document) {
|
||||
std::shared_ptr<esvg::LinearGradient> gradient = std::dynamic_pointer_cast<esvg::LinearGradient>(base);
|
||||
if (gradient != nullptr) {
|
||||
m_linear = true;
|
||||
ESVG_INFO("get for color linear:");
|
||||
ESVG_VERBOSE("get for color linear:");
|
||||
gradient->display(2);
|
||||
m_unit = gradient->m_unit;
|
||||
m_spread = gradient->m_spread;
|
||||
ESVG_INFO(" viewport = {" << m_viewPort.first << "," << m_viewPort.second << "}");
|
||||
ESVG_VERBOSE(" viewport = {" << m_viewPort.first << "," << m_viewPort.second << "}");
|
||||
vec2 size = m_viewPort.second - m_viewPort.first;
|
||||
|
||||
esvg::Dimension dimPos1 = gradient->getPosition1();
|
||||
@ -286,47 +349,54 @@ void esvg::render::DynamicColorSpecial::generate(esvg::Document* _document) {
|
||||
ESVG_ERROR("Can not cast in a linear gradient: '" << m_colorName << "' ==> wrong type");
|
||||
return;
|
||||
}
|
||||
ESVG_INFO("get for color Radial:");
|
||||
ESVG_VERBOSE("get for color Radial:");
|
||||
gradient->display(2);
|
||||
m_unit = gradient->m_unit;
|
||||
m_spread = gradient->m_spread;
|
||||
ESVG_INFO(" viewport = {" << m_viewPort.first << "," << m_viewPort.second << "}");
|
||||
ESVG_VERBOSE(" viewport = {" << m_viewPort.first << "," << m_viewPort.second << "}");
|
||||
vec2 size = m_viewPort.second - m_viewPort.first;
|
||||
|
||||
esvg::Dimension dimCenter = gradient->getCenter();
|
||||
m_pos1 = dimCenter.getPixel(size);
|
||||
vec2 center = dimCenter.getPixel(size);
|
||||
if (dimCenter.getType() == esvg::distance_pourcent) {
|
||||
m_pos1 += m_viewPort.first;
|
||||
center += m_viewPort.first;
|
||||
}
|
||||
esvg::Dimension dimFocal = gradient->getFocal();
|
||||
m_focal = dimFocal.getPixel(size);
|
||||
vec2 focal = dimFocal.getPixel(size);
|
||||
if (dimFocal.getType() == esvg::distance_pourcent) {
|
||||
m_focal += m_viewPort.first;
|
||||
focal += m_viewPort.first;
|
||||
}
|
||||
esvg::Dimension1D dimRadius = gradient->getRadius();
|
||||
m_pos2.setX(dimRadius.getPixel(size.x()));
|
||||
m_pos2.setY(dimRadius.getPixel(size.y()));
|
||||
m_pos2 += m_pos1;
|
||||
/*
|
||||
if (dimRadius.getType() == esvg::distance_pourcent) {
|
||||
m_pos2 += m_viewPort.first;
|
||||
}
|
||||
*/
|
||||
// in the basic vertion of the gradient the color is calculated with the ration in X and Y in the bonding box associated (it is rotate with the object..
|
||||
vec2 delta = m_pos1 - m_pos2;
|
||||
if (delta.x() < 0.0f) {
|
||||
m_axeX = vec2(-1.0f, 0.0f);
|
||||
// in the basic vertion of the gradient the color is calculated with the ration in X and Y in the bonding box associated (it is rotate with the object)..
|
||||
if (center == focal) {
|
||||
m_centerIsFocal = true;
|
||||
m_pos2.setX(dimRadius.getPixel(size.x()));
|
||||
m_pos2.setY(dimRadius.getPixel(size.y()));
|
||||
m_pos2 += center;
|
||||
vec2 delta = center - m_pos2;
|
||||
if (delta.x() < 0.0f) {
|
||||
m_axeX = vec2(-1.0f, 0.0f);
|
||||
} else {
|
||||
m_axeX = vec2(1.0f, 0.0f);
|
||||
}
|
||||
if (delta.y() < 0.0f) {
|
||||
m_axeY = vec2(0.0f, -1.0f);
|
||||
} else {
|
||||
m_axeY = vec2(0.0f, 1.0f);
|
||||
}
|
||||
m_pos1 = center;
|
||||
} else {
|
||||
m_axeX = vec2(1.0f, 0.0f);
|
||||
}
|
||||
if (delta.y() < 0.0f) {
|
||||
m_axeY = vec2(0.0f, -1.0f);
|
||||
} else {
|
||||
m_axeY = vec2(0.0f, 1.0f);
|
||||
m_centerIsFocal = false;
|
||||
m_axeX = (center - focal).safeNormalize();
|
||||
m_axeY = vec2(m_axeX.y(), -m_axeX.x());
|
||||
|
||||
m_pos2 = m_axeX * dimRadius.getPixel(size.x()) + m_axeY * dimRadius.getPixel(size.y());
|
||||
m_pos2 += center;
|
||||
m_pos1 = center;
|
||||
}
|
||||
// Move the positions ...
|
||||
m_pos1 = m_matrix * m_pos1;
|
||||
m_focal = m_matrix * m_focal;
|
||||
center = m_matrix * center;
|
||||
m_pos2 = m_matrix * m_pos2;
|
||||
m_axeX = m_matrix.applyScaleRotation(m_axeX);
|
||||
m_axeY = m_matrix.applyScaleRotation(m_axeY);
|
||||
@ -335,8 +405,18 @@ void esvg::render::DynamicColorSpecial::generate(esvg::Document* _document) {
|
||||
m_pos2, m_axeY);
|
||||
vec2 intersecY = getIntersect(m_pos1, m_axeY,
|
||||
m_pos2, m_axeX);
|
||||
m_baseSize = vec2((m_pos1 - intersecX).length(),
|
||||
(m_pos1 - intersecY).length());
|
||||
m_baseSize = vec2((intersecX - m_pos1).length(),
|
||||
(intersecY - m_pos1).length());
|
||||
if (m_centerIsFocal == false) {
|
||||
m_focalLength = (center - m_matrix * focal).length();
|
||||
if (m_focalLength >= m_baseSize.x()) {
|
||||
ESVG_DEBUG("Change position of the Focal ... ==> set it inside the circle");
|
||||
m_focalLength = m_baseSize.x()*0.999998f;
|
||||
m_clipOut = true;
|
||||
} else {
|
||||
m_clipOut = false;
|
||||
}
|
||||
}
|
||||
ESVG_VERBOSE("baseSize=" << m_baseSize << " m_pos1=" << m_pos1 << " dim=" << dimCenter << " m_focal=" << m_focal << " m_pos2=" << m_pos2 << " dim=" << dimRadius);
|
||||
// get all the colors
|
||||
m_data = gradient->getColors(_document);
|
||||
|
@ -62,6 +62,9 @@ namespace esvg {
|
||||
vec2 m_axeX;
|
||||
vec2 m_axeY;
|
||||
vec2 m_baseSize;
|
||||
float m_focalLength;
|
||||
bool m_clipOut;
|
||||
bool m_centerIsFocal;
|
||||
std::vector<std::pair<float, etk::Color<float,4>>> m_data;
|
||||
public:
|
||||
DynamicColorSpecial(const std::string& _link, const mat2& _mtx);
|
||||
|
@ -227,4 +227,98 @@ TEST(TestGradientRadial, unitUser_spreadRepeat) {
|
||||
doc.generateAnImage(ivec2(100, 100), "TestGradientRadial_unitUser_spreadRepeat.bmp", g_visualDebug);
|
||||
}
|
||||
|
||||
TEST(TestGradientRadial, unitUser_spreadPad_unCenter) {
|
||||
std::string data("<?xml version='1.0' encoding='UTF-8' standalone='no'?>\n"
|
||||
"<svg height='100' width='100'>\n"
|
||||
" <defs>\n"
|
||||
" <radialGradient id='grad1' cx='50' cy='50' r='24' fx='40' fy='40' spreadMethod='pad' gradientUnits='userSpaceOnUse' >\n"
|
||||
" <stop offset='0%' style='stop-color:orange;stop-opacity:1' />\n"
|
||||
" <stop offset='45%' style='stop-color:red;stop-opacity:1' />\n"
|
||||
" <stop offset='55%' style='stop-color:blue;stop-opacity:1' />\n"
|
||||
" <stop offset='100%' style='stop-color:green;stop-opacity:1' />\n"
|
||||
" </radialGradient>\n"
|
||||
" </defs>\n"
|
||||
" <ellipse cx='50' cy='50' rx='50' ry='20' fill='url(#grad1)' />\n"
|
||||
"</svg>\n");
|
||||
esvg::Document doc;
|
||||
doc.parse(data);
|
||||
etk::FSNodeWriteAllData("TestGradientRadial_unitUser_spreadPad_unCenter.svg", data);
|
||||
doc.generateAnImage(ivec2(100, 100), "TestGradientRadial_unitUser_spreadPad_unCenter.bmp", g_visualDebug);
|
||||
}
|
||||
|
||||
TEST(TestGradientRadial, unitUser_spreadReflect_unCenter) {
|
||||
std::string data("<?xml version='1.0' encoding='UTF-8' standalone='no'?>\n"
|
||||
"<svg height='100' width='100'>\n"
|
||||
" <defs>\n"
|
||||
" <radialGradient id='grad1' cx='50' cy='50' r='24' fx='40' fy='40' spreadMethod='reflect' gradientUnits='userSpaceOnUse' >\n"
|
||||
" <stop offset='0%' style='stop-color:orange;stop-opacity:1' />\n"
|
||||
" <stop offset='45%' style='stop-color:red;stop-opacity:1' />\n"
|
||||
" <stop offset='55%' style='stop-color:blue;stop-opacity:1' />\n"
|
||||
" <stop offset='100%' style='stop-color:green;stop-opacity:1' />\n"
|
||||
" </radialGradient>\n"
|
||||
" </defs>\n"
|
||||
" <ellipse cx='50' cy='50' rx='50' ry='20' fill='url(#grad1)' />\n"
|
||||
"</svg>\n");
|
||||
esvg::Document doc;
|
||||
doc.parse(data);
|
||||
etk::FSNodeWriteAllData("TestGradientRadial_unitUser_spreadReflect_unCenter.svg", data);
|
||||
doc.generateAnImage(ivec2(100, 100), "TestGradientRadial_unitUser_spreadReflect_unCenter.bmp", g_visualDebug);
|
||||
}
|
||||
|
||||
TEST(TestGradientRadial, unitUser_spreadRepeat_unCenter) {
|
||||
std::string data("<?xml version='1.0' encoding='UTF-8' standalone='no'?>\n"
|
||||
"<svg height='100' width='100'>\n"
|
||||
" <defs>\n"
|
||||
" <radialGradient id='grad1' cx='50' cy='50' r='24' fx='40' fy='40' spreadMethod='repeat' gradientUnits='userSpaceOnUse' >\n"
|
||||
" <stop offset='0%' style='stop-color:orange;stop-opacity:1' />\n"
|
||||
" <stop offset='45%' style='stop-color:red;stop-opacity:1' />\n"
|
||||
" <stop offset='55%' style='stop-color:blue;stop-opacity:1' />\n"
|
||||
" <stop offset='100%' style='stop-color:green;stop-opacity:1' />\n"
|
||||
" </radialGradient>\n"
|
||||
" </defs>\n"
|
||||
" <ellipse cx='50' cy='50' rx='50' ry='20' fill='url(#grad1)' />\n"
|
||||
"</svg>\n");
|
||||
esvg::Document doc;
|
||||
doc.parse(data);
|
||||
etk::FSNodeWriteAllData("TestGradientRadial_unitUser_spreadRepeat_unCenter.svg", data);
|
||||
doc.generateAnImage(ivec2(100, 100), "TestGradientRadial_unitUser_spreadRepeat_unCenter.bmp", g_visualDebug);
|
||||
}
|
||||
|
||||
TEST(TestGradientRadial, unitUser_spreadRepeat_unCenter2) {
|
||||
std::string data("<?xml version='1.0' encoding='UTF-8' standalone='no'?>\n"
|
||||
"<svg height='100' width='100'>\n"
|
||||
" <defs>\n"
|
||||
" <radialGradient id='grad1' cx='50' cy='50' r='24' fx='60' fy='60' spreadMethod='repeat' gradientUnits='userSpaceOnUse' >\n"
|
||||
" <stop offset='0%' style='stop-color:orange;stop-opacity:1' />\n"
|
||||
" <stop offset='45%' style='stop-color:red;stop-opacity:1' />\n"
|
||||
" <stop offset='55%' style='stop-color:blue;stop-opacity:1' />\n"
|
||||
" <stop offset='100%' style='stop-color:green;stop-opacity:1' />\n"
|
||||
" </radialGradient>\n"
|
||||
" </defs>\n"
|
||||
" <ellipse cx='50' cy='50' rx='50' ry='20' fill='url(#grad1)' />\n"
|
||||
"</svg>\n");
|
||||
esvg::Document doc;
|
||||
doc.parse(data);
|
||||
etk::FSNodeWriteAllData("TestGradientRadial_unitUser_spreadRepeat_unCenter2.svg", data);
|
||||
doc.generateAnImage(ivec2(100, 100), "TestGradientRadial_unitUser_spreadRepeat_unCenter2.bmp", g_visualDebug);
|
||||
}
|
||||
|
||||
|
||||
TEST(TestGradientRadial, unitUser_spreadRepeat_out) {
|
||||
std::string data("<?xml version='1.0' encoding='UTF-8' standalone='no'?>\n"
|
||||
"<svg height='100' width='100'>\n"
|
||||
" <defs>\n"
|
||||
" <radialGradient id='grad1' cx='50' cy='50' r='24' fx='20' fy='40' spreadMethod='reflect' gradientUnits='userSpaceOnUse' >\n"
|
||||
" <stop offset='0%' style='stop-color:orange;stop-opacity:1' />\n"
|
||||
" <stop offset='45%' style='stop-color:red;stop-opacity:1' />\n"
|
||||
" <stop offset='55%' style='stop-color:blue;stop-opacity:1' />\n"
|
||||
" <stop offset='100%' style='stop-color:green;stop-opacity:1' />\n"
|
||||
" </radialGradient>\n"
|
||||
" </defs>\n"
|
||||
" <ellipse cx='50' cy='50' rx='50' ry='20' fill='url(#grad1)' />\n"
|
||||
"</svg>\n");
|
||||
esvg::Document doc;
|
||||
doc.parse(data);
|
||||
etk::FSNodeWriteAllData("TestGradientRadial_unitUser_spreadRepeat_out.svg", data);
|
||||
doc.generateAnImage(ivec2(100, 100), "TestGradientRadial_unitUser_spreadRepeat_out.bmp", g_visualDebug);
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user