Try to retrieve callout, to be improved...
Change-Id: I4755b2ae173dedb5ce36401417b48b7eb81b14fa
diff --git a/src/lib/IWORKShape.cpp b/src/lib/IWORKShape.cpp
index c22ddba..61d9ebf 100644
--- a/src/lib/IWORKShape.cpp
+++ b/src/lib/IWORKShape.cpp
@@ -293,22 +293,142 @@
IWORKPathPtr_t makeCalloutPath(const IWORKSize &size, const double radius, const double tailSize, const double tailX, const double tailY)
{
// user space canvas: [-1:1] x [-1:1]
double wRadius=2*radius<size.m_width ? radius : size.m_width/2;
double hRadius=2*radius<size.m_height ? radius : size.m_height/2;
double tail[2]= {tailX-size.m_width/2, tailY-size.m_height/2};
double xPos[4]= {-size.m_width/2,-size.m_width/2+wRadius,size.m_width/2-wRadius,size.m_width/2};
double yPos[4]= {-size.m_height/2,-size.m_height/2+hRadius,size.m_height/2-hRadius,size.m_height/2};
const double tSize=tailSize<0 ? -tailSize : tailSize;
glm::dmat3 trans=translate(size.m_width/2, size.m_height/2);
// reorient figure so that the tail is in RB
trans=trans*scale(tail[0]<0 ? -1 : 1,tail[1]<0 ? -1 : 1);
if (tail[0]<0) tail[0]*=-1;
if (tail[1]<0) tail[1]*=-1;
// first check if tail is in the round rect
if (tailX>=0 && tailX<=size.m_width && tailY>=0 && tailY<=size.m_height &&
(tail[0]-xPos[2])*(tail[0]-xPos[2])*hRadius*hRadius+
(tail[1]-yPos[2])*(tail[1]-yPos[2])*wRadius*wRadius
<= wRadius*wRadius*hRadius*hRadius)
return makeRoundedRectanglePath(size,radius);
if (tail[0]*yPos[3]<tail[1]*xPos[3])
{
using std::swap;
swap(tail[0],tail[1]);
swap(wRadius,hRadius);
for (int i=0; i<4; ++i) swap(xPos[i], yPos[i]);
trans=trans*glm::dmat3(0, 1, 0, 1, 0, 0, 0, 0, 1);
}
deque<Point> points;
std::vector<char> orders;
orders.push_back('M');
points.push_back(Point(xPos[1],yPos[3]));
orders.push_back('Q');
points.push_back(Point(xPos[0],yPos[3]));
points.push_back(Point(xPos[0],yPos[2]));
orders.push_back('L');
points.push_back(Point(xPos[0],yPos[1]));
orders.push_back('Q');
points.push_back(Point(xPos[0],yPos[0]));
points.push_back(Point(xPos[1],yPos[0]));
orders.push_back('L');
points.push_back(Point(xPos[2],yPos[0]));
orders.push_back('Q');
points.push_back(Point(xPos[3],yPos[0]));
points.push_back(Point(xPos[3],yPos[1]));
// TODO: draw correctly instead of just approximating
(void) radius;
(void) tailSize;
(void) tailX;
(void) tailY;
// ok first compute the intersection of OT with the rectangle side x=xPos[3]
double y1=tail[0]>0 ? tail[1]*xPos[3]/tail[0] : 0;
// go to the y1-tSize
if (y1-tSize <= yPos[1]) // ok
;
else if (y1-tSize <= yPos[2])
{
orders.push_back('L');
points.push_back(Point(xPos[3],y1-tSize));
}
else
{
orders.push_back('L');
points.push_back(Point(xPos[3],yPos[2]));
deque<Point> points = rotatePoint(Point(-1, -1), 4);
points.push_back(Point(-1, 0.5));
points.push_back(Point(-2, 0));
points.push_back(Point(-1, -0.5));
// create the path
transform(points, scale(size.m_width, size.m_height) * scale(0.5, 0.5) * translate(1, 1));
const IWORKPathPtr_t path = makePolyLine(points);
double delta[2]= {wRadius,y1-tSize-yPos[2]};
double alpha=std::atan2(wRadius*delta[1],hRadius*delta[0]);
orders.push_back('Q');
points.push_back(Point(xPos[3],yPos[2]+hRadius*std::tan(alpha/2)));
points.push_back(Point(xPos[2]+wRadius*std::cos(alpha),yPos[2]+hRadius*std::sin(alpha)));
}
// the tail
orders.push_back('L');
points.push_back(Point(tail[0],tail[1]));
// after the tail
if (y1+tSize <= yPos[2])
{
orders.push_back('L');
points.push_back(Point(xPos[3],y1+tSize));
orders.push_back('L');
points.push_back(Point(xPos[3],yPos[2]));
orders.push_back('Q');
points.push_back(Point(xPos[3],yPos[3]));
points.push_back(Point(xPos[2],yPos[3]));
}
else if (y1+tSize < yPos[3])
{
double delta[2]= {wRadius,y1+tSize-yPos[2]};
double alpha=std::atan2(wRadius*delta[1],hRadius*delta[0]);
// go back to circle
orders.push_back('L');
points.push_back(Point(xPos[2]+wRadius*std::cos(alpha),yPos[2]+hRadius*std::sin(alpha)));
// end circle
orders.push_back('Q');
points.push_back(Point(xPos[2]+wRadius*std::tan((1.5707963268-alpha)/2),yPos[3]));
points.push_back(Point(xPos[2],yPos[3]));
}
else if (xPos[2]-(y1+tSize-yPos[3])>xPos[1])
{
// clearly to small but...
points.push_back(Point(xPos[2]-(y1+tSize-yPos[3]),yPos[3]));
orders.push_back('L');
}
transform(points, trans);
IWORKPathPtr_t path(new IWORKPath);
size_t numPoints=points.size();
for (size_t i=0, pPos=0; i<orders.size(); ++i)
{
switch (orders[i])
{
case 'M':
if (pPos>=numPoints)
{
ETONYEK_DEBUG_MSG(("makeCalloutPath[IWORKShape]: can not find a point\n"));
return IWORKPathPtr_t();
}
path->appendMoveTo(points[pPos].x, points[pPos].y);
++pPos;
break;
case 'L':
if (pPos>=numPoints)
{
ETONYEK_DEBUG_MSG(("makeCalloutPath[IWORKShape]: can not find a point\n"));
return IWORKPathPtr_t();
}
path->appendLineTo(points[pPos].x, points[pPos].y);
++pPos;
break;
case 'Q':
if (pPos+1>=numPoints)
{
ETONYEK_DEBUG_MSG(("makeCalloutPath[IWORKShape]: can not find a point\n"));
return IWORKPathPtr_t();
}
path->appendQCurveTo(points[pPos].x, points[pPos].y, points[pPos+1].x, points[pPos+1].y);
pPos+=2;
break;
default:
ETONYEK_DEBUG_MSG(("makeCalloutPath[IWORKShape]: unknown order %c\n", orders[i]));
return IWORKPathPtr_t();
}
}
path->appendClose();
return path;
}