若是普通的箭头,则使用<maker>通过设置maker-end,maker-start便可以使得箭头方向随着线条的方向改变而改变。对于那种棒状的箭头,并没有成熟的API接口可以使用,只好采用记录所有转折点的方式,通过<path>绘制。
通过记录所有关键点的方式绘制箭头,同时也意味着图形的变化会导致关键点的变化,而且其变换方式较为复杂。如图,橙色关键点用来调控组件的宽度,以及箭头的形状,蓝色关键点则用来调整组件的位置。
可以将其看做一条位于中间的线,随后将其扩充,最后依次连接,整个图形是对称的,可以多次利用这个性质。
在计算过程中会用到一些基础的计算几何知识。比如点关于直线的对称点,点位于直线的左侧或者右侧,点在直线上的垂足。等等。
计算对称点
Lewzen::Point2D Line::getFlipPoint(Lewzen::Point2D p) {
double x1 = startPoint->getX(), y1 = startPoint->getY(), x2 = endPoint->getX(), y2 = endPoint->getY();
double a = y2 - y1, b = x1 - x2, c = x2 * y1 - x1 * y2;
double m = p.get_x(), n = p.get_y();
Lewzen::Point2D cz((b * b * m - a * b * n - a * c) / (a * a + b * b),
(a * a * n - a * b * m - b * c) / (a * a + b * b));
return Lewzen::Point2D(2 * cz.get_x() - p.get_x(), 2 * cz.get_y() - p.get_y());
}
点是否在线的同侧
void Line::onSameSideF() {
auto s = Lewzen::Point2D(startPoint->getX(),startPoint->getY());
auto e = Lewzen::Point2D(pointList[2]->getX(),pointList[2]->getY());
int sz = pointList.size()-1;
auto s1 = Lewzen::Point2D(pointList[sz-2]->getX(),pointList[sz-2]->getY());
auto e1 = Lewzen::Point2D(endPoint->getX(),endPoint->getY());
double x1 = s.get_x(), y1 = s.get_y(), x2 = e.get_x(), y2 = e.get_y();
double x0 = arrowCPoint->getX(),y0 = arrowCPoint->getY();
double flagS = (x2-x1)*(y0-y1)-(y2-y1)*(x0-x1);
x1 = s1.get_x();
y1 = s1.get_y();
x2 = e1.get_x();
y2 = e1.get_y();
x0 = midCPoint->getX();
y0 = midCPoint->getY();
double flagE = (x2-x1)*(y0-y1)-(y2-y1)*(x0-x1);
if(flagS*flagE < 0){
auto t = getFlipP(Lewzen::Point2D(arrowPoint->getX(),arrowPoint->getY()),s,e);
arrowPoint->setX(t.get_x());
arrowPoint->setY(t.get_y());
t = getFlipP(Lewzen::Point2D(arrowCPoint->getX(),arrowCPoint->getY()),s,e);
arrowCPoint->setX(t.get_x());
arrowCPoint->setY(t.get_y());
}
}