Loading files
This file is pinned to the selected release. Download the original to open it in your design tool.
8a92ff80bThis 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 "boarddesignrules.h"
#include "../../serialization/sexpression.h"
#include "drc/boarddesignrulechecksettings.h"
#include <QtCore>
/*******************************************************************************
* Namespace
******************************************************************************/
namespace librepcb {
/*******************************************************************************
* Constructors / Destructor
******************************************************************************/
BoardDesignRules::BoardDesignRules() noexcept
: // default values
mDefaultTraceWidth(500000), // 0.5mm
mDefaultViaDrillDiameter(300000), // 0.3mm
// stop mask
mStopMaskMaxViaDrillDiameter(300000), // 0.3mm
mStopMaskClearance(UnsignedRatio(Ratio::fromPercent(0)), // 0%
UnsignedLength(100000), // 0.1mm
UnsignedLength(100000)), // 0.1mm
// solder paste
mSolderPasteClearance(UnsignedRatio(Ratio::fromPercent(10)), // 10%
UnsignedLength(0), // 0mm
UnsignedLength(1000000)), // 1mm
// pad annular ring
mPadCmpSideAutoAnnularRing(false),
mPadInnerAutoAnnularRing(true),
mPadAnnularRing(UnsignedRatio(Ratio::fromPercent(25)), // 25%
UnsignedLength(250000), // 0.25mm
UnsignedLength(2000000)), // 2mm
// via annular ring
mViaAnnularRing(UnsignedRatio(Ratio::fromPercent(25)), // 25%
UnsignedLength(200000), // 0.2mm
UnsignedLength(2000000)) // 2mm
{
}
BoardDesignRules::BoardDesignRules(const BoardDesignRules& other)
: BoardDesignRules() {
*this = other;
}
BoardDesignRules::BoardDesignRules(const SExpression& node)
: // default values
mDefaultTraceWidth(
deserialize<PositiveLength>(node.getChild("default_trace_width/@0"))),
mDefaultViaDrillDiameter(deserialize<PositiveLength>(
node.getChild("default_via_drill_diameter/@0"))),
// stop mask
mStopMaskMaxViaDrillDiameter(deserialize<UnsignedLength>(
node.getChild("stopmask_max_via_drill_diameter/@0"))),
mStopMaskClearance(node.getChild("stopmask_clearance")),
// solder paste
mSolderPasteClearance(node.getChild("solderpaste_clearance")),
// pad annular ring
mPadCmpSideAutoAnnularRing(
parsePadAutoAnnular(node.getChild("pad_annular_ring/outer/@0"))),
mPadInnerAutoAnnularRing(
parsePadAutoAnnular(node.getChild("pad_annular_ring/inner/@0"))),
mPadAnnularRing(node.getChild("pad_annular_ring")),
// via annular ring
mViaAnnularRing(node.getChild("via_annular_ring")) {
}
BoardDesignRules::~BoardDesignRules() noexcept {
}
/*******************************************************************************
* General Methods
******************************************************************************/
void BoardDesignRules::restoreDefaults() noexcept {
*this = BoardDesignRules();
}
void BoardDesignRules::adjustToDrcSettings(
const BoardDesignRuleCheckSettings& s) noexcept {
const auto defaults = BoardDesignRules();
if (mDefaultTraceWidth < s.getMinCopperWidth()) {
mDefaultTraceWidth = PositiveLength(*s.getMinCopperWidth());
}
if (mDefaultViaDrillDiameter < s.getMinNpthDrillDiameter()) {
mDefaultViaDrillDiameter = PositiveLength(*s.getMinNpthDrillDiameter());
}
if (mStopMaskMaxViaDrillDiameter < s.getMaxTentedViaDrillDiameter()) {
mStopMaskMaxViaDrillDiameter = s.getMaxTentedViaDrillDiameter();
}
const UnsignedLength minPadAnnular = std::max(
defaults.getPadAnnularRing().getMinValue(), s.getMinPthAnnularRing());
mPadAnnularRing = BoundedUnsignedRatio(
mPadAnnularRing.getRatio(), minPadAnnular,
std::max(mPadAnnularRing.getMaxValue(), minPadAnnular));
const UnsignedLength minViaAnnular = std::max(
defaults.getPadAnnularRing().getMinValue(), s.getMinPthAnnularRing());
mViaAnnularRing = BoundedUnsignedRatio(
mViaAnnularRing.getRatio(), minViaAnnular,
std::max(mViaAnnularRing.getMaxValue(), minViaAnnular));
}
void BoardDesignRules::serialize(SExpression& root) const {
// default values
root.ensureLineBreak();
root.appendChild("default_trace_width", mDefaultTraceWidth);
root.ensureLineBreak();
root.appendChild("default_via_drill_diameter", mDefaultViaDrillDiameter);
// stop mask
root.ensureLineBreak();
root.appendChild("stopmask_max_via_drill_diameter",
mStopMaskMaxViaDrillDiameter);
root.ensureLineBreak();
mStopMaskClearance.serialize(root.appendList("stopmask_clearance"));
// solder paste
root.ensureLineBreak();
mSolderPasteClearance.serialize(root.appendList("solderpaste_clearance"));
// pad annular ring
{
root.ensureLineBreak();
SExpression& node = root.appendList("pad_annular_ring");
node.appendChild(
"outer",
SExpression::createToken(mPadCmpSideAutoAnnularRing ? "auto" : "full"));
node.appendChild(
"inner",
SExpression::createToken(mPadInnerAutoAnnularRing ? "auto" : "full"));
mPadAnnularRing.serialize(node);
}
// via annular ring
root.ensureLineBreak();
mViaAnnularRing.serialize(root.appendList("via_annular_ring"));
root.ensureLineBreak();
}
/*******************************************************************************
* Helper Methods
******************************************************************************/
bool BoardDesignRules::doesViaRequireStopMaskOpening(
const Length& drillDia) const noexcept {
return drillDia > (*mStopMaskMaxViaDrillDiameter);
}
/*******************************************************************************
* Operator Overloadings
******************************************************************************/
BoardDesignRules& BoardDesignRules::operator=(
const BoardDesignRules& rhs) noexcept {
// default values
mDefaultTraceWidth = rhs.mDefaultTraceWidth;
mDefaultViaDrillDiameter = rhs.mDefaultViaDrillDiameter;
// stop mask
mStopMaskMaxViaDrillDiameter = rhs.mStopMaskMaxViaDrillDiameter;
mStopMaskClearance = rhs.mStopMaskClearance;
// solder paste
mSolderPasteClearance = rhs.mSolderPasteClearance;
// pad annular ring
mPadCmpSideAutoAnnularRing = rhs.mPadCmpSideAutoAnnularRing;
mPadInnerAutoAnnularRing = rhs.mPadInnerAutoAnnularRing;
mPadAnnularRing = rhs.mPadAnnularRing;
// via annular ring
mViaAnnularRing = rhs.mViaAnnularRing;
return *this;
}
bool BoardDesignRules::operator==(const BoardDesignRules& rhs) const noexcept {
// default values
if (mDefaultTraceWidth != rhs.mDefaultTraceWidth) return false;
if (mDefaultViaDrillDiameter != rhs.mDefaultViaDrillDiameter) return false;
// stop mask
if (mStopMaskMaxViaDrillDiameter != rhs.mStopMaskMaxViaDrillDiameter)
return false;
if (mStopMaskClearance != rhs.mStopMaskClearance) return false;
// solder paste
if (mSolderPasteClearance != rhs.mSolderPasteClearance) return false;
// pad annular ring
if (mPadCmpSideAutoAnnularRing != rhs.mPadCmpSideAutoAnnularRing)
return false;
if (mPadInnerAutoAnnularRing != rhs.mPadInnerAutoAnnularRing) return false;
if (mPadAnnularRing != rhs.mPadAnnularRing) return false;
// via annular ring
if (mViaAnnularRing != rhs.mViaAnnularRing) return false;
return true;
}
/*******************************************************************************
* Private Methods
******************************************************************************/
bool BoardDesignRules::parsePadAutoAnnular(const SExpression& node) {
const QString str = node.getValue();
if (str == "auto") {
return true;
} else if (str == "full") {
return false;
} else {
throw RuntimeError(__FILE__, __LINE__,
QString("Invalid pad annular shape: '%1'").arg(str));
}
}
/*******************************************************************************
* End of File
******************************************************************************/
} // namespace librepcb