Loading files
/*
* 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 "boardnetsegmentsplitter.h"
#include "../../utils/toolbox.h"
#include <QtCore>
#include <QtWidgets>
/*******************************************************************************
* Namespace
******************************************************************************/
namespace librepcb {
/*******************************************************************************
* Constructors / Destructor
******************************************************************************/
BoardNetSegmentSplitter::BoardNetSegmentSplitter() noexcept
: mJunctions(), mPads(), mVias(), mTraces() {
}
BoardNetSegmentSplitter::~BoardNetSegmentSplitter() noexcept {
}
/*******************************************************************************
* General Methods
******************************************************************************/
void BoardNetSegmentSplitter::replaceFootprintPadByJunctions(
const TraceAnchor& anchor, const Point& pos) noexcept {
mAnchorsToReplace[anchor] = pos;
}
void BoardNetSegmentSplitter::addJunction(const Junction& junction) noexcept {
mJunctions.append(std::make_shared<Junction>(junction));
}
void BoardNetSegmentSplitter::addPad(const BoardPadData& pad,
bool replaceByJunctions) noexcept {
if (replaceByJunctions) {
mAnchorsToReplace[TraceAnchor::pad(pad.getUuid())] = pad.getPosition();
} else {
mPads.append(std::make_shared<BoardPadData>(pad));
}
}
void BoardNetSegmentSplitter::addVia(const Via& via,
bool replaceByJunctions) noexcept {
if (replaceByJunctions) {
mAnchorsToReplace[TraceAnchor::via(via.getUuid())] = via.getPosition();
} else {
mVias.append(std::make_shared<Via>(via));
}
}
void BoardNetSegmentSplitter::addTrace(const Trace& trace) noexcept {
std::shared_ptr<Trace> copy = std::make_shared<Trace>(trace);
copy->setAnchors(replaceAnchor(copy->getP1(), copy->getLayer()),
replaceAnchor(copy->getP2(), copy->getLayer()));
mTraces.append(copy);
}
QList<BoardNetSegmentSplitter::Segment>
BoardNetSegmentSplitter::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 these lists.
QList<std::shared_ptr<BoardPadData>> availablePads = mPads.values();
QList<std::shared_ptr<Via>> availableVias = mVias.values();
QList<std::shared_ptr<Trace>> availableTraces = mTraces.values();
while (!availableTraces.isEmpty()) {
Segment segment;
findConnectedLinesAndPoints(availableTraces.first()->getP1(), availablePads,
availableVias, availableTraces, segment);
segments.append(segment);
}
Q_ASSERT(availableTraces.isEmpty());
// Add remaining pads & vias as separate segments
while (!availablePads.isEmpty()) {
Segment segment;
segment.pads.append(availablePads.takeAt(0));
segments.append(segment);
}
Q_ASSERT(availablePads.isEmpty());
while (!availableVias.isEmpty()) {
Segment segment;
segment.vias.append(availableVias.takeAt(0));
segments.append(segment);
}
Q_ASSERT(availableVias.isEmpty());
return segments;
}
/*******************************************************************************
* Private Methods
******************************************************************************/
TraceAnchor BoardNetSegmentSplitter::replaceAnchor(
const TraceAnchor& anchor, const Layer& layer) noexcept {
if (mAnchorsToReplace.contains(anchor)) {
auto key = qMakePair(anchor, &layer);
auto it = mReplacedAnchors.find(key);
if (it == mReplacedAnchors.end()) {
std::shared_ptr<Junction> newJunction = std::make_shared<Junction>(
Uuid::createRandom(), mAnchorsToReplace.value(anchor));
mJunctions.append(newJunction);
TraceAnchor newAnchor(TraceAnchor::junction(newJunction->getUuid()));
it = mReplacedAnchors.insert(key, newAnchor);
}
return *it;
} else {
return anchor;
}
}
void BoardNetSegmentSplitter::findConnectedLinesAndPoints(
const TraceAnchor& anchor,
QList<std::shared_ptr<BoardPadData>>& availablePads,
QList<std::shared_ptr<Via>>& availableVias,
QList<std::shared_ptr<Trace>>& availableTraces, 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);
}
}
} else if (std::optional<Uuid> padUuid = anchor.tryGetPad()) {
if (std::shared_ptr<BoardPadData> pad = mPads.find(*padUuid)) {
if (availablePads.contains(pad)) {
segment.pads.append(pad);
availablePads.removeOne(pad);
}
}
} else if (std::optional<Uuid> viaUuid = anchor.tryGetVia()) {
if (std::shared_ptr<Via> via = mVias.find(*viaUuid)) {
if (availableVias.contains(via)) {
segment.vias.append(via);
availableVias.removeOne(via);
}
}
}
for (int i = 0; i < mTraces.count(); ++i) {
std::shared_ptr<Trace> trace = mTraces.value(i);
if (((trace->getP1() == anchor) || (trace->getP2() == anchor)) &&
availableTraces.contains(trace) &&
(!segment.traces.contains(trace.get()))) {
segment.traces.append(trace);
availableTraces.removeOne(trace);
findConnectedLinesAndPoints(trace->getP1(), availablePads, availableVias,
availableTraces, segment);
findConnectedLinesAndPoints(trace->getP2(), availablePads, availableVias,
availableTraces, segment);
}
}
}
/*******************************************************************************
* End of File
******************************************************************************/
} // namespace librepcb
59219ad85This file is pinned to the selected release. Download the original to open it in your design tool.