Loading files
9ac9868b1This file is pinned to the selected release. Download the original to open it in your design tool.
/*
* LibrePCB - Professional EDA for everyone!
* Copyright (C) 2013 LibrePCB Developers, see AUTHORS.md for contributors.
* https://librepcb.org/
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/*******************************************************************************
* Includes
******************************************************************************/
#include "schematicnetsegmentsplitter.h"
#include "../../utils/toolbox.h"
#include <QtCore>
#include <QtWidgets>
/*******************************************************************************
* Namespace
******************************************************************************/
namespace librepcb {
/*******************************************************************************
* Constructors / Destructor
******************************************************************************/
SchematicNetSegmentSplitter::SchematicNetSegmentSplitter() noexcept
: mJunctions(), mNetLines(), mNetLabels() {
}
SchematicNetSegmentSplitter::~SchematicNetSegmentSplitter() noexcept {
}
/*******************************************************************************
* General Methods
******************************************************************************/
void SchematicNetSegmentSplitter::addFixedAnchor(
const NetLineAnchor& anchor, const Point& pos,
bool replaceByJunction) noexcept {
if (replaceByJunction) {
std::shared_ptr<Junction> newJunction =
std::make_shared<Junction>(Uuid::createRandom(), pos);
mJunctions.append(newJunction);
NetLineAnchor newAnchor(NetLineAnchor::junction(newJunction->getUuid()));
mFixedAnchorsToReplace.insert(anchor, newAnchor);
} else {
mFixedAnchorPositions[anchor] = pos;
}
}
void SchematicNetSegmentSplitter::addJunction(
const Junction& junction) noexcept {
mJunctions.append(std::make_shared<Junction>(junction));
}
void SchematicNetSegmentSplitter::addNetLine(const NetLine& netline) noexcept {
std::shared_ptr<NetLine> copy = std::make_shared<NetLine>(netline);
copy->setAnchors(replaceFixedAnchor(copy->getP1()),
replaceFixedAnchor(copy->getP2()));
mNetLines.append(copy);
}
void SchematicNetSegmentSplitter::addNetLabel(
const NetLabel& netlabel) noexcept {
mNetLabels.append(std::make_shared<NetLabel>(netlabel));
}
QList<SchematicNetSegmentSplitter::Segment>
SchematicNetSegmentSplitter::split() noexcept {
QList<Segment> segments;
// Split netsegment by anchors and lines.
// IMPORTANT: Make shallow copies to keep all references valid even though
// findConnectedLinesAndPoints() removes items from this list.
QList<std::shared_ptr<NetLine>> availableNetLines = mNetLines.values();
while (!availableNetLines.isEmpty()) {
Segment segment;
findConnectedLinesAndPoints(availableNetLines.first()->getP1(),
availableNetLines, segment);
segments.append(segment);
}
Q_ASSERT(availableNetLines.isEmpty());
// Add netlabels to their nearest netsegment
for (NetLabel& netlabel : mNetLabels) {
addNetLabelToNearestNetSegment(netlabel, segments);
}
return segments;
}
/*******************************************************************************
* Private Methods
******************************************************************************/
NetLineAnchor SchematicNetSegmentSplitter::replaceFixedAnchor(
const NetLineAnchor& anchor) noexcept {
return mFixedAnchorsToReplace.value(anchor, anchor);
}
void SchematicNetSegmentSplitter::findConnectedLinesAndPoints(
const NetLineAnchor& anchor,
QList<std::shared_ptr<NetLine>>& availableNetLines,
Segment& segment) noexcept {
if (std::optional<Uuid> junctionUuid = anchor.tryGetJunction()) {
if (std::shared_ptr<Junction> junction = mJunctions.find(*junctionUuid)) {
if (!segment.junctions.contains(junction->getUuid())) {
segment.junctions.append(junction);
}
}
}
for (int i = 0; i < mNetLines.count(); ++i) {
std::shared_ptr<NetLine> netline = mNetLines.value(i);
if (((netline->getP1() == anchor) || (netline->getP2() == anchor)) &&
availableNetLines.contains(netline) &&
(!segment.netlines.contains(netline->getUuid()))) {
segment.netlines.append(netline);
availableNetLines.removeOne(netline);
findConnectedLinesAndPoints(netline->getP1(), availableNetLines, segment);
findConnectedLinesAndPoints(netline->getP2(), availableNetLines, segment);
}
}
}
void SchematicNetSegmentSplitter::addNetLabelToNearestNetSegment(
const NetLabel& netlabel, QList<Segment>& segments) const noexcept {
int nearestIndex = -1;
Length nearestDistance;
for (int i = 0; i < segments.count(); ++i) {
Length distance =
getDistanceBetweenNetLabelAndNetSegment(netlabel, segments.at(i));
if ((distance < nearestDistance) || (nearestIndex < 0)) {
nearestIndex = i;
nearestDistance = distance;
}
}
if (nearestIndex >= 0) {
segments[nearestIndex].netlabels.append(
std::make_shared<NetLabel>(netlabel));
}
}
Length SchematicNetSegmentSplitter::getDistanceBetweenNetLabelAndNetSegment(
const NetLabel& netlabel, const Segment& netsegment) const noexcept {
bool firstRun = true;
Length nearestDistance;
for (const NetLine& netline : netsegment.netlines) {
UnsignedLength distance = Toolbox::shortestDistanceBetweenPointAndLine(
netlabel.getPosition(), getAnchorPosition(netline.getP1()),
getAnchorPosition(netline.getP2()));
if ((distance < nearestDistance) || firstRun) {
nearestDistance = *distance;
firstRun = false;
}
}
return nearestDistance;
}
Point SchematicNetSegmentSplitter::getAnchorPosition(
const NetLineAnchor& anchor) const noexcept {
if (mFixedAnchorPositions.contains(anchor)) {
return mFixedAnchorPositions[anchor];
} else if (std::optional<Uuid> junctionUuid = anchor.tryGetJunction()) {
if (mJunctions.contains(*junctionUuid)) {
return mJunctions.get(*junctionUuid)->getPosition();
}
}
qWarning() << "Failed to determine position of net label anchor while "
"splitting segments!";
return Point();
}
/*******************************************************************************
* End of File
******************************************************************************/
} // namespace librepcb