Skip to content

Commit

Permalink
Adjust representation of arc segments in paths
Browse files Browse the repository at this point in the history
The angle of a vertex specified the angle from the last vertex to that
vertex until now. But this does not really make sense because the angle
of the first vertex in a path is always useless.

Now the angle of a vertex specifies the angle from that vertex to the
next vertex. For paths which are implicitly considered as closed (even
if last vertex != first vertex), the last vertex can now be omitted
because the angle is already contained in the vertex before.
  • Loading branch information
ubruhin committed Feb 19, 2018
1 parent b0f4a7c commit 9b0f103
Show file tree
Hide file tree
Showing 7 changed files with 59 additions and 50 deletions.
32 changes: 16 additions & 16 deletions libs/librepcb/common/cam/gerbergenerator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -104,25 +104,25 @@ void GerberGenerator::drawPathOutline(const Path& path, const Length& lineWidth)
setCurrentAperture(mApertureList->setCircle(lineWidth, Length(0)));
moveToPosition(path.getVertices().first().getPos());
for (int i = 1; i < path.getVertices().count(); ++i) {
const Vertex& vertex = path.getVertices().at(i);
if (vertex.getAngle() == 0) {
const Vertex& v = path.getVertices().at(i);
const Vertex& v0 = path.getVertices().at(i-1);
if (v0.getAngle() == 0) {
// linear segment
linearInterpolateToPosition(vertex.getPos());
linearInterpolateToPosition(v.getPos());
} else {
// arc segment
if (vertex.getAngle().abs() <= Angle::deg90()) {
if (v0.getAngle().abs() <= Angle::deg90()) {
setMultiQuadrantArcModeOff();
} else {
setMultiQuadrantArcModeOn();
}
if (vertex.getAngle() < 0) {
if (v0.getAngle() < 0) {
switchToCircularCwInterpolationModeG02();
} else {
switchToCircularCcwInterpolationModeG03();
}
Point start = path.getVertices().at(i-1).getPos();
Point center = Toolbox::arcCenter(start, vertex.getPos(), vertex.getAngle());
circularInterpolateToPosition(start, center, vertex.getPos());
Point center = Toolbox::arcCenter(v0.getPos(), v.getPos(), v0.getAngle());
circularInterpolateToPosition(v0.getPos(), center, v.getPos());
switchToLinearInterpolationModeG01();
}
}
Expand All @@ -138,25 +138,25 @@ void GerberGenerator::drawPathArea(const Path& path) noexcept
setRegionModeOn();
moveToPosition(path.getVertices().first().getPos());
for (int i = 1; i < path.getVertices().count(); ++i) {
const Vertex& vertex = path.getVertices().at(i);
if (vertex.getAngle() == 0) {
const Vertex& v = path.getVertices().at(i);
const Vertex& v0 = path.getVertices().at(i-1);
if (v0.getAngle() == 0) {
// linear segment
linearInterpolateToPosition(vertex.getPos());
linearInterpolateToPosition(v.getPos());
} else {
// arc segment
if (vertex.getAngle().abs() <= Angle::deg90()) {
if (v0.getAngle().abs() <= Angle::deg90()) {
setMultiQuadrantArcModeOff();
} else {
setMultiQuadrantArcModeOn();
}
if (vertex.getAngle() < 0) {
if (v0.getAngle() < 0) {
switchToCircularCwInterpolationModeG02();
} else {
switchToCircularCcwInterpolationModeG03();
}
Point start = path.getVertices().at(i-1).getPos();
Point center = Toolbox::arcCenter(start, vertex.getPos(), vertex.getAngle());
circularInterpolateToPosition(start, center, vertex.getPos());
Point center = Toolbox::arcCenter(v0.getPos(), v.getPos(), v0.getAngle());
circularInterpolateToPosition(v0.getPos(), center, v.getPos());
switchToLinearInterpolationModeG01();
}
}
Expand Down
47 changes: 25 additions & 22 deletions libs/librepcb/common/geometry/path.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -58,28 +58,31 @@ bool Path::isClosed() const noexcept
}
}

const QPainterPath& Path::toQPainterPathPx() const noexcept
const QPainterPath& Path::toQPainterPathPx(bool close) const noexcept
{
if (mPainterPathPx.isEmpty()) {
Point lastPos;
for (int i = 0; i < mVertices.count(); ++i) {
const Vertex& v = mVertices.at(i);
int count = mVertices.count();
if (close && (!isClosed()) && (count > 0)) ++count; // add implicit last point
for (int i = 0; i < count; ++i) {
const Vertex& v = mVertices.at(i % mVertices.count()); // wrap around!
if (i == 0) {
mPainterPathPx.moveTo(v.getPos().toPxQPointF());
} else if (v.getAngle() == 0) {
continue;
}
const Vertex& v0 = mVertices.at(i-1);
if (v0.getAngle() == 0) {
mPainterPathPx.lineTo(v.getPos().toPxQPointF());
} else {
QPointF centerPx = Toolbox::arcCenter(lastPos, v.getPos(),
v.getAngle()).toPxQPointF();
qreal radiusPx = Toolbox::arcRadius(lastPos, v.getPos(),
v.getAngle()).abs().toPx();
QPointF diffPx = lastPos.toPxQPointF() - centerPx;
QPointF centerPx = Toolbox::arcCenter(v0.getPos(), v.getPos(),
v0.getAngle()).toPxQPointF();
qreal radiusPx = Toolbox::arcRadius(v0.getPos(), v.getPos(),
v0.getAngle()).abs().toPx();
QPointF diffPx = v0.getPos().toPxQPointF() - centerPx;
qreal startAngleDeg = -qRadiansToDegrees(qAtan2(diffPx.y(), diffPx.x()));
mPainterPathPx.arcTo(centerPx.x() - radiusPx, centerPx.y() - radiusPx,
radiusPx * 2, radiusPx * 2,
startAngleDeg, v.getAngle().toDeg());
startAngleDeg, v0.getAngle().toDeg());
}
lastPos = v.getPos();
}
}
return mPainterPathPx;
Expand Down Expand Up @@ -206,21 +209,21 @@ Path Path::obround(const Length& width, const Length& height) noexcept
Length ry = height / 2;
if (width > height) {
p.addVertex(Point(ry - rx, ry), Angle::deg0());
p.addVertex(Point(rx - ry, ry), Angle::deg0());
p.addVertex(Point(rx - ry, -ry), -Angle::deg180());
p.addVertex(Point(ry - rx, -ry), Angle::deg0());
p.addVertex(Point(ry - rx, ry), -Angle::deg180());
p.addVertex(Point(rx - ry, ry), -Angle::deg180());
p.addVertex(Point(rx - ry, -ry), Angle::deg0());
p.addVertex(Point(ry - rx, -ry), -Angle::deg180());
p.addVertex(Point(ry - rx, ry), Angle::deg0());
} else if (width < height) {
p.addVertex(Point(rx - ry, rx), Angle::deg0());
p.addVertex(Point(ry - rx, rx), Angle::deg0());
p.addVertex(Point(ry - rx, -rx), -Angle::deg180());
p.addVertex(Point(rx - ry, -rx), Angle::deg0());
p.addVertex(Point(rx - ry, rx), -Angle::deg180());
p.addVertex(Point(ry - rx, rx), -Angle::deg180());
p.addVertex(Point(ry - rx, -rx), Angle::deg0());
p.addVertex(Point(rx - ry, -rx), -Angle::deg180());
p.addVertex(Point(rx - ry, rx), Angle::deg0());
} else {
Q_ASSERT(width == height);
p.addVertex(Point(rx, 0), Angle::deg0());
p.addVertex(Point(-rx, 0), -Angle::deg180());
p.addVertex(Point(rx, 0), -Angle::deg180());
p.addVertex(Point(-rx, 0), -Angle::deg180());
p.addVertex(Point(rx, 0), Angle::deg0());
}
return p;
}
Expand Down
2 changes: 1 addition & 1 deletion libs/librepcb/common/geometry/path.h
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ class Path final : public SerializableObject
bool isClosed() const noexcept;
QVector<Vertex>& getVertices() noexcept {invalidatePainterPath(); return mVertices;}
const QVector<Vertex>& getVertices() const noexcept {return mVertices;}
const QPainterPath& toQPainterPathPx() const noexcept;
const QPainterPath& toQPainterPathPx(bool close = false) const noexcept;

// Transformations
Path& translate(const Point& offset) noexcept;
Expand Down
4 changes: 2 additions & 2 deletions libs/librepcb/common/geometry/polygon.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -71,8 +71,8 @@ Polygon::Polygon(const SExpression& node)
// backward compatibility, remove this some time!
mPath.addVertex(Point(node.getChildByPath("pos")));
foreach (const SExpression& child, node.getChildren("segment")) {
mPath.addVertex(Point(child.getChildByPath("pos")),
child.getValueByPath<Angle>("angle", true));
mPath.getVertices().last().setAngle(child.getValueByPath<Angle>("angle", true));
mPath.addVertex(Point(child.getChildByPath("pos")));
}
}

Expand Down
2 changes: 1 addition & 1 deletion libs/librepcb/common/geometry/vertex.h
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ class Vertex final : public SerializableObject

private: // Data
Point mPos;
Angle mAngle;
Angle mAngle; ///< angle of the line between this vertex and the following vertex
};

/*****************************************************************************************
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,7 @@ bool PackageEditorState_DrawPolygonBase::start(const Point& pos) noexcept
// create path
Path path;
for (int i = 0; i < ((mMode == Mode::RECT) ? 5 : 2); ++i) {
path.addVertex(pos, mLastAngle);
path.addVertex(pos, (i == 0) ? mLastAngle : Angle::deg0());
}

// add polygon
Expand Down Expand Up @@ -243,7 +243,8 @@ bool PackageEditorState_DrawPolygonBase::addNextSegment(const Point& pos) noexce
mContext.undoStack.beginCmdGroup(tr("Add footprint polygon"));
mEditCmd.reset(new CmdPolygonEdit(*mCurrentPolygon));
Path newPath = mCurrentPolygon->getPath();
newPath.addVertex(pos, mLastAngle);
newPath.getVertices().last().setAngle(mLastAngle);
newPath.addVertex(pos, Angle::deg0());
mEditCmd->setPath(newPath, true);
return true;
} catch (const Exception& e) {
Expand Down Expand Up @@ -294,8 +295,10 @@ void PackageEditorState_DrawPolygonBase::angleSpinBoxValueChanged(double value)
mLastAngle = Angle::fromDeg(value);
if (mCurrentPolygon && mEditCmd) {
Path path = mCurrentPolygon->getPath();
path.getVertices().last().setAngle(mLastAngle);
mEditCmd->setPath(path, true);
if (path.getVertices().count() > 1) {
path.getVertices()[path.getVertices().count() - 2].setAngle(mLastAngle);
mEditCmd->setPath(path, true);
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,7 @@ bool SymbolEditorState_DrawPolygonBase::start(const Point& pos) noexcept
// create path
Path path;
for (int i = 0; i < ((mMode == Mode::RECT) ? 5 : 2); ++i) {
path.addVertex(pos, mLastAngle);
path.addVertex(pos, (i == 0) ? mLastAngle : Angle::deg0());
}

// add polygon
Expand Down Expand Up @@ -242,7 +242,8 @@ bool SymbolEditorState_DrawPolygonBase::addNextSegment(const Point& pos) noexcep
mContext.undoStack.beginCmdGroup(tr("Add symbol polygon"));
mEditCmd.reset(new CmdPolygonEdit(*mCurrentPolygon));
Path newPath = mCurrentPolygon->getPath();
newPath.addVertex(pos, mLastAngle);
newPath.getVertices().last().setAngle(mLastAngle);
newPath.addVertex(pos, Angle::deg0());
mEditCmd->setPath(newPath, true);
return true;
} catch (const Exception& e) {
Expand Down Expand Up @@ -293,8 +294,10 @@ void SymbolEditorState_DrawPolygonBase::angleSpinBoxValueChanged(double value) n
mLastAngle = Angle::fromDeg(value);
if (mCurrentPolygon && mEditCmd) {
Path path = mCurrentPolygon->getPath();
path.getVertices().last().setAngle(mLastAngle);
mEditCmd->setPath(path, true);
if (path.getVertices().count() > 1) {
path.getVertices()[path.getVertices().count() - 2].setAngle(mLastAngle);
mEditCmd->setPath(path, true);
}
}
}

Expand Down

0 comments on commit 9b0f103

Please sign in to comment.