线条的变换处理较为容易,通过增加关键点的位置即可,其svg格式即将关键点顺序连接。
关键点分为透明和不透明两种,二者均可以拖动,透明关键点与不透明关键点交叉出现,而且透明关键点位于其相邻的不透明关键点的中点。端点始终是不透明关键点
在拖动关键点时,分为端点和内部的关键点。若是端点,则可以直接改变坐标,若是内部的关键点,则在改变关键点后并多出来两个内部关键点,新的关键点出现在中点处。
而且在拖动内部关键点时,可能会与其相邻的左右关键点成为一条直线,此时要将其删除。
std::string res = "M " + std::to_string(startPoint->getX()) + " "
+ std::to_string(startPoint->getY()) + " ";
for (int i = 2; i < (int) pointList.size(); i += 2) {
res += "L " + std::to_string(pointList[i]->getX()) + " " + std::to_string(pointList[i]->getY()) + " ";
}
return res;
将线条扩充为平行线,首先要记录线条的形状,然后再向外扩充。
主要找各种转折点,然后顺序连线即可,起点和终点都算一种特殊转折点
这样每个线段也就有了对应的2条等距平行线的描述方程,相近的2条等距平行线有且只有1个交点,就是对应的等距平行线上的转折点。
std::vector<Lewzen::Point2D> Line::offsetCoords(std::vector<Lewzen::Point2D> coords, double offset) {
std::vector<Lewzen::Point2D> path;
int N = coords.size() - 1;
int max = N;
double mi, mi1, li, li1, ri, ri1, si, si1, Xi1, Yi1;
Lewzen::Point2D p0(0, 0), p1(0, 0), p2(0, 0);
int isClosed = (coords[0].get_x() == coords[N].get_x() &&
coords[0].get_y() == coords[N].get_y());
if (!isClosed) {
p0 = coords[0];
p1 = coords[1];
p2 = Lewzen::Point2D(p0.get_x() + (p1.get_y() - p0.get_y()) / dist2d(p0, p1) * offset,
p0.get_y() - (p1.get_x() - p0.get_x()) / dist2d(p0, p1) * offset);
path.push_back(p2);
coords.push_back(coords[N]);
N++;
max--;
}
for (int i = 0; i < max; i++) {
p0 = coords[i];
p1 = coords[(i + 1) % N];
p2 = coords[(i + 2) % N];
mi = (p1.get_y() - p0.get_y()) / (p1.get_x() - p0.get_x());
mi1 = (p2.get_y() - p1.get_y()) / (p2.get_x() - p1.get_x());
// Prevent alignements
if (fabs(mi - mi1) > 1e-10) {
// li = Math.sqrt((p1[0] - p0[0])*(p1[0] - p0[0])+(p1[1] - p0[1])*(p1[1] - p0[1]));
// li1 = Math.sqrt((p2[0] - p1[0])*(p2[0] - p1[0])+(p2[1] - p1[1])*(p2[1] - p1[1]));
li = dist2d(p1, p0);
li1 = dist2d(p2, p1);
ri = p0.get_x() + offset * (p1.get_y() - p0.get_y()) / li;
ri1 = p1.get_x() + offset * (p2.get_y() - p1.get_y()) / li1;
si = p0.get_y() - offset * (p1.get_x() - p0.get_x()) / li;
si1 = p1.get_y() - offset * (p2.get_x() - p1.get_x()) / li1;
Xi1 = (mi1 * ri1 - mi * ri + si - si1) / (mi1 - mi);
Yi1 = (mi * mi1 * (ri1 - ri) + mi1 * si - mi * si1) / (mi1 - mi);
// Correction for vertical lines
if (p1.get_x() - p0.get_x() == 0) {
Xi1 = p1.get_x() + offset * (p1.get_y() - p0.get_y()) / fabs(p1.get_y() - p0.get_y());
Yi1 = mi1 * Xi1 - mi1 * ri1 + si1;
}
if (p2.get_x() - p1.get_x() == 0) {
Xi1 = p2.get_x() + offset * (p2.get_y() - p1.get_y()) / fabs(p2.get_y() - p1.get_y());
Yi1 = mi * Xi1 - mi * ri + si;
}
path.push_back(Lewzen::Point2D(Xi1, Yi1));
}
}
if (isClosed) {
path.push_back(path[0]);
} else {
coords.pop_back();
p0 = coords[coords.size() - 1];
p1 = coords[coords.size() - 2];
p2 = Lewzen::Point2D(p0.get_x() - (p1.get_y() - p0.get_y()) / dist2d(p0, p1) * offset,
p0.get_y() + (p1.get_x() - p0.get_x()) / dist2d(p0, p1) * offset);
path.push_back(p2);
}
return path;
}
折线扩充后的形状