[TD]Refactor Dimensions for 3d upgrade
- separate validation, geometry and reference handling into individual files - improve 3d reference geometry handling - eliminate duplicate dim creation code - add Dimension reference repair dialog - Refactor formatting out of DrawViewDimension - move dimension repaint control to ViewProvider
This commit is contained in:
@@ -62,6 +62,7 @@
|
||||
#include "DrawUtil.h"
|
||||
#include "DrawViewAnnotation.h"
|
||||
#include "DrawViewDimension.h"
|
||||
#include "DimensionGeometry.h"
|
||||
#include "DrawViewPart.h"
|
||||
#include "DrawViewPartPy.h"
|
||||
#include "EdgeWalker.h"
|
||||
@@ -725,13 +726,13 @@ private:
|
||||
Base::Vector3d textLocn(dvd->X.getValue() + parentX, dvd->Y.getValue() + parentY, 0.0);
|
||||
Base::Vector3d lineLocn(dvd->X.getValue() + parentX, dvd->Y.getValue() + parentY, 0.0);
|
||||
pointPair pts = dvd->getLinearPoints();
|
||||
Base::Vector3d dimLine = pts.first - pts.second;
|
||||
Base::Vector3d dimLine = pts.first() - pts.second();
|
||||
Base::Vector3d norm(-dimLine.y, dimLine.x, 0.0);
|
||||
norm.Normalize();
|
||||
lineLocn = lineLocn + (norm * gap);
|
||||
Base::Vector3d extLine1Start = Base::Vector3d(pts.first.x, -pts.first.y, 0.0) +
|
||||
Base::Vector3d extLine1Start = Base::Vector3d(pts.first().x, - pts.first().y, 0.0) +
|
||||
Base::Vector3d(parentX, parentY, 0.0);
|
||||
Base::Vector3d extLine2Start = Base::Vector3d(pts.second.x, -pts.second.y, 0.0) +
|
||||
Base::Vector3d extLine2Start = Base::Vector3d(pts.second().x, - pts.second().y, 0.0) +
|
||||
Base::Vector3d(parentX, parentY, 0.0);
|
||||
if (dvd->Type.isValue("DistanceX") ) {
|
||||
type = 1;
|
||||
@@ -743,12 +744,12 @@ private:
|
||||
Base::Vector3d textLocn(dvd->X.getValue() + parentX, dvd->Y.getValue() + parentY, 0.0);
|
||||
Base::Vector3d lineLocn(dvd->X.getValue() + parentX, dvd->Y.getValue() + parentY, 0.0);
|
||||
anglePoints pts = dvd->getAnglePoints();
|
||||
Base::Vector3d end1 = pts.ends.first;
|
||||
Base::Vector3d end1 = pts.first();
|
||||
end1.y = -end1.y;
|
||||
Base::Vector3d end2 = pts.ends.second;
|
||||
Base::Vector3d end2 = pts.second();
|
||||
end2.y = -end2.y;
|
||||
|
||||
Base::Vector3d apex = pts.vertex;
|
||||
Base::Vector3d apex = pts.vertex();
|
||||
apex.y = -apex.y;
|
||||
apex = apex + parentPos;
|
||||
|
||||
@@ -766,7 +767,7 @@ private:
|
||||
Base::Vector3d center = pts.center;
|
||||
center.y = -center.y;
|
||||
center = center + parentPos;
|
||||
Base::Vector3d lineDir = (arrowPts.first - arrowPts.second).Normalize();
|
||||
Base::Vector3d lineDir = (arrowPts.first() - arrowPts.second()).Normalize();
|
||||
Base::Vector3d arcPoint = center + lineDir * pts.radius;
|
||||
writer.exportRadialDim(center, textLocn, arcPoint, dimText);
|
||||
} else if(dvd->Type.isValue("Diameter")){
|
||||
@@ -776,7 +777,7 @@ private:
|
||||
Base::Vector3d center = pts.center;
|
||||
center.y = -center.y;
|
||||
center = center + parentPos;
|
||||
Base::Vector3d lineDir = (arrowPts.first - arrowPts.second).Normalize();
|
||||
Base::Vector3d lineDir = (arrowPts.first() - arrowPts.second()).Normalize();
|
||||
Base::Vector3d end1 = center + lineDir * pts.radius;
|
||||
Base::Vector3d end2 = center - lineDir * pts.radius;
|
||||
writer.exportDiametricDim(textLocn, end1, end2, dimText);
|
||||
|
||||
@@ -108,6 +108,12 @@ SET(Draw_SRCS
|
||||
DrawViewDimExtent.h
|
||||
LandmarkDimension.cpp
|
||||
LandmarkDimension.h
|
||||
DimensionGeometry.cpp
|
||||
DimensionGeometry.h
|
||||
DimensionReferences.cpp
|
||||
DimensionReferences.h
|
||||
DimensionFormatter.cpp
|
||||
DimensionFormatter.h
|
||||
DrawViewBalloon.cpp
|
||||
DrawViewBalloon.h
|
||||
DrawViewSection.cpp
|
||||
|
||||
408
src/Mod/TechDraw/App/DimensionFormatter.cpp
Normal file
408
src/Mod/TechDraw/App/DimensionFormatter.cpp
Normal file
@@ -0,0 +1,408 @@
|
||||
/***************************************************************************
|
||||
* Copyright (c) 2022 WandererFan <wandererfan@gmail.com> *
|
||||
* *
|
||||
* This file is part of the FreeCAD CAx development system. *
|
||||
* *
|
||||
* This library is free software; you can redistribute it and/or *
|
||||
* modify it under the terms of the GNU Library General Public *
|
||||
* License as published by the Free Software Foundation; either *
|
||||
* version 2 of the License, or (at your option) any later version. *
|
||||
* *
|
||||
* This library 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 Library General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Library General Public *
|
||||
* License along with this library; see the file COPYING.LIB. If not, *
|
||||
* write to the Free Software Foundation, Inc., 59 Temple Place, *
|
||||
* Suite 330, Boston, MA 02111-1307, USA *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
#include "PreCompiled.h"
|
||||
#include <QRegularExpression>
|
||||
#ifndef _PreComp_
|
||||
#endif
|
||||
|
||||
#include <Base/Tools.h>
|
||||
#include <Base/UnitsApi.h>
|
||||
|
||||
#include "Preferences.h"
|
||||
#include "DrawViewDimension.h"
|
||||
#include "DimensionFormatter.h"
|
||||
|
||||
using namespace TechDraw;
|
||||
|
||||
bool DimensionFormatter::isMultiValueSchema() const
|
||||
{
|
||||
bool angularMeasure = (m_dimension->Type.isValue("Angle") ||
|
||||
m_dimension->Type.isValue("Angle3Pt"));
|
||||
|
||||
if (Base::UnitsApi::isMultiUnitAngle() &&
|
||||
angularMeasure) {
|
||||
return true;
|
||||
} else if (Base::UnitsApi::isMultiUnitLength() &&
|
||||
!angularMeasure) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//partial = 0 return the unaltered user string from the Units subsystem
|
||||
//partial = 1 return value formatted according to the format spec and preferences for
|
||||
// useAltDecimals and showUnits
|
||||
//partial = 2 return only the unit of measure
|
||||
std::string DimensionFormatter::formatValue(qreal value,
|
||||
QString qFormatSpec,
|
||||
int partial,
|
||||
bool isDim)
|
||||
{
|
||||
bool angularMeasure = false;
|
||||
QLocale loc;
|
||||
|
||||
Base::Quantity asQuantity;
|
||||
asQuantity.setValue(value);
|
||||
if ( (m_dimension->Type.isValue("Angle")) ||
|
||||
(m_dimension->Type.isValue("Angle3Pt")) ) {
|
||||
angularMeasure = true;
|
||||
asQuantity.setUnit(Base::Unit::Angle);
|
||||
} else {
|
||||
asQuantity.setUnit(Base::Unit::Length);
|
||||
}
|
||||
|
||||
QString qUserString = asQuantity.getUserString(); // this handles mm to inch/km/parsec etc
|
||||
// and decimal positions but won't give more than
|
||||
// Global_Decimals precision
|
||||
|
||||
//get formatSpec prefix/suffix/specifier
|
||||
QStringList qsl = getPrefixSuffixSpec(qFormatSpec);
|
||||
QString formatPrefix = qsl[0]; //FormatSpec prefix
|
||||
QString formatSuffix = qsl[1]; //FormatSpec suffix
|
||||
QString formatSpecifier = qsl[2]; //FormatSpec specifier
|
||||
|
||||
QString qMultiValueStr;
|
||||
QString qBasicUnit = Base::Tools::fromStdString(Base::UnitsApi::getBasicLengthUnit());
|
||||
|
||||
QString formattedValue;
|
||||
if (isMultiValueSchema() && partial == 0) {
|
||||
//handle multi value schemes (yd/ft/in, dms, etc). don't even try to use Alt Decimals or hide units
|
||||
qMultiValueStr = formatPrefix + qUserString + formatSuffix;
|
||||
return qMultiValueStr.toStdString();
|
||||
} else {
|
||||
//not multivalue schema
|
||||
if (formatSpecifier.isEmpty()) {
|
||||
Base::Console().Warning("Warning - no numeric format in Format Spec %s - %s\n",
|
||||
qPrintable(qFormatSpec), m_dimension->getNameInDocument());
|
||||
return Base::Tools::toStdString(qFormatSpec);
|
||||
}
|
||||
|
||||
// for older TD drawings the formatSpecifier "%g" was used, but the number of decimals was
|
||||
// neverheless limited. To keep old drawings, we limit the number of decimals too
|
||||
// if the TD preferences option to use the global decimal number is set
|
||||
// the formatSpecifier can have a prefix and/or suffix
|
||||
if (m_dimension->useDecimals() && formatSpecifier.contains(QString::fromLatin1("%g"), Qt::CaseInsensitive)) {
|
||||
int globalPrecision = Base::UnitsApi::getDecimals();
|
||||
// change formatSpecifier to e.g. "%.2f"
|
||||
QString newSpecifier = QString::fromStdString("%." + std::to_string(globalPrecision) + "f");
|
||||
formatSpecifier.replace(QString::fromLatin1("%g"), newSpecifier, Qt::CaseInsensitive);
|
||||
}
|
||||
|
||||
// since we are not using a multiValueSchema, we know that angles are in '°' and for
|
||||
// lengths we can get the unit of measure from UnitsApi::getBasicLengthUnit.
|
||||
|
||||
// TODO: check the weird schemas (MKS, Imperial1)that report different UoM
|
||||
// for different values
|
||||
|
||||
// get value in the base unit with default decimals
|
||||
// for the conversion we use the same method as in DlgUnitsCalculator::valueChanged
|
||||
// get the conversion factor for the unit
|
||||
// the result is now just val / convertValue because val is always in the base unit
|
||||
// don't do this for angular values since they are not in the BaseLengthUnit
|
||||
double userVal;
|
||||
if (angularMeasure) {
|
||||
userVal = asQuantity.getValue();
|
||||
qBasicUnit = QString::fromUtf8("°");
|
||||
} else {
|
||||
double convertValue = Base::Quantity::parse(QString::fromLatin1("1") + qBasicUnit).getValue();
|
||||
userVal = asQuantity.getValue() / convertValue;
|
||||
}
|
||||
|
||||
if (isTooSmall(userVal, formatSpecifier)) {
|
||||
Base::Console().Warning("Dimension value is too small for format specifier: %s\n", qPrintable(formatSpecifier));
|
||||
}
|
||||
|
||||
formattedValue = formatValueToSpec(userVal, formatSpecifier);
|
||||
|
||||
// replace decimal sign if necessary
|
||||
QChar dp = QChar::fromLatin1('.');
|
||||
if (loc.decimalPoint() != dp) {
|
||||
formattedValue.replace(dp, loc.decimalPoint());
|
||||
}
|
||||
}
|
||||
|
||||
//formattedValue is now in formatSpec format with local decimal separator
|
||||
std::string formattedValueString = formattedValue.toStdString();
|
||||
if (partial == 0) { //prefix + unit subsystem string + suffix
|
||||
return Base::Tools::toStdString(formatPrefix) +
|
||||
Base::Tools::toStdString(qUserString) +
|
||||
Base::Tools::toStdString(formatSuffix);
|
||||
} else if (partial == 1) { // prefix number[unit] suffix
|
||||
if (angularMeasure) {
|
||||
//always insert unit after value
|
||||
return Base::Tools::toStdString(formatPrefix) +
|
||||
formattedValueString + "°" +
|
||||
Base::Tools::toStdString(formatSuffix);
|
||||
} else if (m_dimension->showUnits()){
|
||||
if (isDim && m_dimension->haveTolerance()) {
|
||||
//unit will be included in tolerance so don't repeat it here
|
||||
return Base::Tools::toStdString(formatPrefix) +
|
||||
formattedValueString +
|
||||
Base::Tools::toStdString(formatSuffix);
|
||||
} else {
|
||||
//no tolerance, so we need to include unit
|
||||
return Base::Tools::toStdString(formatPrefix) +
|
||||
formattedValueString + " " +
|
||||
Base::Tools::toStdString(qBasicUnit) +
|
||||
Base::Tools::toStdString(formatSuffix);
|
||||
}
|
||||
} else {
|
||||
//showUnits is false
|
||||
return Base::Tools::toStdString(formatPrefix) +
|
||||
formattedValueString +
|
||||
Base::Tools::toStdString(formatSuffix);
|
||||
}
|
||||
} else if (partial == 2) { // just the unit
|
||||
if (angularMeasure) {
|
||||
return Base::Tools::toStdString(qBasicUnit);
|
||||
} else if (m_dimension->showUnits()) {
|
||||
return Base::Tools::toStdString(qBasicUnit);
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
return formattedValueString;
|
||||
}
|
||||
|
||||
std::string DimensionFormatter::getFormattedToleranceValue(int partial)
|
||||
{
|
||||
QString FormatSpec = QString::fromUtf8(m_dimension->FormatSpecOverTolerance.getStrValue().data());
|
||||
QString ToleranceString;
|
||||
|
||||
if (m_dimension->ArbitraryTolerances.getValue())
|
||||
ToleranceString = FormatSpec;
|
||||
else
|
||||
ToleranceString = QString::fromUtf8(formatValue(m_dimension->OverTolerance.getValue(),
|
||||
FormatSpec,
|
||||
partial,
|
||||
false).c_str());
|
||||
|
||||
return ToleranceString.toStdString();
|
||||
}
|
||||
|
||||
//get over and under tolerances
|
||||
std::pair<std::string, std::string> DimensionFormatter::getFormattedToleranceValues(int partial)
|
||||
{
|
||||
QString underFormatSpec = QString::fromUtf8(m_dimension->FormatSpecUnderTolerance.getStrValue().data());
|
||||
QString overFormatSpec = QString::fromUtf8(m_dimension->FormatSpecOverTolerance.getStrValue().data());
|
||||
std::pair<std::string, std::string> tolerances;
|
||||
QString underTolerance, overTolerance;
|
||||
|
||||
if (m_dimension->ArbitraryTolerances.getValue()) {
|
||||
underTolerance = underFormatSpec;
|
||||
overTolerance = overFormatSpec;
|
||||
} else {
|
||||
if (DrawUtil::fpCompare(m_dimension->UnderTolerance.getValue(), 0.0)) {
|
||||
underTolerance = QString::fromUtf8(formatValue(m_dimension->UnderTolerance.getValue(),
|
||||
QString::fromUtf8("%.0f"),
|
||||
partial,
|
||||
false).c_str());
|
||||
}
|
||||
else {
|
||||
underTolerance = QString::fromUtf8(formatValue(m_dimension->UnderTolerance.getValue(),
|
||||
underFormatSpec,
|
||||
partial,
|
||||
false).c_str());
|
||||
}
|
||||
if (DrawUtil::fpCompare(m_dimension->OverTolerance.getValue(), 0.0)) {
|
||||
overTolerance = QString::fromUtf8(formatValue(m_dimension->OverTolerance.getValue(),
|
||||
QString::fromUtf8("%.0f"),
|
||||
partial,
|
||||
false).c_str());
|
||||
}
|
||||
else {
|
||||
overTolerance = QString::fromUtf8(formatValue(m_dimension->OverTolerance.getValue(),
|
||||
overFormatSpec,
|
||||
partial,
|
||||
false).c_str());
|
||||
}
|
||||
}
|
||||
|
||||
tolerances.first = underTolerance.toStdString();
|
||||
tolerances.second = overTolerance.toStdString();
|
||||
|
||||
return tolerances;
|
||||
}
|
||||
|
||||
//partial = 2 unit only
|
||||
std::string DimensionFormatter::getFormattedDimensionValue(int partial)
|
||||
{
|
||||
QString qFormatSpec = QString::fromUtf8(m_dimension->FormatSpec.getStrValue().data());
|
||||
|
||||
if ( (m_dimension->Arbitrary.getValue() && !m_dimension->EqualTolerance.getValue())
|
||||
|| (m_dimension->Arbitrary.getValue() && m_dimension->TheoreticalExact.getValue()) ) {
|
||||
return m_dimension->FormatSpec.getStrValue();
|
||||
}
|
||||
|
||||
if (m_dimension->Arbitrary.getValue()) {
|
||||
return m_dimension->FormatSpec.getStrValue();
|
||||
}
|
||||
|
||||
// if there is an equal over-/undertolerance (so only 1 tolerance to show with +/-) and
|
||||
// not theoretically exact (which has no tolerance), and
|
||||
// tolerance has been specified, ie
|
||||
// (OverTolerance != 0.0 (so a tolerance has been specified) or
|
||||
// ArbitraryTolerances are specified)
|
||||
// concatenate the tolerance to dimension
|
||||
if (m_dimension->EqualTolerance.getValue() &&
|
||||
!m_dimension->TheoreticalExact.getValue() &&
|
||||
(!DrawUtil::fpCompare(m_dimension->OverTolerance.getValue(), 0.0) ||
|
||||
m_dimension->ArbitraryTolerances.getValue())) {
|
||||
QString labelText = QString::fromUtf8(formatValue(m_dimension->getDimValue(),
|
||||
qFormatSpec,
|
||||
1,
|
||||
true).c_str()); //just the number pref/spec[unit]/suf
|
||||
QString unitText = QString::fromUtf8(formatValue(m_dimension->getDimValue(),
|
||||
qFormatSpec,
|
||||
2,
|
||||
false).c_str()); //just the unit
|
||||
QString tolerance = QString::fromStdString(getFormattedToleranceValue(1).c_str());
|
||||
|
||||
// tolerance might start with a plus sign that we don't want, so cut it off
|
||||
// note plus sign is not at pos = 0!
|
||||
QRegularExpression plus(QString::fromUtf8("^\\s*\\+"));
|
||||
tolerance.remove(plus);
|
||||
|
||||
return (labelText +
|
||||
QString::fromUtf8(" \xC2\xB1 ") + // +/- symbol
|
||||
tolerance).toStdString();
|
||||
|
||||
if (partial == 2) {
|
||||
return unitText.toStdString();
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
//tolerance not specified, so just format dimension value?
|
||||
std::string formattedValue = formatValue(m_dimension->getDimValue(), qFormatSpec, partial, true);
|
||||
|
||||
return formattedValue;
|
||||
}
|
||||
|
||||
// format the value using the formatSpec. Also, handle the non-standard format-
|
||||
// specifier '%w', which has the following rules: works as %f, but no trailing zeros
|
||||
QString DimensionFormatter::formatValueToSpec(double value, QString formatSpecifier)
|
||||
{
|
||||
QString formattedValue;
|
||||
if (formatSpecifier.contains(QRegularExpression(QStringLiteral("%.*[wW]")))) {
|
||||
QString fs = formatSpecifier;
|
||||
fs.replace(QRegularExpression(QStringLiteral("%(.*)w")), QStringLiteral("%\\1f"));
|
||||
fs.replace(QRegularExpression(QStringLiteral("%(.*)W")), QStringLiteral("%\\1F"));
|
||||
formattedValue = QString::asprintf(Base::Tools::toStdString(fs).c_str(), value);
|
||||
// First, try to cut trailing zeros, if AFTER decimal dot there are nonzero numbers
|
||||
// Second, try to cut also decimal dot and zeros, if there are just zeros after it
|
||||
formattedValue.replace(QRegularExpression(QStringLiteral("([0-9][0-9]*\\.[0-9]*[1-9])00*$")), QStringLiteral("\\1"));
|
||||
formattedValue.replace(QRegularExpression(QStringLiteral("([0-9][0-9]*)\\.0*$")), QStringLiteral("\\1"));
|
||||
} else {
|
||||
formattedValue = QString::asprintf(Base::Tools::toStdString(formatSpecifier).c_str(), value);
|
||||
}
|
||||
|
||||
return formattedValue;
|
||||
}
|
||||
|
||||
QStringList DimensionFormatter::getPrefixSuffixSpec(QString fSpec)
|
||||
{
|
||||
QStringList result;
|
||||
//find the %x.y tag in FormatSpec
|
||||
QRegularExpression rxFormat(QStringLiteral("%[+-]?[0-9]*\\.*[0-9]*[aefgwAEFGW]")); //printf double format spec
|
||||
QRegularExpressionMatch rxMatch;
|
||||
int pos = fSpec.indexOf(rxFormat, 0, &rxMatch);
|
||||
if (pos != -1) {
|
||||
QString match = rxMatch.captured(0); //entire capture of rx
|
||||
QString formatPrefix = fSpec.left(pos);
|
||||
result.append(formatPrefix);
|
||||
QString formatSuffix = fSpec.right(fSpec.size() - pos - match.size());
|
||||
result.append(formatSuffix);
|
||||
result.append(match);
|
||||
} else { //printf format not found!
|
||||
Base::Console().Warning("Warning - no numeric format in formatSpec %s - %s\n",
|
||||
qPrintable(fSpec), m_dimension->getNameInDocument());
|
||||
result.append(QString());
|
||||
result.append(QString());
|
||||
result.append(fSpec);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string DimensionFormatter::getDefaultFormatSpec(bool isToleranceFormat) const
|
||||
{
|
||||
std::string prefFormat = Preferences::formatSpec();
|
||||
QString formatSpec;
|
||||
QString qPrefix;
|
||||
if (prefFormat.empty()) {
|
||||
QString format1 = Base::Tools::fromStdString("%.");
|
||||
QString format2 = Base::Tools::fromStdString("f");
|
||||
int precision;
|
||||
if (m_dimension->useDecimals()) {
|
||||
precision = Base::UnitsApi::getDecimals();
|
||||
} else {
|
||||
precision = Preferences::altDecimals();
|
||||
}
|
||||
QString formatPrecision = QString::number(precision);
|
||||
|
||||
std::string prefix = m_dimension->getPrefixForDimType();
|
||||
|
||||
if (!prefix.empty()) {
|
||||
qPrefix = QString::fromUtf8(prefix.data(), prefix.size());
|
||||
}
|
||||
|
||||
formatSpec = qPrefix + format1 + formatPrecision + format2;
|
||||
} else {
|
||||
|
||||
std::string prefix = m_dimension->getPrefixForDimType();
|
||||
qPrefix = QString::fromUtf8(prefix.data(), prefix.size());
|
||||
formatSpec = qPrefix + QString::fromStdString(prefFormat);
|
||||
|
||||
}
|
||||
|
||||
if (isToleranceFormat) {
|
||||
formatSpec.replace(QString::fromUtf8("%"), QString::fromUtf8("%+"));
|
||||
}
|
||||
|
||||
return Base::Tools::toStdString(formatSpec);
|
||||
}
|
||||
|
||||
//true if value is too small to display using formatSpec
|
||||
bool DimensionFormatter::isTooSmall(double value, QString formatSpec)
|
||||
{
|
||||
if (DU::fpCompare(value, 0.0)) {
|
||||
//zero values always fit, so it isn't too small
|
||||
return false;
|
||||
}
|
||||
|
||||
QRegularExpression rxFormat(QStringLiteral("%[+-]?[0-9]*\\.*([0-9]*)[aefgwAEFGW]")); //printf double format spec
|
||||
QRegularExpressionMatch rxMatch = rxFormat.match(formatSpec);
|
||||
if (rxMatch.hasMatch()) {
|
||||
QString decimalGroup = rxMatch.captured(1);
|
||||
int factor = decimalGroup.toInt();
|
||||
double minValue = pow(10.0, -factor);
|
||||
if (value < minValue) {
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
Base::Console().Warning("Failed to parse dimension format spec\n");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
57
src/Mod/TechDraw/App/DimensionFormatter.h
Normal file
57
src/Mod/TechDraw/App/DimensionFormatter.h
Normal file
@@ -0,0 +1,57 @@
|
||||
/***************************************************************************
|
||||
* Copyright (c) 2022 WandererFan <wandererfan@gmail.com> *
|
||||
* *
|
||||
* This file is part of the FreeCAD CAx development system. *
|
||||
* *
|
||||
* This library is free software; you can redistribute it and/or *
|
||||
* modify it under the terms of the GNU Library General Public *
|
||||
* License as published by the Free Software Foundation; either *
|
||||
* version 2 of the License, or (at your option) any later version. *
|
||||
* *
|
||||
* This library 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 Library General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Library General Public *
|
||||
* License along with this library; see the file COPYING.LIB. If not, *
|
||||
* write to the Free Software Foundation, Inc., 59 Temple Place, *
|
||||
* Suite 330, Boston, MA 02111-1307, USA *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef DIMENSIONFORMATTER_H
|
||||
#define DIMENSIONFORMATTER_H
|
||||
|
||||
#include <Mod/TechDraw/TechDrawGlobal.h>
|
||||
|
||||
#include <DrawViewDimension.h>
|
||||
|
||||
namespace TechDraw {
|
||||
|
||||
class TechDrawExport DimensionFormatter {
|
||||
public:
|
||||
DimensionFormatter() {}
|
||||
DimensionFormatter(DrawViewDimension* dim) { m_dimension = dim; }
|
||||
~DimensionFormatter() = default;
|
||||
|
||||
void setDimension(DrawViewDimension* dim) { m_dimension = dim; }
|
||||
bool isMultiValueSchema() const;
|
||||
std::string formatValue(qreal value,
|
||||
QString qFormatSpec,
|
||||
int partial,
|
||||
bool isDim);
|
||||
std::string getFormattedToleranceValue(int partial);
|
||||
std::pair<std::string, std::string> getFormattedToleranceValues(int partial);
|
||||
std::string getFormattedDimensionValue(int partial);
|
||||
QStringList getPrefixSuffixSpec(QString fSpec);
|
||||
std::string getDefaultFormatSpec(bool isToleranceFormat) const;
|
||||
bool isTooSmall(double value, QString formatSpec);
|
||||
QString formatValueToSpec(double value, QString formatSpecifier);
|
||||
|
||||
private:
|
||||
DrawViewDimension* m_dimension;
|
||||
};
|
||||
|
||||
} //end namespace TechDraw
|
||||
#endif
|
||||
251
src/Mod/TechDraw/App/DimensionGeometry.cpp
Normal file
251
src/Mod/TechDraw/App/DimensionGeometry.cpp
Normal file
@@ -0,0 +1,251 @@
|
||||
/***************************************************************************
|
||||
* Copyright (c) 2022 WandererFan <wandererfan@gmail.com> *
|
||||
* *
|
||||
* This file is part of the FreeCAD CAx development system. *
|
||||
* *
|
||||
* This library is free software; you can redistribute it and/or *
|
||||
* modify it under the terms of the GNU Library General Public *
|
||||
* License as published by the Free Software Foundation; either *
|
||||
* version 2 of the License, or (at your option) any later version. *
|
||||
* *
|
||||
* This library 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 Library General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Library General Public *
|
||||
* License along with this library; see the file COPYING.LIB. If not, *
|
||||
* write to the Free Software Foundation, Inc., 59 Temple Place, *
|
||||
* Suite 330, Boston, MA 02111-1307, USA *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
#include "PreCompiled.h"
|
||||
|
||||
#ifndef _PreComp_
|
||||
#include <gp_Ax3.hxx>
|
||||
#include <gp_Trsf.hxx>
|
||||
#include <gp_Vec.hxx>
|
||||
#endif
|
||||
|
||||
#include <Base/Console.h>
|
||||
|
||||
#include "DrawViewPart.h"
|
||||
#include "DrawUtil.h"
|
||||
|
||||
#include "DimensionGeometry.h"
|
||||
|
||||
using namespace TechDraw;
|
||||
using DU = DrawUtil;
|
||||
|
||||
pointPair::pointPair(const pointPair& pp)
|
||||
{
|
||||
first(pp.first());
|
||||
second(pp.second());
|
||||
}
|
||||
|
||||
void pointPair::move(Base::Vector3d offset)
|
||||
{
|
||||
m_first = m_first - offset;
|
||||
m_second = m_second - offset;
|
||||
}
|
||||
|
||||
void pointPair::project(DrawViewPart* dvp)
|
||||
{
|
||||
Base::Vector3d normal = DrawUtil::toVector3d(dvp->getProjectionCS().Direction());
|
||||
Base::Vector3d stdOrigin(0.0, 0.0, 0.0);
|
||||
m_first = m_first.ProjectToPlane(stdOrigin, normal) * dvp->getScale();
|
||||
m_second = m_second.ProjectToPlane(stdOrigin, normal) * dvp->getScale();
|
||||
}
|
||||
|
||||
void pointPair::mapToPage(DrawViewPart* dvp)
|
||||
{
|
||||
gp_Trsf xOXYZ;
|
||||
gp_Ax3 OXYZ;
|
||||
xOXYZ.SetTransformation(OXYZ, gp_Ax3(dvp->getProjectionCS()));
|
||||
|
||||
gp_Vec gvFirst = DU::togp_Vec(m_first).Transformed(xOXYZ);
|
||||
m_first = DU::toVector3d(gvFirst);
|
||||
gp_Vec gvSecond = DU::togp_Vec(m_second).Transformed(xOXYZ);
|
||||
m_second = DU::toVector3d(gvSecond);
|
||||
}
|
||||
|
||||
void pointPair::invertY()
|
||||
{
|
||||
m_first = DU::invertY(m_first);
|
||||
m_second = DU::invertY(m_second);
|
||||
}
|
||||
|
||||
void pointPair::dump(std::string text) const
|
||||
{
|
||||
Base::Console().Message("pointPair - %s\n", text.c_str());
|
||||
Base::Console().Message("pointPair - first: %s second: %s\n",
|
||||
DU::formatVector(first()).c_str(),
|
||||
DU::formatVector(second()).c_str());
|
||||
}
|
||||
|
||||
anglePoints::anglePoints()
|
||||
{
|
||||
m_ends.first(Base::Vector3d(0.0, 0.0, 0.0));
|
||||
m_ends.second(Base::Vector3d(0.0, 0.0, 0.0));
|
||||
m_vertex = Base::Vector3d(0.0, 0.0, 0.0);
|
||||
}
|
||||
|
||||
anglePoints::anglePoints(const anglePoints& ap)
|
||||
: m_ends(ap.ends()),
|
||||
m_vertex(ap.vertex())
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
anglePoints& anglePoints::operator= (const anglePoints& ap)
|
||||
{
|
||||
m_ends = ap.ends();
|
||||
m_vertex = ap.vertex();
|
||||
return *this;
|
||||
}
|
||||
|
||||
void anglePoints::move(Base::Vector3d offset)
|
||||
{
|
||||
m_ends.move(offset);
|
||||
m_vertex = m_vertex - offset;
|
||||
}
|
||||
|
||||
void anglePoints::project(DrawViewPart* dvp)
|
||||
{
|
||||
Base::Vector3d normal = DrawUtil::toVector3d(dvp->getProjectionCS().Direction());
|
||||
Base::Vector3d stdOrigin(0.0, 0.0, 0.0);
|
||||
m_ends.project(dvp);
|
||||
m_vertex = m_vertex.ProjectToPlane(stdOrigin, normal) * dvp->getScale();
|
||||
}
|
||||
|
||||
void anglePoints::mapToPage(DrawViewPart* dvp)
|
||||
{
|
||||
m_ends.mapToPage(dvp);
|
||||
|
||||
gp_Trsf xOXYZ;
|
||||
gp_Ax3 OXYZ;
|
||||
xOXYZ.SetTransformation(OXYZ, gp_Ax3(dvp->getProjectionCS()));
|
||||
gp_Vec gvVertex = DU::togp_Vec(m_vertex).Transformed(xOXYZ);
|
||||
m_vertex = DU::toVector3d(gvVertex);
|
||||
}
|
||||
|
||||
void anglePoints::invertY()
|
||||
{
|
||||
m_ends.invertY();
|
||||
m_vertex = DU::invertY(m_vertex);
|
||||
}
|
||||
|
||||
void anglePoints::dump(std::string text) const
|
||||
{
|
||||
Base::Console().Message("anglePoints - %s\n", text.c_str());
|
||||
Base::Console().Message("anglePoints - ends - first: %s second: %s\n",
|
||||
DU::formatVector(first()).c_str(),
|
||||
DU::formatVector(second()).c_str());
|
||||
Base::Console().Message("anglePoints - vertex: %s\n",
|
||||
DU::formatVector(vertex()).c_str());
|
||||
}
|
||||
|
||||
arcPoints::arcPoints()
|
||||
{
|
||||
isArc = false;
|
||||
radius = 0.0;
|
||||
center = Base::Vector3d(0.0, 0.0, 0.0);
|
||||
onCurve.first(Base::Vector3d(0.0, 0.0, 0.0));
|
||||
onCurve.second(Base::Vector3d(0.0, 0.0, 0.0));
|
||||
arcEnds.first(Base::Vector3d(0.0, 0.0, 0.0));
|
||||
arcEnds.second(Base::Vector3d(0.0, 0.0, 0.0));
|
||||
midArc = Base::Vector3d(0.0, 0.0, 0.0);
|
||||
arcCW = false;
|
||||
}
|
||||
|
||||
arcPoints::arcPoints(const arcPoints& ap)
|
||||
: isArc(ap.isArc)
|
||||
, radius(ap.radius)
|
||||
, center(ap.center)
|
||||
, onCurve(ap.onCurve)
|
||||
, arcEnds(ap.arcEnds)
|
||||
, midArc(ap.midArc)
|
||||
, arcCW(ap.arcCW)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
arcPoints& arcPoints::operator= (const arcPoints& ap)
|
||||
{
|
||||
isArc = ap.isArc;
|
||||
radius = ap.radius;
|
||||
center = ap.center;
|
||||
onCurve = ap.onCurve;
|
||||
arcEnds = ap.arcEnds;
|
||||
midArc = ap.midArc;
|
||||
arcCW = ap.arcCW;
|
||||
return *this;
|
||||
}
|
||||
|
||||
void arcPoints::move(Base::Vector3d offset)
|
||||
{
|
||||
center = center - offset;
|
||||
onCurve.first(onCurve.first() - offset);
|
||||
onCurve.second(onCurve.second() - offset);
|
||||
arcEnds.first(arcEnds.first() - offset);
|
||||
arcEnds.second(arcEnds.second() - offset);
|
||||
midArc = midArc - offset;
|
||||
}
|
||||
|
||||
void arcPoints::project(DrawViewPart* dvp)
|
||||
{
|
||||
radius = radius * dvp->getScale();
|
||||
Base::Vector3d normal = DrawUtil::toVector3d(dvp->getProjectionCS().Direction());
|
||||
Base::Vector3d stdOrigin(0.0, 0.0, 0.0);
|
||||
center = center.ProjectToPlane(stdOrigin, normal) * dvp->getScale();
|
||||
onCurve.first(onCurve.first().ProjectToPlane(stdOrigin, normal) * dvp->getScale());
|
||||
onCurve.second(onCurve.second().ProjectToPlane(stdOrigin, normal) * dvp->getScale());
|
||||
arcEnds.first(arcEnds.first().ProjectToPlane(stdOrigin, normal) * dvp->getScale());
|
||||
arcEnds.second(arcEnds.second().ProjectToPlane(stdOrigin, normal) * dvp->getScale());
|
||||
midArc = midArc.ProjectToPlane(stdOrigin, normal) * dvp->getScale();
|
||||
}
|
||||
|
||||
void arcPoints::mapToPage(DrawViewPart* dvp)
|
||||
{
|
||||
gp_Trsf xOXYZ;
|
||||
gp_Ax3 OXYZ;
|
||||
xOXYZ.SetTransformation(OXYZ, gp_Ax3(dvp->getProjectionCS()));
|
||||
|
||||
gp_Vec gvCenter = DU::togp_Vec(center).Transformed(xOXYZ);
|
||||
center = DU::toVector3d(gvCenter);
|
||||
gp_Vec gvOnCurve1 = DU::togp_Vec(onCurve.first()).Transformed(xOXYZ);
|
||||
onCurve.first(DU::toVector3d(gvOnCurve1));
|
||||
gp_Vec gvOnCurve2 = DU::togp_Vec(onCurve.second()).Transformed(xOXYZ);
|
||||
onCurve.second(DU::toVector3d(gvOnCurve2));
|
||||
gp_Vec gvArcEnds1 = DU::togp_Vec(arcEnds.first()).Transformed(xOXYZ);
|
||||
arcEnds.first(DU::toVector3d(gvArcEnds1));
|
||||
gp_Vec gvArcEnds2 = DU::togp_Vec(arcEnds.second()).Transformed(xOXYZ);
|
||||
arcEnds.second(DU::toVector3d(gvArcEnds2));
|
||||
gp_Vec gvMidArc = DU::togp_Vec(midArc).Transformed(xOXYZ);
|
||||
midArc = DU::toVector3d(gvMidArc);
|
||||
}
|
||||
|
||||
void arcPoints::invertY()
|
||||
{
|
||||
center = DU::invertY(center);
|
||||
onCurve.invertY();
|
||||
arcEnds.invertY();
|
||||
midArc = DU::invertY(midArc);
|
||||
}
|
||||
|
||||
void arcPoints::dump(std::string text) const
|
||||
{
|
||||
Base::Console().Message("arcPoints - %s\n", text.c_str());
|
||||
Base::Console().Message("arcPoints - radius: %.3f center: %s\n", radius, DrawUtil::formatVector(center).c_str());
|
||||
Base::Console().Message("arcPoints - isArc: %d arcCW: %d\n", isArc, arcCW);
|
||||
Base::Console().Message("arcPoints - onCurve: %s %s\n",
|
||||
DrawUtil::formatVector(onCurve.first()).c_str(),
|
||||
DrawUtil::formatVector(onCurve.second()).c_str());
|
||||
Base::Console().Message("arcPoints - arcEnds: %s %s\n",
|
||||
DrawUtil::formatVector(arcEnds.first()).c_str(),
|
||||
DrawUtil::formatVector(arcEnds.second()).c_str());
|
||||
Base::Console().Message("arcPoints - midArc: %s\n",
|
||||
DrawUtil::formatVector(midArc).c_str());
|
||||
}
|
||||
|
||||
124
src/Mod/TechDraw/App/DimensionGeometry.h
Normal file
124
src/Mod/TechDraw/App/DimensionGeometry.h
Normal file
@@ -0,0 +1,124 @@
|
||||
/***************************************************************************
|
||||
* Copyright (c) 2022 WandererFan <wandererfan@gmail.com> *
|
||||
* *
|
||||
* This file is part of the FreeCAD CAx development system. *
|
||||
* *
|
||||
* This library is free software; you can redistribute it and/or *
|
||||
* modify it under the terms of the GNU Library General Public *
|
||||
* License as published by the Free Software Foundation; either *
|
||||
* version 2 of the License, or (at your option) any later version. *
|
||||
* *
|
||||
* This library 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 Library General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Library General Public *
|
||||
* License along with this library; see the file COPYING.LIB. If not, *
|
||||
* write to the Free Software Foundation, Inc., 59 Temple Place, *
|
||||
* Suite 330, Boston, MA 02111-1307, USA *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef TECHDRAW_DIMENSIONGEOMETRY_h_
|
||||
#define TECHDRAW_DIMENSIONGEOMETRY_h_
|
||||
|
||||
#include <Mod/TechDraw/TechDrawGlobal.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
#include <Base/Vector3D.h>
|
||||
|
||||
namespace TechDraw
|
||||
{
|
||||
class DrawViewPart;
|
||||
|
||||
//a convenient container for linear dimension end points
|
||||
class TechDrawExport pointPair
|
||||
{
|
||||
public:
|
||||
pointPair() = default;
|
||||
pointPair(Base::Vector3d point0, Base::Vector3d point1) { m_first = point0; m_second = point1; }
|
||||
pointPair(const pointPair& pp);
|
||||
|
||||
pointPair& operator= (const pointPair& pp) {
|
||||
m_first = pp.first();
|
||||
m_second = pp.second();
|
||||
return *this;
|
||||
}
|
||||
|
||||
Base::Vector3d first() const { return m_first; }
|
||||
void first(Base::Vector3d newFirst) { m_first = newFirst; }
|
||||
Base::Vector3d second() const { return m_second; }
|
||||
void second(Base::Vector3d newSecond) { m_second = newSecond; }
|
||||
|
||||
void move(Base::Vector3d offset);
|
||||
void project(DrawViewPart* dvp);
|
||||
void mapToPage(DrawViewPart* dvp);
|
||||
void invertY();
|
||||
void dump(std::string text) const;
|
||||
|
||||
private:
|
||||
Base::Vector3d m_first;
|
||||
Base::Vector3d m_second;
|
||||
};
|
||||
|
||||
//a convenient container for angular dimension points
|
||||
class TechDrawExport anglePoints
|
||||
{
|
||||
public:
|
||||
anglePoints();
|
||||
anglePoints(Base::Vector3d apex, Base::Vector3d point0, Base::Vector3d point1) {
|
||||
vertex(apex); first(point0); second(point1); }
|
||||
anglePoints(const anglePoints& ap);
|
||||
|
||||
anglePoints& operator= (const anglePoints& ap);
|
||||
|
||||
pointPair ends() const { return m_ends; }
|
||||
void ends(pointPair newEnds) { m_ends = newEnds; }
|
||||
Base::Vector3d first() const { return m_ends.first(); }
|
||||
void first(Base::Vector3d newFirst) { m_ends.first(newFirst); }
|
||||
Base::Vector3d second() const { return m_ends.second(); }
|
||||
void second(Base::Vector3d newSecond) { m_ends.second(newSecond); }
|
||||
Base::Vector3d vertex() const { return m_vertex; }
|
||||
void vertex(Base::Vector3d newVertex) { m_vertex = newVertex; }
|
||||
|
||||
void move(Base::Vector3d offset);
|
||||
void project(DrawViewPart* dvp);
|
||||
void mapToPage(DrawViewPart* dvp);
|
||||
void invertY();
|
||||
void dump(std::string text) const;
|
||||
|
||||
private:
|
||||
pointPair m_ends;
|
||||
Base::Vector3d m_vertex;
|
||||
};
|
||||
|
||||
//a convenient container for diameter or radius dimension points
|
||||
class TechDrawExport arcPoints
|
||||
{
|
||||
public:
|
||||
arcPoints();
|
||||
arcPoints(const arcPoints& ap);
|
||||
|
||||
arcPoints& operator= (const arcPoints& ap);
|
||||
|
||||
void move(Base::Vector3d offset);
|
||||
void project(DrawViewPart* dvp);
|
||||
void mapToPage(DrawViewPart* dvp);
|
||||
void invertY();
|
||||
void dump(std::string text) const;
|
||||
|
||||
//TODO: setters and getters
|
||||
bool isArc;
|
||||
double radius;
|
||||
Base::Vector3d center;
|
||||
pointPair onCurve;
|
||||
pointPair arcEnds;
|
||||
Base::Vector3d midArc;
|
||||
bool arcCW;
|
||||
};
|
||||
|
||||
} //end namespace TechDraw
|
||||
|
||||
#endif
|
||||
76
src/Mod/TechDraw/App/DimensionReferences.cpp
Normal file
76
src/Mod/TechDraw/App/DimensionReferences.cpp
Normal file
@@ -0,0 +1,76 @@
|
||||
/***************************************************************************
|
||||
* Copyright (c) 2022 WandererFan <wandererfan@gmail.com *
|
||||
* *
|
||||
* This file is part of the FreeCAD CAx development system. *
|
||||
* *
|
||||
* This library is free software; you can redistribute it and/or *
|
||||
* modify it under the terms of the GNU Library General Public *
|
||||
* License as published by the Free Software Foundation; either *
|
||||
* version 2 of the License, or (at your option) any later version. *
|
||||
* *
|
||||
* This library 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 Library General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Library General Public *
|
||||
* License along with this library; see the file COPYING.LIB. If not, *
|
||||
* write to the Free Software Foundation, Inc., 59 Temple Place, *
|
||||
* Suite 330, Boston, MA 02111-1307, USA *
|
||||
* *
|
||||
***************************************************************************/
|
||||
#include "PreCompiled.h"
|
||||
#ifndef _PreComp_
|
||||
#endif
|
||||
#include <TopoDS_Shape.hxx>
|
||||
|
||||
#include <App/GeoFeature.h>
|
||||
#include <Mod/Part/App/PartFeature.h>
|
||||
#include <Mod/Part/App/TopoShape.h>
|
||||
|
||||
#include "DrawViewPart.h"
|
||||
#include "DrawUtil.h"
|
||||
#include "Geometry.h"
|
||||
#include "DimensionReferences.h"
|
||||
|
||||
using namespace TechDraw;
|
||||
|
||||
TopoDS_Shape ReferenceEntry::getGeometry() const
|
||||
{
|
||||
if ( getObject()->isDerivedFrom(TechDraw::DrawViewPart::getClassTypeId()) ) {
|
||||
TechDraw::DrawViewPart* dvp = static_cast<TechDraw::DrawViewPart*>(getObject());
|
||||
std::string gType = geomType();
|
||||
if (gType == "Vertex") {
|
||||
auto vgeom = dvp->getVertex(getSubName());
|
||||
return vgeom->occVertex;
|
||||
} else if (gType == "Edge") {
|
||||
auto egeom = dvp->getEdge(getSubName());
|
||||
return egeom->occEdge;
|
||||
} else if (gType == "Face") {
|
||||
auto fgeom = dvp->getFace(getSubName());
|
||||
return fgeom->toOccFace();
|
||||
}
|
||||
return TopoDS_Shape();
|
||||
}
|
||||
|
||||
Part::TopoShape shape = Part::Feature::getTopoShape(getObject());
|
||||
App::GeoFeature* geoFeat = dynamic_cast<App::GeoFeature*>(getObject());
|
||||
if (geoFeat) {
|
||||
shape.setPlacement(geoFeat->globalPlacement());
|
||||
}
|
||||
|
||||
if (getSubName().empty()) {
|
||||
return shape.getShape();
|
||||
}
|
||||
return shape.getSubShape(getSubName().c_str());
|
||||
}
|
||||
|
||||
std::string ReferenceEntry::geomType() const
|
||||
{
|
||||
return DrawUtil::getGeomTypeFromName(getSubName());
|
||||
}
|
||||
|
||||
bool ReferenceEntry::isWholeObject() const
|
||||
{
|
||||
return getSubName().empty();
|
||||
}
|
||||
73
src/Mod/TechDraw/App/DimensionReferences.h
Normal file
73
src/Mod/TechDraw/App/DimensionReferences.h
Normal file
@@ -0,0 +1,73 @@
|
||||
/***************************************************************************
|
||||
* Copyright (c) 2022 WandererFan <wandererfan@gmail.com *
|
||||
* *
|
||||
* This file is part of the FreeCAD CAx development system. *
|
||||
* *
|
||||
* This library is free software; you can redistribute it and/or *
|
||||
* modify it under the terms of the GNU Library General Public *
|
||||
* License as published by the Free Software Foundation; either *
|
||||
* version 2 of the License, or (at your option) any later version. *
|
||||
* *
|
||||
* This library 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 Library General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Library General Public *
|
||||
* License along with this library; see the file COPYING.LIB. If not, *
|
||||
* write to the Free Software Foundation, Inc., 59 Temple Place, *
|
||||
* Suite 330, Boston, MA 02111-1307, USA *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef TECHDRAW_DIMENSIONREFERENCES_H
|
||||
#define TECHDRAW_DIMENSIONREFERENCES_H
|
||||
|
||||
#include <Mod/TechDraw/TechDrawGlobal.h>
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <TopoDS_Shape.hxx>
|
||||
|
||||
namespace App
|
||||
{
|
||||
class DocumentObject;
|
||||
}
|
||||
|
||||
namespace TechDraw
|
||||
{
|
||||
|
||||
//a convenient way of handling object+subName references
|
||||
class TechDrawExport ReferenceEntry
|
||||
{
|
||||
public:
|
||||
ReferenceEntry( App::DocumentObject* docObject, std::string subName ) {
|
||||
setObject(docObject);
|
||||
setSubName(subName);
|
||||
}
|
||||
ReferenceEntry(const ReferenceEntry& other) {
|
||||
setObject(other.getObject());
|
||||
setSubName(other.getSubName());
|
||||
}
|
||||
~ReferenceEntry() = default;
|
||||
|
||||
App::DocumentObject* getObject() const { return m_object; }
|
||||
void setObject(App::DocumentObject* docObj) { m_object = docObj; }
|
||||
std::string getSubName() const { return m_subName; }
|
||||
void setSubName(std::string subName) { m_subName = subName; }
|
||||
TopoDS_Shape getGeometry() const;
|
||||
std::string geomType() const;
|
||||
bool isWholeObject() const;
|
||||
|
||||
private:
|
||||
bool is3d();
|
||||
App::DocumentObject* m_object;
|
||||
std::string m_subName;
|
||||
};
|
||||
|
||||
using ReferenceVector = std::vector<ReferenceEntry>;
|
||||
|
||||
} // end namespace
|
||||
|
||||
#endif //TECHDRAW_DIMENSIONREFERENCES_H
|
||||
@@ -23,16 +23,17 @@
|
||||
#include "PreCompiled.h"
|
||||
|
||||
#ifndef _PreComp_
|
||||
# include <cstdlib>
|
||||
# include <sstream>
|
||||
#include <cstdlib>
|
||||
#include <sstream>
|
||||
|
||||
# include <Bnd_Box.hxx>
|
||||
# include <BRepBndLib.hxx>
|
||||
# include <BRepBuilderAPI_MakeEdge.hxx>
|
||||
# include <BRepExtrema_DistShapeShape.hxx>
|
||||
# include <Geom_Line.hxx>
|
||||
# include <gp_Pln.hxx>
|
||||
# include <TopoDS_Edge.hxx>
|
||||
#include <Bnd_Box.hxx>
|
||||
#include <BRepBndLib.hxx>
|
||||
#include <BRep_Builder.hxx>
|
||||
#include <BRepBuilderAPI_MakeEdge.hxx>
|
||||
#include <BRepExtrema_DistShapeShape.hxx>
|
||||
#include <Geom_Line.hxx>
|
||||
#include <gp_Pln.hxx>
|
||||
#include <TopoDS_Edge.hxx>
|
||||
#endif
|
||||
|
||||
#include <App/Document.h>
|
||||
@@ -43,6 +44,7 @@
|
||||
|
||||
#include "DrawDimHelper.h"
|
||||
#include "Geometry.h"
|
||||
#include "GeometryObject.h"
|
||||
#include "Cosmetic.h"
|
||||
#include "DrawPage.h"
|
||||
#include "DrawUtil.h"
|
||||
@@ -57,9 +59,6 @@
|
||||
|
||||
using namespace TechDraw;
|
||||
|
||||
//All this OCC math is being done on edges(&vertices) that have been through the center/scale/mirror process.
|
||||
|
||||
//TODO: this needs to be exposed to Python
|
||||
void DrawDimHelper::makeExtentDim(DrawViewPart* dvp,
|
||||
std::vector<std::string> edgeNames,
|
||||
int direction)
|
||||
@@ -67,7 +66,6 @@ void DrawDimHelper::makeExtentDim(DrawViewPart* dvp,
|
||||
// Base::Console().Message("DDH::makeExtentDim() - dvp: %s edgeNames: %d\n",
|
||||
// dvp->Label.getValue(), edgeNames.size());
|
||||
if (!dvp) {
|
||||
// Base::Console().Message("DDH::makeExtentDim - dvp: %X\n", dvp);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -78,90 +76,132 @@ void DrawDimHelper::makeExtentDim(DrawViewPart* dvp,
|
||||
dimNum = 1;
|
||||
}
|
||||
|
||||
std::pair<Base::Vector3d, Base::Vector3d> endPoints = minMax(dvp,
|
||||
edgeNames,
|
||||
direction);
|
||||
Base::Vector3d refMin = endPoints.first / dvp->getScale(); //unscale from geometry
|
||||
Base::Vector3d refMax = endPoints.second / dvp->getScale();
|
||||
TechDraw::DrawPage* page = dvp->findParentPage();
|
||||
std::string pageName = page->getNameInDocument();
|
||||
|
||||
//pause recomputes
|
||||
dvp->getDocument()->setStatus(App::Document::Status::SkipRecompute, true);
|
||||
|
||||
DrawViewDimension* distDim = makeDistDim(dvp, dimType, refMin, refMax, true);
|
||||
std::string dimName = distDim->getNameInDocument();
|
||||
App::Document* doc = dvp->getDocument();
|
||||
std::string dimName = doc->getUniqueObjectName("DimExtent");
|
||||
Base::Interpreter().runStringArg("App.activeDocument().addObject('TechDraw::DrawViewDimExtent', '%s')",
|
||||
dimName.c_str());
|
||||
Base::Interpreter().runStringArg("App.activeDocument().%s.Type = '%s'",
|
||||
dimName.c_str(), dimType.c_str());
|
||||
Base::Interpreter().runStringArg("App.activeDocument().%s.DirExtent = %d",
|
||||
dimName.c_str(), dimNum);
|
||||
DrawViewDimExtent* extDim = dynamic_cast<DrawViewDimExtent*>(distDim);
|
||||
extDim->Source.setValue(dvp, edgeNames);
|
||||
|
||||
std::vector<std::string> subElements = extDim->References2D.getSubValues();
|
||||
std::vector<std::string> cvTags;
|
||||
std::string tag0;
|
||||
std::string tag1;
|
||||
TechDraw::VertexPtr v0;
|
||||
TechDraw::VertexPtr v1;
|
||||
if (subElements.size() > 1) {
|
||||
int idx0 = DrawUtil::getIndexFromName(subElements[0]);
|
||||
int idx1 = DrawUtil::getIndexFromName(subElements[1]);
|
||||
v0 = dvp->getProjVertexByIndex(idx0);
|
||||
v1 = dvp->getProjVertexByIndex(idx1);
|
||||
if (v0 && !v0->cosmeticTag.empty()) {
|
||||
tag0 = v0->cosmeticTag;
|
||||
}
|
||||
if (v1 && !v1->cosmeticTag.empty()) {
|
||||
tag1 = v1->cosmeticTag;
|
||||
}
|
||||
cvTags.push_back(tag0);
|
||||
cvTags.push_back(tag1);
|
||||
extDim->CosmeticTags.setValues(cvTags);
|
||||
TechDraw::DrawViewDimExtent* dimExt = dynamic_cast<TechDraw::DrawViewDimExtent*>(doc->getObject(dimName.c_str()));
|
||||
if (!dimExt) {
|
||||
throw Base::TypeError("Dim extent not found");
|
||||
}
|
||||
dimExt->Source.setValue(dvp, edgeNames);
|
||||
ReferenceVector newRefs;
|
||||
if (edgeNames.empty()) {
|
||||
ReferenceEntry emptyRef(dvp, std::string());
|
||||
newRefs.push_back(emptyRef);
|
||||
} else {
|
||||
for (auto& edge : edgeNames) {
|
||||
ReferenceEntry ref(dvp, edge);
|
||||
newRefs.push_back(ref);
|
||||
}
|
||||
}
|
||||
dimExt->setReferences2d(newRefs);
|
||||
|
||||
//continue recomputes
|
||||
dvp->getDocument()->setStatus(App::Document::Status::SkipRecompute, false);
|
||||
extDim->recomputeFeature();
|
||||
Base::Interpreter().runStringArg("App.activeDocument().%s.addView(App.activeDocument().%s)",
|
||||
pageName.c_str(), dimName.c_str());
|
||||
|
||||
dimExt->recomputeFeature();
|
||||
}
|
||||
|
||||
void DrawDimHelper::makeExtentDim3d(DrawViewPart* dvp,
|
||||
ReferenceVector references,
|
||||
int direction)
|
||||
{
|
||||
// Base::Console().Message("DDH::makeExtentDim3d() - dvp: %s references: %d\n",
|
||||
// dvp->Label.getValue(), references.size());
|
||||
if (!dvp) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::string dimType = "DistanceX";
|
||||
int dimNum = 0;
|
||||
if (direction == VERTICAL) {
|
||||
dimType = "DistanceY";
|
||||
dimNum = 1;
|
||||
}
|
||||
|
||||
TechDraw::DrawPage* page = dvp->findParentPage();
|
||||
std::string pageName = page->getNameInDocument();
|
||||
|
||||
App::Document* doc = dvp->getDocument();
|
||||
std::string dimName = doc->getUniqueObjectName("DimExtent");
|
||||
Base::Interpreter().runStringArg("App.activeDocument().addObject('TechDraw::DrawViewDimExtent', '%s')",
|
||||
dimName.c_str());
|
||||
Base::Interpreter().runStringArg("App.activeDocument().%s.Type = '%s'",
|
||||
dimName.c_str(), dimType.c_str());
|
||||
Base::Interpreter().runStringArg("App.activeDocument().%s.DirExtent = %d",
|
||||
dimName.c_str(), dimNum);
|
||||
|
||||
TechDraw::DrawViewDimExtent* dimExt = dynamic_cast<TechDraw::DrawViewDimExtent*>(doc->getObject(dimName.c_str()));
|
||||
if (!dimExt) {
|
||||
throw Base::TypeError("Dim extent not found");
|
||||
}
|
||||
|
||||
dimExt->Source.setValue(dvp);
|
||||
|
||||
std::vector<App::DocumentObject*> objs3d;
|
||||
std::vector<std::string> subs3d;
|
||||
for (auto& ref : references) {
|
||||
objs3d.push_back(ref.getObject());
|
||||
subs3d.push_back(ref.getSubName());
|
||||
}
|
||||
dimExt->Source3d.setValues(objs3d, subs3d);
|
||||
|
||||
ReferenceVector newRefs2d;
|
||||
ReferenceEntry emptyRef(dvp, std::string());
|
||||
newRefs2d.push_back(emptyRef);
|
||||
dimExt->setReferences2d(newRefs2d);
|
||||
|
||||
dimExt->setReferences3d(references);
|
||||
|
||||
Base::Interpreter().runStringArg("App.activeDocument().%s.addView(App.activeDocument().%s)",
|
||||
pageName.c_str(), dimName.c_str());
|
||||
|
||||
dimExt->recomputeFeature();
|
||||
}
|
||||
std::pair<Base::Vector3d, Base::Vector3d> DrawDimHelper::minMax(DrawViewPart* dvp,
|
||||
std::vector<std::string> edgeNames,
|
||||
int direction)
|
||||
{
|
||||
// Base::Console().Message("DDH::minMax()\n");
|
||||
// Base::Console().Message("DDH::minMax() - edgeName: %d\n", edgeNames.size());
|
||||
std::pair<Base::Vector3d, Base::Vector3d> result;
|
||||
Base::Vector3d refMin;
|
||||
Base::Vector3d refMax;
|
||||
|
||||
gp_Pnt stdOrg(0.0, 0.0, 0.0);
|
||||
gp_Dir stdZ(0.0, 0.0, 1.0);
|
||||
gp_Dir stdX(1.0, 0.0, 0.0);
|
||||
gp_Ax3 projAx3(stdOrg, stdZ, stdX);
|
||||
gp_Pln projPlane(projAx3); // OZX
|
||||
gp_Ax3 projAx3; // OXYZ
|
||||
gp_Pln projPlane(projAx3);
|
||||
|
||||
BaseGeomPtrVector bgList;
|
||||
if (!edgeNames.empty()) {
|
||||
BaseGeomPtrVector edgeGeomList;
|
||||
if (!edgeNames.empty() && !edgeNames.front().empty()) {
|
||||
//we have edge names and the first one isn't null
|
||||
for (auto& n: edgeNames) {
|
||||
if (!n.empty()) {
|
||||
std::string geomType = DrawUtil::getGeomTypeFromName(n);
|
||||
if (!n.empty() && (geomType == "Edge")) {
|
||||
int i = DrawUtil::getIndexFromName(n);
|
||||
BaseGeomPtr bg = dvp->getGeomByIndex(i);
|
||||
if (bg) {
|
||||
bgList.push_back(bg);
|
||||
}
|
||||
std::string geomType = DrawUtil::getGeomTypeFromName(n);
|
||||
if (geomType == "Edge") {
|
||||
int i = DrawUtil::getIndexFromName(n);
|
||||
BaseGeomPtr bg = dvp->getGeomByIndex(i);
|
||||
if (bg) {
|
||||
edgeGeomList.push_back(bg);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
edgeGeomList = dvp->getEdgeGeometry(); //do the whole View
|
||||
}
|
||||
|
||||
BaseGeomPtrVector selEdges = bgList;
|
||||
if (selEdges.empty()) {
|
||||
selEdges = dvp->getEdgeGeometry(); //do the whole View
|
||||
}
|
||||
|
||||
Bnd_Box edgeBbx;
|
||||
edgeBbx.SetGap(1.0); //make the box a bit bigger
|
||||
|
||||
std::vector<TopoDS_Edge> inEdges;
|
||||
for (auto& bg: selEdges) {
|
||||
for (auto& bg: edgeGeomList) {
|
||||
inEdges.push_back(bg->occEdge);
|
||||
BRepBndLib::Add(bg->occEdge, edgeBbx);
|
||||
}
|
||||
@@ -242,6 +282,94 @@ gp_Pnt DrawDimHelper::findClosestPoint(std::vector<TopoDS_Edge> inEdges,
|
||||
return nearPoint;
|
||||
}
|
||||
|
||||
std::pair<Base::Vector3d, Base::Vector3d> DrawDimHelper::minMax3d(DrawViewPart* dvp,
|
||||
ReferenceVector references,
|
||||
int direction)
|
||||
{
|
||||
// Base::Console().Message("DDH::minMax3d() - references: %d\n", references.size());
|
||||
std::pair<Base::Vector3d, Base::Vector3d> result;
|
||||
Base::Vector3d refMin;
|
||||
Base::Vector3d refMax;
|
||||
|
||||
gp_Ax3 projAx3; //OXYZ
|
||||
gp_Pln projPlane(projAx3);
|
||||
|
||||
BRep_Builder builder;
|
||||
TopoDS_Compound comp;
|
||||
builder.MakeCompound(comp);
|
||||
for (auto& ref : references) {
|
||||
builder.Add(comp, ref.getGeometry());
|
||||
}
|
||||
Base::Vector3d centroid = dvp->getOriginalCentroid();
|
||||
TopoDS_Shape centeredShape = //this result is a throw away. We will work with comp.
|
||||
DrawViewPart::centerScaleRotate(dvp, comp, centroid);
|
||||
|
||||
//project the selected 3d shapes in the dvp's coord system
|
||||
TechDraw::GeometryObjectPtr go(std::make_shared<TechDraw::GeometryObject>(std::string(), nullptr));
|
||||
go->setIsoCount(0);
|
||||
go->isPerspective(false);
|
||||
go->usePolygonHLR(false);
|
||||
go->projectShape(comp, dvp->getProjectionCS());
|
||||
auto edges = go->getEdgeGeometry();
|
||||
|
||||
Bnd_Box shapeBbx;
|
||||
shapeBbx.SetGap(1.0); //make the box a bit bigger
|
||||
|
||||
std::vector<TopoDS_Edge> inEdges;
|
||||
for (auto& bg: edges) {
|
||||
inEdges.push_back(bg->occEdge);
|
||||
BRepBndLib::Add(bg->occEdge, shapeBbx);
|
||||
}
|
||||
|
||||
//from here on this is the same as 2d method
|
||||
double minX, minY, minZ, maxX, maxY, maxZ;
|
||||
shapeBbx.Get(minX, minY, minZ, maxX, maxY, maxZ);
|
||||
double xMid = (maxX + minX) / 2.0;
|
||||
double yMid = (maxY + minY) / 2.0;
|
||||
|
||||
gp_Pnt rightMid(maxX, yMid, 0.0);
|
||||
gp_Pnt leftMid(minX, yMid, 0.0);
|
||||
gp_Pnt topMid(xMid, maxY, 0.0);
|
||||
gp_Pnt bottomMid(xMid, minY, 0.0);
|
||||
|
||||
gp_Dir xDir(1.0, 0.0, 0.0);
|
||||
gp_Dir yDir(0.0, 1.0, 0.0);
|
||||
|
||||
if (direction == HORIZONTAL) {
|
||||
Handle(Geom_Line) lineLeft = new Geom_Line(leftMid, yDir);
|
||||
BRepBuilderAPI_MakeEdge mkEdgeLeft(lineLeft);
|
||||
TopoDS_Edge edgeLeft = mkEdgeLeft.Edge();
|
||||
gp_Pnt leftPoint = findClosestPoint(inEdges,
|
||||
edgeLeft);
|
||||
Handle(Geom_Line) lineRight = new Geom_Line(rightMid, yDir);
|
||||
BRepBuilderAPI_MakeEdge mkEdgeRight(lineRight);
|
||||
TopoDS_Edge edgeRight = mkEdgeRight.Edge();
|
||||
gp_Pnt rightPoint = findClosestPoint(inEdges,
|
||||
edgeRight);
|
||||
|
||||
refMin = Base::Vector3d(leftPoint.X(), leftPoint.Y(), 0.0);
|
||||
refMax = Base::Vector3d(rightPoint.X(), rightPoint.Y(), 0.0);
|
||||
|
||||
} else if (direction == VERTICAL) {
|
||||
Handle(Geom_Line) lineBottom = new Geom_Line(bottomMid, xDir);
|
||||
BRepBuilderAPI_MakeEdge mkEdgeBottom(lineBottom);
|
||||
TopoDS_Edge edgeBottom = mkEdgeBottom.Edge();
|
||||
gp_Pnt bottomPoint = findClosestPoint(inEdges,
|
||||
edgeBottom);
|
||||
Handle(Geom_Line) lineTop = new Geom_Line(topMid, xDir);
|
||||
BRepBuilderAPI_MakeEdge mkEdgeTop(lineTop);
|
||||
TopoDS_Edge edgeTop = mkEdgeTop.Edge();
|
||||
gp_Pnt topPoint = findClosestPoint(inEdges,
|
||||
edgeTop);
|
||||
refMin = Base::Vector3d(bottomPoint.X(), bottomPoint.Y(), 0.0);
|
||||
refMax = Base::Vector3d(topPoint.X(), topPoint.Y(), 0.0);
|
||||
}
|
||||
|
||||
result.first = refMin;
|
||||
result.second = refMax;
|
||||
return result;
|
||||
}
|
||||
|
||||
DrawViewDimension* DrawDimHelper::makeDistDim(DrawViewPart* dvp,
|
||||
std::string dimType,
|
||||
Base::Vector3d inMin, //is this scaled or unscaled??
|
||||
@@ -309,7 +437,6 @@ DrawViewDimension* DrawDimHelper::makeDistDim(DrawViewPart* dvp,
|
||||
Base::Interpreter().runStringArg("App.activeDocument().%s.addView(App.activeDocument().%s)",
|
||||
pageName.c_str(), dimName.c_str());
|
||||
|
||||
|
||||
dvp->requestPaint();
|
||||
return dim;
|
||||
}
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
|
||||
#include <Base/Vector3D.h>
|
||||
#include <Mod/TechDraw/TechDrawGlobal.h>
|
||||
|
||||
#include <Mod/TechDraw/App/DimensionReferences.h>
|
||||
|
||||
namespace TechDraw
|
||||
{
|
||||
@@ -45,6 +45,10 @@ class TechDrawExport DrawDimHelper {
|
||||
static void makeExtentDim(DrawViewPart* dvp,
|
||||
std::vector<std::string> edgeNames,
|
||||
int direction);
|
||||
static void makeExtentDim3d(DrawViewPart* dvp,
|
||||
ReferenceVector references,
|
||||
int direction);
|
||||
|
||||
static gp_Pnt findClosestPoint(std::vector<TopoDS_Edge> inEdges,
|
||||
TopoDS_Edge& boundary);
|
||||
|
||||
@@ -58,6 +62,9 @@ class TechDrawExport DrawDimHelper {
|
||||
static std::pair<Base::Vector3d, Base::Vector3d> minMax(DrawViewPart* dvp,
|
||||
std::vector<std::string> edgeNames,
|
||||
int direction);
|
||||
static std::pair<Base::Vector3d, Base::Vector3d> minMax3d(DrawViewPart* dvp,
|
||||
ReferenceVector references,
|
||||
int direction);
|
||||
};
|
||||
|
||||
} //end namespace TechDraw
|
||||
|
||||
@@ -46,6 +46,7 @@
|
||||
#include <BRepLProp_SLProps.hxx>
|
||||
#include <BRepTools.hxx>
|
||||
#include <GCPnts_AbscissaPoint.hxx>
|
||||
#include <GeomAPI_ExtremaCurveCurve.hxx>
|
||||
#include <gp_Ax3.hxx>
|
||||
#include <gp_Dir.hxx>
|
||||
#include <gp_Elips.hxx>
|
||||
@@ -345,6 +346,25 @@ std::pair<Base::Vector3d, Base::Vector3d> DrawUtil::boxIntersect2d(Base::Vector3
|
||||
return result;
|
||||
}
|
||||
|
||||
//find the apparent intersection of 2 3d curves. We are only interested in curves that are lines, so we will have either 0 or 1
|
||||
//apparent intersection. The intersection is "apparent" because the curve's progenator is a trimmed curve (line segment)
|
||||
bool DrawUtil::apparentIntersection(const Handle(Geom_Curve) curve1,
|
||||
const Handle(Geom_Curve) curve2,
|
||||
Base::Vector3d& result)
|
||||
{
|
||||
GeomAPI_ExtremaCurveCurve intersector(curve1, curve2);
|
||||
if (intersector.NbExtrema() == 0 ||
|
||||
intersector.LowerDistance() > EWTOLERANCE ) {
|
||||
//no intersection
|
||||
return false;
|
||||
}
|
||||
//for our purposes, only one intersection point is required.
|
||||
gp_Pnt p1, p2;
|
||||
intersector.Points(1, p1, p2);
|
||||
result = toVector3d(p1);
|
||||
return true;
|
||||
}
|
||||
|
||||
Base::Vector3d DrawUtil::vertex2Vector(const TopoDS_Vertex& v)
|
||||
{
|
||||
gp_Pnt gp = BRep_Tool::Pnt(v);
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
#include <QPointF>
|
||||
#include <QString>
|
||||
|
||||
#include <Geom_Curve.hxx>
|
||||
#include <gp_Ax2.hxx>
|
||||
#include <gp_Dir.hxx>
|
||||
#include <gp_Dir2d.hxx>
|
||||
@@ -98,6 +99,12 @@ class TechDrawExport DrawUtil {
|
||||
Base::Vector3d dir,
|
||||
double xRange,
|
||||
double yRange) ;
|
||||
static bool apparentIntersection(const Handle(Geom_Curve) curve1,
|
||||
const Handle(Geom_Curve) curve2,
|
||||
Base::Vector3d& result);
|
||||
|
||||
|
||||
|
||||
static Base::Vector3d vertex2Vector(const TopoDS_Vertex& v);
|
||||
|
||||
static std::string formatVector(const Base::Vector3d& v);
|
||||
|
||||
@@ -33,11 +33,9 @@
|
||||
#include <Mod/TechDraw/App/DrawViewDimExtentPy.h> // generated from DrawViewDimExtentPy.xml
|
||||
|
||||
#include "DrawViewDimExtent.h"
|
||||
#include "Cosmetic.h"
|
||||
#include "DrawDimHelper.h"
|
||||
#include "DrawViewPart.h"
|
||||
|
||||
|
||||
using namespace TechDraw;
|
||||
|
||||
//===========================================================================
|
||||
@@ -49,36 +47,19 @@ PROPERTY_SOURCE(TechDraw::DrawViewDimExtent, TechDraw::DrawViewDimension)
|
||||
DrawViewDimExtent::DrawViewDimExtent(void)
|
||||
{
|
||||
App::PropertyLinkSubList Source; //DrawViewPart & SubElements(Edges)
|
||||
//Cosmetic End points are stored in DVD::References2d
|
||||
App::PropertyLinkSubList Source3d; //Part::Feature & SubElements TBI
|
||||
App::PropertyLinkSubList Source3d; //Part::Feature(s) & SubElements
|
||||
|
||||
ADD_PROPERTY_TYPE(Source, (nullptr, nullptr), "", (App::PropertyType)(App::Prop_Output), "View (Edges) to dimension");
|
||||
ADD_PROPERTY_TYPE(Source, (nullptr, nullptr), "", (App::PropertyType)(App::Prop_Output), "View containing the dimension");
|
||||
Source.setScope(App::LinkScope::Global);
|
||||
ADD_PROPERTY_TYPE(Source3d, (nullptr, nullptr), "", (App::PropertyType)(App::Prop_Output), "View (Edges) to dimension"); //TBI
|
||||
|
||||
//Source3d is a candidate for deprecation as References3D contains the same information
|
||||
ADD_PROPERTY_TYPE(Source3d, (nullptr, nullptr), "", (App::PropertyType)(App::Prop_Output), "3d geometry to be dimensioned");
|
||||
Source3d.setScope(App::LinkScope::Global);
|
||||
ADD_PROPERTY_TYPE(DirExtent ,(0), "", App::Prop_Output, "Horizontal / Vertical");
|
||||
|
||||
//CosmeticTags is a candidate for deprecation
|
||||
ADD_PROPERTY_TYPE(CosmeticTags ,(""), "", App::Prop_Output, "Id of cosmetic endpoints");
|
||||
|
||||
//hide the properties the user can't edit in the property editor
|
||||
Source3d.setStatus(App::Property::Hidden, true); //TBI
|
||||
|
||||
}
|
||||
|
||||
void DrawViewDimExtent::onChanged(const App::Property* prop)
|
||||
{
|
||||
if (!isRestoring()) {
|
||||
if (prop == &Source) {
|
||||
// Base::Console().Message("DVDE::onChanged - Source: %X\n", Source.getValue());
|
||||
//recalculate the points?
|
||||
}
|
||||
}
|
||||
DrawViewDimension::onChanged(prop);
|
||||
}
|
||||
|
||||
short DrawViewDimExtent::mustExecute() const
|
||||
{
|
||||
return DrawViewDimension::mustExecute();
|
||||
}
|
||||
|
||||
App::DocumentObjectExecReturn *DrawViewDimExtent::execute(void)
|
||||
@@ -87,137 +68,81 @@ App::DocumentObjectExecReturn *DrawViewDimExtent::execute(void)
|
||||
if (!keepUpdated()) {
|
||||
return App::DocumentObject::StdReturn;
|
||||
}
|
||||
|
||||
App::DocumentObject* docObj = Source.getValue();
|
||||
if (!docObj)
|
||||
return App::DocumentObject::StdReturn;
|
||||
DrawViewPart* dvp = dynamic_cast<DrawViewPart*>(docObj);
|
||||
if (!dvp)
|
||||
if (!dvp)
|
||||
return App::DocumentObject::StdReturn;
|
||||
|
||||
double tolerance = 0.00001;
|
||||
std::vector<std::string> edgeNames = getSubNames();
|
||||
int direction = DirExtent.getValue();
|
||||
ReferenceVector references = getEffectiveReferences();
|
||||
|
||||
std::pair<Base::Vector3d, Base::Vector3d> endPoints =
|
||||
DrawDimHelper::minMax(dvp,
|
||||
edgeNames,
|
||||
direction);
|
||||
Base::Vector3d refMin = endPoints.first;
|
||||
Base::Vector3d refMax = endPoints.second;
|
||||
resetLinear();
|
||||
resetAngular();
|
||||
resetArc();
|
||||
|
||||
std::vector<std::string> cTags = CosmeticTags.getValues();
|
||||
if (cTags.size() <= 1) {
|
||||
//not ready yet.
|
||||
return DrawView::execute();
|
||||
}
|
||||
|
||||
TechDraw::VertexPtr v0 = dvp->getProjVertexByCosTag(cTags[0]);
|
||||
TechDraw::VertexPtr v1 = dvp->getProjVertexByCosTag(cTags[1]);
|
||||
if (!v0 || !v1) {
|
||||
//either not ready yet or something has gone wrong
|
||||
return DrawView::execute();
|
||||
}
|
||||
|
||||
double length00 = (v0->pnt - refMin).Length();
|
||||
double length11 = (v1->pnt - refMax).Length();
|
||||
double length01 = (v0->pnt - refMax).Length();
|
||||
double length10 = (v1->pnt - refMin).Length();
|
||||
|
||||
if ((length00 >= tolerance || length11 >= tolerance) &&
|
||||
(length01 >= tolerance || length10 >= tolerance)) { // Something has changed
|
||||
//update GV
|
||||
v0->pnt = refMin;
|
||||
v1->pnt = refMax;
|
||||
// v0->occVertex = ???
|
||||
// v1->occVertex = ???
|
||||
//update CV
|
||||
double scale = dvp->getScale();
|
||||
CosmeticVertex* cvTemp = dvp->getCosmeticVertex(cTags[0]);
|
||||
cvTemp->permaPoint = refMin / scale;
|
||||
cvTemp = dvp->getCosmeticVertex(cTags[1]);
|
||||
cvTemp->permaPoint = refMax / scale;
|
||||
if ( Type.isValue("Distance") ||
|
||||
Type.isValue("DistanceX") ||
|
||||
Type.isValue("DistanceY") ) {
|
||||
setLinearPoints(getPointsExtent(references));
|
||||
}
|
||||
|
||||
overrideKeepUpdated(false);
|
||||
return DrawViewDimension::execute();
|
||||
}
|
||||
|
||||
//getSubValues returns a garbage 1st entry if there are no subelements.
|
||||
std::vector<std::string> DrawViewDimExtent::getSubNames(void)
|
||||
{
|
||||
std::vector<std::string> edgeNames = Source.getSubValues();
|
||||
// Base::Console().Message("DVDE::getSubNames - edgeNames: %d\n", edgeNames.size());
|
||||
if (edgeNames.empty() ||
|
||||
edgeNames[0].empty()) {
|
||||
return std::vector<std::string>(); //garbage first entry - nop
|
||||
}
|
||||
return edgeNames;
|
||||
}
|
||||
|
||||
pointPair DrawViewDimExtent::getPointsTwoVerts()
|
||||
{
|
||||
// Base::Console().Message("DVDE::getPointsTwoVerts() - %s\n", getNameInDocument());
|
||||
pointPair errorValue(
|
||||
Base::Vector3d(0.0, 0.0, 0.0),
|
||||
Base::Vector3d(0.0, 0.0, 0.0)
|
||||
);
|
||||
|
||||
TechDraw::DrawViewPart* dvp = getViewPart();
|
||||
if (!dvp) {
|
||||
return errorValue;
|
||||
}
|
||||
|
||||
std::vector<std::string> cTags = CosmeticTags.getValues();
|
||||
if (cTags.size() < 2) {
|
||||
// Base::Console().Message("DVDE::getPointsTwoVerts - not enough tags!\n");
|
||||
return errorValue;
|
||||
}
|
||||
|
||||
TechDraw::VertexPtr v0 = dvp->getProjVertexByCosTag(cTags[0]);
|
||||
TechDraw::VertexPtr v1 = dvp->getProjVertexByCosTag(cTags[1]);
|
||||
if (!v0 || !v1)
|
||||
return errorValue;
|
||||
|
||||
return pointPair(v0->pnt, v1->pnt);
|
||||
return DrawView::execute();
|
||||
}
|
||||
|
||||
//! validate 2D references - only checks if the target exists
|
||||
bool DrawViewDimExtent::checkReferences2D() const
|
||||
{
|
||||
// Base::Console().Message("DVDE::checkReFerences2d() - %s\n", getNameInDocument());
|
||||
TechDraw::DrawViewPart* dvp = getViewPart();
|
||||
if (!dvp) {
|
||||
// Base::Console().Message("DVDE::checkReferences2d() - %s\n", getNameInDocument());
|
||||
const std::vector<App::DocumentObject*> &objects = References2D.getValues();
|
||||
if (objects.empty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
std::vector<std::string> cTags = CosmeticTags.getValues();
|
||||
if (cTags.size() < 2) {
|
||||
//still building this dimension, so treat as valid?
|
||||
const std::vector<std::string> &subElements = References2D.getSubValues();
|
||||
//extent dims are the only dims allowed to have no subElements
|
||||
if (subElements.empty() || subElements.front().empty()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
CosmeticVertex* cv0 = dvp->getCosmeticVertex(cTags[0]);
|
||||
CosmeticVertex* cv1 = dvp->getCosmeticVertex(cTags[1]);
|
||||
if (!cv0 || !cv1)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
//if we have an object and a non-empty subelement list, then extent dims are the same as other dims
|
||||
return DrawViewDimension::checkReferences2D();
|
||||
}
|
||||
|
||||
void DrawViewDimExtent::unsetupObject()
|
||||
pointPair DrawViewDimExtent::getPointsExtent(ReferenceVector references)
|
||||
{
|
||||
// bool isRemoving = testStatus(App::ObjectStatus::Remove);
|
||||
// Base::Console().Message("DVDE::unsetupObject - isRemove: %d status: %X\n",
|
||||
// isRemoving, getStatus());
|
||||
TechDraw::DrawViewPart* dvp = getViewPart();
|
||||
// Base::Console().Message("DVD::getPointsExtent() - %s\n", getNameInDocument());
|
||||
App::DocumentObject* refObject = references.front().getObject();
|
||||
int direction = DirExtent.getValue();
|
||||
if (refObject->isDerivedFrom(TechDraw::DrawViewPart::getClassTypeId())) {
|
||||
auto dvp = static_cast<TechDraw::DrawViewPart*>(refObject);
|
||||
|
||||
std::vector<std::string> cTags = CosmeticTags.getValues();
|
||||
dvp->removeCosmeticVertex(cTags);
|
||||
DrawViewDimension::unsetupObject();
|
||||
std::vector<std::string> edgeNames; //empty list means we are using all the edges
|
||||
if (!references.at(0).getSubName().empty()) {
|
||||
//this is the usual case of selected edges in a dvp
|
||||
for (auto& ref : references) {
|
||||
if (ref.getSubName().empty()) {
|
||||
continue;
|
||||
}
|
||||
std::string geomType = DrawUtil::getGeomTypeFromName(ref.getSubName());
|
||||
if (geomType == "Edge") {
|
||||
edgeNames.push_back(ref.getSubName());
|
||||
}
|
||||
}
|
||||
}
|
||||
std::pair<Base::Vector3d, Base::Vector3d> endPoints =
|
||||
DrawDimHelper::minMax(dvp,
|
||||
edgeNames,
|
||||
direction);
|
||||
return pointPair(endPoints.first, endPoints.second);
|
||||
}
|
||||
|
||||
//dvp probably needs recomp/repaint here.
|
||||
dvp->enforceRecompute();
|
||||
//this is a 3d reference
|
||||
std::pair<Base::Vector3d, Base::Vector3d> endPoints =
|
||||
DrawDimHelper::minMax3d(getViewPart(),
|
||||
references,
|
||||
direction);
|
||||
return pointPair(endPoints.first, endPoints.second);
|
||||
}
|
||||
|
||||
PyObject *DrawViewDimExtent::getPyObject(void)
|
||||
|
||||
@@ -47,23 +47,17 @@ public:
|
||||
//Cosmetic End points are stored in DVD::References2d
|
||||
App::PropertyLinkSubList Source3d; //Part::Feature & SubElements TBI
|
||||
App::PropertyInteger DirExtent; //Horizontal, Vertical, TBD
|
||||
App::PropertyStringList CosmeticTags; //id of cosmetic end points.
|
||||
App::PropertyStringList CosmeticTags; //id of cosmetic end points. obsolete!
|
||||
|
||||
App::DocumentObjectExecReturn *execute() override;
|
||||
short mustExecute() const override;
|
||||
void unsetupObject() override;
|
||||
|
||||
bool checkReferences2D() const override;
|
||||
int getRefType() const override { return twoVertex; }
|
||||
pointPair getLinearPoints() override { return getPointsTwoVerts(); }
|
||||
int getRefType() const override { return extent; }
|
||||
|
||||
//return PyObject as DrawViewDimExtentPy
|
||||
PyObject *getPyObject() override;
|
||||
|
||||
protected:
|
||||
void onChanged(const App::Property* prop) override;
|
||||
std::vector<std::string> getSubNames();
|
||||
pointPair getPointsTwoVerts() override;
|
||||
virtual pointPair getPointsExtent(ReferenceVector references);
|
||||
bool checkReferences2D() const override;
|
||||
|
||||
private:
|
||||
};
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -25,13 +25,22 @@
|
||||
|
||||
#include <tuple>
|
||||
|
||||
#include <gp_Ax3.hxx>
|
||||
|
||||
#include <App/DocumentObject.h>
|
||||
#include <Base/Console.h>
|
||||
#include <Base/UnitsApi.h>
|
||||
#include <Mod/TechDraw/TechDrawGlobal.h>
|
||||
|
||||
#include "DrawViewPart.h"
|
||||
#include "DimensionGeometry.h"
|
||||
#include "DimensionReferences.h"
|
||||
|
||||
#include "Geometry.h"
|
||||
#include "DrawView.h"
|
||||
#include "DrawUtil.h"
|
||||
|
||||
|
||||
using DU = TechDraw::DrawUtil;
|
||||
class TopoDS_Shape;
|
||||
|
||||
namespace Measure {
|
||||
@@ -40,94 +49,26 @@ class Measurement;
|
||||
namespace TechDraw
|
||||
{
|
||||
class DrawViewPart;
|
||||
|
||||
struct DimRef {
|
||||
DrawViewPart* part;
|
||||
std::string sub;
|
||||
};
|
||||
|
||||
using pointPair = std::pair<Base::Vector3d,Base::Vector3d>;
|
||||
|
||||
struct anglePoints
|
||||
{
|
||||
pointPair ends;
|
||||
Base::Vector3d vertex;
|
||||
|
||||
anglePoints()
|
||||
{
|
||||
ends.first = Base::Vector3d(0.0, 0.0, 0.0);
|
||||
ends.second = Base::Vector3d(0.0, 0.0, 0.0);
|
||||
vertex = Base::Vector3d(0.0, 0.0, 0.0);
|
||||
}
|
||||
|
||||
anglePoints(const anglePoints& ap)
|
||||
: ends(ap.ends)
|
||||
, vertex(ap.vertex)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
anglePoints& operator= (const anglePoints& ap)
|
||||
{
|
||||
ends = ap.ends;
|
||||
vertex = ap.vertex;
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
struct arcPoints
|
||||
{
|
||||
bool isArc;
|
||||
double radius;
|
||||
Base::Vector3d center;
|
||||
pointPair onCurve;
|
||||
pointPair arcEnds;
|
||||
Base::Vector3d midArc;
|
||||
bool arcCW;
|
||||
|
||||
arcPoints()
|
||||
{
|
||||
isArc = false;
|
||||
radius = 0.0;
|
||||
center = Base::Vector3d(0.0, 0.0, 0.0);
|
||||
onCurve.first = Base::Vector3d(0.0, 0.0, 0.0);
|
||||
onCurve.second = Base::Vector3d(0.0, 0.0, 0.0);
|
||||
arcEnds.first = Base::Vector3d(0.0, 0.0, 0.0);
|
||||
arcEnds.second = Base::Vector3d(0.0, 0.0, 0.0);
|
||||
midArc = Base::Vector3d(0.0, 0.0, 0.0);
|
||||
arcCW = false;
|
||||
}
|
||||
|
||||
arcPoints(const arcPoints& ap)
|
||||
: isArc(ap.isArc)
|
||||
, radius(ap.radius)
|
||||
, center(ap.center)
|
||||
, onCurve(ap.onCurve)
|
||||
, arcEnds(ap.arcEnds)
|
||||
, midArc(ap.midArc)
|
||||
, arcCW(ap.arcCW)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
arcPoints& operator= (const arcPoints& ap)
|
||||
{
|
||||
isArc = ap.isArc;
|
||||
radius = ap.radius;
|
||||
center = ap.center;
|
||||
onCurve = ap.onCurve;
|
||||
arcEnds = ap.arcEnds;
|
||||
midArc = ap.midArc;
|
||||
arcCW = ap.arcCW;
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
class DimensionFormatter;
|
||||
|
||||
class TechDrawExport DrawViewDimension : public TechDraw::DrawView
|
||||
{
|
||||
PROPERTY_HEADER_WITH_OVERRIDE(TechDraw::DrawViewDimension);
|
||||
|
||||
public:
|
||||
|
||||
// keep this enum synchronized with TypeEnums
|
||||
enum DimensionType {
|
||||
Distance,
|
||||
DistanceX,
|
||||
DistanceY,
|
||||
DistanceZ,
|
||||
Radius,
|
||||
Diameter,
|
||||
Angle,
|
||||
Angle3Pt
|
||||
};
|
||||
|
||||
/// Constructor
|
||||
DrawViewDimension();
|
||||
~DrawViewDimension() override;
|
||||
@@ -158,7 +99,8 @@ public:
|
||||
twoEdge,
|
||||
twoVertex,
|
||||
vertexEdge,
|
||||
threeVertex
|
||||
threeVertex,
|
||||
extent
|
||||
};
|
||||
|
||||
|
||||
@@ -194,35 +136,49 @@ public:
|
||||
QRectF getRect() const override { return {0, 0, 1, 1}; } //pretend dimensions always fit!
|
||||
virtual int getRefType() const; //Vertex-Vertex, Edge, Edge-Edge
|
||||
static int getRefTypeSubElements(const std::vector<std::string> &); //Vertex-Vertex, Edge, Edge-Edge
|
||||
|
||||
void setReferences2d(ReferenceVector refs);
|
||||
void setReferences3d(ReferenceVector refs);
|
||||
|
||||
void setAll3DMeasurement();
|
||||
void clear3DMeasurements();
|
||||
virtual bool checkReferences2D() const;
|
||||
virtual pointPair getLinearPoints() {return m_linearPoints; }
|
||||
virtual pointPair getLinearPoints() const {return m_linearPoints; }
|
||||
virtual void setLinearPoints(Base::Vector3d point0, Base::Vector3d point1) { m_linearPoints.first(point0);
|
||||
m_linearPoints.second(point1); };
|
||||
virtual void setLinearPoints(pointPair newPair) { m_linearPoints = newPair; }
|
||||
arcPoints getArcPoints() {return m_arcPoints; }
|
||||
anglePoints getAnglePoints() {return m_anglePoints; }
|
||||
bool leaderIntersectsArc(Base::Vector3d s, Base::Vector3d pointOnCircle);
|
||||
|
||||
bool isMultiValueSchema() const;
|
||||
|
||||
std::string getBaseLengthUnit(Base::UnitSystem system);
|
||||
|
||||
pointPair getArrowPositions();
|
||||
void saveArrowPositions(const Base::Vector2d positions[]);
|
||||
|
||||
bool showUnits() const;
|
||||
bool useDecimals() const;
|
||||
bool isExtentDim() const;
|
||||
virtual ReferenceVector getEffectiveReferences() const;
|
||||
|
||||
protected:
|
||||
void handleChangedPropertyType(Base::XMLReader &, const char * , App::Property * ) override;
|
||||
void Restore(Base::XMLReader& reader) override;
|
||||
void onChanged(const App::Property* prop) override;
|
||||
void onDocumentRestored() override;
|
||||
std::string getPrefix() const;
|
||||
std::string getPrefixForDimType() const;
|
||||
std::string getDefaultFormatSpec(bool isToleranceFormat = false) const;
|
||||
virtual pointPair getPointsOneEdge();
|
||||
virtual pointPair getPointsTwoEdges();
|
||||
virtual pointPair getPointsTwoVerts();
|
||||
virtual pointPair getPointsEdgeVert();
|
||||
virtual pointPair getPointsOneEdge(ReferenceVector references);
|
||||
virtual pointPair getPointsTwoEdges(ReferenceVector references);
|
||||
virtual pointPair getPointsTwoVerts(ReferenceVector references);
|
||||
virtual pointPair getPointsEdgeVert(ReferenceVector references);
|
||||
|
||||
virtual arcPoints getArcParameters(ReferenceVector references);
|
||||
virtual arcPoints arcPointsFromBaseGeom(TechDraw::BaseGeomPtr base);
|
||||
virtual arcPoints arcPointsFromEdge(TopoDS_Edge occEdge);
|
||||
|
||||
virtual anglePoints getAnglePointsTwoEdges(ReferenceVector references);
|
||||
virtual anglePoints getAnglePointsThreeVerts(ReferenceVector references);
|
||||
|
||||
protected:
|
||||
Measure::Measurement *measurement;
|
||||
@@ -232,8 +188,6 @@ protected:
|
||||
Base::Vector3d e2) const;
|
||||
pointPair closestPoints(TopoDS_Shape s1,
|
||||
TopoDS_Shape s2) const;
|
||||
pointPair m_linearPoints;
|
||||
pointPair m_arrowPositions;
|
||||
|
||||
void resetLinear();
|
||||
void resetAngular();
|
||||
@@ -244,10 +198,14 @@ private:
|
||||
static const char* MeasureTypeEnums[];
|
||||
void dumpRefs2D(const char* text) const;
|
||||
//Dimension "geometry"
|
||||
/* pointPair m_linearPoints;*/
|
||||
pointPair m_linearPoints;
|
||||
pointPair m_arrowPositions;
|
||||
arcPoints m_arcPoints;
|
||||
anglePoints m_anglePoints;
|
||||
bool m_hasGeometry;
|
||||
|
||||
friend class DimensionFormatter;
|
||||
DimensionFormatter* m_formatter;
|
||||
};
|
||||
|
||||
} //namespace TechDraw
|
||||
|
||||
@@ -73,8 +73,8 @@ PyObject* DrawViewDimensionPy::getLinearPoints(PyObject* args)
|
||||
DrawViewDimension* dvd = getDrawViewDimensionPtr();
|
||||
pointPair pts = dvd->getLinearPoints();
|
||||
Py::List ret;
|
||||
ret.append(Py::asObject(new Base::VectorPy(new Base::Vector3d(pts.first))));
|
||||
ret.append(Py::asObject(new Base::VectorPy(new Base::Vector3d(pts.second))));
|
||||
ret.append(Py::asObject(new Base::VectorPy(new Base::Vector3d(pts.first()))));
|
||||
ret.append(Py::asObject(new Base::VectorPy(new Base::Vector3d(pts.second()))));
|
||||
return Py::new_reference_to(ret);
|
||||
}
|
||||
|
||||
@@ -88,10 +88,10 @@ PyObject* DrawViewDimensionPy::getArcPoints(PyObject* args)
|
||||
arcPoints pts = dvd->getArcPoints();
|
||||
Py::List ret;
|
||||
ret.append(Py::asObject(new Base::VectorPy(new Base::Vector3d(pts.center))));
|
||||
ret.append(Py::asObject(new Base::VectorPy(new Base::Vector3d(pts.onCurve.first))));
|
||||
ret.append(Py::asObject(new Base::VectorPy(new Base::Vector3d(pts.onCurve.second))));
|
||||
ret.append(Py::asObject(new Base::VectorPy(new Base::Vector3d(pts.arcEnds.first))));
|
||||
ret.append(Py::asObject(new Base::VectorPy(new Base::Vector3d(pts.arcEnds.second))));
|
||||
ret.append(Py::asObject(new Base::VectorPy(new Base::Vector3d(pts.onCurve.first()))));
|
||||
ret.append(Py::asObject(new Base::VectorPy(new Base::Vector3d(pts.onCurve.second()))));
|
||||
ret.append(Py::asObject(new Base::VectorPy(new Base::Vector3d(pts.arcEnds.first()))));
|
||||
ret.append(Py::asObject(new Base::VectorPy(new Base::Vector3d(pts.arcEnds.second()))));
|
||||
ret.append(Py::asObject(new Base::VectorPy(new Base::Vector3d(pts.midArc))));
|
||||
return Py::new_reference_to(ret);
|
||||
}
|
||||
@@ -105,9 +105,9 @@ PyObject* DrawViewDimensionPy::getAnglePoints(PyObject* args)
|
||||
DrawViewDimension* dvd = getDrawViewDimensionPtr();
|
||||
anglePoints pts = dvd->getAnglePoints();
|
||||
Py::List ret;
|
||||
ret.append(Py::asObject(new Base::VectorPy(new Base::Vector3d(pts.ends.first))));
|
||||
ret.append(Py::asObject(new Base::VectorPy(new Base::Vector3d(pts.ends.second))));
|
||||
ret.append(Py::asObject(new Base::VectorPy(new Base::Vector3d(pts.vertex))));
|
||||
ret.append(Py::asObject(new Base::VectorPy(new Base::Vector3d(pts.first()))));
|
||||
ret.append(Py::asObject(new Base::VectorPy(new Base::Vector3d(pts.second()))));
|
||||
ret.append(Py::asObject(new Base::VectorPy(new Base::Vector3d(pts.vertex()))));
|
||||
return Py::new_reference_to(ret);
|
||||
}
|
||||
|
||||
@@ -120,8 +120,8 @@ PyObject* DrawViewDimensionPy::getArrowPositions(PyObject* args)
|
||||
DrawViewDimension* dvd = getDrawViewDimensionPtr();
|
||||
pointPair pts = dvd->getArrowPositions();
|
||||
Py::List ret;
|
||||
ret.append(Py::asObject(new Base::VectorPy(new Base::Vector3d(pts.first))));
|
||||
ret.append(Py::asObject(new Base::VectorPy(new Base::Vector3d(pts.second))));
|
||||
ret.append(Py::asObject(new Base::VectorPy(new Base::Vector3d(pts.first()))));
|
||||
ret.append(Py::asObject(new Base::VectorPy(new Base::Vector3d(pts.second()))));
|
||||
return Py::new_reference_to(ret);
|
||||
}
|
||||
PyObject *DrawViewDimensionPy::getCustomAttributes(const char* /*attr*/) const
|
||||
|
||||
@@ -264,7 +264,6 @@ App::DocumentObjectExecReturn* DrawViewPart::execute(void)
|
||||
XDirection.purgeTouched();//don't trigger updates!
|
||||
}
|
||||
|
||||
m_saveShape = shape;
|
||||
partExec(shape);
|
||||
|
||||
return DrawView::execute();
|
||||
@@ -319,28 +318,38 @@ void DrawViewPart::partExec(TopoDS_Shape& shape)
|
||||
//prepare the shape for HLR processing by centering, scaling and rotating it
|
||||
GeometryObjectPtr DrawViewPart::makeGeometryForShape(TopoDS_Shape& shape)
|
||||
{
|
||||
// Base::Console().Message("DVP::makeGeometryForShape() - %s\n", getNameInDocument());
|
||||
gp_Pnt inputCenter;
|
||||
Base::Vector3d stdOrg(0.0, 0.0, 0.0);
|
||||
gp_Ax2 viewAxis = getProjectionCS(stdOrg);
|
||||
inputCenter = TechDraw::findCentroid(shape, viewAxis);
|
||||
Base::Vector3d centroid(inputCenter.X(), inputCenter.Y(), inputCenter.Z());
|
||||
|
||||
//center shape on origin
|
||||
TopoDS_Shape centeredShape = TechDraw::moveShape(shape, centroid * -1.0);
|
||||
m_saveCentroid = centroid;
|
||||
m_saveShape = centeredShape;
|
||||
|
||||
TopoDS_Shape scaledShape = TechDraw::scaleShape(centeredShape, getScale());
|
||||
if (!DrawUtil::fpCompare(Rotation.getValue(), 0.0)) {
|
||||
scaledShape = TechDraw::rotateShape(scaledShape, viewAxis,
|
||||
Rotation.getValue());//conventional rotation
|
||||
}
|
||||
|
||||
GeometryObjectPtr go = buildGeometryObject(scaledShape, viewAxis);
|
||||
// Base::Console().Message("DVP::makeGeometryForShape() - %s\n", getNameInDocument());
|
||||
gp_Pnt inputCenter = TechDraw::findCentroid(shape,
|
||||
getProjectionCS());
|
||||
m_saveCentroid = DU::toVector3d(inputCenter);
|
||||
m_saveShape = centerScaleRotate(this, shape, m_saveCentroid);
|
||||
GeometryObjectPtr go = buildGeometryObject(shape, getProjectionCS());
|
||||
return go;
|
||||
}
|
||||
|
||||
//Modify a shape by centering, scaling and rotating and return the centered (but not rotated) shape
|
||||
TopoDS_Shape DrawViewPart::centerScaleRotate(DrawViewPart* dvp,
|
||||
TopoDS_Shape& inOutShape,
|
||||
Base::Vector3d centroid)
|
||||
{
|
||||
// Base::Console().Message("DVP::centerScaleRotate() - %s\n", dvp->getNameInDocument());
|
||||
gp_Ax2 viewAxis = dvp->getProjectionCS();
|
||||
|
||||
//center shape on origin
|
||||
TopoDS_Shape centeredShape = TechDraw::moveShape(inOutShape,
|
||||
centroid * -1.0);
|
||||
|
||||
inOutShape = TechDraw::scaleShape(centeredShape, dvp->getScale());
|
||||
if (!DrawUtil::fpCompare(dvp->Rotation.getValue(), 0.0)) {
|
||||
inOutShape = TechDraw::rotateShape(inOutShape,
|
||||
viewAxis,
|
||||
dvp->Rotation.getValue()); //conventional rotation
|
||||
}
|
||||
// BRepTools::Write(inOutShape, "DVPScaled.brep"); //debug
|
||||
return centeredShape;
|
||||
}
|
||||
|
||||
|
||||
//create a geometry object and trigger the HLR process in another thread
|
||||
TechDraw::GeometryObjectPtr DrawViewPart::buildGeometryObject(TopoDS_Shape& shape,
|
||||
const gp_Ax2& viewAxis)
|
||||
@@ -770,6 +779,53 @@ const std::vector<TechDraw::VertexPtr> DrawViewPart::getVertexGeometry() const
|
||||
return result;
|
||||
}
|
||||
|
||||
TechDraw::VertexPtr DrawViewPart::getVertex(std::string vertexName) const
|
||||
{
|
||||
const std::vector<TechDraw::VertexPtr> allVertex(DrawViewPart::getVertexGeometry());
|
||||
size_t iTarget = DrawUtil::getIndexFromName(vertexName);
|
||||
if (allVertex.empty()) {
|
||||
//should not happen
|
||||
throw Base::IndexError("DVP::getVertex - No vertices found.");
|
||||
}
|
||||
if (iTarget > allVertex.size()) {
|
||||
//should not happen
|
||||
throw Base::IndexError("DVP::getVertex - Vertex not found.");
|
||||
}
|
||||
|
||||
return allVertex.at(iTarget);
|
||||
}
|
||||
|
||||
//! returns existing BaseGeom of 2D Edge
|
||||
TechDraw::BaseGeomPtr DrawViewPart::getEdge(std::string edgeName) const
|
||||
{
|
||||
const std::vector<TechDraw::BaseGeomPtr> &geoms = getEdgeGeometry();
|
||||
if (geoms.empty()) {
|
||||
//should not happen
|
||||
throw Base::IndexError("DVP::getEdge - No edges found.");
|
||||
}
|
||||
size_t iEdge = DrawUtil::getIndexFromName(edgeName);
|
||||
if ((unsigned)iEdge >= geoms.size()) {
|
||||
throw Base::IndexError("DVP::getEdge - Edge not found.");
|
||||
}
|
||||
return geoms.at(iEdge);
|
||||
}
|
||||
|
||||
//! returns existing 2d Face
|
||||
TechDraw::FacePtr DrawViewPart::getFace(std::string faceName) const
|
||||
{
|
||||
const std::vector<TechDraw::FacePtr> &faces = getFaceGeometry();
|
||||
if (faces.empty()) {
|
||||
//should not happen
|
||||
throw Base::IndexError("DVP::getFace - No faces found.");
|
||||
}
|
||||
size_t iFace = DrawUtil::getIndexFromName(faceName);
|
||||
if (iFace >= faces.size()) {
|
||||
throw Base::IndexError("DVP::getFace - Face not found.");
|
||||
}
|
||||
return faces.at(iFace);
|
||||
}
|
||||
|
||||
|
||||
const std::vector<TechDraw::FacePtr> DrawViewPart::getFaceGeometry() const
|
||||
{
|
||||
std::vector<TechDraw::FacePtr> result;
|
||||
|
||||
@@ -114,6 +114,9 @@ public:
|
||||
const char* getViewProviderName() const override { return "TechDrawGui::ViewProviderViewPart"; }
|
||||
PyObject* getPyObject() override;
|
||||
|
||||
static TopoDS_Shape centerScaleRotate(DrawViewPart* dvp,
|
||||
TopoDS_Shape& inOutShape,
|
||||
Base::Vector3d centroid);
|
||||
std::vector<TechDraw::DrawHatch*> getHatches() const;
|
||||
std::vector<TechDraw::DrawGeomHatch*> getGeomHatches() const;
|
||||
std::vector<TechDraw::DrawViewDimension*> getDimensions() const;
|
||||
@@ -127,10 +130,13 @@ public:
|
||||
bool hasGeometry() const;
|
||||
TechDraw::GeometryObjectPtr getGeometryObject() const { return geometryObject; }
|
||||
|
||||
TechDraw::BaseGeomPtr
|
||||
getGeomByIndex(int idx) const;//get existing geom for edge idx in projection
|
||||
TechDraw::VertexPtr
|
||||
getProjVertexByIndex(int idx) const;//get existing geom for vertex idx in projection
|
||||
TechDraw::VertexPtr getVertex(std::string vertexName) const;
|
||||
TechDraw::BaseGeomPtr getEdge(std::string edgeName) const;
|
||||
TechDraw::FacePtr getFace(std::string faceName) const;
|
||||
|
||||
TechDraw::BaseGeomPtr getGeomByIndex(int idx) const; //get existing geom for edge idx in projection
|
||||
TechDraw::VertexPtr getProjVertexByIndex(int idx) const; //get existing geom for vertex idx in projection
|
||||
|
||||
TechDraw::VertexPtr getProjVertexByCosTag(std::string cosTag);
|
||||
std::vector<TechDraw::BaseGeomPtr>
|
||||
getFaceEdgesByIndex(int idx) const;//get edges for face idx in projection
|
||||
|
||||
@@ -1271,198 +1271,15 @@ bool BSpline::isLine()
|
||||
//used by DVDim for approximate dims
|
||||
bool BSpline::isCircle()
|
||||
{
|
||||
bool result = false;
|
||||
double radius;
|
||||
Base::Vector3d center;
|
||||
bool isArc = false;
|
||||
getCircleParms(result, radius, center, isArc);
|
||||
return result;
|
||||
}
|
||||
|
||||
//used by DVDim for approximate dims
|
||||
void BSpline::getCircleParms(bool& isCircle, double& radius, Base::Vector3d& center, bool& isArc)
|
||||
{
|
||||
double curveLimit = 0.0001;
|
||||
BRepAdaptor_Curve c(occEdge);
|
||||
Handle(Geom_BSplineCurve) spline = c.BSpline();
|
||||
double f, l;
|
||||
f = c.FirstParameter();
|
||||
l = c.LastParameter();
|
||||
double parmRange = fabs(l - f);
|
||||
int testCount = 6;
|
||||
double parmStep = parmRange/testCount;
|
||||
std::vector<double> curvatures;
|
||||
std::vector<gp_Pnt> centers;
|
||||
gp_Pnt curveCenter;
|
||||
double sumCurvature = 0;
|
||||
Base::Vector3d sumCenter, valueAt;
|
||||
try {
|
||||
GeomLProp_CLProps prop(spline, f, 3, Precision::Confusion());
|
||||
curvatures.push_back(prop.Curvature());
|
||||
sumCurvature += prop.Curvature();
|
||||
prop.CentreOfCurvature(curveCenter);
|
||||
centers.push_back(curveCenter);
|
||||
sumCenter += Base::Vector3d(curveCenter.X(), curveCenter.Y(), curveCenter.Z());
|
||||
|
||||
for (int i = 1; i < (testCount - 1); i++) {
|
||||
prop.SetParameter(parmStep * i);
|
||||
curvatures.push_back(prop.Curvature());
|
||||
sumCurvature += prop.Curvature();
|
||||
prop.CentreOfCurvature(curveCenter);
|
||||
centers.push_back(curveCenter);
|
||||
sumCenter += Base::Vector3d(curveCenter.X(), curveCenter.Y(), curveCenter.Z());
|
||||
}
|
||||
prop.SetParameter(l);
|
||||
curvatures.push_back(prop.Curvature());
|
||||
sumCurvature += prop.Curvature();
|
||||
prop.CentreOfCurvature(curveCenter);
|
||||
centers.push_back(curveCenter);
|
||||
sumCenter += Base::Vector3d(curveCenter.X(), curveCenter.Y(), curveCenter.Z());
|
||||
}
|
||||
catch (Standard_Failure&) {
|
||||
Base::Console().Log("TechDraw - GEO::BSpline::getCircleParms - CLProps failed\n");
|
||||
isCircle = false;
|
||||
return;
|
||||
}
|
||||
Base::Vector3d avgCenter = sumCenter/testCount;
|
||||
double errorCenter = 0;
|
||||
for (auto& c: centers) {
|
||||
errorCenter += (avgCenter - Base::Vector3d(c.X(), c.Y(), c.Z())).Length();
|
||||
}
|
||||
errorCenter = errorCenter/testCount;
|
||||
|
||||
double avgCurve = sumCurvature/testCount;
|
||||
double errorCurve = 0;
|
||||
for (auto& cv: curvatures) {
|
||||
errorCurve += fabs(avgCurve - cv); //fabs???
|
||||
}
|
||||
errorCurve = errorCurve/testCount;
|
||||
|
||||
isArc = !c.IsClosed();
|
||||
isCircle = false;
|
||||
if ( errorCurve < curveLimit ) {
|
||||
isCircle = true;
|
||||
radius = 1.0/avgCurve;
|
||||
center = avgCenter;
|
||||
}
|
||||
return GeometryUtils::isCircle(occEdge);
|
||||
}
|
||||
|
||||
// make a circular edge from BSpline
|
||||
TopoDS_Edge BSpline::asCircle(bool& arc)
|
||||
{
|
||||
TopoDS_Edge result;
|
||||
BRepAdaptor_Curve c(occEdge);
|
||||
|
||||
// find the two ends
|
||||
Handle(Geom_Curve) curve = c.Curve().Curve();
|
||||
double f = c.FirstParameter();
|
||||
double l = c.LastParameter();
|
||||
gp_Pnt s = c.Value(f);
|
||||
gp_Pnt e = c.Value(l);
|
||||
|
||||
if (s.IsEqual(e, 0.001)) { //more reliable
|
||||
arc = false;
|
||||
} else {
|
||||
arc = true;
|
||||
}
|
||||
// arc = !c.IsClosed(); //reliable?
|
||||
|
||||
Handle(Geom_BSplineCurve) spline = c.BSpline();
|
||||
|
||||
if (spline->NbPoles() < 5) { //need 5 poles (s-p1-pm-p2-e) for algo
|
||||
return result; //how to do with fewer poles?
|
||||
}
|
||||
|
||||
try {
|
||||
// get three points on curve (non extreme poles)
|
||||
int nb_poles = spline->NbPoles();
|
||||
gp_Pnt p1 = spline->Pole(2); //OCC numbering starts at 1!!
|
||||
gp_Pnt p2 = spline->Pole(nb_poles-1);
|
||||
gp_Pnt pm;
|
||||
if (nb_poles == 5) {
|
||||
pm = spline->Pole(3); //5 poles => 2.5 => 2
|
||||
} else {
|
||||
pm = spline->Pole(nb_poles / 2);
|
||||
}
|
||||
|
||||
// project three poles onto the curve
|
||||
GeomAPI_ProjectPointOnCurve proj1;
|
||||
GeomAPI_ProjectPointOnCurve proj2;
|
||||
GeomAPI_ProjectPointOnCurve projm;
|
||||
proj1.Init(p1, curve, f, l);
|
||||
proj1.Perform(p1);
|
||||
proj2.Init(p2, curve, f, l);
|
||||
proj2.Perform(p2);
|
||||
projm.Init(pm, curve, f, l);
|
||||
projm.Perform(pm);
|
||||
if ( (proj1.NbPoints() == 0) ||
|
||||
(proj2.NbPoints() == 0) ||
|
||||
(projm.NbPoints() == 0) ) {
|
||||
return result;
|
||||
}
|
||||
gp_Pnt pc1, pc2, pcm;
|
||||
|
||||
// get projected points
|
||||
pc1 = proj1.NearestPoint();
|
||||
pc2 = proj2.NearestPoint();
|
||||
pcm = projm.NearestPoint();
|
||||
|
||||
// make 2 circles and find their radii
|
||||
gce_MakeCirc gce_circ1 = gce_MakeCirc(s, pc1, pcm); //3 point circle
|
||||
if (gce_circ1.Status() != gce_Done) {
|
||||
return result;
|
||||
}
|
||||
gp_Circ circle1 = gce_circ1.Value();
|
||||
double radius1 = circle1.Radius();
|
||||
gp_Pnt center1 = circle1.Location();
|
||||
Base::Vector3d vc1 = DrawUtil::toVector3d(center1);
|
||||
|
||||
gce_MakeCirc gce_circ2 = gce_MakeCirc(pcm, pc2, e);
|
||||
if (gce_circ2.Status() != gce_Done) {
|
||||
return result;
|
||||
}
|
||||
gp_Circ circle2 = gce_circ2.Value();
|
||||
double radius2 = circle2.Radius();
|
||||
gp_Pnt center2 = circle2.Location();
|
||||
Base::Vector3d vc2 = DrawUtil::toVector3d(center2);
|
||||
|
||||
// compare radii & centers
|
||||
double allowError = 0.001; //mm^-3 good enough for printing
|
||||
double radius;
|
||||
Base::Vector3d center;
|
||||
if ( (DrawUtil::fpCompare(radius2, radius1, allowError)) &&
|
||||
(vc1.IsEqual(vc2, allowError)) ) {
|
||||
if (arc) {
|
||||
GC_MakeArcOfCircle makeArc(s, pcm, e);
|
||||
Handle(Geom_TrimmedCurve) tCurve = makeArc.Value();
|
||||
BRepBuilderAPI_MakeEdge newEdge(tCurve);
|
||||
result = newEdge;
|
||||
} else {
|
||||
radius = (radius1 + radius2) / 2.0;
|
||||
center = (vc1 + vc2) / 2.0;
|
||||
gp_Pnt gCenter(center.x, center.y, center.z);
|
||||
gp_Ax2 stdZ(gCenter, gp_Dir(0, 0, 1));
|
||||
gp_Circ newCirc(stdZ, radius);
|
||||
BRepBuilderAPI_MakeEdge newEdge(newCirc);
|
||||
result = newEdge;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (const Standard_Failure& e) {
|
||||
Base::Console().Log("Geom::asCircle - OCC error - %s - while approx spline as circle\n",
|
||||
e.GetMessageString());
|
||||
TopoDS_Edge nullReturn;
|
||||
result = nullReturn;
|
||||
}
|
||||
catch (...) {
|
||||
Base::Console().Log("Geom::asCircle - unknown error occurred while approx spline as circle\n");
|
||||
TopoDS_Edge nullReturn;
|
||||
result = nullReturn;
|
||||
}
|
||||
return result;
|
||||
return GeometryUtils::asCircle(occEdge, arc);
|
||||
}
|
||||
|
||||
|
||||
bool BSpline::intersectsArc(Base::Vector3d p1, Base::Vector3d p2)
|
||||
{
|
||||
gp_Pnt pnt1(p1.x, p1.y,p1.z);
|
||||
@@ -1771,4 +1588,186 @@ TopoDS_Edge GeometryUtils::edgeFromCircleArc(TechDraw::AOCPtr c)
|
||||
return aMakeEdge.Edge();
|
||||
}
|
||||
|
||||
//used by DVDim for approximate dims
|
||||
bool GeometryUtils::isCircle(TopoDS_Edge occEdge)
|
||||
{
|
||||
double radius;
|
||||
Base::Vector3d center;
|
||||
bool isArc = false;
|
||||
return GeometryUtils::getCircleParms(occEdge, radius, center, isArc);
|
||||
}
|
||||
|
||||
//tries to interpret a BSpline edge as a circle. Used by DVDim for approximate dimensions.
|
||||
bool GeometryUtils::getCircleParms(TopoDS_Edge occEdge, double& radius, Base::Vector3d& center, bool& isArc)
|
||||
{
|
||||
double curveLimit = EWTOLERANCE;
|
||||
BRepAdaptor_Curve c(occEdge);
|
||||
Handle(Geom_BSplineCurve) spline = c.BSpline();
|
||||
double f, l;
|
||||
f = c.FirstParameter();
|
||||
l = c.LastParameter();
|
||||
double parmRange = fabs(l - f);
|
||||
int testCount = 6;
|
||||
double parmStep = parmRange/testCount;
|
||||
std::vector<double> curvatures;
|
||||
std::vector<gp_Pnt> centers;
|
||||
gp_Pnt curveCenter;
|
||||
double sumCurvature = 0;
|
||||
Base::Vector3d sumCenter, valueAt;
|
||||
try {
|
||||
GeomLProp_CLProps prop(spline, f, 3, Precision::Confusion());
|
||||
curvatures.push_back(prop.Curvature());
|
||||
sumCurvature += prop.Curvature();
|
||||
prop.CentreOfCurvature(curveCenter);
|
||||
centers.push_back(curveCenter);
|
||||
sumCenter += DrawUtil::toVector3d(curveCenter);
|
||||
|
||||
for (int i = 1; i < (testCount - 1); i++) {
|
||||
prop.SetParameter(parmStep * i);
|
||||
curvatures.push_back(prop.Curvature());
|
||||
sumCurvature += prop.Curvature();
|
||||
prop.CentreOfCurvature(curveCenter);
|
||||
centers.push_back(curveCenter);
|
||||
sumCenter += DrawUtil::toVector3d(curveCenter);
|
||||
}
|
||||
prop.SetParameter(l);
|
||||
curvatures.push_back(prop.Curvature());
|
||||
sumCurvature += prop.Curvature();
|
||||
prop.CentreOfCurvature(curveCenter);
|
||||
centers.push_back(curveCenter);
|
||||
sumCenter += DrawUtil::toVector3d(curveCenter);
|
||||
}
|
||||
catch (Standard_Failure&) {
|
||||
Base::Console().Error("OCC error. Could not interpret BSpline as Circle\n");
|
||||
return false;
|
||||
}
|
||||
Base::Vector3d avgCenter = sumCenter/testCount;
|
||||
|
||||
double avgCurve = sumCurvature/testCount;
|
||||
double errorCurve = 0;
|
||||
for (auto& cv: curvatures) {
|
||||
errorCurve += fabs(avgCurve - cv); //fabs???
|
||||
}
|
||||
errorCurve = errorCurve/testCount;
|
||||
|
||||
isArc = !c.IsClosed();
|
||||
bool isCircle(false);
|
||||
if ( errorCurve < curveLimit ) {
|
||||
isCircle = true;
|
||||
radius = 1.0/avgCurve;
|
||||
center = avgCenter;
|
||||
}
|
||||
return isCircle;
|
||||
}
|
||||
|
||||
// make a circle or arc of circle Edge from BSpline Edge
|
||||
TopoDS_Edge GeometryUtils::asCircle(TopoDS_Edge occEdge, bool& arc)
|
||||
{
|
||||
TopoDS_Edge result;
|
||||
BRepAdaptor_Curve c(occEdge);
|
||||
|
||||
// find the two ends
|
||||
Handle(Geom_Curve) curve = c.Curve().Curve();
|
||||
double f = c.FirstParameter();
|
||||
double l = c.LastParameter();
|
||||
gp_Pnt s = c.Value(f);
|
||||
gp_Pnt e = c.Value(l);
|
||||
|
||||
if (s.IsEqual(e, 0.001)) { //more reliable
|
||||
arc = false;
|
||||
} else {
|
||||
arc = true;
|
||||
}
|
||||
// arc = !c.IsClosed(); //reliable?
|
||||
|
||||
Handle(Geom_BSplineCurve) spline = c.BSpline();
|
||||
|
||||
if (spline->NbPoles() < 5) { //need 5 poles (s-p1-pm-p2-e) for algo
|
||||
return result; //how to do with fewer poles?
|
||||
}
|
||||
|
||||
try {
|
||||
// get three points on curve (non extreme poles)
|
||||
int nb_poles = spline->NbPoles();
|
||||
gp_Pnt p1 = spline->Pole(2); //OCC numbering starts at 1!!
|
||||
gp_Pnt p2 = spline->Pole(nb_poles-1);
|
||||
gp_Pnt pm;
|
||||
if (nb_poles == 5) {
|
||||
pm = spline->Pole(3); //5 poles => 2.5 => 2
|
||||
} else {
|
||||
pm = spline->Pole(nb_poles / 2);
|
||||
}
|
||||
|
||||
// project three poles onto the curve
|
||||
GeomAPI_ProjectPointOnCurve proj1;
|
||||
GeomAPI_ProjectPointOnCurve proj2;
|
||||
GeomAPI_ProjectPointOnCurve projm;
|
||||
proj1.Init(p1, curve, f, l);
|
||||
proj1.Perform(p1);
|
||||
proj2.Init(p2, curve, f, l);
|
||||
proj2.Perform(p2);
|
||||
projm.Init(pm, curve, f, l);
|
||||
projm.Perform(pm);
|
||||
if ( (proj1.NbPoints() == 0) ||
|
||||
(proj2.NbPoints() == 0) ||
|
||||
(projm.NbPoints() == 0) ) {
|
||||
return result;
|
||||
}
|
||||
gp_Pnt pc1, pc2, pcm;
|
||||
|
||||
// get projected points
|
||||
pc1 = proj1.NearestPoint();
|
||||
pc2 = proj2.NearestPoint();
|
||||
pcm = projm.NearestPoint();
|
||||
|
||||
// make 2 circles and find their radii
|
||||
gce_MakeCirc gce_circ1 = gce_MakeCirc(s, pc1, pcm); //3 point circle
|
||||
if (gce_circ1.Status() != gce_Done) {
|
||||
return result;
|
||||
}
|
||||
gp_Circ circle1 = gce_circ1.Value();
|
||||
double radius1 = circle1.Radius();
|
||||
gp_Pnt center1 = circle1.Location();
|
||||
Base::Vector3d vc1 = DrawUtil::toVector3d(center1);
|
||||
|
||||
gce_MakeCirc gce_circ2 = gce_MakeCirc(pcm, pc2, e);
|
||||
if (gce_circ2.Status() != gce_Done) {
|
||||
return result;
|
||||
}
|
||||
gp_Circ circle2 = gce_circ2.Value();
|
||||
double radius2 = circle2.Radius();
|
||||
gp_Pnt center2 = circle2.Location();
|
||||
Base::Vector3d vc2 = DrawUtil::toVector3d(center2);
|
||||
|
||||
// compare radii & centers
|
||||
double allowError = 0.001; //mm^-3 good enough for printing
|
||||
double radius;
|
||||
Base::Vector3d center;
|
||||
if ( (DrawUtil::fpCompare(radius2, radius1, allowError)) &&
|
||||
(vc1.IsEqual(vc2, allowError)) ) {
|
||||
if (arc) {
|
||||
GC_MakeArcOfCircle makeArc(s, pcm, e);
|
||||
Handle(Geom_TrimmedCurve) tCurve = makeArc.Value();
|
||||
BRepBuilderAPI_MakeEdge mkEdge(tCurve);
|
||||
result = mkEdge.Edge();
|
||||
} else {
|
||||
radius = (radius1 + radius2) / 2.0;
|
||||
center = (vc1 + vc2) / 2.0;
|
||||
gp_Pnt gCenter(center.x, center.y, center.z);
|
||||
gp_Ax2 stdZ(gCenter, gp_Dir(0, 0, 1));
|
||||
gp_Circ newCirc(stdZ, radius);
|
||||
BRepBuilderAPI_MakeEdge mkEdge(newCirc);
|
||||
result = mkEdge.Edge();
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (const Standard_Failure& e) {
|
||||
Base::Console().Error("asCircle - OCC error - %s - while approx spline as circle\n",
|
||||
e.GetMessageString());
|
||||
throw Base::RuntimeError("Failed to make circle from bspline");
|
||||
}
|
||||
catch (...) {
|
||||
Base::Console().Error("asCircle - unknown error occurred while approx spline as circle\n");
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -274,7 +274,7 @@ class TechDrawExport BSpline: public BaseGeom
|
||||
bool isLine();
|
||||
bool isCircle();
|
||||
TopoDS_Edge asCircle(bool& isArc);
|
||||
void getCircleParms(bool& isCircle, double& radius, Base::Vector3d& center, bool& isArc);
|
||||
// void getCircleParms(bool& isCircle, double& radius, Base::Vector3d& center, bool& isArc);
|
||||
bool intersectsArc(Base::Vector3d p1, Base::Vector3d p2);
|
||||
std::vector<BezierSegment> segments;
|
||||
};
|
||||
@@ -390,6 +390,10 @@ class TechDrawExport GeometryUtils
|
||||
static TopoDS_Edge edgeFromGeneric(TechDraw::GenericPtr g);
|
||||
static TopoDS_Edge edgeFromCircle(TechDraw::CirclePtr c);
|
||||
static TopoDS_Edge edgeFromCircleArc(TechDraw::AOCPtr c);
|
||||
|
||||
static bool isCircle(TopoDS_Edge occEdge);
|
||||
static bool getCircleParms(TopoDS_Edge occEdge, double& radius, Base::Vector3d& center, bool& isArc);
|
||||
static TopoDS_Edge asCircle(TopoDS_Edge occEdge, bool& arc);
|
||||
};
|
||||
|
||||
} //end namespace TechDraw
|
||||
|
||||
@@ -143,6 +143,7 @@ void GeometryObject::clear()
|
||||
|
||||
void GeometryObject::projectShape(const TopoDS_Shape& inShape, const gp_Ax2& viewAxis)
|
||||
{
|
||||
// Base::Console().Message("GO::projectShape()\n");
|
||||
clear();
|
||||
|
||||
Handle(HLRBRep_Algo) brep_hlr;
|
||||
@@ -251,9 +252,11 @@ void GeometryObject::projectShape(const TopoDS_Shape& inShape, const gp_Ax2& vie
|
||||
//convert the hlr output into TD Geometry
|
||||
void GeometryObject::makeTDGeometry()
|
||||
{
|
||||
extractGeometry(TechDraw::ecHARD,//always show the hard&outline visible lines
|
||||
true);
|
||||
extractGeometry(TechDraw::ecOUTLINE, true);
|
||||
// Base::Console().Message("GO::makeTDGeometry()\n");
|
||||
extractGeometry(TechDraw::ecHARD, //always show the hard&outline visible lines
|
||||
true);
|
||||
extractGeometry(TechDraw::ecOUTLINE,
|
||||
true);
|
||||
|
||||
const DrawViewPart* dvp = static_cast<const DrawViewPart*>(m_parent);
|
||||
if (!dvp) {
|
||||
|
||||
@@ -87,7 +87,7 @@ short LandmarkDimension::mustExecute() const
|
||||
|
||||
App::DocumentObjectExecReturn *LandmarkDimension::execute()
|
||||
{
|
||||
// Base::Console().Message("LD::execute() - %s\n", getNameInDocument());
|
||||
Base::Console().Message("LD::execute() - %s\n", getNameInDocument());
|
||||
if (!keepUpdated()) {
|
||||
return App::DocumentObject::StdReturn;
|
||||
}
|
||||
@@ -99,6 +99,7 @@ App::DocumentObjectExecReturn *LandmarkDimension::execute()
|
||||
References2D.setValue(dvp);
|
||||
|
||||
std::vector<DocumentObject*> features = References3D.getValues();
|
||||
Base::Console().Message("LD::execute - features: %d\n", features.size());
|
||||
//if distance, required size = 2
|
||||
//if angle, required size = 3; //not implemented yet
|
||||
unsigned int requiredSize = 2;
|
||||
@@ -129,17 +130,16 @@ App::DocumentObjectExecReturn *LandmarkDimension::execute()
|
||||
index++;
|
||||
}
|
||||
}
|
||||
m_linearPoints.first = points.front();
|
||||
m_linearPoints.second = points.back();
|
||||
|
||||
//m_anglePoints.first = //not implemented yet
|
||||
Base::Console().Message("LD::execute - front: %s back: %s\n",
|
||||
DrawUtil::formatVector(points.front()).c_str(),
|
||||
DrawUtil::formatVector(points.back()).c_str());
|
||||
setLinearPoints(points.front(), points.back());
|
||||
|
||||
App::DocumentObjectExecReturn* dvdResult = DrawViewDimension::execute();
|
||||
|
||||
// dvp->resetReferenceVerts();
|
||||
dvp->addReferencesToGeom();
|
||||
dvp->requestPaint();
|
||||
|
||||
dvp->requestPaint();
|
||||
|
||||
overrideKeepUpdated(false);
|
||||
return dvdResult;
|
||||
}
|
||||
@@ -159,51 +159,6 @@ Base::Vector3d LandmarkDimension::projectPoint(const Base::Vector3d& pt, DrawVie
|
||||
return result;
|
||||
}
|
||||
|
||||
std::vector<Base::Vector3d> LandmarkDimension::get2DPoints() const
|
||||
{
|
||||
// Base::Console().Message("LD::get2DPoints()\n");
|
||||
std::vector<Base::Vector3d> result;
|
||||
std::vector<App::DocumentObject*> refs3 = References3D.getValues();
|
||||
TechDraw::DrawViewPart* dvp = getViewPart();
|
||||
for (auto& r: refs3) {
|
||||
Base::Vector3d loc3d = ShapeExtractor::getLocation3dFromFeat(r);
|
||||
Base::Vector3d loc2d = projectPoint(loc3d, dvp);
|
||||
result.push_back(loc2d);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
//! References2D are only used to store ParentView
|
||||
bool LandmarkDimension::has2DReferences() const
|
||||
{
|
||||
bool result = false;
|
||||
const std::vector<App::DocumentObject*> &objects = References2D.getValues();
|
||||
if (!objects.empty()) {
|
||||
result = true;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
//! References2D are only used to store ParentView
|
||||
bool LandmarkDimension::checkReferences2D() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
pointPair LandmarkDimension::getPointsTwoVerts()
|
||||
{
|
||||
// Base::Console().Message("LD::getPointsTwoVerts() - %s\n", getNameInDocument());
|
||||
pointPair result;
|
||||
|
||||
TechDraw::DrawViewPart* dvp = getViewPart();
|
||||
if (dvp) {
|
||||
std::vector<Base::Vector3d> points = get2DPoints();
|
||||
result.first = points.at(0) * dvp->getScale();
|
||||
result.second = points.at(1) * dvp->getScale();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
int LandmarkDimension::getRefType() const
|
||||
{
|
||||
//TODO: need changes here when other reference dim types added
|
||||
@@ -239,18 +194,13 @@ void LandmarkDimension::onDocumentRestored()
|
||||
}
|
||||
ReferenceTags.setValues(tags);
|
||||
|
||||
m_linearPoints.first = points.front();
|
||||
m_linearPoints.second = points.back();
|
||||
setLinearPoints(points.front(), points.back());
|
||||
|
||||
DrawViewDimension::onDocumentRestored();
|
||||
}
|
||||
|
||||
void LandmarkDimension::unsetupObject()
|
||||
{
|
||||
|
||||
// bool isRemoving = testStatus(App::ObjectStatus::Remove);
|
||||
// Base::Console().Message("LD::unsetupObject - isRemove: %d status: %X\n",
|
||||
// isRemoving, getStatus());
|
||||
TechDraw::DrawViewPart* dvp = getViewPart();
|
||||
|
||||
std::vector<std::string> tags = ReferenceTags.getValues();
|
||||
@@ -261,14 +211,3 @@ void LandmarkDimension::unsetupObject()
|
||||
dvp->requestPaint();
|
||||
}
|
||||
|
||||
|
||||
//??? why does getPyObject work sometimes and no others???
|
||||
//PyObject *LandmarkDimension::getPyObject(void)
|
||||
//{
|
||||
// if (PythonObject.is(Py::_None())) {
|
||||
// // ref counter is set to 1
|
||||
// PythonObject = Py::Object(new LandmarkDimensionPy(this), true);
|
||||
// }
|
||||
// return Py::new_reference_to(PythonObject);
|
||||
//}
|
||||
|
||||
|
||||
@@ -28,7 +28,6 @@
|
||||
|
||||
#include "DrawViewDimension.h"
|
||||
|
||||
|
||||
class TopoDS_Shape;
|
||||
class gp_Ax2;
|
||||
|
||||
@@ -56,12 +55,7 @@ public:
|
||||
|
||||
const char* getViewProviderName() const override {
|
||||
return "TechDrawGui::ViewProviderDimension"; }
|
||||
/* virtual PyObject *getPyObject(void) override;*/
|
||||
|
||||
bool checkReferences2D() const override;
|
||||
bool has2DReferences() const override;
|
||||
pointPair getPointsTwoVerts() override;
|
||||
std::vector<Base::Vector3d> get2DPoints() const;
|
||||
DrawViewPart* getViewPart() const override;
|
||||
int getRefType() const override;
|
||||
|
||||
|
||||
@@ -84,6 +84,8 @@ set(TechDrawGui_UIC_SRCS
|
||||
TaskMoveView.ui
|
||||
TaskProjection.ui
|
||||
TaskComplexSection.ui
|
||||
TaskDimRepair.ui
|
||||
|
||||
)
|
||||
|
||||
SET(MRTE_SRCS
|
||||
@@ -108,6 +110,8 @@ SET(TechDrawGui_SRCS
|
||||
CommandExtensionDims.cpp
|
||||
CommandExtensionPack.cpp
|
||||
CommandStack.cpp
|
||||
DimensionValidators.cpp
|
||||
DimensionValidators.h
|
||||
Resources/TechDraw.qrc
|
||||
PreCompiled.cpp
|
||||
PreCompiled.h
|
||||
@@ -209,9 +213,9 @@ SET(TechDrawGui_SRCS
|
||||
TaskDetail.h
|
||||
PreferencesGui.cpp
|
||||
PreferencesGui.h
|
||||
TaskCosmeticLine.ui
|
||||
TaskCosmeticLine.cpp
|
||||
TaskCosmeticLine.h
|
||||
TaskCosmeticLine.ui
|
||||
TaskMoveView.ui
|
||||
TaskProjection.cpp
|
||||
TaskProjection.h
|
||||
@@ -219,6 +223,9 @@ SET(TechDrawGui_SRCS
|
||||
TaskComplexSection.cpp
|
||||
TaskComplexSection.h
|
||||
TaskComplexSection.ui
|
||||
TaskDimRepair.cpp
|
||||
TaskDimRepair.h
|
||||
TaskDimRepair.ui
|
||||
Widgets/CompassDialWidget.cpp
|
||||
Widgets/CompassDialWidget.h
|
||||
Widgets/CompassWidget.cpp
|
||||
@@ -429,6 +436,7 @@ SET(TechDrawGuiTaskDlgs_SRCS
|
||||
TaskMoveView.ui
|
||||
TaskProjection.ui
|
||||
TaskComplexSection.ui
|
||||
TaskDimRepair.ui
|
||||
)
|
||||
|
||||
SOURCE_GROUP("MRTE" FILES ${MRTE_SRCS})
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -569,8 +569,8 @@ void execPosHorizChainDimension(Gui::Command* cmd) {
|
||||
for (auto dim : validDimension) {
|
||||
dim->Y.setValue(yMaster);
|
||||
pointPair pp = dim->getLinearPoints();
|
||||
Base::Vector3d p1 = pp.first;
|
||||
Base::Vector3d p2 = pp.second;
|
||||
Base::Vector3d p1 = pp.first();
|
||||
Base::Vector3d p2 = pp.second();
|
||||
dim->X.setValue((p1.x + p2.x) / 2.0);
|
||||
}
|
||||
Gui::Command::commitCommand();
|
||||
@@ -631,8 +631,8 @@ void execPosVertChainDimension(Gui::Command* cmd) {
|
||||
for (auto dim : validDimension) {
|
||||
dim->X.setValue(xMaster);
|
||||
pointPair pp = dim->getLinearPoints();
|
||||
Base::Vector3d p1 = pp.first;
|
||||
Base::Vector3d p2 = pp.second;
|
||||
Base::Vector3d p1 = pp.first();
|
||||
Base::Vector3d p2 = pp.second();
|
||||
dim->Y.setValue((p1.y + p2.y) / -2.0 + 0.5 * fontSize);
|
||||
}
|
||||
Gui::Command::commitCommand();
|
||||
@@ -692,7 +692,7 @@ void execPosObliqueChainDimension(Gui::Command* cmd) {
|
||||
float yMaster = validDimension[0]->Y.getValue();
|
||||
Base::Vector3d pMaster(xMaster, yMaster, 0.0);
|
||||
pointPair pp = validDimension[0]->getLinearPoints();
|
||||
Base::Vector3d dirMaster = pp.second - pp.first;
|
||||
Base::Vector3d dirMaster = pp.second() - pp.first();
|
||||
dirMaster.y = -dirMaster.y;
|
||||
for (auto dim : validDimension) {
|
||||
float xDim = dim->X.getValue();
|
||||
@@ -881,8 +881,8 @@ void execCascadeHorizDimension(Gui::Command* cmd) {
|
||||
for (auto dim : validDimension) {
|
||||
dim->Y.setValue(yMaster);
|
||||
pointPair pp = dim->getLinearPoints();
|
||||
Base::Vector3d p1 = pp.first;
|
||||
Base::Vector3d p2 = pp.second;
|
||||
Base::Vector3d p1 = pp.first();
|
||||
Base::Vector3d p2 = pp.second();
|
||||
dim->X.setValue((p1.x + p2.x) / 2.0);
|
||||
yMaster = yMaster + dimDistance;
|
||||
}
|
||||
@@ -948,8 +948,8 @@ void execCascadeVertDimension(Gui::Command* cmd) {
|
||||
for (auto dim : validDimension) {
|
||||
dim->X.setValue(xMaster);
|
||||
pointPair pp = dim->getLinearPoints();
|
||||
Base::Vector3d p1 = pp.first;
|
||||
Base::Vector3d p2 = pp.second;
|
||||
Base::Vector3d p1 = pp.first();
|
||||
Base::Vector3d p2 = pp.second();
|
||||
dim->Y.setValue((p1.y + p2.y) / -2.0 + 0.5 * fontSize);
|
||||
xMaster = xMaster + dimDistance;
|
||||
}
|
||||
@@ -1011,7 +1011,7 @@ void execCascadeObliqueDimension(Gui::Command* cmd) {
|
||||
float yMaster = validDimension[0]->Y.getValue();
|
||||
Base::Vector3d pMaster(xMaster, yMaster, 0.0);
|
||||
pointPair pp = validDimension[0]->getLinearPoints();
|
||||
Base::Vector3d dirMaster = pp.second - pp.first;
|
||||
Base::Vector3d dirMaster = pp.second() - pp.first();
|
||||
dirMaster.y = -dirMaster.y;
|
||||
Base::Vector3d origin(0.0, 0.0, 0.0);
|
||||
Base::Vector3d ipDelta = _getTrianglePoint(pMaster, dirMaster, origin);
|
||||
@@ -1206,7 +1206,7 @@ void execCreateHorizChainDimension(Gui::Command* cmd) {
|
||||
TechDraw::DrawViewDimension* dim;
|
||||
dim = _createLinDimension(cmd, objFeat, allVertexes[n].name, allVertexes[n + 1].name, "DistanceX");
|
||||
TechDraw::pointPair pp = dim->getLinearPoints();
|
||||
Base::Vector3d mid = (pp.first + pp.second) / 2.0;
|
||||
Base::Vector3d mid = (pp.first() + pp.second()) / 2.0;
|
||||
dim->X.setValue(mid.x);
|
||||
if (n == 0)
|
||||
yMaster = -mid.y;
|
||||
@@ -1271,7 +1271,7 @@ void execCreateVertChainDimension(Gui::Command* cmd) {
|
||||
TechDraw::DrawViewDimension* dim;
|
||||
dim = _createLinDimension(cmd, objFeat, allVertexes[n].name, allVertexes[n + 1].name, "DistanceY");
|
||||
TechDraw::pointPair pp = dim->getLinearPoints();
|
||||
Base::Vector3d mid = (pp.first + pp.second) / 2.0;
|
||||
Base::Vector3d mid = (pp.first() + pp.second()) / 2.0;
|
||||
if (n == 0)
|
||||
xMaster = mid.x;
|
||||
dim->X.setValue(xMaster);
|
||||
@@ -1363,7 +1363,7 @@ void execCreateObliqueChainDimension(Gui::Command* cmd) {
|
||||
TechDraw::DrawViewDimension* dim;
|
||||
dim = _createLinDimension(cmd, objFeat, carrierVertexes[n].name, carrierVertexes[n + 1].name, "Distance");
|
||||
TechDraw::pointPair pp = dim->getLinearPoints();
|
||||
Base::Vector3d mid = (pp.first + pp.second) / 2.0 + delta;
|
||||
Base::Vector3d mid = (pp.first() + pp.second()) / 2.0 + delta;
|
||||
dim->X.setValue(mid.x);
|
||||
dim->Y.setValue(-mid.y + 0.5 * fontSize);
|
||||
}
|
||||
@@ -1548,7 +1548,7 @@ void execCreateHorizCoordDimension(Gui::Command* cmd) {
|
||||
TechDraw::DrawViewDimension* dim;
|
||||
dim = _createLinDimension(cmd, objFeat, allVertexes[0].name, allVertexes[n + 1].name, "DistanceX");
|
||||
TechDraw::pointPair pp = dim->getLinearPoints();
|
||||
Base::Vector3d mid = (pp.first + pp.second) / 2.0;
|
||||
Base::Vector3d mid = (pp.first() + pp.second()) / 2.0;
|
||||
dim->X.setValue(mid.x);
|
||||
dim->Y.setValue(-yMaster - dimDistance * n);
|
||||
}
|
||||
@@ -1620,7 +1620,7 @@ void execCreateVertCoordDimension(Gui::Command* cmd) {
|
||||
TechDraw::DrawViewDimension* dim;
|
||||
dim = _createLinDimension(cmd, objFeat, allVertexes[0].name, allVertexes[n + 1].name, "DistanceY");
|
||||
TechDraw::pointPair pp = dim->getLinearPoints();
|
||||
Base::Vector3d mid = (pp.first + pp.second) / 2.0;
|
||||
Base::Vector3d mid = (pp.first() + pp.second()) / 2.0;
|
||||
dim->X.setValue(xMaster + dimDistance * n);
|
||||
dim->Y.setValue(-mid.y + 0.5 * fontSize);
|
||||
}
|
||||
@@ -1717,7 +1717,7 @@ void execCreateObliqueCoordDimension(Gui::Command* cmd) {
|
||||
TechDraw::DrawViewDimension* dim;
|
||||
dim = _createLinDimension(cmd, objFeat, carrierVertexes[0].name, carrierVertexes[n + 1].name, "Distance");
|
||||
TechDraw::pointPair pp = dim->getLinearPoints();
|
||||
Base::Vector3d mid = (pp.first + pp.second) / 2.0 + delta * (n + 1);
|
||||
Base::Vector3d mid = (pp.first() + pp.second()) / 2.0 + delta * (n + 1);
|
||||
dim->X.setValue(mid.x);
|
||||
dim->Y.setValue(-mid.y + 0.5 * fontSize);
|
||||
}
|
||||
@@ -1905,7 +1905,7 @@ void execCreateHorizChamferDimension(Gui::Command* cmd) {
|
||||
if (std::signbit(allVertexes[0].point.y))
|
||||
yMax = -yMax;
|
||||
TechDraw::pointPair pp = dim->getLinearPoints();
|
||||
Base::Vector3d mid = (pp.first + pp.second) / 2.0;
|
||||
Base::Vector3d mid = (pp.first() + pp.second()) / 2.0;
|
||||
dim->X.setValue(mid.x);
|
||||
dim->Y.setValue(-yMax);
|
||||
float dx = allVertexes[0].point.x - allVertexes[1].point.x;
|
||||
@@ -1972,7 +1972,7 @@ void execCreateVertChamferDimension(Gui::Command* cmd) {
|
||||
if (std::signbit(allVertexes[0].point.x))
|
||||
xMax = -xMax;
|
||||
TechDraw::pointPair pp = dim->getLinearPoints();
|
||||
Base::Vector3d mid = (pp.first + pp.second) / 2.0;
|
||||
Base::Vector3d mid = (pp.first() + pp.second()) / 2.0;
|
||||
dim->X.setValue(xMax);
|
||||
dim->Y.setValue(-mid.y);
|
||||
float dx = allVertexes[0].point.x - allVertexes[1].point.x;
|
||||
@@ -2169,7 +2169,7 @@ void CmdTechDrawExtensionCreateLengthArc::activated(int iMsg) {
|
||||
TechDraw::DrawViewDimension* dim;
|
||||
dim = _createLinDimension(this, objFeat, startName.str(), endName.str(), "Distance");
|
||||
TechDraw::pointPair pp = dim->getLinearPoints();
|
||||
Base::Vector3d mid = (pp.first + pp.second) / 2.0;
|
||||
Base::Vector3d mid = (pp.first() + pp.second()) / 2.0;
|
||||
dim->X.setValue(mid.x);
|
||||
dim->Y.setValue(-mid.y);
|
||||
Base::Vector3d radVec1 = startPt - centerPt;
|
||||
|
||||
712
src/Mod/TechDraw/Gui/DimensionValidators.cpp
Normal file
712
src/Mod/TechDraw/Gui/DimensionValidators.cpp
Normal file
@@ -0,0 +1,712 @@
|
||||
/***************************************************************************
|
||||
* Copyright (c) 2022 WandererFan <wandererfan@gmail.com *
|
||||
* *
|
||||
* This file is part of the FreeCAD CAx development system. *
|
||||
* *
|
||||
* This library is free software; you can redistribute it and/or *
|
||||
* modify it under the terms of the GNU Library General Public *
|
||||
* License as published by the Free Software Foundation; either *
|
||||
* version 2 of the License, or (at your option) any later version. *
|
||||
* *
|
||||
* This library 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 Library General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Library General Public *
|
||||
* License along with this library; see the file COPYING.LIB. If not, *
|
||||
* write to the Free Software Foundation, Inc., 59 Temple Place, *
|
||||
* Suite 330, Boston, MA 02111-1307, USA *
|
||||
* *
|
||||
***************************************************************************/
|
||||
#ifndef _PreComp_
|
||||
#include <BRepAdaptor_Curve.hxx>
|
||||
#include <BRep_Tool.hxx>
|
||||
#include <GeomAbs_CurveType.hxx>
|
||||
#include <TopAbs_ShapeEnum.hxx>
|
||||
#include <TopExp.hxx>
|
||||
#endif //#ifndef _PreComp_
|
||||
|
||||
#include <App/DocumentObject.h>
|
||||
#include <Base/Exception.h>
|
||||
#include <Base/Console.h>
|
||||
#include <Gui/Selection.h>
|
||||
|
||||
#include <Mod/TechDraw/App/Geometry.h>
|
||||
#include <Mod/TechDraw/App/DrawUtil.h>
|
||||
#include <Mod/TechDraw/App/DrawViewPart.h>
|
||||
#include <Mod/TechDraw/App/ShapeExtractor.h>
|
||||
#include <Mod/TechDraw/App/ShapeExtractor.h>
|
||||
|
||||
#include "DimensionValidators.h"
|
||||
|
||||
using namespace TechDraw;
|
||||
using DU = DrawUtil;
|
||||
|
||||
TechDraw::DrawViewPart* TechDraw::getReferencesFromSelection( ReferenceVector& references2d, ReferenceVector& references3d )
|
||||
{
|
||||
TechDraw::DrawViewPart* dvp(nullptr);
|
||||
TechDraw::DrawViewDimension* dim(nullptr);
|
||||
std::vector<Gui::SelectionObject> selectionAll = Gui::Selection().getSelectionEx();
|
||||
for (auto& selItem : selectionAll) {
|
||||
if (selItem.getObject()->isDerivedFrom(TechDraw::DrawViewDimension::getClassTypeId())) {
|
||||
//we are probably repairing a dimension, but we will check later
|
||||
dim = static_cast<TechDraw::DrawViewDimension*> (selItem.getObject());
|
||||
} else if (selItem.getObject()->isDerivedFrom(TechDraw::DrawViewPart::getClassTypeId())) {
|
||||
//this could be a 2d geometry selection or just a DrawViewPart for context in
|
||||
//a 3d selection
|
||||
dvp = static_cast<TechDraw::DrawViewPart*> (selItem.getObject());
|
||||
if (selItem.getSubNames().empty()) {
|
||||
//there are no subNames, so we think this is a 3d case,
|
||||
//and we only need to select the view. We set the reference
|
||||
//subName to a null string to avoid later misunderstandings.
|
||||
ReferenceEntry ref(dvp, std::string());
|
||||
references2d.push_back(ref);
|
||||
}
|
||||
for (auto& sub : selItem.getSubNames()) {
|
||||
ReferenceEntry ref(dvp, sub);
|
||||
references2d.push_back(ref);
|
||||
}
|
||||
} else if ( !selItem.getObject()->isDerivedFrom(TechDraw::DrawView::getClassTypeId()) ) {
|
||||
//this is not a TechDraw object, so we check to see if it has 3d geometry
|
||||
std::vector<App::DocumentObject*> links;
|
||||
links.push_back(selItem.getObject());
|
||||
if (!ShapeExtractor::getShapes(links).IsNull()) {
|
||||
//this item has 3d geometry so we are interested
|
||||
App::DocumentObject* obj3d = selItem.getObject();
|
||||
if (selItem.getSubNames().empty()) {
|
||||
if (ShapeExtractor::isPointType(obj3d)) {
|
||||
//a point object may not have a subName when selected,
|
||||
//so we need to perform some special handling.
|
||||
ReferenceEntry ref(obj3d, "Vertex1");
|
||||
references3d.push_back(ref);
|
||||
continue;
|
||||
} else {
|
||||
//this is a whole object reference, probably for an extent dimension
|
||||
ReferenceEntry ref(obj3d, std::string());
|
||||
references3d.push_back(ref);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
//this is a regular reference in form obj+subelement
|
||||
for (auto& sub3d : selItem.getSubNames()) {
|
||||
ReferenceEntry ref(obj3d, sub3d);
|
||||
references3d.push_back(ref);
|
||||
}
|
||||
} else {
|
||||
Base::Console().Message("DV::getRefsFromSel - %s has no shape!\n", selItem.getObject()->getNameInDocument());
|
||||
}
|
||||
}
|
||||
}
|
||||
if (dim) {
|
||||
if (!dvp) {
|
||||
ReferenceEntry ref(dim->getViewPart(), std::string());
|
||||
references2d.push_back(ref);
|
||||
return dim->getViewPart();
|
||||
}
|
||||
}
|
||||
return dvp;
|
||||
}
|
||||
|
||||
//! verify that the proposed references contains valid geometries from a 2d DrawViewPart.
|
||||
DimensionGeometryType TechDraw::validateDimSelection(ReferenceVector references, //[(dvp*, std::string),...,(dvp*, std::string)]
|
||||
StringVector acceptableGeometry, //"Edge", "Vertex", etc
|
||||
std::vector<int> minimumCounts, //how many of each geometry are needed for a good dimension
|
||||
std::vector<DimensionGeometryType> acceptableDimensionGeometrys) //isVertical, isHorizontal, ...
|
||||
{
|
||||
StringVector subNames;
|
||||
TechDraw::DrawViewPart* dvpSave(nullptr);
|
||||
for (auto& ref : references) {
|
||||
TechDraw::DrawViewPart* dvp = dynamic_cast<TechDraw::DrawViewPart *>(ref.getObject());
|
||||
if ( dvp ) {
|
||||
dvpSave = dvp;
|
||||
//TODO: check for non-empty subname?
|
||||
subNames.push_back(ref.getSubName());
|
||||
}
|
||||
}
|
||||
if (!dvpSave) {
|
||||
//must have 1 DVP in selection
|
||||
return isInvalid;
|
||||
}
|
||||
|
||||
if (subNames.front().empty()) {
|
||||
//no geometry referenced. can not make a dim from this mess. We are being called to validate
|
||||
//a selection for a 3d reference
|
||||
return isViewReference;
|
||||
}
|
||||
|
||||
//check for invalid geometry descriptors in the subNames
|
||||
std::unordered_set<std::string> acceptableGeometrySet(acceptableGeometry.begin(),
|
||||
acceptableGeometry.end());
|
||||
if (!TechDraw::validateSubnameList(subNames, acceptableGeometrySet)) {
|
||||
//can not make a dimension from this
|
||||
return isInvalid;
|
||||
}
|
||||
|
||||
//check for wrong number of geometry
|
||||
GeomCountVector foundCounts;
|
||||
GeomCountMap minimumCountMap = loadRequiredCounts(acceptableGeometry, minimumCounts);
|
||||
if (!checkGeometryOccurences(subNames, minimumCountMap)) {
|
||||
//too many or too few geometry descriptors.
|
||||
return isInvalid;
|
||||
}
|
||||
|
||||
//we have a (potentially valid collection of 2d geometry
|
||||
ReferenceVector valid2dReferences;
|
||||
for (auto& sub : subNames) {
|
||||
ReferenceEntry validEntry(dvpSave, sub);
|
||||
valid2dReferences.push_back(validEntry);
|
||||
}
|
||||
|
||||
DimensionGeometryType foundGeometry = getGeometryConfiguration(valid2dReferences);
|
||||
if (acceptableDimensionGeometrys.empty()) {
|
||||
//if the list is empty, we are accepting anything
|
||||
return foundGeometry;
|
||||
}
|
||||
for (auto& acceptable : acceptableDimensionGeometrys) {
|
||||
if (foundGeometry == acceptable) {
|
||||
return foundGeometry;
|
||||
}
|
||||
}
|
||||
|
||||
return isInvalid;
|
||||
}
|
||||
|
||||
//! verify that the proposed references contains valid geometries from non-TechDraw objects.
|
||||
DimensionGeometryType TechDraw::validateDimSelection3d(TechDraw::DrawViewPart* dvp,
|
||||
ReferenceVector references, //[(dvp*, std::string),...,(dvp*, std::string)]
|
||||
StringVector acceptableGeometry, //"Edge", "Vertex", etc
|
||||
std::vector<int> minimumCounts, //how many of each geometry are needed for a good dimension
|
||||
std::vector<DimensionGeometryType> acceptableDimensionGeometrys) //isVertical, isHorizontal, ...
|
||||
{
|
||||
// Base::Console().Message("DV::validateDimSelection3d() - references: %d\n", references.size());
|
||||
StringVector subNames;
|
||||
for (auto& ref : references) {
|
||||
if (!ref.getSubName().empty()) {
|
||||
subNames.push_back(ref.getSubName());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//check for invalid geometry descriptors in the subNames
|
||||
std::unordered_set<std::string> acceptableGeometrySet(acceptableGeometry.begin(),
|
||||
acceptableGeometry.end());
|
||||
if (!TechDraw::validateSubnameList(subNames, acceptableGeometrySet)) {
|
||||
//can not make a dimension from this
|
||||
return isInvalid;
|
||||
}
|
||||
|
||||
//check for wrong number of geometry
|
||||
GeomCountMap minimumCountMap = loadRequiredCounts(acceptableGeometry, minimumCounts);
|
||||
if (!checkGeometryOccurences(subNames, minimumCountMap)) {
|
||||
//too many or too few geometry descriptors.
|
||||
return isInvalid;
|
||||
}
|
||||
|
||||
//we have a (potentially valid collection of 3d geometry
|
||||
DimensionGeometryType foundGeometry = getGeometryConfiguration3d(dvp, references);
|
||||
if (acceptableDimensionGeometrys.empty()) {
|
||||
//if the list is empty, we are accepting anything
|
||||
return foundGeometry;
|
||||
}
|
||||
for (auto& acceptable : acceptableDimensionGeometrys) {
|
||||
if (foundGeometry == acceptable) {
|
||||
return foundGeometry;
|
||||
}
|
||||
}
|
||||
|
||||
return isInvalid;
|
||||
}
|
||||
bool TechDraw::validateSubnameList(StringVector subNames,
|
||||
GeometrySet acceptableGeometrySet)
|
||||
{
|
||||
// Base::Console().Message("DV::validateSubNameList()\n");
|
||||
for (auto& sub : subNames) {
|
||||
std::string geometryType = DrawUtil::getGeomTypeFromName(sub);
|
||||
if (acceptableGeometrySet.count(geometryType) == 0) {
|
||||
//this geometry type is not allowed
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
//count how many of each "Edge", "Vertex, etc and compare totals to required minimum
|
||||
bool TechDraw::checkGeometryOccurences(StringVector subNames,
|
||||
GeomCountMap keyedMinimumCounts)
|
||||
{
|
||||
// Base::Console().Message("DV::checkGeometryOccurences() - subNames: %d\n", subNames.size());
|
||||
//how many of each geometry descriptor are input
|
||||
GeomCountMap foundCounts;
|
||||
for (auto& sub : subNames) {
|
||||
std::string geometryType = DrawUtil::getGeomTypeFromName(sub);
|
||||
std::map<std::string, int>::iterator it0(foundCounts.find(geometryType));
|
||||
if (it0 == foundCounts.end()) {
|
||||
//already have this geometryType
|
||||
it0->second++;
|
||||
} else {
|
||||
//first occurrence of this geometryType
|
||||
foundCounts[geometryType] = 1;
|
||||
}
|
||||
}
|
||||
|
||||
//check found geometry counts against required counts
|
||||
for (auto& foundItem : foundCounts) {
|
||||
std::string currentKey = foundItem.first;
|
||||
int foundCount = foundItem.second;
|
||||
auto itAccept = keyedMinimumCounts.find(currentKey);
|
||||
if (itAccept == keyedMinimumCounts.end()) {
|
||||
//not supposed to happen by this point
|
||||
throw Base::IndexError("Dimension validation counts and geometry do not match");
|
||||
}
|
||||
if (foundCount < keyedMinimumCounts[currentKey]) {
|
||||
//not enough of this type of geom to make a good dimension - ex 1 Vertex
|
||||
return false;
|
||||
}
|
||||
}
|
||||
//we have no complaints about the input
|
||||
return true;
|
||||
}
|
||||
|
||||
//return the first valid configuration contained in the already validated references
|
||||
DimensionGeometryType TechDraw::getGeometryConfiguration(ReferenceVector valid2dReferences)
|
||||
{
|
||||
DimensionGeometryType config = isValidMultiEdge(valid2dReferences);
|
||||
if ( config > isInvalid) {
|
||||
return config;
|
||||
}
|
||||
config = isValidVertexes(valid2dReferences);
|
||||
if ( config > isInvalid) {
|
||||
return config;
|
||||
}
|
||||
config = isValidSingleEdge(valid2dReferences.front());
|
||||
if ( config > isInvalid) {
|
||||
return config;
|
||||
}
|
||||
config = isValidHybrid(valid2dReferences);
|
||||
if ( config > isInvalid) {
|
||||
return config;
|
||||
}
|
||||
|
||||
// no valid configuration found
|
||||
return isInvalid;
|
||||
}
|
||||
|
||||
//return the first valid configuration contained in the already validated references
|
||||
DimensionGeometryType TechDraw::getGeometryConfiguration3d(DrawViewPart* dvp, ReferenceVector valid3dReferences)
|
||||
{
|
||||
// Base::Console().Message("DV::getGeometryConfig3d() - refs: %d\n", valid3dReferences.size());
|
||||
//first we check for whole object references
|
||||
ReferenceVector wholeObjectRefs;
|
||||
ReferenceVector subElementRefs;
|
||||
for (auto& ref : valid3dReferences) {
|
||||
if (ref.isWholeObject()) {
|
||||
wholeObjectRefs.push_back(ref);
|
||||
} else {
|
||||
subElementRefs.push_back(ref);
|
||||
}
|
||||
}
|
||||
if (subElementRefs.empty()) {
|
||||
//only whole object references
|
||||
return isMultiEdge;
|
||||
}
|
||||
if (!wholeObjectRefs.empty()) {
|
||||
//mix of whole object and subelement refs
|
||||
return isMultiEdge; //??? correct ???
|
||||
}
|
||||
|
||||
//only have subelement refs
|
||||
DimensionGeometryType config = isValidMultiEdge3d(dvp, valid3dReferences);
|
||||
if ( config > isInvalid) {
|
||||
return config;
|
||||
}
|
||||
config = isValidVertexes3d(dvp, valid3dReferences);
|
||||
if ( config > isInvalid) {
|
||||
return config;
|
||||
}
|
||||
config = isValidSingleEdge3d(dvp, valid3dReferences.front());
|
||||
if ( config > isInvalid) {
|
||||
return config;
|
||||
}
|
||||
config = isValidHybrid3d(dvp, valid3dReferences);
|
||||
if ( config > isInvalid) {
|
||||
return config;
|
||||
}
|
||||
|
||||
// no valid configuration found
|
||||
return isInvalid;
|
||||
}
|
||||
|
||||
//fill the GeomCountMap with pairs made from corresponding items in acceptableGeometry
|
||||
//and minimumCounts
|
||||
GeomCountMap TechDraw::loadRequiredCounts(StringVector& acceptableGeometry,
|
||||
std::vector<int>& minimumCounts)
|
||||
{
|
||||
if (acceptableGeometry.size() != minimumCounts.size()) {
|
||||
throw Base::IndexError("acceptableGeometry and minimum counts have different sizes.");
|
||||
}
|
||||
|
||||
GeomCountMap result;
|
||||
int iCount = 0;
|
||||
for (auto& acceptableItem : acceptableGeometry) {
|
||||
result[acceptableItem] = minimumCounts.at(iCount);
|
||||
iCount++;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
//! verify that Selection contains a valid Geometry for a single Edge Dimension
|
||||
DimensionGeometryType TechDraw::isValidSingleEdge(ReferenceEntry ref)
|
||||
{
|
||||
auto objFeat( dynamic_cast<TechDraw::DrawViewPart *>(ref.getObject()) );
|
||||
if (!objFeat)
|
||||
return isInvalid;
|
||||
|
||||
//the Name starts with "Edge"
|
||||
std::string geomName = DrawUtil::getGeomTypeFromName(ref.getSubName());
|
||||
if (geomName != "Edge") {
|
||||
return isInvalid;
|
||||
}
|
||||
|
||||
//the geometry exists (redundant?)
|
||||
int GeoId( TechDraw::DrawUtil::getIndexFromName(ref.getSubName()) );
|
||||
TechDraw::BaseGeomPtr geom = objFeat->getGeomByIndex(GeoId);
|
||||
if (!geom) {
|
||||
return isInvalid;
|
||||
}
|
||||
|
||||
if(geom->geomType == TechDraw::GENERIC) {
|
||||
TechDraw::GenericPtr gen1 = std::static_pointer_cast<TechDraw::Generic>(geom);
|
||||
if(gen1->points.size() < 2) {
|
||||
return isInvalid;
|
||||
}
|
||||
Base::Vector3d line = gen1->points.at(1) - gen1->points.at(0);
|
||||
if(fabs(line.y) < FLT_EPSILON ) {
|
||||
return TechDraw::isHorizontal;
|
||||
} else if(fabs(line.x) < FLT_EPSILON) {
|
||||
return TechDraw::isVertical;
|
||||
} else {
|
||||
return TechDraw::isDiagonal;
|
||||
}
|
||||
} else if (geom->geomType == TechDraw::CIRCLE ||
|
||||
geom->geomType == TechDraw::ARCOFCIRCLE ) {
|
||||
return isCircle;
|
||||
} else if (geom->geomType == TechDraw::ELLIPSE ||
|
||||
geom->geomType == TechDraw::ARCOFELLIPSE) {
|
||||
return isEllipse;
|
||||
} else if (geom->geomType == TechDraw::BSPLINE) {
|
||||
TechDraw::BSplinePtr spline = std::static_pointer_cast<TechDraw::BSpline> (geom);
|
||||
if (spline->isCircle()) {
|
||||
return isBSplineCircle;
|
||||
} else {
|
||||
return isBSpline;
|
||||
}
|
||||
}
|
||||
return isInvalid;
|
||||
}
|
||||
|
||||
//! verify that Selection contains a valid Geometry for a single Edge Dimension
|
||||
DimensionGeometryType TechDraw::isValidSingleEdge3d(DrawViewPart *dvp, ReferenceEntry ref)
|
||||
{
|
||||
(void) dvp;
|
||||
//the Name starts with "Edge"
|
||||
std::string geomName = DrawUtil::getGeomTypeFromName(ref.getSubName());
|
||||
if (geomName != "Edge") {
|
||||
return isInvalid;
|
||||
}
|
||||
|
||||
TopoDS_Shape refShape = ref.getGeometry();
|
||||
if (refShape.IsNull() || refShape.ShapeType() != TopAbs_EDGE) {
|
||||
throw Base::RuntimeError("Geometry for reference is not an edge.");
|
||||
}
|
||||
|
||||
TopoDS_Edge occEdge = TopoDS::Edge(refShape);
|
||||
BRepAdaptor_Curve adapt(occEdge);
|
||||
if (adapt.GetType() == GeomAbs_Line) {
|
||||
Base::Vector3d point0 = DU::toVector3d(BRep_Tool::Pnt(TopExp::FirstVertex(occEdge)));
|
||||
Base::Vector3d point1 = DU::toVector3d(BRep_Tool::Pnt(TopExp::LastVertex(occEdge)));
|
||||
Base::Vector3d line = point1 - point0;
|
||||
if(fabs(line.y) < FLT_EPSILON ) {
|
||||
return TechDraw::isHorizontal;
|
||||
} else if(fabs(line.x) < FLT_EPSILON) {
|
||||
return TechDraw::isVertical;
|
||||
} else if(fabs(line.z) < FLT_EPSILON) {
|
||||
return TechDraw::isZLimited;
|
||||
} else {
|
||||
return TechDraw::isDiagonal;
|
||||
}
|
||||
} else if (adapt.GetType() == GeomAbs_Circle) {
|
||||
return isCircle;
|
||||
} else if (adapt.GetType() == GeomAbs_Ellipse) {
|
||||
return isEllipse;
|
||||
} else if (adapt.GetType() == GeomAbs_BSplineCurve) {
|
||||
if (GeometryUtils::isCircle(occEdge)) {
|
||||
return isBSplineCircle;
|
||||
} else {
|
||||
return isBSpline;
|
||||
}
|
||||
}
|
||||
|
||||
return isInvalid;
|
||||
}
|
||||
|
||||
//! verify that the edge references can make a dimension. Currently only extent
|
||||
//! dimensions support more than 2 edges
|
||||
DimensionGeometryType TechDraw::isValidMultiEdge(ReferenceVector refs)
|
||||
{
|
||||
//there has to be at least 2
|
||||
if(refs.size() < 2) {
|
||||
return isInvalid;
|
||||
}
|
||||
|
||||
//must be an extent?
|
||||
if (refs.size() > 2) {
|
||||
return isMultiEdge;
|
||||
}
|
||||
|
||||
auto objFeat0( dynamic_cast<TechDraw::DrawViewPart *>(refs.at(0).getObject()));
|
||||
if ( !objFeat0 ) {
|
||||
//probably redundant
|
||||
throw Base::RuntimeError("Logic error in isValidMultiEdge");
|
||||
}
|
||||
|
||||
//they both must start with "Edge"
|
||||
if(TechDraw::DrawUtil::getGeomTypeFromName(refs.at(0).getSubName()) != "Edge" ||
|
||||
TechDraw::DrawUtil::getGeomTypeFromName(refs.at(1).getSubName()) != "Edge") {
|
||||
return isInvalid;
|
||||
}
|
||||
|
||||
int GeoId0( TechDraw::DrawUtil::getIndexFromName(refs.at(0).getSubName()) );
|
||||
int GeoId1( TechDraw::DrawUtil::getIndexFromName(refs.at(1).getSubName()) );
|
||||
TechDraw::BaseGeomPtr geom0 = objFeat0->getGeomByIndex(GeoId0);
|
||||
TechDraw::BaseGeomPtr geom1 = objFeat0->getGeomByIndex(GeoId1);
|
||||
|
||||
if(geom0->geomType == TechDraw::GENERIC &&
|
||||
geom1->geomType == TechDraw::GENERIC) {
|
||||
TechDraw::GenericPtr gen0 = std::static_pointer_cast<TechDraw::Generic> (geom0);
|
||||
TechDraw::GenericPtr gen1 = std::static_pointer_cast<TechDraw::Generic> (geom1);
|
||||
if(gen0->points.size() > 2 ||
|
||||
gen1->points.size() > 2) { //the edge is a polyline
|
||||
return isInvalid; //not supported yet
|
||||
}
|
||||
Base::Vector3d line0 = gen0->points.at(1) - gen0->points.at(0);
|
||||
Base::Vector3d line1 = gen1->points.at(1) - gen1->points.at(0);
|
||||
double xprod = fabs(line0.x * line1.y - line0.y * line1.x);
|
||||
if (xprod > FLT_EPSILON) { //edges are not parallel
|
||||
return isAngle; //angle or distance
|
||||
} else {
|
||||
return isDiagonal; //distance || line
|
||||
}
|
||||
} else {
|
||||
return isDiagonal; //two edges, not both straight lines
|
||||
}
|
||||
|
||||
return isInvalid;
|
||||
}
|
||||
|
||||
//! verify that the edge references can make a dimension. Currently only extent
|
||||
//! dimensions support more than 2 edges
|
||||
DimensionGeometryType TechDraw::isValidMultiEdge3d(DrawViewPart *dvp, ReferenceVector refs)
|
||||
{
|
||||
(void) dvp;
|
||||
//there has to be at least 2
|
||||
if(refs.size() < 2) {
|
||||
return isInvalid;
|
||||
}
|
||||
|
||||
std::vector<TopoDS_Edge> edges;
|
||||
for (auto& ref : refs) {
|
||||
std::vector<TopoDS_Shape> shapesAll = ShapeExtractor::getShapesFromObject(ref.getObject());
|
||||
if (shapesAll.empty()) {
|
||||
//reference has no geometry
|
||||
return isInvalid;
|
||||
}
|
||||
|
||||
//the Name starts with "Edge"
|
||||
std::string geomName = DrawUtil::getGeomTypeFromName(ref.getSubName().c_str());
|
||||
if (geomName != "Edge") {
|
||||
return isInvalid;
|
||||
}
|
||||
}
|
||||
std::vector<TopoDS_Edge> edgesAll;
|
||||
std::vector<int> typeAll;
|
||||
for (auto& ref : refs) {
|
||||
TopoDS_Shape geometry = ref.getGeometry();
|
||||
if (geometry.ShapeType() != TopAbs_EDGE) {
|
||||
return isInvalid;
|
||||
}
|
||||
TopoDS_Edge edge = TopoDS::Edge(geometry);
|
||||
BRepAdaptor_Curve adapt(edge);
|
||||
if (adapt.GetType() != GeomAbs_Line) {
|
||||
//not a line, so this must be an extent dim?
|
||||
return isMultiEdge;
|
||||
}
|
||||
edgesAll.push_back(edge);
|
||||
}
|
||||
if (edgesAll.size() > 2) {
|
||||
//must be an extent dimension of lines?
|
||||
return isMultiEdge;
|
||||
} else if (edgesAll.size() == 2) {
|
||||
Base::Vector3d first0 = DU::toVector3d(BRep_Tool::Pnt(TopExp::FirstVertex(edgesAll.at(0))));
|
||||
Base::Vector3d last0 = DU::toVector3d(BRep_Tool::Pnt(TopExp::LastVertex(edgesAll.at(1))));
|
||||
Base::Vector3d line0 = last0 - first0;
|
||||
Base::Vector3d first1 = DU::toVector3d(BRep_Tool::Pnt(TopExp::FirstVertex(edgesAll.at(0))));
|
||||
Base::Vector3d last1 = DU::toVector3d(BRep_Tool::Pnt(TopExp::LastVertex(edgesAll.at(1))));
|
||||
Base::Vector3d line1 = last1 - first1;
|
||||
if (DU::fpCompare(fabs(line0.Dot(line1)), 1)) {
|
||||
//lines are parallel, must be distance dim
|
||||
return isDiagonal;
|
||||
} else {
|
||||
//lines are skew, could be angle, could be distance?
|
||||
return isAngle;
|
||||
}
|
||||
}
|
||||
|
||||
return isInvalid;
|
||||
}
|
||||
|
||||
//! verify that the vertex references can make a dimension
|
||||
DimensionGeometryType TechDraw::isValidVertexes(ReferenceVector refs)
|
||||
{
|
||||
TechDraw::DrawViewPart* dvp( dynamic_cast<TechDraw::DrawViewPart*>(refs.front().getObject()) );
|
||||
if ( !dvp ) {
|
||||
//probably redundant
|
||||
throw Base::RuntimeError("Logic error in isValidMultiEdge");
|
||||
}
|
||||
|
||||
if (refs.size() == 2) {
|
||||
//2 vertices can only make a distance dimension
|
||||
TechDraw::VertexPtr v0 = dvp->getVertex(refs.at(0).getSubName());
|
||||
TechDraw::VertexPtr v1 = dvp->getVertex(refs.at(1).getSubName());
|
||||
Base::Vector3d line = v1->point() - v0->point();
|
||||
if(fabs(line.y) < FLT_EPSILON ) {
|
||||
return isHorizontal;
|
||||
} else if(fabs(line.x) < FLT_EPSILON) {
|
||||
return isVertical;
|
||||
} else {
|
||||
return isDiagonal;
|
||||
}
|
||||
} else if (refs.size() == 3) {
|
||||
//three vertices make an angle dimension
|
||||
return isAngle3Pt;
|
||||
}
|
||||
|
||||
// did not find a valid configuration
|
||||
return isInvalid;
|
||||
}
|
||||
|
||||
//! verify that the vertex references can make a dimension
|
||||
DimensionGeometryType TechDraw::isValidVertexes3d(DrawViewPart *dvp, ReferenceVector refs)
|
||||
{
|
||||
// Base::Console().Message("DV::isValidVertexes3d() - refs: %d\n", refs.size());
|
||||
(void) dvp;
|
||||
if (refs.size() == 2) {
|
||||
//2 vertices can only make a distance dimension
|
||||
TopoDS_Shape geometry0 = refs.at(0).getGeometry();
|
||||
TopoDS_Shape geometry1 = refs.at(1).getGeometry();
|
||||
if (geometry0.IsNull() || geometry1.IsNull() ||
|
||||
geometry0.ShapeType() != TopAbs_VERTEX ||
|
||||
geometry1.ShapeType() != TopAbs_VERTEX) {
|
||||
return isInvalid;
|
||||
}
|
||||
Base::Vector3d point0 = DU::toVector3d(BRep_Tool::Pnt(TopoDS::Vertex(geometry0)));
|
||||
point0 = dvp->projectPoint(point0);
|
||||
Base::Vector3d point1 = DU::toVector3d(BRep_Tool::Pnt(TopoDS::Vertex(geometry1)));
|
||||
point1 = dvp->projectPoint(point1);
|
||||
Base::Vector3d line = point1 - point0;
|
||||
if(fabs(line.y) < FLT_EPSILON ) {
|
||||
return isHorizontal;
|
||||
} else if(fabs(line.x) < FLT_EPSILON) {
|
||||
return isVertical;
|
||||
// } else if(fabs(line.z) < FLT_EPSILON) {
|
||||
// return isZLimited;
|
||||
} else {
|
||||
return isDiagonal;
|
||||
}
|
||||
} else if (refs.size() == 3) {
|
||||
//three vertices make an angle dimension
|
||||
//we could check here that all the geometries are Vertex
|
||||
return isAngle3Pt;
|
||||
}
|
||||
|
||||
// did not find a valid configuration
|
||||
return isInvalid;
|
||||
}
|
||||
|
||||
//! verify that the mixed bag (ex Vertex-Edge) of references can make a dimension
|
||||
DimensionGeometryType TechDraw::isValidHybrid(ReferenceVector refs)
|
||||
{
|
||||
if (refs.empty()) {
|
||||
return isInvalid;
|
||||
}
|
||||
|
||||
int vertexCount(0);
|
||||
int edgeCount(0);
|
||||
for (auto& ref : refs) {
|
||||
if (DU::getGeomTypeFromName(ref.getSubName()) == "Vertex") {
|
||||
vertexCount++;
|
||||
}
|
||||
if (DU::getGeomTypeFromName(ref.getSubName()) == "Edge") {
|
||||
edgeCount++;
|
||||
}
|
||||
}
|
||||
if (vertexCount > 0 &&
|
||||
edgeCount > 0) {
|
||||
//must be a diagonal dim? could it be isHorizontal or isVertical?
|
||||
return isDiagonal;
|
||||
}
|
||||
|
||||
return isInvalid;
|
||||
}
|
||||
|
||||
//! verify that the mixed bag (ex Vertex-Edge) of references can make a dimension
|
||||
DimensionGeometryType TechDraw::isValidHybrid3d(DrawViewPart *dvp, ReferenceVector refs)
|
||||
{
|
||||
(void) dvp;
|
||||
//we don't have a special check for 3d in this case
|
||||
return isValidHybrid(refs);
|
||||
}
|
||||
|
||||
//handle situations where revised geometry type is valid but not suitable for existing dimType
|
||||
long int TechDraw::mapGeometryTypeToDimType(long int dimType,
|
||||
DimensionGeometryType geometry2d,
|
||||
DimensionGeometryType geometry3d)
|
||||
{
|
||||
if (geometry2d == isInvalid && geometry3d == isInvalid) {
|
||||
//probably an error, but we can't do anything with this
|
||||
return dimType;
|
||||
}
|
||||
|
||||
if (geometry2d == isViewReference && geometry3d != isInvalid) {
|
||||
switch (geometry3d) {
|
||||
case isDiagonal:
|
||||
return DrawViewDimension::Distance;
|
||||
case isHorizontal:
|
||||
return DrawViewDimension::DistanceX;
|
||||
case isVertical:
|
||||
return DrawViewDimension::DistanceY;
|
||||
case isAngle:
|
||||
return DrawViewDimension::Angle;
|
||||
case isAngle3Pt:
|
||||
return DrawViewDimension::Angle3Pt;
|
||||
default:
|
||||
return dimType;
|
||||
}
|
||||
} else if (geometry2d != isViewReference) {
|
||||
switch (geometry2d) {
|
||||
case isDiagonal:
|
||||
return DrawViewDimension::Distance;
|
||||
case isHorizontal:
|
||||
return DrawViewDimension::DistanceX;
|
||||
case isVertical:
|
||||
return DrawViewDimension::DistanceY;
|
||||
case isAngle:
|
||||
return DrawViewDimension::Angle;
|
||||
case isAngle3Pt:
|
||||
return DrawViewDimension::Angle3Pt;
|
||||
default:
|
||||
return dimType;
|
||||
}
|
||||
}
|
||||
return dimType;
|
||||
}
|
||||
102
src/Mod/TechDraw/Gui/DimensionValidators.h
Normal file
102
src/Mod/TechDraw/Gui/DimensionValidators.h
Normal file
@@ -0,0 +1,102 @@
|
||||
/***************************************************************************
|
||||
* Copyright (c) 2022 WandererFan <wandererfan@gmail.com *
|
||||
* *
|
||||
* This file is part of the FreeCAD CAx development system. *
|
||||
* *
|
||||
* This library is free software; you can redistribute it and/or *
|
||||
* modify it under the terms of the GNU Library General Public *
|
||||
* License as published by the Free Software Foundation; either *
|
||||
* version 2 of the License, or (at your option) any later version. *
|
||||
* *
|
||||
* This library 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 Library General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Library General Public *
|
||||
* License along with this library; see the file COPYING.LIB. If not, *
|
||||
* write to the Free Software Foundation, Inc., 59 Temple Place, *
|
||||
* Suite 330, Boston, MA 02111-1307, USA *
|
||||
* *
|
||||
***************************************************************************/
|
||||
#ifndef TECHDRAW_DIMENSIONVALIDATORS_H
|
||||
#define TECHDRAW_DIMENSIONVALIDATORS_H
|
||||
|
||||
#include <Mod/TechDraw/TechDrawGlobal.h>
|
||||
|
||||
#include <Mod/TechDraw/App/DrawViewDimension.h>
|
||||
|
||||
namespace App
|
||||
{
|
||||
class Document;
|
||||
class DocumentObject;
|
||||
}
|
||||
|
||||
using StringVector = std::vector<std::string>;
|
||||
using GeomCount = std::pair<std::string, int>; //geometry descriptor ("Edge") + counter pair
|
||||
using GeomCountVector = std::vector<GeomCount>;
|
||||
using GeomCountMap = std::map<std::string, int>;
|
||||
using GeometrySet = std::unordered_set<std::string>; //queryable unique set of geometrty descriptors
|
||||
|
||||
using DimensionGeometryType = int;
|
||||
|
||||
namespace TechDraw
|
||||
{
|
||||
|
||||
class DrawViewPart;
|
||||
|
||||
enum DimensionGeometryEnum {
|
||||
isInvalid,
|
||||
isHorizontal,
|
||||
isVertical,
|
||||
isDiagonal,
|
||||
isCircle,
|
||||
isEllipse,
|
||||
isBSplineCircle,
|
||||
isBSpline,
|
||||
isAngle,
|
||||
isAngle3Pt,
|
||||
isMultiEdge,
|
||||
isZLimited,
|
||||
isViewReference //never needs to be specified in the acceptable list
|
||||
};
|
||||
|
||||
TechDraw::DrawViewPart* TechDrawExport getReferencesFromSelection( ReferenceVector& references2d, ReferenceVector& references3d );
|
||||
DimensionGeometryType TechDrawExport validateDimSelection(ReferenceVector references,
|
||||
StringVector acceptableGeometry, //"Edge", "Vertex", etc
|
||||
std::vector<int> minimumCounts, //how many of each geometry are needed for a good dimension
|
||||
std::vector<DimensionGeometryType> acceptableDimensionGeometrys); //isVertical, isHorizontal, ...
|
||||
DimensionGeometryType TechDrawExport validateDimSelection3d(TechDraw::DrawViewPart* dvp,
|
||||
ReferenceVector references,
|
||||
StringVector acceptableGeometry, //"Edge", "Vertex", etc
|
||||
std::vector<int> minimumCounts, //how many of each geometry are needed for a good dimension
|
||||
std::vector<DimensionGeometryType> acceptableDimensionGeometrys); //isVertical, isHorizontal, ...
|
||||
|
||||
bool TechDrawExport validateSubnameList(StringVector subNames,
|
||||
GeometrySet acceptableGeometrySet);
|
||||
|
||||
DimensionGeometryType TechDrawExport getGeometryConfiguration(TechDraw::ReferenceVector valid2dReferences);
|
||||
DimensionGeometryType TechDrawExport getGeometryConfiguration3d(TechDraw::DrawViewPart* dvp,
|
||||
TechDraw::ReferenceVector valid3dReferences);
|
||||
|
||||
GeomCountMap TechDrawExport loadRequiredCounts(StringVector& acceptableGeometry,
|
||||
std::vector<int>& minimumCouts);
|
||||
bool TechDrawExport checkGeometryOccurences(StringVector subNames,
|
||||
GeomCountMap keyedMinimumCounts);
|
||||
|
||||
DimensionGeometryType TechDrawExport isValidVertexes(TechDraw::ReferenceVector refs);
|
||||
DimensionGeometryType TechDrawExport isValidMultiEdge(TechDraw::ReferenceVector refs);
|
||||
DimensionGeometryType TechDrawExport isValidSingleEdge(TechDraw::ReferenceEntry ref);
|
||||
DimensionGeometryType TechDrawExport isValidHybrid(TechDraw::ReferenceVector refs);
|
||||
|
||||
DimensionGeometryType TechDrawExport isValidVertexes3d(TechDraw::DrawViewPart* dvp, TechDraw::ReferenceVector refs);
|
||||
DimensionGeometryType TechDrawExport isValidMultiEdge3d(TechDraw::DrawViewPart* dvp, TechDraw::ReferenceVector refs);
|
||||
DimensionGeometryType TechDrawExport isValidSingleEdge3d(TechDraw::DrawViewPart* dvp, TechDraw::ReferenceEntry ref);
|
||||
DimensionGeometryType TechDrawExport isValidHybrid3d(TechDraw::DrawViewPart* dvp, TechDraw::ReferenceVector refs);
|
||||
|
||||
long int TechDrawExport mapGeometryTypeToDimType(long int dimType,
|
||||
DimensionGeometryType geometry2d,
|
||||
DimensionGeometryType geometry3d);
|
||||
}
|
||||
#endif //TECHDRAW_DIMENSIONVALIDATORS_H
|
||||
|
||||
@@ -2097,7 +2097,7 @@ void QGIViewDimension::drawDistance(TechDraw::DrawViewDimension* dimension,
|
||||
lineAngle = M_PI_2;
|
||||
}
|
||||
else {
|
||||
lineAngle = (fromQtApp(linePoints.second) - fromQtApp(linePoints.first)).Angle();
|
||||
lineAngle = (fromQtApp(linePoints.second()) - fromQtApp(linePoints.first())).Angle();
|
||||
}
|
||||
|
||||
int standardStyle = viewProvider->StandardAndStyle.getValue();
|
||||
@@ -2106,14 +2106,14 @@ void QGIViewDimension::drawDistance(TechDraw::DrawViewDimension* dimension,
|
||||
|
||||
|
||||
if (dimension->AngleOverride.getValue()) {
|
||||
drawDistanceOverride(fromQtApp(linePoints.first), fromQtApp(linePoints.second),
|
||||
drawDistanceOverride(fromQtApp(linePoints.first()), fromQtApp(linePoints.second()),
|
||||
dimension->LineAngle.getValue() * M_PI / 180.0, labelRectangle,
|
||||
standardStyle, renderExtent, flipArrows,
|
||||
dimension->ExtensionAngle.getValue() * M_PI / 180.0);
|
||||
}
|
||||
else {
|
||||
drawDistanceExecutive(fromQtApp(linePoints.first), fromQtApp(linePoints.second), lineAngle,
|
||||
labelRectangle, standardStyle, renderExtent, flipArrows);
|
||||
drawDistanceExecutive(fromQtApp(linePoints.first()), fromQtApp(linePoints.second()),
|
||||
lineAngle, labelRectangle, standardStyle, renderExtent, flipArrows);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2127,10 +2127,12 @@ void QGIViewDimension::drawRadius(TechDraw::DrawViewDimension* dimension,
|
||||
double endAngle;
|
||||
double startRotation;
|
||||
if (curvePoints.isArc) {
|
||||
endAngle = (fromQtApp(curvePoints.arcEnds.second) - fromQtApp(curvePoints.center)).Angle();
|
||||
endAngle =
|
||||
(fromQtApp(curvePoints.arcEnds.second()) - fromQtApp(curvePoints.center)).Angle();
|
||||
startRotation =
|
||||
(fromQtApp(curvePoints.arcEnds.first) - fromQtApp(curvePoints.center)).Angle()
|
||||
(fromQtApp(curvePoints.arcEnds.first()) - fromQtApp(curvePoints.center)).Angle()
|
||||
- endAngle;
|
||||
|
||||
if (startRotation != 0.0 && ((startRotation > 0.0) != curvePoints.arcCW)) {
|
||||
startRotation += curvePoints.arcCW ? +M_2PI : -M_2PI;
|
||||
}
|
||||
@@ -2323,9 +2325,9 @@ void QGIViewDimension::drawAngle(TechDraw::DrawViewDimension* dimension,
|
||||
|
||||
anglePoints anglePoints = dimension->getAnglePoints();
|
||||
|
||||
Base::Vector2d angleVertex = fromQtApp(anglePoints.vertex);
|
||||
Base::Vector2d startPoint = fromQtApp(anglePoints.ends.first);
|
||||
Base::Vector2d endPoint = fromQtApp(anglePoints.ends.second);
|
||||
Base::Vector2d angleVertex = fromQtApp(anglePoints.vertex());
|
||||
Base::Vector2d startPoint = fromQtApp(anglePoints.first());
|
||||
Base::Vector2d endPoint = fromQtApp(anglePoints.second());
|
||||
|
||||
double endAngle = (endPoint - angleVertex).Angle();
|
||||
double startAngle = (startPoint - angleVertex).Angle();
|
||||
|
||||
@@ -83,6 +83,7 @@
|
||||
<file>icons/TechDraw_Balloon.svg</file>
|
||||
<file>icons/TechDraw_DiameterDimension.svg</file>
|
||||
<file>icons/TechDraw_Dimension.svg</file>
|
||||
<file>icons/TechDraw_DimensionRepair.svg</file>
|
||||
<file>icons/TechDraw_ExtensionAreaAnnotation.svg</file>
|
||||
<file>icons/TechDraw_ExtensionCascadeHorizDimension.svg</file>
|
||||
<file>icons/TechDraw_ExtensionCascadeObliqueDimension.svg</file>
|
||||
|
||||
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 5.6 KiB |
346
src/Mod/TechDraw/Gui/TaskDimRepair.cpp
Normal file
346
src/Mod/TechDraw/Gui/TaskDimRepair.cpp
Normal file
@@ -0,0 +1,346 @@
|
||||
/***************************************************************************
|
||||
* Copyright (c) 2022 WandererFan <wandererfan@gmail.com > *
|
||||
* *
|
||||
* This file is part of the FreeCAD CAx development system. *
|
||||
* *
|
||||
* This library is free software; you can redistribute it and/or *
|
||||
* modify it under the terms of the GNU Library General Public *
|
||||
* License as published by the Free Software Foundation; either *
|
||||
* version 2 of the License, or (at your option) any later version. *
|
||||
* *
|
||||
* This library 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 Library General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Library General Public *
|
||||
* License along with this library; see the file COPYING.LIB. If not, *
|
||||
* write to the Free Software Foundation, Inc., 59 Temple Place, *
|
||||
* Suite 330, Boston, MA 02111-1307, USA *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
#include "PreCompiled.h"
|
||||
|
||||
#include <QMessageBox>
|
||||
#include <QTableWidgetItem>
|
||||
|
||||
#ifndef _PreComp_
|
||||
#include <cmath>
|
||||
#endif // #ifndef _PreComp_
|
||||
|
||||
#include <Base/Console.h>
|
||||
#include <Base/Tools.h>
|
||||
#include <Base/Vector3D.h>
|
||||
|
||||
#include <Gui/Application.h>
|
||||
#include <Gui/BitmapFactory.h>
|
||||
#include <Gui/Command.h>
|
||||
#include <Gui/Document.h>
|
||||
#include <Gui/MainWindow.h>
|
||||
#include <Gui/Selection.h>
|
||||
#include <Gui/ViewProvider.h>
|
||||
|
||||
#include <App/Application.h>
|
||||
#include <App/Document.h>
|
||||
#include <App/DocumentObject.h>
|
||||
|
||||
#include <Mod/TechDraw/App/DrawView.h>
|
||||
#include <Mod/TechDraw/App/DrawViewPart.h>
|
||||
#include <Mod/TechDraw/App/DrawUtil.h>
|
||||
|
||||
#include "PreferencesGui.h"
|
||||
#include "DimensionValidators.h"
|
||||
#include "TaskDimRepair.h"
|
||||
#include <Mod/TechDraw/Gui/ui_TaskDimRepair.h>
|
||||
|
||||
using namespace Gui;
|
||||
using namespace TechDraw;
|
||||
using namespace TechDrawGui;
|
||||
|
||||
TaskDimRepair::TaskDimRepair(TechDraw::DrawViewDimension* inDvd,
|
||||
ReferenceVector references2d,
|
||||
ReferenceVector references3d) :
|
||||
ui(new Ui_TaskDimRepair),
|
||||
m_dim(inDvd),
|
||||
m_references2d(references2d),
|
||||
m_references3d(references3d)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
|
||||
connect(ui->pbSelection, SIGNAL(clicked(bool)), this, SLOT(slotUseSelection()));
|
||||
|
||||
saveDimState();
|
||||
setUiPrimary();
|
||||
}
|
||||
|
||||
TaskDimRepair::~TaskDimRepair()
|
||||
{
|
||||
}
|
||||
|
||||
void TaskDimRepair::setUiPrimary()
|
||||
{
|
||||
setWindowTitle(QObject::tr("Dimension Repair"));
|
||||
ui->leName->setReadOnly(true);
|
||||
ui->leLabel->setReadOnly(true);
|
||||
|
||||
ui->leName->setText(Base::Tools::fromStdString(m_dim->getNameInDocument()));
|
||||
ui->leLabel->setText(Base::Tools::fromStdString(m_dim->Label.getValue()));
|
||||
|
||||
std::string objName = m_dim->getViewPart()->getNameInDocument();
|
||||
std::string objLabel = m_dim->getViewPart()->Label.getValue();
|
||||
ui->leObject2d->setText(Base::Tools::fromStdString(objName + " / " + objLabel));
|
||||
const std::vector<std::string>& subElements2d = m_dim->References2D.getSubValues();
|
||||
std::vector<std::string> noLabels(subElements2d.size());
|
||||
fillList(ui->lwGeometry2d, subElements2d, noLabels);
|
||||
|
||||
const std::vector<App::DocumentObject*>& objs3d = m_dim->References3D.getValues();
|
||||
QStringList headers;
|
||||
headers << tr("Object Name")
|
||||
<< tr("Object Label")
|
||||
<< tr("SubElement");
|
||||
ui->twReferences3d->setHorizontalHeaderLabels(headers);
|
||||
|
||||
ReferenceVector references3d;
|
||||
if (!m_references3d.empty()) {
|
||||
references3d = m_references3d;
|
||||
} else if (!objs3d.empty()) {
|
||||
references3d = m_dim->getEffectiveReferences();
|
||||
}
|
||||
loadTableWidget(ui->twReferences3d, references3d);
|
||||
}
|
||||
|
||||
void TaskDimRepair::saveDimState()
|
||||
{
|
||||
m_saveMeasureType = m_dim->MeasureType.getValue();
|
||||
m_saveDimType = m_dim->Type.getValue();
|
||||
m_dimType = m_dim->Type.getValue();
|
||||
m_saveObjs3d = m_dim->References3D.getValues();
|
||||
m_saveSubs3d = m_dim->References3D.getSubValues();
|
||||
m_saveDvp = static_cast<DrawViewPart*>(m_dim->References2D.getValues().front());
|
||||
m_saveSubs2d = m_dim->References2D.getSubValues();
|
||||
}
|
||||
|
||||
//restore the start conditions
|
||||
void TaskDimRepair::restoreDimState()
|
||||
{
|
||||
// Base::Console().Message("TDR::restoreDimState()\n");
|
||||
if (m_dim != nullptr) {
|
||||
std::vector<App::DocumentObject*> objs2d(m_saveSubs2d.size());
|
||||
std::iota(objs2d.begin(), objs2d.end(), m_saveDvp);
|
||||
m_dim->References2D.setValues(objs2d, m_saveSubs2d);
|
||||
m_dim->References3D.setValues(m_saveObjs3d, m_saveSubs3d);
|
||||
}
|
||||
}
|
||||
|
||||
//similar to code in CommandCreateDims.cpp
|
||||
//use the current selection to replace the references in dim
|
||||
void TaskDimRepair::slotUseSelection()
|
||||
{
|
||||
const std::vector<App::DocumentObject*> dimObjects = Gui::Selection().getObjectsOfType(TechDraw::DrawViewDimension::getClassTypeId());
|
||||
if (dimObjects.empty()) {
|
||||
//selection does not include a dimension, so we need to add our dimension to keep the
|
||||
//validators happy
|
||||
//bool accepted =
|
||||
static_cast<void> (Gui::Selection().addSelection(m_dim->getDocument()->getName(),
|
||||
m_dim->getNameInDocument()));
|
||||
}
|
||||
ReferenceVector references2d;
|
||||
ReferenceVector references3d;
|
||||
TechDraw::DrawViewPart* dvp = TechDraw::getReferencesFromSelection(references2d, references3d);
|
||||
if (dvp != m_saveDvp) {
|
||||
QMessageBox::warning(Gui::getMainWindow(),
|
||||
QObject::tr("Incorrect Selection"),
|
||||
QObject::tr("Can not use references from a different View"));
|
||||
return;
|
||||
}
|
||||
|
||||
StringVector acceptableGeometry( { "Edge", "Vertex" } );
|
||||
std::vector<int> minimumCounts( { 1, 1 } );
|
||||
std::vector<DimensionGeometryType> acceptableDimensionGeometrys; //accept anything
|
||||
DimensionGeometryType geometryRefs2d = validateDimSelection(references2d,
|
||||
acceptableGeometry,
|
||||
minimumCounts,
|
||||
acceptableDimensionGeometrys);
|
||||
if (geometryRefs2d == isInvalid) {
|
||||
QMessageBox::warning(Gui::getMainWindow(),
|
||||
QObject::tr("Incorrect Selection"),
|
||||
QObject::tr("Can not make a dimension from selection"));
|
||||
return;
|
||||
}
|
||||
//what 3d geometry configuration did we receive?
|
||||
DimensionGeometryType geometryRefs3d(isInvalid);
|
||||
if (geometryRefs2d == TechDraw::isViewReference &&
|
||||
!references3d.empty()) {
|
||||
geometryRefs3d = validateDimSelection3d(dvp,
|
||||
references3d,
|
||||
acceptableGeometry,
|
||||
minimumCounts,
|
||||
acceptableDimensionGeometrys);
|
||||
if ( geometryRefs3d == isInvalid) {
|
||||
QMessageBox::warning(Gui::getMainWindow(),
|
||||
QObject::tr("Incorrect Selection"),
|
||||
QObject::tr("Can not make dimension from selection"));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
m_dimType = mapGeometryTypeToDimType(m_dim->Type.getValue(),
|
||||
geometryRefs2d,
|
||||
geometryRefs3d);
|
||||
m_references2d = references2d;
|
||||
if (references3d.empty()) {
|
||||
m_references3d.clear();
|
||||
} else {
|
||||
m_references3d = references3d;
|
||||
}
|
||||
updateUi();
|
||||
}
|
||||
|
||||
void TaskDimRepair::updateUi()
|
||||
{
|
||||
// Base::Console().Message("TDR::updateUi()\n");
|
||||
std::string objName = m_dim->getViewPart()->getNameInDocument();
|
||||
std::string objLabel = m_dim->getViewPart()->Label.getValue();
|
||||
ui->leObject2d->setText(Base::Tools::fromStdString(objName + " / " + objLabel));
|
||||
|
||||
std::vector<std::string> subElements2d;
|
||||
for (auto& ref : m_references2d) {
|
||||
subElements2d.push_back(ref.getSubName());
|
||||
}
|
||||
std::vector<std::string> noLabels(subElements2d.size());
|
||||
fillList(ui->lwGeometry2d, subElements2d, noLabels);
|
||||
loadTableWidget(ui->twReferences3d, m_references3d);
|
||||
}
|
||||
|
||||
void TaskDimRepair::loadTableWidget(QTableWidget* tw, ReferenceVector refs)
|
||||
{
|
||||
// Base::Console().Message("TDR::loadTableWidget() - refs: %d\n", refs.size());
|
||||
tw->clearContents();
|
||||
tw->setRowCount(refs.size() + 1);
|
||||
size_t iRow = 0;
|
||||
for (auto& ref : refs) {
|
||||
QString qName = Base::Tools::fromStdString(ref.getObject()->getNameInDocument());
|
||||
QTableWidgetItem* itemName = new QTableWidgetItem(qName);
|
||||
itemName->setTextAlignment(Qt::AlignRight | Qt::AlignVCenter);
|
||||
tw->setItem(iRow,0, itemName);
|
||||
QString qLabel = Base::Tools::fromStdString(std::string(ref.getObject()->Label.getValue()));
|
||||
QTableWidgetItem* itemLabel = new QTableWidgetItem(qLabel);
|
||||
itemLabel->setTextAlignment(Qt::AlignRight | Qt::AlignVCenter);
|
||||
tw->setItem(iRow,1, itemLabel);
|
||||
QString qSubName = Base::Tools::fromStdString(ref.getSubName());
|
||||
QTableWidgetItem* itemSubName = new QTableWidgetItem(qSubName);
|
||||
itemSubName->setTextAlignment(Qt::AlignRight | Qt::AlignVCenter);
|
||||
tw->setItem(iRow,2, itemSubName);
|
||||
iRow++;
|
||||
}
|
||||
}
|
||||
|
||||
void TaskDimRepair::fillList(QListWidget* lwItems, std::vector<std::string> labels, std::vector<std::string> names)
|
||||
{
|
||||
QListWidgetItem* item;
|
||||
QString qLabel;
|
||||
QString qName;
|
||||
QString qText;
|
||||
int labelCount = labels.size();
|
||||
int i = 0;
|
||||
lwItems->clear();
|
||||
for (; i < labelCount; i++) {
|
||||
qLabel = Base::Tools::fromStdString(labels[i]);
|
||||
qName = Base::Tools::fromStdString(names[i]);
|
||||
qText = QString::fromUtf8("%1 %2").arg(qName, qLabel);
|
||||
item = new QListWidgetItem(qText, lwItems);
|
||||
item->setTextAlignment(Qt::AlignRight | Qt::AlignVCenter);
|
||||
item->setData(Qt::UserRole, qName);
|
||||
}
|
||||
}
|
||||
void TaskDimRepair::replaceReferences()
|
||||
{
|
||||
if (m_dim) {
|
||||
m_dim->setReferences2d(m_references2d);
|
||||
m_dim->setReferences3d(m_references3d);
|
||||
}
|
||||
}
|
||||
|
||||
void TaskDimRepair::updateTypes()
|
||||
{
|
||||
if (m_references3d.empty()) {
|
||||
m_dim->MeasureType.setValue("Projected");
|
||||
} else {
|
||||
m_dim->MeasureType.setValue("True");
|
||||
}
|
||||
m_dim->Type.setValue(m_dimType);
|
||||
}
|
||||
|
||||
|
||||
bool TaskDimRepair::accept()
|
||||
{
|
||||
// Base::Console().Message("TDR::accept()\n");
|
||||
Gui::Command::doCommand(Gui::Command::Gui, "Gui.ActiveDocument.resetEdit()");
|
||||
replaceReferences();
|
||||
updateTypes();
|
||||
m_dim->recomputeFeature();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TaskDimRepair::reject()
|
||||
{
|
||||
// Base::Console().Message("TDR::reject()\n");
|
||||
restoreDimState();
|
||||
Gui::Command::doCommand(Gui::Command::Gui, "Gui.ActiveDocument.resetEdit()");
|
||||
return false;
|
||||
}
|
||||
|
||||
void TaskDimRepair::changeEvent(QEvent *e)
|
||||
{
|
||||
if (e->type() == QEvent::LanguageChange) {
|
||||
ui->retranslateUi(this);
|
||||
}
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
TaskDlgDimReference::TaskDlgDimReference(TechDraw::DrawViewDimension* inDvd,
|
||||
ReferenceVector references2d,
|
||||
ReferenceVector references3d) :
|
||||
TaskDialog()
|
||||
{
|
||||
widget = new TaskDimRepair(inDvd, references2d, references3d);
|
||||
taskbox = new Gui::TaskView::TaskBox(Gui::BitmapFactory().pixmap("TechDraw_DimensionRepair"),
|
||||
widget->windowTitle(), true, 0);
|
||||
taskbox->groupLayout()->addWidget(widget);
|
||||
Content.push_back(taskbox);
|
||||
}
|
||||
|
||||
|
||||
TaskDlgDimReference::~TaskDlgDimReference()
|
||||
{
|
||||
}
|
||||
|
||||
void TaskDlgDimReference::update()
|
||||
{
|
||||
//widget->updateTask();
|
||||
}
|
||||
|
||||
//==== calls from the TaskView ===============================================================
|
||||
void TaskDlgDimReference::open()
|
||||
{
|
||||
}
|
||||
|
||||
void TaskDlgDimReference::clicked(int i)
|
||||
{
|
||||
Q_UNUSED(i);
|
||||
}
|
||||
|
||||
bool TaskDlgDimReference::accept()
|
||||
{
|
||||
widget->accept();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TaskDlgDimReference::reject()
|
||||
{
|
||||
widget->reject();
|
||||
return true;
|
||||
}
|
||||
|
||||
#include <Mod/TechDraw/Gui/moc_TaskDimRepair.cpp>
|
||||
125
src/Mod/TechDraw/Gui/TaskDimRepair.h
Normal file
125
src/Mod/TechDraw/Gui/TaskDimRepair.h
Normal file
@@ -0,0 +1,125 @@
|
||||
/***************************************************************************
|
||||
* Copyright (c) 2022 WandererFan <wandererfan@gmail.com> *
|
||||
* *
|
||||
* This file is part of the FreeCAD CAx development system. *
|
||||
* *
|
||||
* This library is free software; you can redistribute it and/or *
|
||||
* modify it under the terms of the GNU Library General Public *
|
||||
* License as published by the Free Software Foundation; either *
|
||||
* version 2 of the License, or (at your option) any later version. *
|
||||
* *
|
||||
* This library 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 Library General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Library General Public *
|
||||
* License along with this library; see the file COPYING.LIB. If not, *
|
||||
* write to the Free Software Foundation, Inc., 59 Temple Place, *
|
||||
* Suite 330, Boston, MA 02111-1307, USA *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef TECHDRAW_TASKDIMREPAIR_H
|
||||
#define TECHDRAW_TASKDIMREPAIR_H
|
||||
|
||||
#include <Mod/TechDraw/TechDrawGlobal.h>
|
||||
|
||||
#include <Gui/TaskView/TaskDialog.h>
|
||||
#include <Gui/TaskView/TaskView.h>
|
||||
|
||||
#include <Mod/TechDraw/App/DrawViewDimension.h>
|
||||
#include <Mod/TechDraw/App/DimensionReferences.h>
|
||||
#include <Mod/TechDraw/Gui/ui_TaskDimRepair.h>
|
||||
|
||||
|
||||
class Ui_TaskDimRepair;
|
||||
|
||||
namespace App
|
||||
{
|
||||
class DocumentObject;
|
||||
}
|
||||
|
||||
namespace TechDrawGui
|
||||
{
|
||||
|
||||
class TaskDimRepair : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
TaskDimRepair(TechDraw::DrawViewDimension* inDvd,
|
||||
TechDraw::ReferenceVector references2d,
|
||||
TechDraw::ReferenceVector references3d);
|
||||
~TaskDimRepair();
|
||||
|
||||
public:
|
||||
virtual bool accept();
|
||||
virtual bool reject();
|
||||
|
||||
protected Q_SLOTS:
|
||||
void slotUseSelection();
|
||||
|
||||
protected:
|
||||
void changeEvent(QEvent *e);
|
||||
|
||||
void setUiPrimary();
|
||||
void replaceReferences();
|
||||
void updateTypes();
|
||||
void updateUi();
|
||||
void fillList(QListWidget* lwItems, std::vector<std::string> labels, std::vector<std::string> names);
|
||||
void loadTableWidget(QTableWidget* tw, TechDraw::ReferenceVector refs);
|
||||
void saveDimState();
|
||||
void restoreDimState();
|
||||
|
||||
private:
|
||||
std::unique_ptr<Ui_TaskDimRepair> ui;
|
||||
TechDraw::DrawViewDimension* m_dim;
|
||||
TechDraw::ReferenceVector m_references2d;
|
||||
TechDraw::ReferenceVector m_references3d;
|
||||
long int m_dimType;
|
||||
|
||||
long int m_saveMeasureType;
|
||||
long int m_saveDimType;
|
||||
TechDraw::DrawViewPart* m_saveDvp;
|
||||
std::vector<std::string> m_saveSubs2d;
|
||||
std::vector<App::DocumentObject*> m_saveObjs3d;
|
||||
std::vector<std::string> m_saveSubs3d;
|
||||
};
|
||||
|
||||
class TaskDlgDimReference : public Gui::TaskView::TaskDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
TaskDlgDimReference(TechDraw::DrawViewDimension* inDvd,
|
||||
TechDraw::ReferenceVector references2d,
|
||||
TechDraw::ReferenceVector references3d);
|
||||
~TaskDlgDimReference();
|
||||
|
||||
public:
|
||||
/// is called the TaskView when the dialog is opened
|
||||
virtual void open();
|
||||
/// is called by the framework if an button is clicked which has no accept or reject role
|
||||
virtual void clicked(int);
|
||||
/// is called by the framework if the dialog is accepted (Ok)
|
||||
virtual bool accept();
|
||||
/// is called by the framework if the dialog is rejected (Cancel)
|
||||
virtual bool reject();
|
||||
/// is called by the framework if the user presses the help button
|
||||
virtual void helpRequested() { return;}
|
||||
virtual bool isAllowedAlterDocument(void) const
|
||||
{ return false; }
|
||||
|
||||
void update();
|
||||
|
||||
protected:
|
||||
|
||||
private:
|
||||
TaskDimRepair * widget;
|
||||
Gui::TaskView::TaskBox* taskbox;
|
||||
};
|
||||
|
||||
} //namespace TechDrawGui
|
||||
|
||||
#endif // #ifndef TECHDRAW_TASKDIMREPAIR_H
|
||||
211
src/Mod/TechDraw/Gui/TaskDimRepair.ui
Normal file
211
src/Mod/TechDraw/Gui/TaskDimRepair.ui
Normal file
@@ -0,0 +1,211 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>TaskDimRepair</class>
|
||||
<widget class="QWidget" name="TaskDimRepair">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>356</width>
|
||||
<height>512</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Dimension Repair</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QGroupBox" name="gbDimension">
|
||||
<property name="title">
|
||||
<string>Dimension</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<item>
|
||||
<layout class="QFormLayout" name="formLayout">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>Name</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>Label</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QLineEdit" name="leName">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
<property name="readOnly">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QLineEdit" name="leLabel">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
<property name="readOnly">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QPushButton" name="pbSelection">
|
||||
<property name="text">
|
||||
<string>Replace References with Current Selection</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="gbReferences2D">
|
||||
<property name="title">
|
||||
<string>References 2D</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_3">
|
||||
<item>
|
||||
<layout class="QFormLayout" name="formLayout_2">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_5">
|
||||
<property name="text">
|
||||
<string>Object</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QLineEdit" name="leObject2d">
|
||||
<property name="toolTip">
|
||||
<string>The View that owns this Dimension</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
<property name="readOnly">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_6">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>16777215</width>
|
||||
<height>90</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Geometry</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QListWidget" name="lwGeometry2d">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="MinimumExpanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>64</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>16777215</width>
|
||||
<height>90</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>The subelements of the View that define the geometry for this Dimension</string>
|
||||
</property>
|
||||
<property name="editTriggers">
|
||||
<set>QAbstractItemView::NoEditTriggers</set>
|
||||
</property>
|
||||
<property name="alternatingRowColors">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="resizeMode">
|
||||
<enum>QListView::Adjust</enum>
|
||||
</property>
|
||||
<property name="itemAlignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="gbReferences3d">
|
||||
<property name="title">
|
||||
<string>References 3D</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_4">
|
||||
<item>
|
||||
<widget class="QTableWidget" name="twReferences3d">
|
||||
<property name="alternatingRowColors">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="selectionMode">
|
||||
<enum>QAbstractItemView::NoSelection</enum>
|
||||
</property>
|
||||
<property name="selectionBehavior">
|
||||
<enum>QAbstractItemView::SelectRows</enum>
|
||||
</property>
|
||||
<property name="columnCount">
|
||||
<number>3</number>
|
||||
</property>
|
||||
<attribute name="horizontalHeaderStretchLastSection">
|
||||
<bool>true</bool>
|
||||
</attribute>
|
||||
<attribute name="verticalHeaderVisible">
|
||||
<bool>false</bool>
|
||||
</attribute>
|
||||
<column/>
|
||||
<column/>
|
||||
<column/>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
@@ -327,8 +327,8 @@ void TaskDimension::onDimUseDefaultClicked()
|
||||
{
|
||||
pointPair points = m_parent->getDimFeat()->getLinearPoints();
|
||||
//duplicate coordinate conversion logic from QGIViewDimension
|
||||
Base::Vector2d first2(points.first.x, -points.first.y);
|
||||
Base::Vector2d second2(points.second.x, -points.second.y);
|
||||
Base::Vector2d first2(points.first().x, -points.first().y);
|
||||
Base::Vector2d second2(points.second().x, -points.second().y);
|
||||
double lineAngle = (second2 - first2).Angle();
|
||||
ui->dsbDimAngle->setValue(lineAngle * 180.0 / M_PI);
|
||||
}
|
||||
@@ -345,8 +345,8 @@ void TaskDimension::onExtUseDefaultClicked()
|
||||
{
|
||||
pointPair points = m_parent->getDimFeat()->getLinearPoints();
|
||||
//duplicate coordinate conversion logic from QGIViewDimension
|
||||
Base::Vector2d first2(points.first.x, -points.first.y);
|
||||
Base::Vector2d second2(points.second.x, -points.second.y);
|
||||
Base::Vector2d first2(points.first().x, -points.first().y);
|
||||
Base::Vector2d second2(points.second().x, -points.second().y);
|
||||
Base::Vector2d lineDirection = second2 - first2;
|
||||
Base::Vector2d extensionDirection(-lineDirection.y, lineDirection.x);
|
||||
double extensionAngle = extensionDirection.Angle();
|
||||
|
||||
@@ -99,7 +99,8 @@ void ViewProviderDimension::attach(App::DocumentObject *pcFeat)
|
||||
// call parent attach method
|
||||
ViewProviderDrawingView::attach(pcFeat);
|
||||
|
||||
sPixmap = "TechDraw_Dimension";
|
||||
// sPixmap = "TechDraw_Dimension";
|
||||
setPixmapForType();
|
||||
if (getViewObject()->isDerivedFrom(TechDraw::LandmarkDimension::getClassTypeId())) {
|
||||
sPixmap = "TechDraw_LandmarkDimension";
|
||||
}
|
||||
@@ -141,20 +142,7 @@ bool ViewProviderDimension::setEdit(int ModNum)
|
||||
void ViewProviderDimension::updateData(const App::Property* prop)
|
||||
{
|
||||
if (prop == &(getViewObject()->Type)) {
|
||||
if (getViewObject()->Type.isValue("DistanceX")) {
|
||||
sPixmap = "TechDraw_HorizontalDimension";
|
||||
} else if (getViewObject()->Type.isValue("DistanceY")) {
|
||||
sPixmap = "TechDraw_VerticalDimension";
|
||||
} else if (getViewObject()->Type.isValue("Radius")) {
|
||||
sPixmap = "TechDraw_RadiusDimension";
|
||||
} else if (getViewObject()->Type.isValue("Diameter")) {
|
||||
sPixmap = "TechDraw_DiameterDimension";
|
||||
} else if (getViewObject()->Type.isValue("Angle")) {
|
||||
sPixmap = "TechDraw_AngleDimension";
|
||||
} else if (getViewObject()->Type.isValue("Angle3Pt")) {
|
||||
sPixmap = "TechDraw_3PtAngleDimension";
|
||||
}
|
||||
return;
|
||||
setPixmapForType();
|
||||
}
|
||||
|
||||
//Dimension handles X, Y updates differently that other QGIView
|
||||
@@ -171,7 +159,8 @@ void ViewProviderDimension::updateData(const App::Property* prop)
|
||||
prop == &(getViewObject()->EqualTolerance) ||
|
||||
prop == &(getViewObject()->OverTolerance) ||
|
||||
prop == &(getViewObject()->UnderTolerance) ||
|
||||
prop == &(getViewObject()->Inverted) ){
|
||||
prop == &(getViewObject()->Inverted) ) {
|
||||
|
||||
QGIView* qgiv = getQView();
|
||||
if (qgiv) {
|
||||
qgiv->updateView(true);
|
||||
@@ -183,6 +172,23 @@ void ViewProviderDimension::updateData(const App::Property* prop)
|
||||
Gui::ViewProviderDocumentObject::updateData(prop);
|
||||
}
|
||||
|
||||
void ViewProviderDimension::setPixmapForType()
|
||||
{
|
||||
if (getViewObject()->Type.isValue("DistanceX")) {
|
||||
sPixmap = "TechDraw_HorizontalDimension";
|
||||
} else if (getViewObject()->Type.isValue("DistanceY")) {
|
||||
sPixmap = "TechDraw_VerticalDimension";
|
||||
} else if (getViewObject()->Type.isValue("Radius")) {
|
||||
sPixmap = "TechDraw_RadiusDimension";
|
||||
} else if (getViewObject()->Type.isValue("Diameter")) {
|
||||
sPixmap = "TechDraw_DiameterDimension";
|
||||
} else if (getViewObject()->Type.isValue("Angle")) {
|
||||
sPixmap = "TechDraw_AngleDimension";
|
||||
} else if (getViewObject()->Type.isValue("Angle3Pt")) {
|
||||
sPixmap = "TechDraw_3PtAngleDimension";
|
||||
}
|
||||
}
|
||||
|
||||
void ViewProviderDimension::onChanged(const App::Property* p)
|
||||
{
|
||||
if ((p == &Font) ||
|
||||
|
||||
@@ -23,8 +23,8 @@
|
||||
|
||||
#ifndef DRAWINGGUI_VIEWPROVIDERDIMENSION_H
|
||||
#define DRAWINGGUI_VIEWPROVIDERDIMENSION_H
|
||||
|
||||
#include <Mod/TechDraw/TechDrawGlobal.h>
|
||||
|
||||
#include <Mod/TechDraw/TechDrawGlobal.h>
|
||||
|
||||
#include <App/PropertyUnits.h>
|
||||
|
||||
@@ -84,6 +84,7 @@ public:
|
||||
double prefWeight() const;
|
||||
int prefStandardAndStyle() const;
|
||||
bool canDelete(App::DocumentObject* obj) const override;
|
||||
void setPixmapForType();
|
||||
|
||||
protected:
|
||||
void handleChangedPropertyType(Base::XMLReader &reader, const char *TypeName, App::Property * prop) override;
|
||||
|
||||
@@ -86,6 +86,7 @@ Gui::MenuItem* Workbench::setupMenuBar() const
|
||||
*dimensions << "TechDraw_VerticalExtentDimension";
|
||||
*dimensions << "TechDraw_LinkDimension";
|
||||
*dimensions << "TechDraw_LandmarkDimension";
|
||||
*dimensions << "TechDraw_DimensionRepair";
|
||||
|
||||
// extension: attributes and modifications
|
||||
Gui::MenuItem* toolattrib = new Gui::MenuItem;
|
||||
@@ -269,13 +270,16 @@ Gui::ToolBarItem* Workbench::setupToolBars() const
|
||||
|
||||
Gui::ToolBarItem *dims = new Gui::ToolBarItem(root);
|
||||
dims->setCommand("TechDraw Dimensions");
|
||||
*dims << "TechDraw_LengthDimension";
|
||||
*dims << "TechDraw_HorizontalDimension";
|
||||
*dims << "TechDraw_VerticalDimension";
|
||||
*dims << "TechDraw_RadiusDimension";
|
||||
*dims << "TechDraw_DiameterDimension";
|
||||
*dims << "TechDraw_AngleDimension";
|
||||
*dims << "TechDraw_3PtAngleDimension";
|
||||
*dims << "TechDraw_LinearGroup";
|
||||
// *dims << "TechDraw_LengthDimension";
|
||||
// *dims << "TechDraw_HorizontalDimension";
|
||||
// *dims << "TechDraw_VerticalDimension";
|
||||
*dims << "TechDraw_RadialGroup";
|
||||
// *dims << "TechDraw_RadiusDimension";
|
||||
// *dims << "TechDraw_DiameterDimension";
|
||||
*dims << "TechDraw_AngularGroup";
|
||||
// *dims << "TechDraw_AngleDimension";
|
||||
// *dims << "TechDraw_3PtAngleDimension";
|
||||
*dims << "TechDraw_ExtentGroup";
|
||||
// *dims << "TechDraw_HorizontalExtentDimension";
|
||||
// *dims << "TechDraw_VerticalExtentDimension";
|
||||
@@ -283,6 +287,7 @@ Gui::ToolBarItem* Workbench::setupToolBars() const
|
||||
*dims << "TechDraw_Balloon";
|
||||
*dims << "TechDraw_LandmarkDimension";
|
||||
// *dims << "TechDraw_Dimension"
|
||||
*dims << "TechDraw_DimensionRepair";
|
||||
|
||||
Gui::ToolBarItem *extattribs = new Gui::ToolBarItem(root);
|
||||
extattribs->setCommand("TechDraw Attributes");
|
||||
@@ -416,13 +421,16 @@ Gui::ToolBarItem* Workbench::setupCommandBars() const
|
||||
|
||||
Gui::ToolBarItem *dims = new Gui::ToolBarItem(root);
|
||||
dims->setCommand("TechDraw Dimensions");
|
||||
*dims << "TechDraw_LengthDimension";
|
||||
*dims << "TechDraw_HorizontalDimension";
|
||||
*dims << "TechDraw_VerticalDimension";
|
||||
*dims << "TechDraw_RadiusDimension";
|
||||
*dims << "TechDraw_DiameterDimension";
|
||||
*dims << "TechDraw_AngleDimension";
|
||||
*dims << "TechDraw_3PtAngleDimension";
|
||||
*dims << "TechDraw_LinearGroup";
|
||||
// *dims << "TechDraw_LengthDimension";
|
||||
// *dims << "TechDraw_HorizontalDimension";
|
||||
// *dims << "TechDraw_VerticalDimension";
|
||||
*dims << "TechDraw_RadialGroup";
|
||||
// *dims << "TechDraw_RadiusDimension";
|
||||
// *dims << "TechDraw_DiameterDimension";
|
||||
*dims << "TechDraw_AngularGroup";
|
||||
// *dims << "TechDraw_AngleDimension";
|
||||
// *dims << "TechDraw_3PtAngleDimension";
|
||||
*dims << "TechDraw_ExtentGroup";
|
||||
// *dims << "TechDraw_HorizontalExtentDimension";
|
||||
// *dims << "TechDraw_VerticalExtentDimension";
|
||||
@@ -430,6 +438,7 @@ Gui::ToolBarItem* Workbench::setupCommandBars() const
|
||||
*dims << "TechDraw_Balloon";
|
||||
*dims << "TechDraw_LandmarkDimension";
|
||||
// *dims << "TechDraw_Dimension";
|
||||
*dims << "TechDraw_DimensionRepair";
|
||||
|
||||
Gui::ToolBarItem *extattribs = new Gui::ToolBarItem(root);
|
||||
extattribs->setCommand("TechDraw Attributes");
|
||||
|
||||
Reference in New Issue
Block a user