Merge branch 'master' into removeGZstream

This commit is contained in:
mosfet80
2023-03-01 19:43:56 +01:00
committed by GitHub
917 changed files with 76371 additions and 58452 deletions
+145 -70
View File
@@ -204,6 +204,7 @@ jobs:
mkdir -p ${{ env.fixesdir }}
mkdir -p ${{ env.reportdir }}
echo "reportFile=${{ env.reportfilename }}" >> $GITHUB_OUTPUT
# Run generic lints
- name: Check for non Unix line ending
if: inputs.checkLineendings && always()
continue-on-error: ${{ inputs.lineendingsFailSilent }}
@@ -304,76 +305,7 @@ jobs:
echo "" >> ${{env.reportdir}}${{ env.reportfilename }}
# Exit the step with appropriate code
[ $tabErrors -eq 0 ]
- name: Check old Qt string-based connections (https://wiki.qt.io/New_Signal_Slot_Syntax)
if: inputs.checkQtConnections && inputs.changedCppFiles != '' && always()
continue-on-error: ${{ inputs.qtConnectionsFailSilent }}
run: |
qtconnectionSyntax=0
exclude="*[.md,.log,.ts,.git]"
# Check all files for QT string-based connections
for file in ${{ inputs.changedFiles }} #TODO does this makes sense in Python files ?
do
grep -nIHE --exclude="$exclude" $' SIGNAL| SLOT' $file | sed -e "s/$/ <--Consider using Functor-Based Connections/" >> ${{ env.logdir }}qtConnections.log || true #TODO seems to trigger false positives
done
# Write the Log to the console with the Problem Matchers
if [ -f ${{ env.logdir }}qtConnections.log ]; then
echo "::add-matcher::${{ runner.workspace }}/FreeCAD/.github/problemMatcher/grepMatcherWarning.json"
cat ${{ env.logdir }}qtConnections.log
echo "::remove-matcher owner=grepMatcher-warning::"
qtconnectionSyntax=$(wc -l < ${{ env.logdir }}qtConnections.log)
fi
echo "Found $qtconnectionSyntax QT string-based connections"
# Write the report
if [ $qtconnectionSyntax -gt 0 ]; then
echo "<details><summary>:information_source: Found $qtconnectionSyntax QT string-based connections :arrow_right: consider using QT functor-Based Connections</summary>" >> ${{env.reportdir}}${{ env.reportfilename }}
echo "" >> ${{env.reportdir}}${{ env.reportfilename }}
# documentation link
echo "For more information see: https://wiki.qt.io/New_Signal_Slot_Syntax or https://github.com/FreeCAD/FreeCAD/issues/6166" >> ${{env.reportdir}}${{ env.reportfilename }}
echo '```' >> ${{env.reportdir}}${{ env.reportfilename }}
cat ${{ env.logdir }}qtConnections.log >> ${{env.reportdir}}${{ env.reportfilename }}
echo '```' >> ${{env.reportdir}}${{ env.reportfilename }}
echo "</details>" >> ${{env.reportdir}}${{ env.reportfilename }}
else
echo ":heavy_check_mark: No string-based connections found " >> ${{env.reportdir}}${{ env.reportfilename }}
fi
echo "" >> ${{env.reportdir}}${{ env.reportfilename }}
# Exit the step with appropriate code
[ $qtconnectionSyntax -eq 0 ]
- name: Cpplint
if: inputs.checkCpplint && inputs.changedCppFiles != '' && always()
continue-on-error: ${{ inputs.cpplintFailSilent }}
run: |
cpplintErrors=0
pip install cpplint
# Run cpplint
for file in ${{ inputs.changedCppFiles }}
do
cpplint --filter=${{ inputs.cpplintFilters }} --linelength=${{ inputs.cpplintLineLength }} $file &>> ${{ env.logdir }}cpplint.log || true
done
# If cpplint has run successfully, write the Log to the console with the Problem Matchers
if [ ${{ env.logdir }}cpplint.log ]
then
echo "::add-matcher::${{ runner.workspace }}/FreeCAD/.github/problemMatcher/cpplint.json"
cat ${{ env.logdir }}cpplint.log
echo "::remove-matcher owner=cpplint::"
cpplintErrors=$(grep -nIHE "\[[0-9]\]$" ${{ env.logdir }}cpplint.log | wc -l ) || true
fi
echo "Found $cpplintErrors cpplint errors"
# Write the report
if [ $cpplintErrors -gt 0 ]
then
echo "<details><summary>:warning: CppLint found $cpplintErrors errors / warnings</summary>" >> ${{env.reportdir}}${{ env.reportfilename }}
else
echo "<details><summary>:heavy_check_mark: No cpplint errors found </summary> " >> ${{env.reportdir}}${{ env.reportfilename }}
fi
echo "" >> ${{env.reportdir}}${{ env.reportfilename }}
echo '```' >> ${{env.reportdir}}${{ env.reportfilename }}
cat ${{ env.logdir }}cpplint.log >> ${{env.reportdir}}${{ env.reportfilename }}
echo '```' >> ${{env.reportdir}}${{ env.reportfilename }}
echo "</details>" >> ${{env.reportdir}}${{ env.reportfilename }}
echo "" >> ${{env.reportdir}}${{ env.reportfilename }}
# Exit the step with appropriate code
[ $cpplintErrors -eq 0 ]
# Run Python lints
- name: Pylint
if: inputs.checkPylint && inputs.changedPythonFiles != '' && always()
continue-on-error: ${{ inputs.pylintFailSilent }}
@@ -470,6 +402,149 @@ jobs:
echo "" >> ${{env.reportdir}}${{ env.reportfilename }}
# Exit the step with appropriate code
[ $exitCode -eq 0 ]
# Run C++ lints
- name: Install FreeCAD dependencies
if: inputs.changedCppFiles != '' && always()
run: |
sudo apt-get update -qq
sudo apt-get install -y --no-install-recommends \
doxygen \
graphviz \
imagemagick \
libboost-date-time-dev \
libboost-dev \
libboost-filesystem-dev \
libboost-graph-dev \
libboost-iostreams-dev \
libboost-program-options-dev \
libboost-python-dev \
libboost-regex-dev \
libboost-serialization-dev \
libboost-thread-dev \
libcoin-dev \
libeigen3-dev \
libgts-bin \
libgts-dev \
libkdtree++-dev \
libmedc-dev \
libocct-data-exchange-dev \
libocct-ocaf-dev \
libocct-visualization-dev \
libopencv-dev \
libproj-dev \
libpyside2-dev \
libqt5opengl5-dev \
libqt5svg5-dev \
libqt5x11extras5-dev \
libqt5xmlpatterns5-dev \
libshiboken2-dev \
libspnav-dev \
libvtk7-dev \
libx11-dev \
libxerces-c-dev \
libzipios++-dev \
netgen \
netgen-headers \
occt-draw \
pyqt5-dev-tools \
pyside2-tools \
python3-dev \
python3-git \
python3-markdown \
python3-matplotlib \
python3-packaging \
python3-pivy \
python3-ply \
python3-pyside2.qtcore \
python3-pyside2.qtgui \
python3-pyside2.qtnetwork \
python3-pyside2.qtsvg \
python3-pyside2.qtwebengine \
python3-pyside2.qtwebenginecore \
python3-pyside2.qtwebenginewidgets \
python3-pyside2.qtwebchannel \
python3-pyside2.qtwidgets \
qtbase5-dev \
qttools5-dev \
qtwebengine5-dev \
shiboken2 \
swig \
ccache \
xvfb
- name: Run CMake # This is needed for Clang tools to work correctly
if: inputs.changedCppFiles != '' && always()
run: |
mkdir build && cmake -S ./ -B ./build/ -D CMAKE_EXPORT_COMPILE_COMMANDS:BOOL=TRUE
- name: Check old Qt string-based connections (https://wiki.qt.io/New_Signal_Slot_Syntax)
if: inputs.checkQtConnections && inputs.changedCppFiles != '' && always()
continue-on-error: ${{ inputs.qtConnectionsFailSilent }}
run: |
qtconnectionSyntax=0
exclude="*[.md,.log,.ts,.git]"
# Check all files for QT string-based connections
for file in ${{ inputs.changedFiles }} #TODO does this makes sense in Python files ?
do
grep -nIHE --exclude="$exclude" $' SIGNAL| SLOT' $file | sed -e "s/$/ <--Consider using Functor-Based Connections/" >> ${{ env.logdir }}qtConnections.log || true #TODO seems to trigger false positives
done
# Write the Log to the console with the Problem Matchers
if [ -f ${{ env.logdir }}qtConnections.log ]; then
echo "::add-matcher::${{ runner.workspace }}/FreeCAD/.github/problemMatcher/grepMatcherWarning.json"
cat ${{ env.logdir }}qtConnections.log
echo "::remove-matcher owner=grepMatcher-warning::"
qtconnectionSyntax=$(wc -l < ${{ env.logdir }}qtConnections.log)
fi
echo "Found $qtconnectionSyntax QT string-based connections"
# Write the report
if [ $qtconnectionSyntax -gt 0 ]; then
echo "<details><summary>:information_source: Found $qtconnectionSyntax QT string-based connections :arrow_right: consider using QT functor-Based Connections</summary>" >> ${{env.reportdir}}${{ env.reportfilename }}
echo "" >> ${{env.reportdir}}${{ env.reportfilename }}
# documentation link
echo "For more information see: https://wiki.qt.io/New_Signal_Slot_Syntax or https://github.com/FreeCAD/FreeCAD/issues/6166" >> ${{env.reportdir}}${{ env.reportfilename }}
echo '```' >> ${{env.reportdir}}${{ env.reportfilename }}
cat ${{ env.logdir }}qtConnections.log >> ${{env.reportdir}}${{ env.reportfilename }}
echo '```' >> ${{env.reportdir}}${{ env.reportfilename }}
echo "</details>" >> ${{env.reportdir}}${{ env.reportfilename }}
else
echo ":heavy_check_mark: No string-based connections found " >> ${{env.reportdir}}${{ env.reportfilename }}
fi
echo "" >> ${{env.reportdir}}${{ env.reportfilename }}
# Exit the step with appropriate code
[ $qtconnectionSyntax -eq 0 ]
- name: Cpplint
if: inputs.checkCpplint && inputs.changedCppFiles != '' && always()
continue-on-error: ${{ inputs.cpplintFailSilent }}
run: |
cpplintErrors=0
pip install cpplint
# Run cpplint
for file in ${{ inputs.changedCppFiles }}
do
cpplint --filter=${{ inputs.cpplintFilters }} --linelength=${{ inputs.cpplintLineLength }} $file &>> ${{ env.logdir }}cpplint.log || true
done
# If cpplint has run successfully, write the Log to the console with the Problem Matchers
if [ ${{ env.logdir }}cpplint.log ]
then
echo "::add-matcher::${{ runner.workspace }}/FreeCAD/.github/problemMatcher/cpplint.json"
cat ${{ env.logdir }}cpplint.log
echo "::remove-matcher owner=cpplint::"
cpplintErrors=$(grep -nIHE "\[[0-9]\]$" ${{ env.logdir }}cpplint.log | wc -l ) || true
fi
echo "Found $cpplintErrors cpplint errors"
# Write the report
if [ $cpplintErrors -gt 0 ]
then
echo "<details><summary>:warning: CppLint found $cpplintErrors errors / warnings</summary>" >> ${{env.reportdir}}${{ env.reportfilename }}
else
echo "<details><summary>:heavy_check_mark: No cpplint errors found </summary> " >> ${{env.reportdir}}${{ env.reportfilename }}
fi
echo "" >> ${{env.reportdir}}${{ env.reportfilename }}
echo '```' >> ${{env.reportdir}}${{ env.reportfilename }}
cat ${{ env.logdir }}cpplint.log >> ${{env.reportdir}}${{ env.reportfilename }}
echo '```' >> ${{env.reportdir}}${{ env.reportfilename }}
echo "</details>" >> ${{env.reportdir}}${{ env.reportfilename }}
echo "" >> ${{env.reportdir}}${{ env.reportfilename }}
# Exit the step with appropriate code
[ $cpplintErrors -eq 0 ]
- name: Clang-format
if: inputs.checkClangFormat && inputs.changedCppFiles != '' && always()
continue-on-error: ${{ inputs.clangFormatFailSilent }}
+10 -10
View File
@@ -24,15 +24,15 @@ The FreeCAD Contribution Process is expressed here with the following specific g
## 2. Fundamentals
1. FreeCAD uses the git distributed revision control system.
2. Source code for the main application and related subprojects is hosted on github.com in the FreeCAD organization, hereafter referred to as 'the Platform'.
2. Source code for the main application and related subprojects is hosted on github.com in the FreeCAD organization.
3. Problems are discrete, well-defined limitations or bugs.
4. FreeCAD uses the Platform's issue-tracking system to track problems and contributions. For help requests and general discussions, use the project forum.
4. FreeCAD uses GitHub's issue-tracking system to track problems and contributions. For help requests and general discussions, use the project forum.
5. Contributions are sets of code changes that resolve a single problem.
6. FreeCAD uses the Pull Request workflow for evaluating and accepting contributions.
## 3. Roles
1. "User": An member of the wider FreeCAD community who uses the software.
2. "Contributor": A person who submits a contribution that resolves a previously identified problem. Contributors do not have commit access to the repository unless they are also Maintainers. Everyone, without distinction or discrimination, SHALL have an equal right to become a Contributor.
2. "Contributor": A person who submits a contribution that resolves a previously identified problem. Contributors do not have commit access to the repository unless they are also Maintainers. Everyone, without distinction or discrimination, SHALL have an equal right to become a Contributor.
3. "Maintainer": A person who merges contributions. Maintainers may or may not be Contributors. Their role is to enforce the process. Maintainers have commit access to the repository.
4. "Administrator": Administrators have additional authority to maintain the list of designated Maintainers.
@@ -47,14 +47,14 @@ The FreeCAD Contribution Process is expressed here with the following specific g
## 5. Contribution Requirements
1. Contributions are submitted in the form of Pull Requests (PR).
2. Maintainers and Contributors MUST have a Platform account and SHOULD use their real names or a well-known alias.
3. If the Platform alias differs from the account alias on the FreeCAD Forum, effort SHOULD be taken to avoid confusion.
2. Maintainers and Contributors MUST have a GitHub account and SHOULD use their real names or a well-known alias.
3. If the GitHub username differs from the username on the FreeCAD Forum, effort SHOULD be taken to avoid confusion.
4. A PR SHOULD be a minimal and accurate answer to exactly one identified and agreed-on problem.
5. A PR SHOULD refrain from adding additional dependencies to the FreeCAD project unless no other option is available.
6. Code submissions MUST adhere to the code style guidelines of the project if these are defined.
7. If a PR contains multiple commits, each commit MUST compile cleanly when merged with all previous commits of the same PR. Each commit SHOULD add value to the history of the project. Checkpoint commits SHOULD be squashed.
8. A PR SHALL NOT include non-trivial code from other projects unless the Contributor is the original author of that code.
9. A PR MUST compile cleanly and pass project self-tests on all target Platforms.
9. A PR MUST compile cleanly and pass project self-tests on all target platforms.
10. Each commit message in a PR MUST succinctly explain what the commit achieves. The commit message SHALL follow the suggestions in the `git commit --help` documentation, section DISCUSSION.
11. The PR message MUST consist of a single short line, the PR Title, summarizing the problem being solved, followed by a blank line and then the proposed solution in the Body. If a PR consists of more than one commit, the PR Title MUST succinctly explain what the PR achieves. The Body MAY be as detailed as needed.
12. A “Valid PR” is one which satisfies the above requirements.
@@ -62,15 +62,15 @@ The FreeCAD Contribution Process is expressed here with the following specific g
## 6. Process
1. Change on the project follows the pattern of accurately identifying problems and applying minimal, accurate solutions to these problems.
2. To request changes, a User logs an issue on the project Platform issue tracker.
3. The User or Contributor SHOULD write the issue by describing the problem they face or observe. Links to the forum or other resources are permitted but the issue SHOULD be complete and accurate and SHOULD NOT require the reader to visit the forum or any other Platform to understand what is being described.
2. To request changes, a User logs an issue on the project GitHub issue tracker.
3. The User or Contributor SHOULD write the issue by describing the problem they face or observe. Links to the forum or other resources are permitted but the issue SHOULD be complete and accurate and SHOULD NOT require the reader to visit the forum or any other platform to understand what is being described.
4. Issue authors SHOULD strive to describe the minimum acceptable condition.
5. Issue authors SHOULD focus on User tasks and avoid comparisons to other software solutions.
6. The User or Contributor SHOULD seek consensus on the accuracy of their observation and the value of solving the problem.
7. To submit a solution to a problem, a Contributor SHALL create a pull request back to the project.
8. Contributors and Maintainers SHALL NOT commit changes directly to the target branch.
9. To discuss a proposed solution, Users MAY comment on the Platform Pull Request. Forum conversations regarding the solution SHOULD be discouraged and conversation redirected to the Pull Request or the related issue.
10. To accept or reject a Pull Request, a Maintainer SHALL use the Platform interface.
9. To discuss a proposed solution, Users MAY comment on the Pull Request in GitHub. Forum conversations regarding the solution SHOULD be discouraged and conversation redirected to the Pull Request or the related issue.
10. To accept or reject a Pull Request, a Maintainer SHALL use GitHub's interface.
11. Maintainers SHOULD NOT merge their own PRs except:
1. in exceptional cases, such as non-responsiveness from other Maintainers for an extended period.
2. If the Maintainer is also the primary developer of the workbench or subsystem.
+54 -14
View File
@@ -1904,20 +1904,6 @@ void Application::initTypes()
App::PropertyPrecision ::init();
App::PropertyQuantity ::init();
App::PropertyQuantityConstraint ::init();
App::PropertyAngle ::init();
App::PropertyDistance ::init();
App::PropertyLength ::init();
App::PropertyArea ::init();
App::PropertyVolume ::init();
App::PropertyFrequency ::init();
App::PropertySpeed ::init();
App::PropertyAcceleration ::init();
App::PropertyForce ::init();
App::PropertyPressure ::init();
App::PropertyCurrentDensity ::init();
App::PropertyElectricPotential ::init();
App::PropertyMagnetization ::init();
App::PropertyVacuumPermittivity ::init();
App::PropertyInteger ::init();
App::PropertyIntegerConstraint ::init();
App::PropertyPercent ::init();
@@ -1975,6 +1961,60 @@ void Application::initTypes()
App::PropertyPythonObject ::init();
App::PropertyExpressionContainer::init();
App::PropertyExpressionEngine ::init();
// all know unit properties
App::PropertyAcceleration ::init();
App::PropertyAmountOfSubstance ::init();
App::PropertyAngle ::init();
App::PropertyArea ::init();
App::PropertyCompressiveStrength ::init();
App::PropertyCurrentDensity ::init();
App::PropertyDensity ::init();
App::PropertyDissipationRate ::init();
App::PropertyDistance ::init();
App::PropertyDynamicViscosity ::init();
App::PropertyElectricalCapacitance ::init();
App::PropertyElectricalConductance ::init();
App::PropertyElectricalConductivity ::init();
App::PropertyElectricalInductance ::init();
App::PropertyElectricalResistance ::init();
App::PropertyElectricCharge ::init();
App::PropertyElectricCurrent ::init();
App::PropertyElectricPotential ::init();
App::PropertyFrequency ::init();
App::PropertyForce ::init();
App::PropertyHeatFlux ::init();
App::PropertyInverseArea ::init();
App::PropertyInverseLength ::init();
App::PropertyInverseVolume ::init();
App::PropertyKinematicViscosity ::init();
App::PropertyLength ::init();
App::PropertyLuminousIntensity ::init();
App::PropertyMagneticFieldStrength ::init();
App::PropertyMagneticFlux ::init();
App::PropertyMagneticFluxDensity ::init();
App::PropertyMagnetization ::init();
App::PropertyMass ::init();
App::PropertyPressure ::init();
App::PropertyPower ::init();
App::PropertyShearModulus ::init();
App::PropertySpecificEnergy ::init();
App::PropertySpecificHeat ::init();
App::PropertySpeed ::init();
App::PropertyStiffness ::init();
App::PropertyStress ::init();
App::PropertyTemperature ::init();
App::PropertyThermalConductivity ::init();
App::PropertyThermalExpansionCoefficient::init();
App::PropertyThermalTransferCoefficient ::init();
App::PropertyTime ::init();
App::PropertyUltimateTensileStrength ::init();
App::PropertyVacuumPermittivity ::init();
App::PropertyVolume ::init();
App::PropertyVolumeFlowRate ::init();
App::PropertyVolumetricThermalExpansionCoefficient::init();
App::PropertyWork ::init();
App::PropertyYieldStrength ::init();
App::PropertyYoungsModulus ::init();
// Extension classes
App::Extension ::init();
+4
View File
@@ -140,6 +140,7 @@ SET(Document_CPP_SRCS
DocumentObserverPython.cpp
DocumentPyImp.cpp
Expression.cpp
ExpressionTokenizer.cpp
FeaturePython.cpp
FeatureTest.cpp
GeoFeature.cpp
@@ -182,6 +183,7 @@ SET(Document_HPP_SRCS
DocumentObserverPython.h
Expression.h
ExpressionParser.h
ExpressionTokenizer.h
ExpressionVisitors.h
FeatureCustom.h
FeaturePython.h
@@ -254,6 +256,7 @@ SET(FreeCADApp_CPP_SRCS
ApplicationPy.cpp
AutoTransaction.cpp
Branding.cpp
Color.cpp
ColorModel.cpp
ComplexGeoData.cpp
ComplexGeoDataPyImp.cpp
@@ -270,6 +273,7 @@ SET(FreeCADApp_HPP_SRCS
Application.h
AutoTransaction.h
Branding.h
Color.h
ColorModel.h
ComplexGeoData.h
Enumeration.h
+167
View File
@@ -0,0 +1,167 @@
/***************************************************************************
* Copyright (c) 2005 Jürgen Riegel <[email protected]> *
* *
* 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 <iomanip>
#include <sstream>
#endif
#include "Color.h"
using namespace App;
// NOLINTNEXTLINE(bugprone-easily-swappable-parameters)
Color::Color(float red, float green, float blue, float alpha)
: r(red)
, g(green)
, b(blue)
, a(alpha)
{
}
Color::Color(uint32_t rgba)
: Color{}
{
setPackedValue(rgba);
}
bool Color::operator==(const Color& color) const
{
return getPackedValue() == color.getPackedValue();
}
bool Color::operator!=(const Color& color) const
{
return !operator==(color);
}
// NOLINTNEXTLINE(bugprone-easily-swappable-parameters)
void Color::set(float red, float green, float blue, float alpha)
{
r = red;
g = green;
b = blue;
a = alpha;
}
// NOLINTBEGIN(cppcoreguidelines-avoid-magic-numbers,readability-magic-numbers)
Color& Color::setPackedValue(uint32_t rgba)
{
// clang-format off
this->set(static_cast<float> (rgba >> 24) / 255.0F,
static_cast<float>((rgba >> 16) & 0xff) / 255.0F,
static_cast<float>((rgba >> 8) & 0xff) / 255.0F,
static_cast<float> (rgba & 0xff) / 255.0F);
return *this;
// clang-format on
}
uint32_t Color::getPackedValue() const
{
// clang-format off
return (static_cast<uint32_t>(r * 255.0F + 0.5F) << 24 |
static_cast<uint32_t>(g * 255.0F + 0.5F) << 16 |
static_cast<uint32_t>(b * 255.0F + 0.5F) << 8 |
static_cast<uint32_t>(a * 255.0F + 0.5F));
// clang-format on
}
uint32_t Color::getPackedARGB() const
{
// clang-format off
return (static_cast<uint32_t>(a * 255.0F + 0.5F) << 24 |
static_cast<uint32_t>(r * 255.0F + 0.5F) << 16 |
static_cast<uint32_t>(g * 255.0F + 0.5F) << 8 |
static_cast<uint32_t>(b * 255.0F + 0.5F));
// clang-format on
}
void Color::setPackedARGB(uint32_t argb)
{
// clang-format off
this->set(static_cast<float>((argb >> 16) & 0xff) / 255.0F,
static_cast<float>((argb >> 8) & 0xff) / 255.0F,
static_cast<float> (argb & 0xff) / 255.0F,
static_cast<float> (argb >> 24) / 255.0F);
// clang-format on
}
std::string Color::asHexString() const
{
std::stringstream ss;
ss << "#" << std::hex << std::uppercase << std::setfill('0')
<< std::setw(2) << int(r * 255.0F)
<< std::setw(2) << int(g * 255.0F)
<< std::setw(2) << int(b * 255.0F);
return ss.str();
}
bool Color::fromHexString(const std::string& hex)
{
if (hex.size() < 7 || hex[0] != '#') {
return false;
}
// #RRGGBB
if (hex.size() == 7) {
std::stringstream ss(hex);
unsigned int rgb;
char ch{};
ss >> ch >> std::hex >> rgb;
int rc = (rgb >> 16) & 0xff;
int gc = (rgb >> 8) & 0xff;
int bc = rgb & 0xff;
r = rc / 255.0F;
g = gc / 255.0F;
b = bc / 255.0F;
return true;
}
// #RRGGBBAA
if (hex.size() == 9) {
std::stringstream ss(hex);
unsigned int rgba;
char ch{};
ss >> ch >> std::hex >> rgba;
int rc = (rgba >> 24) & 0xff;
int gc = (rgba >> 16) & 0xff;
int bc = (rgba >> 8) & 0xff;
int ac = rgba & 0xff;
r = rc / 255.0F;
g = gc / 255.0F;
b = bc / 255.0F;
a = ac / 255.0F;
return true;
}
return false;
}
// NOLINTEND(cppcoreguidelines-avoid-magic-numbers,readability-magic-numbers)
+143
View File
@@ -0,0 +1,143 @@
/***************************************************************************
* Copyright (c) 2005 Jürgen Riegel <[email protected]> *
* *
* 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 APP_COLOR_H
#define APP_COLOR_H
#ifdef __GNUC__
# include <cstdint>
#endif
#include <string>
#include <FCGlobal.h>
namespace App
{
/** Color class
*/
class AppExport Color
{
public:
/**
* Defines the color as (R,G,B,A) whereas all values are in the range [0,1].
* \a A defines the transparency.
*/
explicit Color(float R=0.0,float G=0.0, float B=0.0, float A=0.0);
/**
* Does basically the same as the constructor above unless that (R,G,B,A) is
* encoded as an unsigned int.
*/
explicit Color(uint32_t rgba);
/** Copy constructor. */
Color(const Color& c) = default;
Color(Color&&) = default;
/** Returns true if both colors are equal. Therefore all components must be equal. */
bool operator==(const Color& c) const;
bool operator!=(const Color& c) const;
/**
* Defines the color as (R,G,B,A) whereas all values are in the range [0,1].
* \a A defines the transparency, 0 means complete opaque and 1 invisible.
*/
void set(float R,float G, float B, float A=0.0);
Color& operator=(const Color& c) = default;
Color& operator=(Color&& c) = default;
/**
* Sets the color value as a 32 bit combined red/green/blue/alpha value.
* Each component is 8 bit wide (i.e. from 0x00 to 0xff), and the red
* value should be stored leftmost, like this: 0xRRGGBBAA.
*
* \sa getPackedValue().
*/
Color& setPackedValue(uint32_t rgba);
/**
* Returns color as a 32 bit packed unsigned int in the form 0xRRGGBBAA.
*
* \sa setPackedValue().
*/
uint32_t getPackedValue() const;
/**
* Returns color as a 32 bit packed unsigned int in the form 0xAARRGGBB.
*/
uint32_t getPackedARGB() const;
/**
* Sets color as a 32 bit packed unsigned int in the form 0xAARRGGBB.
*/
void setPackedARGB(uint32_t);
template <typename T>
static uint32_t asPackedRGBA(const T& color) {
return (color.red() << 24) | (color.green() << 16) | (color.blue() << 8) | color.alpha();
}
template <typename T>
static T fromPackedRGBA(uint32_t color) {
return T((color >> 24) & 0xff, (color >> 16) & 0xff, (color >> 8) & 0xff, color & 0xff);
}
template <typename T>
static uint32_t asPackedRGB(const T& color) {
return (color.red() << 24) | (color.green() << 16) | (color.blue() << 8);
}
template <typename T>
static T fromPackedRGB(uint32_t color) {
return T((color >> 24) & 0xff, (color >> 16) & 0xff, (color >> 8) & 0xff);
}
/**
* creates FC Color from template type, e.g. Qt QColor
*/
template <typename T>
void setValue(const T& q) {
set(q.redF(),q.greenF(),q.blueF());
}
/**
* returns a template type e.g. Qt color equivalent to FC color
*
*/
template <typename T>
inline T asValue() const {
return(T(int(r*255.0f),int(g*255.0f),int(b*255.0f)));
}
/**
* returns color as hex color "#RRGGBB"
*
*/
std::string asHexString() const;
/**
* gets color from hex color "#RRGGBB"
*
*/
bool fromHexString(const std::string& hex);
/// color values, public accessible
float r,g,b,a;
};
} //namespace App
#endif // APP_COLOR_H
+33
View File
@@ -1578,6 +1578,7 @@ void OperatorExpression::_toString(std::ostream &s, bool persistent,int) const
s << " >= ";
break;
case UNIT:
s << " ";
break;
default:
assert(0);
@@ -1740,6 +1741,7 @@ FunctionExpression::FunctionExpression(const DocumentObject *_owner, Function _f
case TAN:
case TANH:
case SQRT:
case CBRT:
case COS:
case COSH:
case ROUND:
@@ -2188,6 +2190,31 @@ Py::Object FunctionExpression::evaluate(const Expression *expr, int f, const std
s.Angle);
break;
}
case CBRT: {
unit = v1.getUnit();
// All components of unit must be either zero or dividable by 3
UnitSignature s = unit.getSignature();
if ( !((s.Length % 3) == 0) &&
((s.Mass % 3) == 0) &&
((s.Time % 3) == 0) &&
((s.ElectricCurrent % 3) == 0) &&
((s.ThermodynamicTemperature % 3) == 0) &&
((s.AmountOfSubstance % 3) == 0) &&
((s.LuminousIntensity % 3) == 0) &&
((s.Angle % 3) == 0))
_EXPR_THROW("All dimensions must be multiples of 3 to compute the cube root.",expr);
unit = Unit(s.Length /3,
s.Mass / 3,
s.Time / 3,
s.ElectricCurrent / 3,
s.ThermodynamicTemperature / 3,
s.AmountOfSubstance / 3,
s.LuminousIntensity / 3,
s.Angle);
break;
}
case ATAN2:
if (e2.isNone())
_EXPR_THROW("Invalid second argument.",expr);
@@ -2276,6 +2303,9 @@ Py::Object FunctionExpression::evaluate(const Expression *expr, int f, const std
case SQRT:
output = sqrt(value);
break;
case CBRT:
output = cbrt(value);
break;
case COS:
output = cos(value);
break;
@@ -2391,6 +2421,8 @@ void FunctionExpression::_toString(std::ostream &ss, bool persistent,int) const
ss << "tanh("; break;;
case SQRT:
ss << "sqrt("; break;;
case CBRT:
ss << "cbrt("; break;;
case COS:
ss << "cos("; break;;
case COSH:
@@ -3247,6 +3279,7 @@ static void initParser(const App::DocumentObject *owner)
registered_functions["tan"] = FunctionExpression::TAN;
registered_functions["tanh"] = FunctionExpression::TANH;
registered_functions["sqrt"] = FunctionExpression::SQRT;
registered_functions["cbrt"] = FunctionExpression::CBRT;
registered_functions["cos"] = FunctionExpression::COS;
registered_functions["cosh"] = FunctionExpression::COSH;
registered_functions["atan2"] = FunctionExpression::ATAN2;
+1
View File
@@ -256,6 +256,7 @@ public:
TAN,
TANH,
SQRT,
CBRT,
COS,
COSH,
ATAN2,
+150
View File
@@ -0,0 +1,150 @@
/***************************************************************************
* Copyright (c) 2015 Eivind Kvedalen <[email protected]> *
* *
* 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 <string>
#include <tuple>
#endif
#include "ExpressionParser.h"
#include "ExpressionTokenizer.h"
using namespace App;
// Code below inspired by blog entry:
// https://john.nachtimwald.com/2009/07/04/qcompleter-and-comma-separated-tags/
QString ExpressionTokenizer::perform(const QString& prefix, int pos)
{
// ExpressionParser::tokenize() only supports std::string but we need a tuple QString
// because due to UTF-8 encoding a std::string may be longer than a QString
// See https://forum.freecadweb.org/viewtopic.php?f=3&t=69931
auto tokenizeExpression = [](const QString& expr) {
std::vector<std::tuple<int, int, std::string>> result =
ExpressionParser::tokenize(expr.toStdString());
std::vector<std::tuple<int, int, QString>> tokens;
std::transform(result.cbegin(),
result.cend(),
std::back_inserter(tokens),
[&](const std::tuple<int, int, std::string>& item) {
return std::make_tuple(
std::get<0>(item),
QString::fromStdString(expr.toStdString().substr(0, std::get<1>(item))).size(),
QString::fromStdString(std::get<2>(item))
);
});
return tokens;
};
QString completionPrefix;
// Compute start; if prefix starts with =, start parsing from offset 1.
int start = (prefix.size() > 0 && prefix.at(0) == QChar::fromLatin1('=')) ? 1 : 0;
// Tokenize prefix
std::vector<std::tuple<int, int, QString> > tokens = tokenizeExpression(prefix.mid(start));
// No tokens
if (tokens.empty()) {
return QString();
}
prefixEnd = prefix.size();
// Pop those trailing tokens depending on the given position, which may be
// in the middle of a token, and we shall include that token.
for (auto it = tokens.begin(); it != tokens.end(); ++it) {
if (std::get<1>(*it) >= pos) {
// Include the immediately followed '.' or '#', because we'll be
// inserting these separators too, in ExpressionCompleteModel::pathFromIndex()
if (it != tokens.begin() && std::get<0>(*it) != '.' && std::get<0>(*it) != '#')
it = it - 1;
tokens.resize(it - tokens.begin() + 1);
prefixEnd = start + std::get<1>(*it) + (int)std::get<2>(*it).size();
break;
}
}
int trim = 0;
if (prefixEnd > pos)
trim = prefixEnd - pos;
// Extract last tokens that can be rebuilt to a variable
long i = static_cast<long>(tokens.size()) - 1;
// First, check if we have unclosing string starting from the end
bool stringing = false;
for (; i >= 0; --i) {
int token = std::get<0>(tokens[i]);
if (token == ExpressionParser::STRING) {
stringing = false;
break;
}
if (token == ExpressionParser::LT && i > 0
&& std::get<0>(tokens[i - 1]) == ExpressionParser::LT) {
--i;
stringing = true;
break;
}
}
// Not an unclosed string and the last character is a space
if (!stringing && !prefix.isEmpty() &&
prefixEnd > 0 && prefixEnd <= prefix.size() &&
prefix[prefixEnd-1] == QChar(32)) {
return QString();
}
if (!stringing) {
i = static_cast<long>(tokens.size()) - 1;
for (; i >= 0; --i) {
int token = std::get<0>(tokens[i]);
if (token != '.' &&
token != '#' &&
token != ExpressionParser::IDENTIFIER &&
token != ExpressionParser::STRING &&
token != ExpressionParser::UNIT)
break;
}
++i;
}
// Set prefix start for use when replacing later
if (i == static_cast<long>(tokens.size()))
prefixStart = prefixEnd;
else
prefixStart = start + std::get<1>(tokens[i]);
// Build prefix from tokens
while (i < static_cast<long>(tokens.size())) {
completionPrefix += std::get<2>(tokens[i]);
++i;
}
if (trim && trim < int(completionPrefix.size()))
completionPrefix.resize(completionPrefix.size() - trim);
return completionPrefix;
}
+53
View File
@@ -0,0 +1,53 @@
/***************************************************************************
* Copyright (c) 2015 Eivind Kvedalen <[email protected]> *
* *
* 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 EXPRESSIONTOKENIZER_H
#define EXPRESSIONTOKENIZER_H
#include <QString>
#include <FCGlobal.h>
namespace App
{
class AppExport ExpressionTokenizer
{
public:
QString perform(const QString& text, int pos);
void getPrefixRange(int &start, int &end) const {
start = prefixStart;
end = prefixEnd;
}
void updatePrefixEnd(int end) {
prefixEnd = end;
}
private:
int prefixStart = 0;
int prefixEnd = 0;
};
}
#endif //EXPRESSIONTOKENIZER_H
+213 -195
View File
@@ -1,195 +1,213 @@
/***************************************************************************
* Copyright (c) 2016 Stefan Tröger <[email protected]> *
* *
* 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 <cassert>
#endif
#include <Base/PyObjectBase.h>
#include "Extension.h"
#include "ExtensionContainer.h"
#include "ExtensionPython.h"
#include <ExtensionPy.h>
/* We do not use a standard property macro for type initiation. The reason is that we have the first
* PropertyData in the extension chain, there is no parent property data.
*/
EXTENSION_TYPESYSTEM_SOURCE_P(App::Extension)
const App::PropertyData * App::Extension::extensionGetPropertyDataPtr(){return &propertyData;}
const App::PropertyData & App::Extension::extensionGetPropertyData() const{return propertyData;}
App::PropertyData App::Extension::propertyData;
void App::Extension::init(){
assert(Extension::classTypeId == Base::Type::badType() && "don't init() twice!");
/* Set up entry in the type system. */
Extension::classTypeId = Base::Type::createType(Base::Type::badType(), "App::Extension",
Extension::create);
}
using namespace App;
Extension::Extension()
{
}
Extension::~Extension()
{
if (!ExtensionPythonObject.is(Py::_None())){
// Remark: The API of Py::Object has been changed to set whether the wrapper owns the passed
// Python object or not. In the constructor we forced the wrapper to own the object so we need
// not to dec'ref the Python object any more.
// But we must still invalidate the Python object because it need not to be
// destructed right now because the interpreter can own several references to it.
Base::PyObjectBase* obj = static_cast<Base::PyObjectBase*>(ExtensionPythonObject.ptr());
// Call before decrementing the reference counter, otherwise a heap error can occur
obj->setInvalid();
}
}
void Extension::initExtensionType(Base::Type type) {
m_extensionType = type;
if (m_extensionType.isBad())
throw Base::RuntimeError("Extension: Extension type not set");
}
void Extension::initExtension(ExtensionContainer* obj) {
if (m_extensionType.isBad())
throw Base::RuntimeError("Extension: Extension type not set");
//all properties are initialised without PropertyContainer father. Now that we know it we can
//finally finish the property initialisation
std::vector<Property*> list;
extensionGetPropertyData().getPropertyList(this, list);
for(Property* prop : list)
prop->setContainer(obj);
m_base = obj;
m_base->registerExtension( m_extensionType, this );
}
PyObject* Extension::getExtensionPyObject() {
if (ExtensionPythonObject.is(Py::_None())){
// ref counter is set to 1
auto grp = new ExtensionPy(this);
ExtensionPythonObject = Py::Object(grp,true);
}
return Py::new_reference_to(ExtensionPythonObject);
}
std::string Extension::name() const {
if (m_extensionType.isBad())
throw Base::RuntimeError("Extension::name: Extension type not set");
std::string temp(m_extensionType.getName());
std::string::size_type pos = temp.find_last_of(':');
if (pos != std::string::npos)
return temp.substr(pos+1);
else
return std::string();
}
Property* Extension::extensionGetPropertyByName(const char* name) const {
return extensionGetPropertyData().getPropertyByName(this, name);
}
short int Extension::extensionGetPropertyType(const Property* prop) const {
return extensionGetPropertyData().getType(this, prop);
}
short int Extension::extensionGetPropertyType(const char* name) const {
return extensionGetPropertyData().getType(this, name);
}
const char* Extension::extensionGetPropertyName(const Property* prop) const {
return extensionGetPropertyData().getName(this,prop);
}
const char* Extension::extensionGetPropertyGroup(const Property* prop) const {
return extensionGetPropertyData().getGroup(this,prop);
}
const char* Extension::extensionGetPropertyGroup(const char* name) const {
return extensionGetPropertyData().getGroup(this,name);
}
const char* Extension::extensionGetPropertyDocumentation(const Property* prop) const {
return extensionGetPropertyData().getDocumentation(this, prop);
}
const char* Extension::extensionGetPropertyDocumentation(const char* name) const {
return extensionGetPropertyData().getDocumentation(this, name);
}
void Extension::extensionGetPropertyList(std::vector< Property* >& List) const {
extensionGetPropertyData().getPropertyList(this, List);
}
void Extension::extensionGetPropertyMap(std::map< std::string, Property* >& Map) const {
extensionGetPropertyData().getPropertyMap(this, Map);
}
void Extension::initExtensionSubclass(Base::Type& toInit, const char* ClassName, const char* ParentName,
Base::Type::instantiationMethod method) {
// don't init twice!
assert(toInit == Base::Type::badType());
// get the parent class
Base::Type parentType(Base::Type::fromName(ParentName));
// forgot init parent!
assert(parentType != Base::Type::badType() );
// create the new type
toInit = Base::Type::createType(parentType, ClassName, method);
}
namespace App {
EXTENSION_PROPERTY_SOURCE_TEMPLATE(App::ExtensionPython, App::ExtensionPython::Inherited)
// explicit template instantiation
template class AppExport ExtensionPythonT<Extension>;
}
/***************************************************************************
* Copyright (c) 2016 Stefan Tröger <[email protected]> *
* *
* 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 <cassert>
#endif
#include <Base/PyObjectBase.h>
#include "Extension.h"
#include "ExtensionContainer.h"
#include "ExtensionPython.h"
#include <ExtensionPy.h>
/* We do not use a standard property macro for type initiation. The reason is that we have the first
* PropertyData in the extension chain, there is no parent property data.
*/
EXTENSION_TYPESYSTEM_SOURCE_P(App::Extension)
const App::PropertyData * App::Extension::extensionGetPropertyDataPtr(){return &propertyData;}
const App::PropertyData & App::Extension::extensionGetPropertyData() const{return propertyData;}
App::PropertyData App::Extension::propertyData;
void App::Extension::init(){
assert(Extension::classTypeId == Base::Type::badType() && "don't init() twice!");
/* Set up entry in the type system. */
Extension::classTypeId = Base::Type::createType(Base::Type::badType(), "App::Extension",
Extension::create);
}
using namespace App;
Extension::Extension()
{
}
Extension::~Extension()
{
if (!ExtensionPythonObject.is(Py::_None())){
// Remark: The API of Py::Object has been changed to set whether the wrapper owns the passed
// Python object or not. In the constructor we forced the wrapper to own the object so we need
// not to dec'ref the Python object any more.
// But we must still invalidate the Python object because it need not to be
// destructed right now because the interpreter can own several references to it.
Base::PyObjectBase* obj = static_cast<Base::PyObjectBase*>(ExtensionPythonObject.ptr());
// Call before decrementing the reference counter, otherwise a heap error can occur
obj->setInvalid();
}
}
void Extension::initExtensionType(Base::Type type) {
m_extensionType = type;
if (m_extensionType.isBad())
throw Base::RuntimeError("Extension: Extension type not set");
}
void Extension::initExtension(ExtensionContainer* obj) {
if (m_extensionType.isBad())
throw Base::RuntimeError("Extension: Extension type not set");
//all properties are initialised without PropertyContainer father. Now that we know it we can
//finally finish the property initialisation
std::vector<Property*> list;
extensionGetPropertyData().getPropertyList(this, list);
for(Property* prop : list)
prop->setContainer(obj);
m_base = obj;
m_base->registerExtension( m_extensionType, this );
}
PyObject* Extension::getExtensionPyObject() {
if (ExtensionPythonObject.is(Py::_None())){
// ref counter is set to 1
auto grp = new ExtensionPy(this);
ExtensionPythonObject = Py::Object(grp,true);
}
return Py::new_reference_to(ExtensionPythonObject);
}
std::string Extension::name() const {
if (m_extensionType.isBad())
throw Base::RuntimeError("Extension::name: Extension type not set");
std::string temp(m_extensionType.getName());
std::string::size_type pos = temp.find_last_of(':');
if (pos != std::string::npos)
return temp.substr(pos+1);
else
return std::string();
}
Property* Extension::extensionGetPropertyByName(const char* name) const {
return extensionGetPropertyData().getPropertyByName(this, name);
}
short int Extension::extensionGetPropertyType(const Property* prop) const {
return extensionGetPropertyData().getType(this, prop);
}
short int Extension::extensionGetPropertyType(const char* name) const {
return extensionGetPropertyData().getType(this, name);
}
const char* Extension::extensionGetPropertyName(const Property* prop) const {
return extensionGetPropertyData().getName(this,prop);
}
const char* Extension::extensionGetPropertyGroup(const Property* prop) const {
return extensionGetPropertyData().getGroup(this,prop);
}
const char* Extension::extensionGetPropertyGroup(const char* name) const {
return extensionGetPropertyData().getGroup(this,name);
}
const char* Extension::extensionGetPropertyDocumentation(const Property* prop) const {
return extensionGetPropertyData().getDocumentation(this, prop);
}
const char* Extension::extensionGetPropertyDocumentation(const char* name) const {
return extensionGetPropertyData().getDocumentation(this, name);
}
void Extension::extensionGetPropertyList(std::vector< Property* >& List) const {
extensionGetPropertyData().getPropertyList(this, List);
}
void Extension::extensionGetPropertyMap(std::map< std::string, Property* >& Map) const {
extensionGetPropertyData().getPropertyMap(this, Map);
}
void Extension::initExtensionSubclass(Base::Type& toInit, const char* ClassName, const char* ParentName,
Base::Type::instantiationMethod method) {
// don't init twice!
assert(toInit == Base::Type::badType());
// get the parent class
Base::Type parentType(Base::Type::fromName(ParentName));
// forgot init parent!
assert(parentType != Base::Type::badType() );
// create the new type
toInit = Base::Type::createType(parentType, ClassName, method);
}
bool Extension::extensionHandleChangedPropertyName(Base::XMLReader &reader, const char * TypeName, const char *PropName)
{
(void) reader;
(void) TypeName;
(void) PropName;
return false;
};
bool Extension::extensionHandleChangedPropertyType(Base::XMLReader &reader, const char * TypeName, Property * prop)
{
(void) reader;
(void) TypeName;
(void) prop;
return false;
};
namespace App {
EXTENSION_PROPERTY_SOURCE_TEMPLATE(App::ExtensionPython, App::ExtensionPython::Inherited)
// explicit template instantiation
template class AppExport ExtensionPythonT<Extension>;
}
+328 -323
View File
@@ -1,323 +1,328 @@
/***************************************************************************
* Copyright (c) 2016 Stefan Tröger <stefantroeger@gmx.net> *
* *
* 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 APP_EXTENSION_H
#define APP_EXTENSION_H
#include "PropertyContainer.h"
#include <Base/SmartPtrPy.h>
namespace App {
class ExtensionContainer;
/// define Extension types
#define EXTENSION_TYPESYSTEM_HEADER() \
public: \
static Base::Type getExtensionClassTypeId(void); \
virtual Base::Type getExtensionTypeId(void) const; \
static void init(void);\
static void *create(void);\
private: \
static Base::Type classTypeId
/// Like EXTENSION_TYPESYSTEM_HEADER, with getExtensionTypeId declared override
#define EXTENSION_TYPESYSTEM_HEADER_WITH_OVERRIDE() \
public: \
static Base::Type getExtensionClassTypeId(void); \
virtual Base::Type getExtensionTypeId(void) const override; \
static void init(void);\
static void *create(void);\
private: \
static Base::Type classTypeId
/// define to implement a subclass of Base::BaseClass
#define EXTENSION_TYPESYSTEM_SOURCE_P(_class_) \
Base::Type _class_::getExtensionClassTypeId(void) { return _class_::classTypeId; } \
Base::Type _class_::getExtensionTypeId(void) const { return _class_::classTypeId; } \
Base::Type _class_::classTypeId = Base::Type::badType(); \
void * _class_::create(void){\
return new _class_ ();\
}
/// define to implement a subclass of Base::BaseClass
#define EXTENSION_TYPESYSTEM_SOURCE_ABSTRACT_P(_class_) \
Base::Type _class_::getExtensionClassTypeId(void) { return _class_::classTypeId; } \
Base::Type _class_::getExtensionTypeId(void) const { return _class_::classTypeId; } \
Base::Type _class_::classTypeId = Base::Type::badType(); \
void * _class_::create(void){return 0;}
/// define to implement a subclass of Base::BaseClass
#define EXTENSION_TYPESYSTEM_SOURCE(_class_, _parentclass_) \
EXTENSION_TYPESYSTEM_SOURCE_P(_class_)\
void _class_::init(void){\
initExtensionSubclass(_class_::classTypeId, #_class_ , #_parentclass_, &(_class_::create) ); \
}
#define EXTENSION_TYPESYSTEM_SOURCE_TEMPLATE(_class_) \
template<> Base::Type _class_::classTypeId = Base::Type::badType(); \
template<> Base::Type _class_::getExtensionClassTypeId(void) { return _class_::classTypeId; } \
template<> Base::Type _class_::getExtensionTypeId(void) const { return _class_::classTypeId; } \
template<> void * _class_::create(void){\
return new _class_ ();\
}
// init property stuff
#define EXTENSION_PROPERTY_HEADER(_class_) \
EXTENSION_TYPESYSTEM_HEADER(); \
protected: \
static const App::PropertyData * extensionGetPropertyDataPtr(void); \
virtual const App::PropertyData &extensionGetPropertyData(void) const; \
private: \
static App::PropertyData propertyData
/// Like EXTENSION_PROPERTY_HEADER, but with override declarations.
#define EXTENSION_PROPERTY_HEADER_WITH_OVERRIDE(_class_) \
EXTENSION_TYPESYSTEM_HEADER_WITH_OVERRIDE(); \
protected: \
static const App::PropertyData * extensionGetPropertyDataPtr(void); \
virtual const App::PropertyData &extensionGetPropertyData(void) const override; \
private: \
static App::PropertyData propertyData
#define EXTENSION_PROPERTY_SOURCE(_class_, _parentclass_) \
EXTENSION_TYPESYSTEM_SOURCE_P(_class_)\
const App::PropertyData * _class_::extensionGetPropertyDataPtr(void){return &propertyData;} \
const App::PropertyData & _class_::extensionGetPropertyData(void) const{return propertyData;} \
App::PropertyData _class_::propertyData; \
void _class_::init(void){\
initExtensionSubclass(_class_::classTypeId, #_class_ , #_parentclass_, &(_class_::create) ); \
_class_::propertyData.parentPropertyData = _parentclass_::extensionGetPropertyDataPtr();\
}
#define EXTENSION_PROPERTY_SOURCE_TEMPLATE(_class_, _parentclass_) \
EXTENSION_TYPESYSTEM_SOURCE_TEMPLATE(_class_)\
template<> App::PropertyData _class_::propertyData = App::PropertyData(); \
template<> const App::PropertyData * _class_::extensionGetPropertyDataPtr(void){return &propertyData;} \
template<> const App::PropertyData & _class_::extensionGetPropertyData(void) const{return propertyData;} \
template<> void _class_::init(void){\
initExtensionSubclass(_class_::classTypeId, #_class_ , #_parentclass_, &(_class_::create) ); \
_class_::propertyData.parentPropertyData = _parentclass_::extensionGetPropertyDataPtr();\
}
/**
* @brief Base class for all extension that can be added to a DocumentObject
*
* For general documentation on why extension system exists and how to use it see the ExtensionContainer
* documentation. Following is a description howto create custom extensions.
*
* Extensions are like every other FreeCAD object and based on properties. All information storage
* and persistence should be achieved by use of those. Additional any number of methods can be
* added to provide functionality around the properties. There are 3 small difference to normal objects:
* 1. They must be derived from Extension class
* 2. Properties must be handled with special extension macros
* 3. Extensions must be initialised
* This works as simple as
* @code
* class MyExtension : public Extension {
* EXTENSION_PROPERTY_HEADER(MyExtension);
* PropertyInt MyProp;
* virtual bool overridableMethod(DocumentObject* obj) {};
* };
*
* EXTENSION_PROPERTY_SOURCE(App::MyExtension, App::Extension)
* MyExtension::MyExtension() {
*
* EXTENSION_ADD_PROPERTY(MyProp, (0)) *
* initExtension(MyExtension::getExtensionClassTypeId());
* }
* using MyExtensionPython = ExtensionPythonT<MyExtension>;
* @endcode
*
* The special python extension type created above is important, as only those python extensions
* can be added to an object from python. It does not work to add the c++ version directly there.
*
* Note that every method of the extension becomes part of the extended object when added from c++.
* This means one should carefully design the API and make only necessary methods public or protected.
* Every internal method should be private.
*
* The automatic availability of methods in the class does not hold for the python interface, only
* for c++ classes. This is like every where else in FreeCAD, there is no automatic creation of python
* API from c++ classes. Hence the extension creator must also create a custom python object of its
* extension, which works exactly like the normal FreeCAD python object workflow. There is nothing
* special at all for extension python objects, the normal xml + imp.cpp approach is used. It must
* only be taken care that the objects father is the correct extension base class. Of course also
* make sure your extension returns the correct python object in its "getPyObject" call.
* Every method you create in the extensions python will be later added to an extended object. This
* happens automatically for both, c++ and python extension, if "getPyObject" returns the correct
* python object. No extra work needs to be done.
*
* A special case that needs to be handled for extensions is the possibility of overridden methods.
* Often it is desired to customise extension behaviour by allowing the user to override methods
* provided by the extension. On c++ side this is trivial, such methods are simply marked as "virtual"
* and can than be overridden in any derived class. This is more involved for the python interface and
* here special care needs to be taken.
*
* As already seen above one needs to create a special ExtensionPythonT<> object for extension from
* python. This is done exactly for the purpose of allowing to have overridable methods. The
* ExtensionPythonT wrapper adds a proxy property which holds a PyObject which itself will contain
* the implementations for the overridden methods. This design is equal to the ObjectPythonT<> design
* of normal document objects.
* As this wrapper inherits the c++ extension class it can also override the virtual functions the
* user designed to be overridden. What it should do at a call of the virtual method is to check if
* this method is implemented in the proxy object and if so call it, and if not call the normal
* c++ version. It is the extensions creators responsibility to implement this check and call behaviour
* for every overridable method.
* This is done by creating a custom wrapper just like ExtensionPythonT<> and overriding all virtual
* methods.
* @code
* template<typename ExtensionT> class MyExtensionPythonT : public ExtensionT {
* public:
*
* MyExtensionPythonT() {}
* virtual ~MyExtensionPythonT() {}
*
* virtual bool overridableMethod(DocumentObject* obj) override {
* Py::Object pyobj = Py::asObject(obj->getPyObject());
* EXTENSION_PROXY_ONEARG(allowObject, pyobj);
*
* if(result.isNone())
* ExtensionT::allowObject(obj);
*
* if(result.isBoolean())
* return result.isTrue();
*
* return false;
* };
* };
* @endcode
* @Note As seen in the code there are multiple helper macros to ease the repetitive work of querying
* and calling methods of the proxy object. See the macro documentation for how to use them.
*
* To ensure that your wrapper is used when a extension is created from python the extension type must
* be exposed as follows:
* @code
* using MyExtensionPython = ExtensionPythonT<MyExtensionPythonT<MyExtension>>;
* @endcode
*
* This boilerplate is absolutely necessary to allow overridable methods in python and it is the
* extension creator's responsibility to ensure full implementation.
*
*/
class AppExport Extension
{
//The cass does not have properties itself, but it is important to provide the property access
//functions. see cpp file for details
EXTENSION_PROPERTY_HEADER(App::Extension);
public:
Extension();
virtual ~Extension();
virtual void initExtension(App::ExtensionContainer* obj);
App::ExtensionContainer* getExtendedContainer() {return m_base;}
const App::ExtensionContainer* getExtendedContainer() const {return m_base;}
//get extension name without namespace
std::string name() const;
bool isPythonExtension() {return m_isPythonExtension;}
virtual PyObject* getExtensionPyObject();
/** @name Access properties */
//@{
/// find a property by its name
virtual Property *extensionGetPropertyByName(const char* name) const;
/// get the name of a property
virtual const char* extensionGetPropertyName(const Property* prop) const;
/// get all properties of the class (including properties of the parent)
virtual void extensionGetPropertyMap(std::map<std::string,Property*> &Map) const;
/// get all properties of the class (including properties of the parent)
virtual void extensionGetPropertyList(std::vector<Property*> &List) const;
/// get the Type of a Property
virtual short extensionGetPropertyType(const Property* prop) const;
/// get the Type of a named Property
virtual short extensionGetPropertyType(const char *name) const;
/// get the Group of a Property
virtual const char* extensionGetPropertyGroup(const Property* prop) const;
/// get the Group of a named Property
virtual const char* extensionGetPropertyGroup(const char *name) const;
/// get the Group of a Property
virtual const char* extensionGetPropertyDocumentation(const Property* prop) const;
/// get the Group of a named Property
virtual const char* extensionGetPropertyDocumentation(const char *name) const;
//@}
/** @name Persistence */
//@{
virtual void extensionSave(Base::Writer&) const {}
virtual void extensionRestore(Base::XMLReader&) {}
//@}
/** @name TypeHandling */
//@{
bool extensionIsDerivedFrom(const Base::Type type) const {return getExtensionTypeId().isDerivedFrom(type);}
protected:
static void initExtensionSubclass(Base::Type &toInit,const char* ClassName, const char *ParentName,
Base::Type::instantiationMethod method=nullptr);
//@}
virtual void extensionOnChanged(const Property* p) {(void)(p);}
friend class App::ExtensionContainer;
protected:
void initExtensionType(Base::Type type);
bool m_isPythonExtension = false;
Py::SmartPtr ExtensionPythonObject;
private:
Base::Type m_extensionType;
App::ExtensionContainer* m_base = nullptr;
};
// Property define
#define _EXTENSION_ADD_PROPERTY(_name, _prop_, _defaultval_) \
do { \
this->_prop_.setValue _defaultval_;\
propertyData.addProperty(static_cast<App::Extension*>(this), _name, &this->_prop_); \
} while (0)
#define EXTENSION_ADD_PROPERTY(_prop_, _defaultval_) \
_EXTENSION_ADD_PROPERTY(#_prop_, _prop_, _defaultval_)
#define _EXTENSION_ADD_PROPERTY_TYPE(_name, _prop_, _defaultval_, _group_,_type_,_Docu_) \
do { \
this->_prop_.setValue _defaultval_;\
propertyData.addProperty(static_cast<App::Extension*>(this), _name, &this->_prop_, (_group_),(_type_),(_Docu_)); \
} while (0)
#define EXTENSION_ADD_PROPERTY_TYPE(_prop_, _defaultval_, _group_,_type_,_Docu_) \
_EXTENSION_ADD_PROPERTY_TYPE(#_prop_, _prop_, _defaultval_, _group_,_type_,_Docu_)
} //App
#endif // APP_EXTENSION_H
/***************************************************************************
* Copyright (c) 2016 Stefan Tröger <stefantroeger@gmx.net> *
* *
* 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 APP_EXTENSION_H
#define APP_EXTENSION_H
#include "PropertyContainer.h"
#include <Base/SmartPtrPy.h>
namespace App {
class ExtensionContainer;
/// define Extension types
#define EXTENSION_TYPESYSTEM_HEADER() \
public: \
static Base::Type getExtensionClassTypeId(void); \
virtual Base::Type getExtensionTypeId(void) const; \
static void init(void);\
static void *create(void);\
private: \
static Base::Type classTypeId
/// Like EXTENSION_TYPESYSTEM_HEADER, with getExtensionTypeId declared override
#define EXTENSION_TYPESYSTEM_HEADER_WITH_OVERRIDE() \
public: \
static Base::Type getExtensionClassTypeId(void); \
virtual Base::Type getExtensionTypeId(void) const override; \
static void init(void);\
static void *create(void);\
private: \
static Base::Type classTypeId
/// define to implement a subclass of Base::BaseClass
#define EXTENSION_TYPESYSTEM_SOURCE_P(_class_) \
Base::Type _class_::getExtensionClassTypeId(void) { return _class_::classTypeId; } \
Base::Type _class_::getExtensionTypeId(void) const { return _class_::classTypeId; } \
Base::Type _class_::classTypeId = Base::Type::badType(); \
void * _class_::create(void){\
return new _class_ ();\
}
/// define to implement a subclass of Base::BaseClass
#define EXTENSION_TYPESYSTEM_SOURCE_ABSTRACT_P(_class_) \
Base::Type _class_::getExtensionClassTypeId(void) { return _class_::classTypeId; } \
Base::Type _class_::getExtensionTypeId(void) const { return _class_::classTypeId; } \
Base::Type _class_::classTypeId = Base::Type::badType(); \
void * _class_::create(void){return 0;}
/// define to implement a subclass of Base::BaseClass
#define EXTENSION_TYPESYSTEM_SOURCE(_class_, _parentclass_) \
EXTENSION_TYPESYSTEM_SOURCE_P(_class_)\
void _class_::init(void){\
initExtensionSubclass(_class_::classTypeId, #_class_ , #_parentclass_, &(_class_::create) ); \
}
#define EXTENSION_TYPESYSTEM_SOURCE_TEMPLATE(_class_) \
template<> Base::Type _class_::classTypeId = Base::Type::badType(); \
template<> Base::Type _class_::getExtensionClassTypeId(void) { return _class_::classTypeId; } \
template<> Base::Type _class_::getExtensionTypeId(void) const { return _class_::classTypeId; } \
template<> void * _class_::create(void){\
return new _class_ ();\
}
// init property stuff
#define EXTENSION_PROPERTY_HEADER(_class_) \
EXTENSION_TYPESYSTEM_HEADER(); \
protected: \
static const App::PropertyData * extensionGetPropertyDataPtr(void); \
virtual const App::PropertyData &extensionGetPropertyData(void) const; \
private: \
static App::PropertyData propertyData
/// Like EXTENSION_PROPERTY_HEADER, but with override declarations.
#define EXTENSION_PROPERTY_HEADER_WITH_OVERRIDE(_class_) \
EXTENSION_TYPESYSTEM_HEADER_WITH_OVERRIDE(); \
protected: \
static const App::PropertyData * extensionGetPropertyDataPtr(void); \
virtual const App::PropertyData &extensionGetPropertyData(void) const override; \
private: \
static App::PropertyData propertyData
#define EXTENSION_PROPERTY_SOURCE(_class_, _parentclass_) \
EXTENSION_TYPESYSTEM_SOURCE_P(_class_)\
const App::PropertyData * _class_::extensionGetPropertyDataPtr(void){return &propertyData;} \
const App::PropertyData & _class_::extensionGetPropertyData(void) const{return propertyData;} \
App::PropertyData _class_::propertyData; \
void _class_::init(void){\
initExtensionSubclass(_class_::classTypeId, #_class_ , #_parentclass_, &(_class_::create) ); \
_class_::propertyData.parentPropertyData = _parentclass_::extensionGetPropertyDataPtr();\
}
#define EXTENSION_PROPERTY_SOURCE_TEMPLATE(_class_, _parentclass_) \
EXTENSION_TYPESYSTEM_SOURCE_TEMPLATE(_class_)\
template<> App::PropertyData _class_::propertyData = App::PropertyData(); \
template<> const App::PropertyData * _class_::extensionGetPropertyDataPtr(void){return &propertyData;} \
template<> const App::PropertyData & _class_::extensionGetPropertyData(void) const{return propertyData;} \
template<> void _class_::init(void){\
initExtensionSubclass(_class_::classTypeId, #_class_ , #_parentclass_, &(_class_::create) ); \
_class_::propertyData.parentPropertyData = _parentclass_::extensionGetPropertyDataPtr();\
}
/**
* @brief Base class for all extension that can be added to a DocumentObject
*
* For general documentation on why extension system exists and how to use it see the ExtensionContainer
* documentation. Following is a description howto create custom extensions.
*
* Extensions are like every other FreeCAD object and based on properties. All information storage
* and persistence should be achieved by use of those. Additional any number of methods can be
* added to provide functionality around the properties. There are 3 small difference to normal objects:
* 1. They must be derived from Extension class
* 2. Properties must be handled with special extension macros
* 3. Extensions must be initialised
* This works as simple as
* @code
* class MyExtension : public Extension {
* EXTENSION_PROPERTY_HEADER(MyExtension);
* PropertyInt MyProp;
* virtual bool overridableMethod(DocumentObject* obj) {};
* };
*
* EXTENSION_PROPERTY_SOURCE(App::MyExtension, App::Extension)
* MyExtension::MyExtension() {
*
* EXTENSION_ADD_PROPERTY(MyProp, (0)) *
* initExtension(MyExtension::getExtensionClassTypeId());
* }
* using MyExtensionPython = ExtensionPythonT<MyExtension>;
* @endcode
*
* The special python extension type created above is important, as only those python extensions
* can be added to an object from python. It does not work to add the c++ version directly there.
*
* Note that every method of the extension becomes part of the extended object when added from c++.
* This means one should carefully design the API and make only necessary methods public or protected.
* Every internal method should be private.
*
* The automatic availability of methods in the class does not hold for the python interface, only
* for c++ classes. This is like every where else in FreeCAD, there is no automatic creation of python
* API from c++ classes. Hence the extension creator must also create a custom python object of its
* extension, which works exactly like the normal FreeCAD python object workflow. There is nothing
* special at all for extension python objects, the normal xml + imp.cpp approach is used. It must
* only be taken care that the objects father is the correct extension base class. Of course also
* make sure your extension returns the correct python object in its "getPyObject" call.
* Every method you create in the extensions python will be later added to an extended object. This
* happens automatically for both, c++ and python extension, if "getPyObject" returns the correct
* python object. No extra work needs to be done.
*
* A special case that needs to be handled for extensions is the possibility of overridden methods.
* Often it is desired to customise extension behaviour by allowing the user to override methods
* provided by the extension. On c++ side this is trivial, such methods are simply marked as "virtual"
* and can than be overridden in any derived class. This is more involved for the python interface and
* here special care needs to be taken.
*
* As already seen above one needs to create a special ExtensionPythonT<> object for extension from
* python. This is done exactly for the purpose of allowing to have overridable methods. The
* ExtensionPythonT wrapper adds a proxy property which holds a PyObject which itself will contain
* the implementations for the overridden methods. This design is equal to the ObjectPythonT<> design
* of normal document objects.
* As this wrapper inherits the c++ extension class it can also override the virtual functions the
* user designed to be overridden. What it should do at a call of the virtual method is to check if
* this method is implemented in the proxy object and if so call it, and if not call the normal
* c++ version. It is the extensions creators responsibility to implement this check and call behaviour
* for every overridable method.
* This is done by creating a custom wrapper just like ExtensionPythonT<> and overriding all virtual
* methods.
* @code
* template<typename ExtensionT> class MyExtensionPythonT : public ExtensionT {
* public:
*
* MyExtensionPythonT() {}
* virtual ~MyExtensionPythonT() {}
*
* virtual bool overridableMethod(DocumentObject* obj) override {
* Py::Object pyobj = Py::asObject(obj->getPyObject());
* EXTENSION_PROXY_ONEARG(allowObject, pyobj);
*
* if(result.isNone())
* ExtensionT::allowObject(obj);
*
* if(result.isBoolean())
* return result.isTrue();
*
* return false;
* };
* };
* @endcode
* @Note As seen in the code there are multiple helper macros to ease the repetitive work of querying
* and calling methods of the proxy object. See the macro documentation for how to use them.
*
* To ensure that your wrapper is used when a extension is created from python the extension type must
* be exposed as follows:
* @code
* using MyExtensionPython = ExtensionPythonT<MyExtensionPythonT<MyExtension>>;
* @endcode
*
* This boilerplate is absolutely necessary to allow overridable methods in python and it is the
* extension creator's responsibility to ensure full implementation.
*
*/
class AppExport Extension
{
//The cass does not have properties itself, but it is important to provide the property access
//functions. see cpp file for details
EXTENSION_PROPERTY_HEADER(App::Extension);
public:
Extension();
virtual ~Extension();
virtual void initExtension(App::ExtensionContainer* obj);
App::ExtensionContainer* getExtendedContainer() {return m_base;}
const App::ExtensionContainer* getExtendedContainer() const {return m_base;}
//get extension name without namespace
std::string name() const;
bool isPythonExtension() {return m_isPythonExtension;}
virtual PyObject* getExtensionPyObject();
/** @name Access properties */
//@{
/// find a property by its name
virtual Property *extensionGetPropertyByName(const char* name) const;
/// get the name of a property
virtual const char* extensionGetPropertyName(const Property* prop) const;
/// get all properties of the class (including properties of the parent)
virtual void extensionGetPropertyMap(std::map<std::string,Property*> &Map) const;
/// get all properties of the class (including properties of the parent)
virtual void extensionGetPropertyList(std::vector<Property*> &List) const;
/// get the Type of a Property
virtual short extensionGetPropertyType(const Property* prop) const;
/// get the Type of a named Property
virtual short extensionGetPropertyType(const char *name) const;
/// get the Group of a Property
virtual const char* extensionGetPropertyGroup(const Property* prop) const;
/// get the Group of a named Property
virtual const char* extensionGetPropertyGroup(const char *name) const;
/// get the Group of a Property
virtual const char* extensionGetPropertyDocumentation(const Property* prop) const;
/// get the Group of a named Property
virtual const char* extensionGetPropertyDocumentation(const char *name) const;
//@}
/** @name Persistence */
//@{
virtual void extensionSave(Base::Writer&) const {}
virtual void extensionRestore(Base::XMLReader&) {}
//@}
/** @name TypeHandling */
//@{
bool extensionIsDerivedFrom(const Base::Type type) const {return getExtensionTypeId().isDerivedFrom(type);}
protected:
static void initExtensionSubclass(Base::Type &toInit,const char* ClassName, const char *ParentName,
Base::Type::instantiationMethod method=nullptr);
//@}
virtual void extensionOnChanged(const Property* p) {(void)(p);}
/// returns true if the property name change was handled by the extension.
virtual bool extensionHandleChangedPropertyName(Base::XMLReader &reader, const char * TypeName, const char *PropName);
/// returns true if the property type change was handled by the extension.
virtual bool extensionHandleChangedPropertyType(Base::XMLReader &reader, const char * TypeName, Property * prop);
friend class App::ExtensionContainer;
protected:
void initExtensionType(Base::Type type);
bool m_isPythonExtension = false;
Py::SmartPtr ExtensionPythonObject;
private:
Base::Type m_extensionType;
App::ExtensionContainer* m_base = nullptr;
};
// Property define
#define _EXTENSION_ADD_PROPERTY(_name, _prop_, _defaultval_) \
do { \
this->_prop_.setValue _defaultval_;\
propertyData.addProperty(static_cast<App::Extension*>(this), _name, &this->_prop_); \
} while (0)
#define EXTENSION_ADD_PROPERTY(_prop_, _defaultval_) \
_EXTENSION_ADD_PROPERTY(#_prop_, _prop_, _defaultval_)
#define _EXTENSION_ADD_PROPERTY_TYPE(_name, _prop_, _defaultval_, _group_,_type_,_Docu_) \
do { \
this->_prop_.setValue _defaultval_;\
propertyData.addProperty(static_cast<App::Extension*>(this), _name, &this->_prop_, (_group_),(_type_),(_Docu_)); \
} while (0)
#define EXTENSION_ADD_PROPERTY_TYPE(_prop_, _defaultval_, _group_,_type_,_Docu_) \
_EXTENSION_ADD_PROPERTY_TYPE(#_prop_, _prop_, _defaultval_, _group_,_type_,_Docu_)
} //App
#endif // APP_EXTENSION_H
+446 -418
View File
@@ -1,418 +1,446 @@
/***************************************************************************
* Copyright (c) 2016 Stefan Tröger <stefantroeger@gmx.net> *
* *
* 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 <Base/Console.h>
#include <Base/Exception.h>
#include <Base/Reader.h>
#include <Base/Writer.h>
#include "Extension.h"
#include "ExtensionContainer.h"
using namespace App;
TYPESYSTEM_SOURCE(App::ExtensionContainer, App::PropertyContainer)
ExtensionContainer::ExtensionContainer() = default;
ExtensionContainer::~ExtensionContainer() {
//we need to delete all dynamically added extensions
for(const auto& entry : _extensions) {
if(entry.second->isPythonExtension())
delete entry.second;
}
}
void ExtensionContainer::registerExtension(Base::Type extension, Extension* ext) {
if(ext->getExtendedContainer() != this)
throw Base::ValueError("ExtensionContainer::registerExtension: Extension has not this as base object");
//no duplicate extensions (including base classes)
if(hasExtension(extension)) {
for(const auto& entry : _extensions) {
if(entry.first == extension || entry.first.isDerivedFrom(extension)) {
_extensions.erase(entry.first);
break;
}
}
}
_extensions[extension] = ext;
}
bool ExtensionContainer::hasExtension(Base::Type t, bool derived) const {
//check for the exact type
bool found = _extensions.find(t) != _extensions.end();
if(!found && derived) {
//and for types derived from it, as they can be cast to the extension
for(const auto& entry : _extensions) {
if(entry.first.isDerivedFrom(t))
return true;
}
return false;
}
return found;
}
bool ExtensionContainer::hasExtension(const std::string& name) const {
//and for types derived from it, as they can be cast to the extension
for(const auto& entry : _extensions) {
if(entry.second->name() == name)
return true;
}
return false;
}
Extension* ExtensionContainer::getExtension(Base::Type t, bool derived, bool no_except) const {
auto result = _extensions.find(t);
if((result == _extensions.end()) && derived) {
//we need to check for derived types
for(const auto& entry : _extensions) {
if(entry.first.isDerivedFrom(t))
return entry.second;
}
if(no_except)
return nullptr;
//if we arrive here we don't have anything matching
throw Base::TypeError("ExtensionContainer::getExtension: No extension of given type available");
}
else if (result != _extensions.end()) {
return result->second;
}
else {
if(no_except)
return nullptr;
//if we arrive here we don't have anything matching
throw Base::TypeError("ExtensionContainer::getExtension: No extension of given type available");
}
}
bool ExtensionContainer::hasExtensions() const {
return !_extensions.empty();
}
Extension* ExtensionContainer::getExtension(const std::string& name) const {
//and for types derived from it, as they can be cast to the extension
for(const auto& entry : _extensions) {
if(entry.second->name() == name)
return entry.second;
}
return nullptr;
}
std::vector< Extension* > ExtensionContainer::getExtensionsDerivedFrom(Base::Type type) const {
std::vector<Extension*> vec;
//and for types derived from it, as they can be cast to the extension
for(const auto& entry : _extensions) {
if(entry.first.isDerivedFrom(type))
vec.push_back(entry.second);
}
return vec;
}
void ExtensionContainer::getPropertyList(std::vector< Property* >& List) const {
App::PropertyContainer::getPropertyList(List);
for(const auto& entry : _extensions)
entry.second->extensionGetPropertyList(List);
}
void ExtensionContainer::getPropertyMap(std::map< std::string, Property* >& Map) const {
App::PropertyContainer::getPropertyMap(Map);
for(const auto& entry : _extensions)
entry.second->extensionGetPropertyMap(Map);
}
Property* ExtensionContainer::getPropertyByName(const char* name) const {
auto prop = App::PropertyContainer::getPropertyByName(name);
if(prop)
return prop;
for(const auto& entry : _extensions) {
auto prop = entry.second->extensionGetPropertyByName(name);
if(prop)
return prop;
}
return nullptr;
}
short int ExtensionContainer::getPropertyType(const Property* prop) const {
short int res = App::PropertyContainer::getPropertyType(prop);
if(res != 0)
return res;
for(const auto& entry : _extensions) {
res = entry.second->extensionGetPropertyType(prop);
if(res != 0)
return res;
}
return 0;
}
short int ExtensionContainer::getPropertyType(const char* name) const {
short int res = App::PropertyContainer::getPropertyType(name);
if(res != 0)
return res;
for(const auto& entry : _extensions) {
res = entry.second->extensionGetPropertyType(name);
if(res != 0)
return res;
}
return 0;
}
const char* ExtensionContainer::getPropertyName(const Property* prop) const {
const char* res = App::PropertyContainer::getPropertyName(prop);
if (res)
return res;
for (const auto& entry : _extensions) {
res = entry.second->extensionGetPropertyName(prop);
if (res)
return res;
}
return nullptr;
}
const char* ExtensionContainer::getPropertyGroup(const Property* prop) const {
const char* res = App::PropertyContainer::getPropertyGroup(prop);
if (res)
return res;
for (const auto& entry : _extensions) {
res = entry.second->extensionGetPropertyGroup(prop);
if (res)
return res;
}
return nullptr;
}
const char* ExtensionContainer::getPropertyGroup(const char* name) const {
const char* res = App::PropertyContainer::getPropertyGroup(name);
if (res)
return res;
for (const auto& entry : _extensions) {
res = entry.second->extensionGetPropertyGroup(name);
if (res)
return res;
}
return nullptr;
}
const char* ExtensionContainer::getPropertyDocumentation(const Property* prop) const {
const char* res = App::PropertyContainer::getPropertyDocumentation(prop);
if (res)
return res;
for (const auto& entry : _extensions) {
res = entry.second->extensionGetPropertyDocumentation(prop);
if (res)
return res;
}
return nullptr;
}
const char* ExtensionContainer::getPropertyDocumentation(const char* name) const {
const char* res = App::PropertyContainer::getPropertyDocumentation(name);
if (res)
return res;
for(const auto& entry : _extensions) {
res = entry.second->extensionGetPropertyDocumentation(name);
if (res)
return res;
}
return nullptr;
}
void ExtensionContainer::onChanged(const Property* prop) {
//inform all extensions about changed property. This includes all properties from the
//extended object (this) as well as all extension properties
for(const auto& entry : _extensions)
entry.second->extensionOnChanged(prop);
App::PropertyContainer::onChanged(prop);
}
void ExtensionContainer::Save(Base::Writer& writer) const {
//Note: save extensions must be called first to ensure that the extension element is always the
// very first inside the object element. This is needed since extension element works together with
// an object attribute, and if another element would be read first the object attributes would be
// cleared.
saveExtensions(writer);
App::PropertyContainer::Save(writer);
}
void ExtensionContainer::Restore(Base::XMLReader& reader) {
//restore dynamic extensions.
//Note 1: The extension element must be read first, before all other object elements. That is
// needed as the element works together with an object element attribute, which would be
// cleared if another attribute is read first
//Note 2: This must happen before the py object of this container is used, as only in the
// pyobject constructor the extension methods are added to the container.
restoreExtensions(reader);
App::PropertyContainer::Restore(reader);
}
void ExtensionContainer::saveExtensions(Base::Writer& writer) const {
//we don't save anything if there are no dynamic extensions
if(!hasExtensions())
return;
//save dynamic extensions
writer.incInd(); // indentation for 'Extensions'
writer.Stream() << writer.ind() << "<Extensions Count=\"" << _extensions.size() << "\">" << std::endl;
for(const auto& entry : _extensions) {
auto ext = entry.second;
writer.incInd(); // indentation for 'Extension name'
writer.Stream() << writer.ind() << "<Extension"
<< " type=\"" << ext->getExtensionTypeId().getName() <<"\""
<< " name=\"" << ext->name() << "\">" << std::endl;
writer.incInd(); // indentation for the actual Extension
try {
// We must make sure to handle all exceptions accordingly so that
// the project file doesn't get invalidated. In the error case this
// means to proceed instead of aborting the write operation.
ext->extensionSave(writer);
}
catch (const Base::Exception &e) {
Base::Console().Error("%s\n", e.what());
}
catch (const std::exception &e) {
Base::Console().Error("%s\n", e.what());
}
catch (const char* e) {
Base::Console().Error("%s\n", e);
}
#ifndef FC_DEBUG
catch (...) {
Base::Console().Error("ExtensionContainer::Save: Unknown C++ exception thrown. Try to continue...\n");
}
#endif
writer.decInd(); // indentation for the actual extension
writer.Stream() << writer.ind() << "</Extension>" << std::endl;
writer.decInd(); // indentation for 'Extension name'
}
writer.Stream() << writer.ind() << "</Extensions>" << std::endl;
writer.decInd();
}
void ExtensionContainer::restoreExtensions(Base::XMLReader& reader) {
//Dynamic extensions are optional (also because they are introduced late into the document format)
//and hence it is possible that the element does not exist. As we cannot check for the existence of
//an element a object attribute is set if extensions are available. Here we check that
//attribute, and only if it exists the extensions element will be available.
if(!reader.hasAttribute("Extensions"))
return;
reader.readElement("Extensions");
int Cnt = reader.getAttributeAsInteger("Count");
for (int i=0 ;i<Cnt ;i++) {
reader.readElement("Extension");
const char* Type = reader.getAttribute("type");
const char* Name = reader.getAttribute("name");
try {
App::Extension* ext = getExtension(Name);
if(!ext) {
//get the extension type asked for
Base::Type extension = Base::Type::fromName(Type);
if (extension.isBad() || !extension.isDerivedFrom(App::Extension::getExtensionClassTypeId())) {
std::stringstream str;
str << "No extension found of type '" << Type << "'" << std::ends;
throw Base::TypeError(str.str());
}
//register the extension
ext = static_cast<App::Extension*>(extension.createInstance());
//check if this really is a python extension!
if (!ext->isPythonExtension()) {
delete ext;
std::stringstream str;
str << "Extension is not a python addable version: '" << Type << "'" << std::ends;
throw Base::TypeError(str.str());
}
ext->initExtension(this);
}
if (ext && strcmp(ext->getExtensionTypeId().getName(), Type) == 0)
ext->extensionRestore(reader);
}
catch (const Base::XMLParseException&) {
throw; // re-throw
}
catch (const Base::Exception &e) {
Base::Console().Error("%s\n", e.what());
}
catch (const std::exception &e) {
Base::Console().Error("%s\n", e.what());
}
catch (const char* e) {
Base::Console().Error("%s\n", e);
}
#ifndef FC_DEBUG
catch (...) {
Base::Console().Error("ExtensionContainer::Restore: Unknown C++ exception thrown\n");
}
#endif
reader.readEndElement("Extension");
}
reader.readEndElement("Extensions");
}
/***************************************************************************
* Copyright (c) 2016 Stefan Tröger <stefantroeger@gmx.net> *
* *
* 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 <Base/Console.h>
#include <Base/Exception.h>
#include <Base/Reader.h>
#include <Base/Writer.h>
#include "Extension.h"
#include "ExtensionContainer.h"
using namespace App;
TYPESYSTEM_SOURCE(App::ExtensionContainer, App::PropertyContainer)
ExtensionContainer::ExtensionContainer() = default;
ExtensionContainer::~ExtensionContainer() {
//we need to delete all dynamically added extensions
for(const auto& entry : _extensions) {
if(entry.second->isPythonExtension())
delete entry.second;
}
}
void ExtensionContainer::registerExtension(Base::Type extension, Extension* ext) {
if(ext->getExtendedContainer() != this)
throw Base::ValueError("ExtensionContainer::registerExtension: Extension has not this as base object");
//no duplicate extensions (including base classes)
if(hasExtension(extension)) {
for(const auto& entry : _extensions) {
if(entry.first == extension || entry.first.isDerivedFrom(extension)) {
_extensions.erase(entry.first);
break;
}
}
}
_extensions[extension] = ext;
}
bool ExtensionContainer::hasExtension(Base::Type t, bool derived) const {
//check for the exact type
bool found = _extensions.find(t) != _extensions.end();
if(!found && derived) {
//and for types derived from it, as they can be cast to the extension
for(const auto& entry : _extensions) {
if(entry.first.isDerivedFrom(t))
return true;
}
return false;
}
return found;
}
bool ExtensionContainer::hasExtension(const std::string& name) const {
//and for types derived from it, as they can be cast to the extension
for(const auto& entry : _extensions) {
if(entry.second->name() == name)
return true;
}
return false;
}
Extension* ExtensionContainer::getExtension(Base::Type t, bool derived, bool no_except) const {
auto result = _extensions.find(t);
if((result == _extensions.end()) && derived) {
//we need to check for derived types
for(const auto& entry : _extensions) {
if(entry.first.isDerivedFrom(t))
return entry.second;
}
if(no_except)
return nullptr;
//if we arrive here we don't have anything matching
throw Base::TypeError("ExtensionContainer::getExtension: No extension of given type available");
}
else if (result != _extensions.end()) {
return result->second;
}
else {
if(no_except)
return nullptr;
//if we arrive here we don't have anything matching
throw Base::TypeError("ExtensionContainer::getExtension: No extension of given type available");
}
}
bool ExtensionContainer::hasExtensions() const {
return !_extensions.empty();
}
Extension* ExtensionContainer::getExtension(const std::string& name) const {
//and for types derived from it, as they can be cast to the extension
for(const auto& entry : _extensions) {
if(entry.second->name() == name)
return entry.second;
}
return nullptr;
}
std::vector< Extension* > ExtensionContainer::getExtensionsDerivedFrom(Base::Type type) const {
std::vector<Extension*> vec;
//and for types derived from it, as they can be cast to the extension
for(const auto& entry : _extensions) {
if(entry.first.isDerivedFrom(type))
vec.push_back(entry.second);
}
return vec;
}
void ExtensionContainer::getPropertyList(std::vector< Property* >& List) const {
App::PropertyContainer::getPropertyList(List);
for(const auto& entry : _extensions)
entry.second->extensionGetPropertyList(List);
}
void ExtensionContainer::getPropertyMap(std::map< std::string, Property* >& Map) const {
App::PropertyContainer::getPropertyMap(Map);
for(const auto& entry : _extensions)
entry.second->extensionGetPropertyMap(Map);
}
Property* ExtensionContainer::getPropertyByName(const char* name) const {
auto prop = App::PropertyContainer::getPropertyByName(name);
if(prop)
return prop;
for(const auto& entry : _extensions) {
auto prop = entry.second->extensionGetPropertyByName(name);
if(prop)
return prop;
}
return nullptr;
}
short int ExtensionContainer::getPropertyType(const Property* prop) const {
short int res = App::PropertyContainer::getPropertyType(prop);
if(res != 0)
return res;
for(const auto& entry : _extensions) {
res = entry.second->extensionGetPropertyType(prop);
if(res != 0)
return res;
}
return 0;
}
short int ExtensionContainer::getPropertyType(const char* name) const {
short int res = App::PropertyContainer::getPropertyType(name);
if(res != 0)
return res;
for(const auto& entry : _extensions) {
res = entry.second->extensionGetPropertyType(name);
if(res != 0)
return res;
}
return 0;
}
const char* ExtensionContainer::getPropertyName(const Property* prop) const {
const char* res = App::PropertyContainer::getPropertyName(prop);
if (res)
return res;
for (const auto& entry : _extensions) {
res = entry.second->extensionGetPropertyName(prop);
if (res)
return res;
}
return nullptr;
}
const char* ExtensionContainer::getPropertyGroup(const Property* prop) const {
const char* res = App::PropertyContainer::getPropertyGroup(prop);
if (res)
return res;
for (const auto& entry : _extensions) {
res = entry.second->extensionGetPropertyGroup(prop);
if (res)
return res;
}
return nullptr;
}
const char* ExtensionContainer::getPropertyGroup(const char* name) const {
const char* res = App::PropertyContainer::getPropertyGroup(name);
if (res)
return res;
for (const auto& entry : _extensions) {
res = entry.second->extensionGetPropertyGroup(name);
if (res)
return res;
}
return nullptr;
}
const char* ExtensionContainer::getPropertyDocumentation(const Property* prop) const {
const char* res = App::PropertyContainer::getPropertyDocumentation(prop);
if (res)
return res;
for (const auto& entry : _extensions) {
res = entry.second->extensionGetPropertyDocumentation(prop);
if (res)
return res;
}
return nullptr;
}
const char* ExtensionContainer::getPropertyDocumentation(const char* name) const {
const char* res = App::PropertyContainer::getPropertyDocumentation(name);
if (res)
return res;
for(const auto& entry : _extensions) {
res = entry.second->extensionGetPropertyDocumentation(name);
if (res)
return res;
}
return nullptr;
}
void ExtensionContainer::onChanged(const Property* prop) {
//inform all extensions about changed property. This includes all properties from the
//extended object (this) as well as all extension properties
for(const auto& entry : _extensions)
entry.second->extensionOnChanged(prop);
App::PropertyContainer::onChanged(prop);
}
void ExtensionContainer::Save(Base::Writer& writer) const {
//Note: save extensions must be called first to ensure that the extension element is always the
// very first inside the object element. This is needed since extension element works together with
// an object attribute, and if another element would be read first the object attributes would be
// cleared.
saveExtensions(writer);
App::PropertyContainer::Save(writer);
}
void ExtensionContainer::Restore(Base::XMLReader& reader) {
//restore dynamic extensions.
//Note 1: The extension element must be read first, before all other object elements. That is
// needed as the element works together with an object element attribute, which would be
// cleared if another attribute is read first
//Note 2: This must happen before the py object of this container is used, as only in the
// pyobject constructor the extension methods are added to the container.
restoreExtensions(reader);
App::PropertyContainer::Restore(reader);
}
void ExtensionContainer::saveExtensions(Base::Writer& writer) const {
//we don't save anything if there are no dynamic extensions
if(!hasExtensions())
return;
//save dynamic extensions
writer.incInd(); // indentation for 'Extensions'
writer.Stream() << writer.ind() << "<Extensions Count=\"" << _extensions.size() << "\">" << std::endl;
for(const auto& entry : _extensions) {
auto ext = entry.second;
writer.incInd(); // indentation for 'Extension name'
writer.Stream() << writer.ind() << "<Extension"
<< " type=\"" << ext->getExtensionTypeId().getName() <<"\""
<< " name=\"" << ext->name() << "\">" << std::endl;
writer.incInd(); // indentation for the actual Extension
try {
// We must make sure to handle all exceptions accordingly so that
// the project file doesn't get invalidated. In the error case this
// means to proceed instead of aborting the write operation.
ext->extensionSave(writer);
}
catch (const Base::Exception &e) {
Base::Console().Error("%s\n", e.what());
}
catch (const std::exception &e) {
Base::Console().Error("%s\n", e.what());
}
catch (const char* e) {
Base::Console().Error("%s\n", e);
}
#ifndef FC_DEBUG
catch (...) {
Base::Console().Error("ExtensionContainer::Save: Unknown C++ exception thrown. Try to continue...\n");
}
#endif
writer.decInd(); // indentation for the actual extension
writer.Stream() << writer.ind() << "</Extension>" << std::endl;
writer.decInd(); // indentation for 'Extension name'
}
writer.Stream() << writer.ind() << "</Extensions>" << std::endl;
writer.decInd();
}
void ExtensionContainer::restoreExtensions(Base::XMLReader& reader) {
//Dynamic extensions are optional (also because they are introduced late into the document format)
//and hence it is possible that the element does not exist. As we cannot check for the existence of
//an element a object attribute is set if extensions are available. Here we check that
//attribute, and only if it exists the extensions element will be available.
if(!reader.hasAttribute("Extensions"))
return;
reader.readElement("Extensions");
int Cnt = reader.getAttributeAsInteger("Count");
for (int i=0 ;i<Cnt ;i++) {
reader.readElement("Extension");
const char* Type = reader.getAttribute("type");
const char* Name = reader.getAttribute("name");
try {
App::Extension* ext = getExtension(Name);
if(!ext) {
//get the extension type asked for
Base::Type extension = Base::Type::fromName(Type);
if (extension.isBad() || !extension.isDerivedFrom(App::Extension::getExtensionClassTypeId())) {
std::stringstream str;
str << "No extension found of type '" << Type << "'" << std::ends;
throw Base::TypeError(str.str());
}
//register the extension
ext = static_cast<App::Extension*>(extension.createInstance());
//check if this really is a python extension!
if (!ext->isPythonExtension()) {
delete ext;
std::stringstream str;
str << "Extension is not a python addable version: '" << Type << "'" << std::ends;
throw Base::TypeError(str.str());
}
ext->initExtension(this);
}
if (ext && strcmp(ext->getExtensionTypeId().getName(), Type) == 0)
ext->extensionRestore(reader);
}
catch (const Base::XMLParseException&) {
throw; // re-throw
}
catch (const Base::Exception &e) {
Base::Console().Error("%s\n", e.what());
}
catch (const std::exception &e) {
Base::Console().Error("%s\n", e.what());
}
catch (const char* e) {
Base::Console().Error("%s\n", e);
}
#ifndef FC_DEBUG
catch (...) {
Base::Console().Error("ExtensionContainer::Restore: Unknown C++ exception thrown\n");
}
#endif
reader.readEndElement("Extension");
}
reader.readEndElement("Extensions");
}
void ExtensionContainer::handleChangedPropertyName(Base::XMLReader &reader, const char * TypeName, const char *PropName)
{
//inform all extensions about changed property name. This includes all properties from the
//extended object (this) as well as all extension properties
for(const auto& entry : _extensions) {
bool handled = entry.second->extensionHandleChangedPropertyName(reader, TypeName, PropName);
if(handled)
return; // one property change needs only be handled once
}
PropertyContainer::handleChangedPropertyName(reader, TypeName, PropName);
}
void ExtensionContainer::handleChangedPropertyType(Base::XMLReader &reader, const char * TypeName, Property * prop)
{
//inform all extensions about changed property type. This includes all properties from the
//extended object (this) as well as all extension properties
for(const auto& entry : _extensions) {
bool handled = entry.second->extensionHandleChangedPropertyType(reader, TypeName, prop);
if(handled)
return; // one property change needs only be handled once
}
PropertyContainer::handleChangedPropertyType(reader, TypeName, prop);
}
+220 -203
View File
@@ -1,203 +1,220 @@
/***************************************************************************
* Copyright (c) 2016 Stefan Tröger <stefantroeger@gmx.net> *
* *
* 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 APP_EXTENSIONCONTAINER_H
#define APP_EXTENSIONCONTAINER_H
#include "PropertyContainer.h"
namespace App {
class Extension;
/**
* @brief Container which can hold extensions
*
* In FreeCAD normally inheritance is a chain, it is not possible to use multiple inheritance.
* The reason for this is that all objects need to be exposed to python, and it is basically
* impossible to handle multiple inheritance in the C-API for python extensions. Also using multiple
* parent classes in python is currently not possible with the default object approach.
*
* The concept of extensions allow to circumvent those problems. Extensions are FreeCAD objects
* which work like normal objects in the sense that they use properties and class methods to define
* their functionality. However, they are not exposed as individual usable entities but are used to
* extend other objects. A extended object gets all the properties and methods of the extension.
* Therefore it is like c++ multiple inheritance, which is indeed used to achieve this on c++ side,
* but provides a few important additional functionalities:
* - Property persistence is handled, save and restore work out of the box
* - The objects python API gets extended too with the extension python API
* - Extensions can be added from c++ and python, even from both together
*
* The interoperability with python is highly important, as in FreeCAD all functionality should be
* as easily accessible from python as from c++. To ensure this, and as already noted, extensions can
* be added to a object from python. However, this means that it is not clear from the c++ object type
* if an extension was added or not. If added from c++ it becomes clear in the type due to the use of
* multiple inheritance. If added from python it is a runtime extension and not visible from type.
* Hence querying existing extensions of an object and accessing its methods works not by type
* casting but by the interface provided in ExtensionContainer. The default workflow is to query if
* an extension exists and then get the extension object. No matter if added from python or c++ this
* interface works always the same.
* @code
* if (object->hasExtension(GroupExtension::getClassTypeId())) {
* App::GroupExtension* group = object->getExtensionByType<GroupExtension>();
* group->hasObject(...);
* }
* @endcode
*
* To add a extension to an object, it must comply to a single restriction: it must be derived
* from ExtensionContainer. This is important to allow adding extensions from python and also to
* access the universal extension API. As DocumentObject itself derives from ExtensionContainer this
* should be the case automatically in most circumstances.
*
* Note that two small boilerplate changes are needed next to the multiple inheritance when adding
* extensions from c++.
* 1. It must be ensured that the property and type registration is aware of the extensions by using
* special macros.
* 2. The extensions need to be initialised in the constructor
*
* Here is a working example:
* @code
* class AppExport Part : public App::DocumentObject, public App::FirstExtension, public App::SecondExtension {
* PROPERTY_HEADER_WITH_EXTENSIONS(App::Part);
* };
* PROPERTY_SOURCE_WITH_EXTENSIONS(App::Part, App::DocumentObject)
* Part::Part(void) {
* FirstExtension::initExtension(this);
* SecondExtension::initExtension(this);
* }
* @endcode
*
* From python adding an extension is easier, it must be simply registered to a document object
* at object initialisation like done with properties. Note that the special python extension objects
* need to be added, not the c++ objects. Normally the only difference in name is the additional
* "Python" at the end of the extension name.
* @code{.py}
* class Test():
* __init(self)__:
* registerExtension("App::FirstExtensionPython", self)
* registerExtension("App::SecondExtensionPython", self)
* @endcode
*
* Extensions can provide methods that should be overridden by the extended object for customisation
* of the extension behaviour. In c++ this is as simple as overriding the provided virtual functions.
* In python a class method must be provided which has the same name as the method to override. This
* method must not necessarily be in the object that is extended, it must be in the object which is
* provided to the "registerExtension" call as second argument. This second argument is used as a
* proxy and enqueired if the method to override exists in this proxy before calling it.
*
* For information on howto create extension see the documentation of Extension
*/
class AppExport ExtensionContainer : public App::PropertyContainer
{
TYPESYSTEM_HEADER_WITH_OVERRIDE();
public:
using ExtensionIterator = std::map<Base::Type, App::Extension*>::iterator;
ExtensionContainer();
~ExtensionContainer() override;
void registerExtension(Base::Type extension, App::Extension* ext);
bool hasExtension(Base::Type, bool derived=true) const; //returns first of type (or derived from if set to true) and throws otherwise
bool hasExtension(const std::string& name) const; //this version does not check derived classes
bool hasExtensions() const;
App::Extension* getExtension(Base::Type, bool derived = true, bool no_except=false) const;
App::Extension* getExtension(const std::string& name) const; //this version does not check derived classes
//returns first of type (or derived from) and throws otherwise
template<typename ExtensionT>
ExtensionT* getExtensionByType(bool no_except=false, bool derived=true) const {
return static_cast<ExtensionT*>(getExtension(ExtensionT::getExtensionClassTypeId(),derived,no_except));
}
//get all extensions which have the given base class
std::vector<Extension*> getExtensionsDerivedFrom(Base::Type type) const;
template<typename ExtensionT>
std::vector<ExtensionT*> getExtensionsDerivedFromType() const {
std::vector<ExtensionT*> typevec;
for(const auto& entry : _extensions) {
if(entry.first.isDerivedFrom(ExtensionT::getExtensionClassTypeId()))
typevec.push_back(static_cast<ExtensionT*>(entry.second));
}
return typevec;
}
ExtensionIterator extensionBegin() {return _extensions.begin();}
ExtensionIterator extensionEnd() {return _extensions.end();}
/** @name Access properties */
//@{
/// find a property by its name
Property *getPropertyByName(const char* name) const override;
/// get the name of a property
const char* getPropertyName(const Property* prop) const override;
/// get all properties of the class (including properties of the parent)
void getPropertyMap(std::map<std::string,Property*> &Map) const override;
/// get all properties of the class (including properties of the parent)
void getPropertyList(std::vector<Property*> &List) const override;
/// get the Type of a Property
short getPropertyType(const Property* prop) const override;
/// get the Type of a named Property
short getPropertyType(const char *name) const override;
/// get the Group of a Property
const char* getPropertyGroup(const Property* prop) const override;
/// get the Group of a named Property
const char* getPropertyGroup(const char *name) const override;
/// get the Group of a Property
const char* getPropertyDocumentation(const Property* prop) const override;
/// get the Group of a named Property
const char* getPropertyDocumentation(const char *name) const override;
//@}
void onChanged(const Property*) override;
void Save(Base::Writer& writer) const override;
void Restore(Base::XMLReader& reader) override;
//those methods save/restore the dynamic extensions without handling properties, which is something
//done by the default Save/Restore methods.
void saveExtensions(Base::Writer& writer) const;
void restoreExtensions(Base::XMLReader& reader);
private:
//stored extensions
std::map<Base::Type, App::Extension*> _extensions;
};
#define PROPERTY_HEADER_WITH_EXTENSIONS(_class_) \
PROPERTY_HEADER_WITH_OVERRIDE(_class)
/// We make sure that the PropertyData of the container is not connected to the one of the extension
#define PROPERTY_SOURCE_WITH_EXTENSIONS(_class_, _parentclass_) \
PROPERTY_SOURCE(_class_, _parentclass_)
#define PROPERTY_SOURCE_ABSTRACT_WITH_EXTENSIONS(_class_, _parentclass_) \
PROPERTY_SOURCE_ABSTRACT(_class_, _parentclass_)
} //App
#endif // APP_EXTENSIONCONTAINER_H
/***************************************************************************
* Copyright (c) 2016 Stefan Tröger <stefantroeger@gmx.net> *
* *
* 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 APP_EXTENSIONCONTAINER_H
#define APP_EXTENSIONCONTAINER_H
#include "PropertyContainer.h"
namespace App {
class Extension;
/**
* @brief Container which can hold extensions
*
* In FreeCAD normally inheritance is a chain, it is not possible to use multiple inheritance.
* The reason for this is that all objects need to be exposed to python, and it is basically
* impossible to handle multiple inheritance in the C-API for python extensions. Also using multiple
* parent classes in python is currently not possible with the default object approach.
*
* The concept of extensions allow to circumvent those problems. Extensions are FreeCAD objects
* which work like normal objects in the sense that they use properties and class methods to define
* their functionality. However, they are not exposed as individual usable entities but are used to
* extend other objects. A extended object gets all the properties and methods of the extension.
* Therefore it is like c++ multiple inheritance, which is indeed used to achieve this on c++ side,
* but provides a few important additional functionalities:
* - Property persistence is handled, save and restore work out of the box
* - The objects python API gets extended too with the extension python API
* - Extensions can be added from c++ and python, even from both together
*
* The interoperability with python is highly important, as in FreeCAD all functionality should be
* as easily accessible from python as from c++. To ensure this, and as already noted, extensions can
* be added to a object from python. However, this means that it is not clear from the c++ object type
* if an extension was added or not. If added from c++ it becomes clear in the type due to the use of
* multiple inheritance. If added from python it is a runtime extension and not visible from type.
* Hence querying existing extensions of an object and accessing its methods works not by type
* casting but by the interface provided in ExtensionContainer. The default workflow is to query if
* an extension exists and then get the extension object. No matter if added from python or c++ this
* interface works always the same.
* @code
* if (object->hasExtension(GroupExtension::getClassTypeId())) {
* App::GroupExtension* group = object->getExtensionByType<GroupExtension>();
* group->hasObject(...);
* }
* @endcode
*
* To add a extension to an object, it must comply to a single restriction: it must be derived
* from ExtensionContainer. This is important to allow adding extensions from python and also to
* access the universal extension API. As DocumentObject itself derives from ExtensionContainer this
* should be the case automatically in most circumstances.
*
* Note that two small boilerplate changes are needed next to the multiple inheritance when adding
* extensions from c++.
* 1. It must be ensured that the property and type registration is aware of the extensions by using
* special macros.
* 2. The extensions need to be initialised in the constructor
*
* Here is a working example:
* @code
* class AppExport Part : public App::DocumentObject, public App::FirstExtension, public App::SecondExtension {
* PROPERTY_HEADER_WITH_EXTENSIONS(App::Part);
* };
* PROPERTY_SOURCE_WITH_EXTENSIONS(App::Part, App::DocumentObject)
* Part::Part(void) {
* FirstExtension::initExtension(this);
* SecondExtension::initExtension(this);
* }
* @endcode
*
* From python adding an extension is easier, it must be simply registered to a document object
* at object initialisation like done with properties. Note that the special python extension objects
* need to be added, not the c++ objects. Normally the only difference in name is the additional
* "Python" at the end of the extension name.
* @code{.py}
* class Test():
* __init(self)__:
* registerExtension("App::FirstExtensionPython", self)
* registerExtension("App::SecondExtensionPython", self)
* @endcode
*
* Extensions can provide methods that should be overridden by the extended object for customisation
* of the extension behaviour. In c++ this is as simple as overriding the provided virtual functions.
* In python a class method must be provided which has the same name as the method to override. This
* method must not necessarily be in the object that is extended, it must be in the object which is
* provided to the "registerExtension" call as second argument. This second argument is used as a
* proxy and enqueired if the method to override exists in this proxy before calling it.
*
* For information on howto create extension see the documentation of Extension
*/
class AppExport ExtensionContainer : public App::PropertyContainer
{
TYPESYSTEM_HEADER_WITH_OVERRIDE();
public:
using ExtensionIterator = std::map<Base::Type, App::Extension*>::iterator;
ExtensionContainer();
~ExtensionContainer() override;
void registerExtension(Base::Type extension, App::Extension* ext);
bool hasExtension(Base::Type, bool derived=true) const; //returns first of type (or derived from if set to true) and throws otherwise
bool hasExtension(const std::string& name) const; //this version does not check derived classes
bool hasExtensions() const;
App::Extension* getExtension(Base::Type, bool derived = true, bool no_except=false) const;
App::Extension* getExtension(const std::string& name) const; //this version does not check derived classes
//returns first of type (or derived from) and throws otherwise
template<typename ExtensionT>
ExtensionT* getExtensionByType(bool no_except=false, bool derived=true) const {
return static_cast<ExtensionT*>(getExtension(ExtensionT::getExtensionClassTypeId(),derived,no_except));
}
//get all extensions which have the given base class
std::vector<Extension*> getExtensionsDerivedFrom(Base::Type type) const;
template<typename ExtensionT>
std::vector<ExtensionT*> getExtensionsDerivedFromType() const {
std::vector<ExtensionT*> typevec;
for(const auto& entry : _extensions) {
if(entry.first.isDerivedFrom(ExtensionT::getExtensionClassTypeId()))
typevec.push_back(static_cast<ExtensionT*>(entry.second));
}
return typevec;
}
ExtensionIterator extensionBegin() {return _extensions.begin();}
ExtensionIterator extensionEnd() {return _extensions.end();}
/** @name Access properties */
//@{
/// find a property by its name
Property *getPropertyByName(const char* name) const override;
/// get the name of a property
const char* getPropertyName(const Property* prop) const override;
/// get all properties of the class (including properties of the parent)
void getPropertyMap(std::map<std::string,Property*> &Map) const override;
/// get all properties of the class (including properties of the parent)
void getPropertyList(std::vector<Property*> &List) const override;
/// get the Type of a Property
short getPropertyType(const Property* prop) const override;
/// get the Type of a named Property
short getPropertyType(const char *name) const override;
/// get the Group of a Property
const char* getPropertyGroup(const Property* prop) const override;
/// get the Group of a named Property
const char* getPropertyGroup(const char *name) const override;
/// get the Group of a Property
const char* getPropertyDocumentation(const Property* prop) const override;
/// get the Group of a named Property
const char* getPropertyDocumentation(const char *name) const override;
//@}
void onChanged(const Property*) override;
void Save(Base::Writer& writer) const override;
void Restore(Base::XMLReader& reader) override;
//those methods save/restore the dynamic extensions without handling properties, which is something
//done by the default Save/Restore methods.
void saveExtensions(Base::Writer& writer) const;
void restoreExtensions(Base::XMLReader& reader);
/** Extends the rules for handling property name changed, so that extensions are given an opportunity to handle it.
* If an extension handles a change, neither the rest of the extensions, nor the container itself get to handle it.
*
* Extensions get their extensionHandleChangedPropertyName() called.
*
* If no extension handles the request, then the containers handleChangedPropertyName() is called.
*/
virtual void handleChangedPropertyName(Base::XMLReader &reader, const char * TypeName, const char *PropName) override;
/** Extends the rules for handling property type changed, so that extensions are given an opportunity to handle it.
* If an extension handles a change, neither the rest of the extensions, nor the container itself get to handle it.
*
* Extensions get their extensionHandleChangedPropertyType() called.
*
* If no extension handles the request, then the containers handleChangedPropertyType() is called.
*/
virtual void handleChangedPropertyType(Base::XMLReader &reader, const char * TypeName, Property * prop) override;
private:
//stored extensions
std::map<Base::Type, App::Extension*> _extensions;
};
#define PROPERTY_HEADER_WITH_EXTENSIONS(_class_) \
PROPERTY_HEADER_WITH_OVERRIDE(_class)
/// We make sure that the PropertyData of the container is not connected to the one of the extension
#define PROPERTY_SOURCE_WITH_EXTENSIONS(_class_, _parentclass_) \
PROPERTY_SOURCE(_class_, _parentclass_)
#define PROPERTY_SOURCE_ABSTRACT_WITH_EXTENSIONS(_class_, _parentclass_) \
PROPERTY_SOURCE_ABSTRACT(_class_, _parentclass_)
} //App
#endif // APP_EXTENSIONCONTAINER_H
+54 -55
View File
@@ -843,64 +843,63 @@ App.Units.Gon = App.Units.Quantity('gon')
App.Units.AngularMinute = App.Units.Quantity().AngularMinute
App.Units.AngularSecond = App.Units.Quantity().AngularSecond
App.Units.Length = App.Units.Unit(1)
App.Units.Area = App.Units.Unit(2)
App.Units.Volume = App.Units.Unit(3)
App.Units.Mass = App.Units.Unit(0,1)
# SI base units
# (length, weight, time, current, temperature, amount of substance, luminous intensity, angle)
App.Units.AmountOfSubstance = App.Units.Unit(0,0,0,0,0,1)
App.Units.ElectricCurrent = App.Units.Unit(0,0,0,1)
App.Units.Length = App.Units.Unit(1)
App.Units.LuminousIntensity = App.Units.Unit(0,0,0,0,0,0,1)
App.Units.Mass = App.Units.Unit(0,1)
App.Units.Temperature = App.Units.Unit(0,0,0,0,1)
App.Units.TimeSpan = App.Units.Unit(0,0,1)
# Angle
App.Units.Angle = App.Units.Unit(0,0,0,0,0,0,0,1)
App.Units.AngleOfFriction = App.Units.Unit(0,0,0,0,0,0,0,1)
# all other combined units
App.Units.Acceleration = App.Units.Unit(1,0,-2)
App.Units.Angle = App.Units.Unit(0,0,0,0,0,0,0,1)
App.Units.AngleOfFriction = App.Units.Unit(0,0,0,0,0,0,0,1)
App.Units.Area = App.Units.Unit(2)
App.Units.CompressiveStrength = App.Units.Unit(-1,1,-2)
App.Units.CurrentDensity = App.Units.Unit(-2,0,0,1)
App.Units.Density = App.Units.Unit(-3,1)
App.Units.DissipationRate = App.Units.Unit(2,0,-3)
App.Units.DynamicViscosity = App.Units.Unit(-1,1,-1)
App.Units.Frequency = App.Units.Unit(0,0,-1)
App.Units.MagneticFluxDensity = App.Units.Unit(0,1,-2,-1)
App.Units.Magnetization = App.Units.Unit(-1,0,0,1)
App.Units.ElectricalCapacitance = App.Units.Unit(-2,-1,4,2)
App.Units.ElectricalConductance = App.Units.Unit(-2,-1,3,2)
App.Units.ElectricalConductivity = App.Units.Unit(-3,-1,3,2)
App.Units.ElectricalInductance = App.Units.Unit(2,1,-2,-2)
App.Units.ElectricalResistance = App.Units.Unit(2,1,-3,-2)
App.Units.ElectricCharge = App.Units.Unit(0,0,1,1)
App.Units.ElectricPotential = App.Units.Unit(2,1,-3,-1)
App.Units.Force = App.Units.Unit(1,1,-2)
App.Units.HeatFlux = App.Units.Unit(0,1,-3,0,0)
App.Units.InverseArea = App.Units.Unit(-2)
App.Units.InverseLength = App.Units.Unit(-1)
App.Units.InverseVolume = App.Units.Unit(-3)
App.Units.KinematicViscosity = App.Units.Unit(2,0,-1)
App.Units.Pressure = App.Units.Unit(-1,1,-2)
App.Units.Power = App.Units.Unit(2,1,-3)
App.Units.ShearModulus = App.Units.Unit(-1,1,-2)
App.Units.SpecificEnergy = App.Units.Unit(2,0,-2)
App.Units.SpecificHeat = App.Units.Unit(2,0,-2,0,-1)
App.Units.Stiffness = App.Units.Unit(0,1,-2)
App.Units.Stress = App.Units.Unit(-1,1,-2)
App.Units.ThermalConductivity = App.Units.Unit(1,1,-3,0,-1)
App.Units.ThermalExpansionCoefficient = App.Units.Unit(0,0,0,0,-1)
App.Units.ThermalTransferCoefficient = App.Units.Unit(0,1,-3,0,-1)
App.Units.UltimateTensileStrength = App.Units.Unit(-1,1,-2)
App.Units.Velocity = App.Units.Unit(1,0,-1)
App.Units.VacuumPermittivity = App.Units.Unit(-3,-1,4,2)
App.Units.Volume = App.Units.Unit(3)
App.Units.VolumeFlowRate = App.Units.Unit(3,0,-1)
App.Units.VolumetricThermalExpansionCoefficient = App.Units.Unit(0,0,0,0,-1)
App.Units.Work = App.Units.Unit(2,1,-2)
App.Units.YieldStrength = App.Units.Unit(-1,1,-2)
App.Units.YoungsModulus = App.Units.Unit(-1,1,-2)
App.Units.Density = App.Units.Unit(-3,1)
App.Units.TimeSpan = App.Units.Unit(0,0,1)
App.Units.Frequency = App.Units.Unit(0,0,-1)
App.Units.Velocity = App.Units.Unit(1,0,-1)
App.Units.Acceleration = App.Units.Unit(1,0,-2)
App.Units.Temperature = App.Units.Unit(0,0,0,0,1)
App.Units.CurrentDensity = App.Units.Unit(-2,0,0,1)
App.Units.ElectricCurrent = App.Units.Unit(0,0,0,1)
App.Units.ElectricPotential = App.Units.Unit(2,1,-3,-1)
App.Units.ElectricCharge = App.Units.Unit(0,0,1,1)
App.Units.MagneticFluxDensity = App.Units.Unit(0,1,-2,-1)
App.Units.Magnetization = App.Units.Unit(-1,0,0,1)
App.Units.ElectricalCapacitance = App.Units.Unit(-2,-1,4,2)
App.Units.ElectricalInductance = App.Units.Unit(2,1,-2,-2)
App.Units.ElectricalConductance = App.Units.Unit(-2,-1,3,2)
App.Units.ElectricalResistance = App.Units.Unit(2,1,-3,-2)
App.Units.ElectricalConductivity = App.Units.Unit(-3,-1,3,2)
App.Units.AmountOfSubstance = App.Units.Unit(0,0,0,0,0,1)
App.Units.LuminousIntensity = App.Units.Unit(0,0,0,0,0,0,1)
# Pressure
App.Units.CompressiveStrength = App.Units.Unit(-1,1,-2)
App.Units.Pressure = App.Units.Unit(-1,1,-2)
App.Units.ShearModulus = App.Units.Unit(-1,1,-2)
App.Units.Stress = App.Units.Unit(-1,1,-2)
App.Units.UltimateTensileStrength = App.Units.Unit(-1,1,-2)
App.Units.YieldStrength = App.Units.Unit(-1,1,-2)
App.Units.YoungsModulus = App.Units.Unit(-1,1,-2)
App.Units.Force = App.Units.Unit(1,1,-2)
App.Units.Work = App.Units.Unit(2,1,-2)
App.Units.Power = App.Units.Unit(2,1,-3)
App.Units.Stiffness = App.Units.Unit(0,1,-2)
App.Units.SpecificEnergy = App.Units.Unit(2,0,-2)
App.Units.ThermalConductivity = App.Units.Unit(1,1,-3,0,-1)
App.Units.ThermalExpansionCoefficient = App.Units.Unit(0,0,0,0,-1)
App.Units.VolumetricThermalExpansionCoefficient = App.Units.Unit(0,0,0,0,-1)
App.Units.SpecificHeat = App.Units.Unit(2,0,-2,0,-1)
App.Units.ThermalTransferCoefficient = App.Units.Unit(0,1,-3,0,-1)
App.Units.HeatFlux = App.Units.Unit(0,1,-3,0,0)
App.Units.DynamicViscosity = App.Units.Unit(-1,1,-1)
App.Units.KinematicViscosity = App.Units.Unit(2,0,-1)
App.Units.VacuumPermittivity = App.Units.Unit(-3,-1,4,2)
# Add an enum for the different unit schemes
from enum import IntEnum
+2
View File
@@ -332,6 +332,8 @@ public:
* Multiple options can be combined by bitwise or operator
*/
enum class OnChangeCopyOptions {
/// No options set
None = 0,
/// If set, then exclude the input from object list to copy on change, or else, include the input object.
Exclude = 1,
/// If set , then apply the setting to all links to the input object, or else, apply only to this link.
+1 -154
View File
@@ -24,164 +24,11 @@
#ifndef APP_MATERIAL_H
#define APP_MATERIAL_H
#ifdef __GNUC__
# include <cstdint>
#endif
#include <sstream>
#include <iomanip>
#include <FCGlobal.h>
#include <App/Color.h>
namespace App
{
/** Color class
*/
class AppExport Color
{
public:
/**
* Defines the color as (R,G,B,A) whereas all values are in the range [0,1].
* \a A defines the transparency.
*/
explicit Color(float R=0.0,float G=0.0, float B=0.0, float A=0.0)
:r(R),g(G),b(B),a(A){}
/**
* Does basically the same as the constructor above unless that (R,G,B,A) is
* encoded as an unsigned int.
*/
explicit Color(uint32_t rgba)
{ setPackedValue( rgba ); }
/** Copy constructor. */
Color(const Color& c)
:r(c.r),g(c.g),b(c.b),a(c.a){}
/** Returns true if both colors are equal. Therefore all components must be equal. */
bool operator==(const Color& c) const
{
return getPackedValue() == c.getPackedValue();
//return (c.r==r && c.g==g && c.b==b && c.a==a);
}
bool operator!=(const Color& c) const
{
return !operator==(c);
}
/**
* Defines the color as (R,G,B,A) whereas all values are in the range [0,1].
* \a A defines the transparency, 0 means complete opaque and 1 invisible.
*/
void set(float R,float G, float B, float A=0.0)
{
r=R;g=G;b=B;a=A;
}
Color& operator=(const Color& c)
{
r=c.r;g=c.g;b=c.b;a=c.a;
return *this;
}
/**
* Sets the color value as a 32 bit combined red/green/blue/alpha value.
* Each component is 8 bit wide (i.e. from 0x00 to 0xff), and the red
* value should be stored leftmost, like this: 0xRRGGBBAA.
*
* \sa getPackedValue().
*/
Color& setPackedValue(uint32_t rgba)
{
this->set((rgba >> 24)/255.0f,
((rgba >> 16)&0xff)/255.0f,
((rgba >> 8)&0xff)/255.0f,
(rgba&0xff)/255.0f);
return *this;
}
/**
* Returns color as a 32 bit packed unsigned int in the form 0xRRGGBBAA.
*
* \sa setPackedValue().
*/
uint32_t getPackedValue() const
{
return (static_cast<uint32_t>(r*255.0f + 0.5f) << 24 |
static_cast<uint32_t>(g*255.0f + 0.5f) << 16 |
static_cast<uint32_t>(b*255.0f + 0.5f) << 8 |
static_cast<uint32_t>(a*255.0f + 0.5f));
}
/**
* creates FC Color from template type, e.g. Qt QColor
*/
template <typename T>
void setValue(const T& q)
{ set(q.redF(),q.greenF(),q.blueF()); }
/**
* returns a template type e.g. Qt color equivalent to FC color
*
*/
template <typename T>
inline T asValue() const {
return(T(int(r*255.0f),int(g*255.0f),int(b*255.0f)));
}
/**
* returns color as hex color "#RRGGBB"
*
*/
std::string asHexString() const {
std::stringstream ss;
ss << "#" << std::hex << std::uppercase << std::setfill('0') << std::setw(2) << int(r*255.0f)
<< std::setw(2) << int(g*255.0f)
<< std::setw(2) << int(b*255.0f);
return ss.str();
}
/**
* gets color from hex color "#RRGGBB"
*
*/
bool fromHexString(const std::string& hex) {
if (hex.size() < 7 || hex[0] != '#')
return false;
// #RRGGBB
if (hex.size() == 7) {
std::stringstream ss(hex);
unsigned int rgb;
char c;
ss >> c >> std::hex >> rgb;
int rc = (rgb >> 16) & 0xff;
int gc = (rgb >> 8) & 0xff;
int bc = rgb & 0xff;
r = rc / 255.0f;
g = gc / 255.0f;
b = bc / 255.0f;
return true;
}
// #RRGGBBAA
if (hex.size() == 9) {
std::stringstream ss(hex);
unsigned int rgba;
char c;
ss >> c >> std::hex >> rgba;
int rc = (rgba >> 24) & 0xff;
int gc = (rgba >> 16) & 0xff;
int bc = (rgba >> 8) & 0xff;
int ac = rgba & 0xff;
r = rc / 255.0f;
g = gc / 255.0f;
b = bc / 255.0f;
a = ac / 255.0f;
return true;
}
return false;
}
/// color values, public accessible
float r,g,b,a;
};
/** Material class
*/
class AppExport Material
+13 -9
View File
@@ -550,24 +550,28 @@ public:
protected:
void setPyValues(const std::vector<PyObject*> &vals, const std::vector<int> &indices) override
void setPyValues(const std::vector<PyObject*>& vals, const std::vector<int>& indices) override
{
if (indices.empty()) {
ListT values;
values.resize(vals.size());
for (std::size_t i=0,count=vals.size();i<count;++i)
values[i] = getPyValue(vals[i]);
ListT values {};
values.reserve(vals.size());
for (auto *valsContent : vals) {
values.push_back(getPyValue(valsContent));
}
setValues(std::move(values));
return;
}
assert(vals.size()==indices.size());
assert(vals.size() == indices.size());
atomic_change guard(*this);
for (int i=0,count=indices.size();i<count;++i)
set1Value(indices[i],getPyValue(vals[i]));
int i {0};
for (auto index : indices) {
set1Value(index, getPyValue(vals[i]));
i++;
}
guard.tryInvoke();
}
virtual T getPyValue(PyObject *item) const = 0;
virtual T getPyValue(PyObject* item) const = 0;
protected:
ListT _lValueList;
File diff suppressed because it is too large Load Diff
+343 -343
View File
@@ -1,343 +1,343 @@
/***************************************************************************
* Copyright (c) 2005 Jürgen Riegel <juergen.riegel@web.de> *
* *
* 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 APP_PROPERTYCONTAINER_H
#define APP_PROPERTYCONTAINER_H
#include <map>
#include <cstring>
#include <Base/Persistence.h>
#include "DynamicProperty.h"
namespace Base {
class Writer;
}
namespace App
{
class Property;
class PropertyContainer;
class DocumentObject;
class Extension;
enum PropertyType
{
Prop_None = 0, /*!< No special property type */
Prop_ReadOnly = 1, /*!< Property is read-only in the editor */
Prop_Transient = 2, /*!< Property content won't be saved to file, but still saves name, type and status */
Prop_Hidden = 4, /*!< Property won't appear in the editor */
Prop_Output = 8, /*!< Modified property doesn't touch its parent container */
Prop_NoRecompute = 16,/*!< Modified property doesn't touch its container for recompute */
Prop_NoPersist = 32,/*!< Property won't be saved to file at all */
};
struct AppExport PropertyData
{
struct PropertySpec
{
const char * Name;
const char * Group;
const char * Docu;
short Offset, Type;
inline PropertySpec(const char *name, const char *group, const char *doc, short offset, short type)
:Name(name),Group(group),Docu(doc),Offset(offset),Type(type)
{}
};
//purpose of this struct is to be constructible from all acceptable container types and to
//be able to return the offset to a property from the accepted containers. This allows to use
//one function implementation for multiple container types without losing all type safety by
//accepting void*
struct OffsetBase
{
OffsetBase(const App::PropertyContainer* container) : m_container(container) {}//explicit bombs
OffsetBase(const App::Extension* container) : m_container(container) {}//explicit bombs
short int getOffsetTo(const App::Property* prop) const {
auto *pt = (const char*)prop;
auto *base = (const char *)m_container;
if(pt<base || pt>base+SHRT_MAX)
return -1;
return (short) (pt-base);
}
char* getOffset() const {return (char*) m_container;}
private:
const void* m_container;
};
// A multi index container for holding the property spec, with the following
// index,
// * a sequence, to preserve creation order
// * hash index on property name
// * hash index on property pointer offset
mutable bmi::multi_index_container<
PropertySpec,
bmi::indexed_by<
bmi::sequenced<>,
bmi::hashed_unique<
bmi::member<PropertySpec, const char*, &PropertySpec::Name>,
CStringHasher,
CStringHasher
>,
bmi::hashed_unique<
bmi::member<PropertySpec, short, &PropertySpec::Offset>
>
>
> propertyData;
mutable bool parentMerged = false;
const PropertyData* parentPropertyData;
void addProperty(OffsetBase offsetBase,const char* PropName, Property *Prop, const char* PropertyGroup= nullptr, PropertyType = Prop_None, const char* PropertyDocu= nullptr );
const PropertySpec *findProperty(OffsetBase offsetBase,const char* PropName) const;
const PropertySpec *findProperty(OffsetBase offsetBase,const Property* prop) const;
const char* getName (OffsetBase offsetBase,const Property* prop) const;
short getType (OffsetBase offsetBase,const Property* prop) const;
short getType (OffsetBase offsetBase,const char* name) const;
const char* getGroup (OffsetBase offsetBase,const char* name) const;
const char* getGroup (OffsetBase offsetBase,const Property* prop) const;
const char* getDocumentation(OffsetBase offsetBase,const char* name) const;
const char* getDocumentation(OffsetBase offsetBase,const Property* prop) const;
Property *getPropertyByName(OffsetBase offsetBase,const char* name) const;
void getPropertyMap(OffsetBase offsetBase,std::map<std::string,Property*> &Map) const;
void getPropertyList(OffsetBase offsetBase,std::vector<Property*> &List) const;
void getPropertyNamedList(OffsetBase offsetBase, std::vector<std::pair<const char*,Property*> > &List) const;
void merge(PropertyData *other=nullptr) const;
void split(PropertyData *other);
};
/** Base class of all classes with properties
*/
class AppExport PropertyContainer: public Base::Persistence
{
TYPESYSTEM_HEADER_WITH_OVERRIDE();
public:
/**
* A constructor.
* A more elaborate description of the constructor.
*/
PropertyContainer();
/**
* A destructor.
* A more elaborate description of the destructor.
*/
~PropertyContainer() override;
unsigned int getMemSize () const override;
virtual std::string getFullName() const {return std::string();}
/// find a property by its name
virtual Property *getPropertyByName(const char* name) const;
/// get the name of a property
virtual const char* getPropertyName(const Property* prop) const;
/// get all properties of the class (including properties of the parent)
virtual void getPropertyMap(std::map<std::string,Property*> &Map) const;
/// get all properties of the class (including properties of the parent)
virtual void getPropertyList(std::vector<Property*> &List) const;
/// get all properties with their names, may contain duplicates and aliases
virtual void getPropertyNamedList(std::vector<std::pair<const char*,Property*> > &List) const;
/// set the Status bit of all properties at once
void setPropertyStatus(unsigned char bit,bool value);
/// get the Type of a Property
virtual short getPropertyType(const Property* prop) const;
/// get the Type of a named Property
virtual short getPropertyType(const char *name) const;
/// get the Group of a Property
virtual const char* getPropertyGroup(const Property* prop) const;
/// get the Group of a named Property
virtual const char* getPropertyGroup(const char *name) const;
/// get the Group of a Property
virtual const char* getPropertyDocumentation(const Property* prop) const;
/// get the Group of a named Property
virtual const char* getPropertyDocumentation(const char *name) const;
/// check if the property is read-only
bool isReadOnly(const Property* prop) const;
/// check if the named property is read-only
bool isReadOnly(const char *name) const;
/// check if the property is hidden
bool isHidden(const Property* prop) const;
/// check if the named property is hidden
bool isHidden(const char *name) const;
virtual App::Property* addDynamicProperty(
const char* type, const char* name=nullptr,
const char* group=nullptr, const char* doc=nullptr,
short attr=0, bool ro=false, bool hidden=false);
DynamicProperty::PropData getDynamicPropertyData(const Property* prop) const {
return dynamicProps.getDynamicPropertyData(prop);
}
bool changeDynamicProperty(const Property *prop, const char *group, const char *doc) {
return dynamicProps.changeDynamicProperty(prop,group,doc);
}
virtual bool removeDynamicProperty(const char* name) {
return dynamicProps.removeDynamicProperty(name);
}
virtual std::vector<std::string> getDynamicPropertyNames() const {
return dynamicProps.getDynamicPropertyNames();
}
virtual App::Property *getDynamicPropertyByName(const char* name) const {
return dynamicProps.getDynamicPropertyByName(name);
}
virtual void onPropertyStatusChanged(const Property &prop, unsigned long oldStatus);
void Save (Base::Writer &writer) const override;
void Restore(Base::XMLReader &reader) override;
virtual void editProperty(const char * /*propName*/) {}
const char *getPropertyPrefix() const {
return _propertyPrefix.c_str();
}
void setPropertyPrefix(const char *prefix) {
_propertyPrefix = prefix;
}
friend class Property;
friend class DynamicProperty;
protected:
/// get called by the container when a property has changed
virtual void onChanged(const Property* /*prop*/){}
/// get called before the value is changed
virtual void onBeforeChange(const Property* /*prop*/){}
//void hasChanged(Property* prop);
static const PropertyData * getPropertyDataPtr();
virtual const PropertyData& getPropertyData() const;
virtual void handleChangedPropertyName(Base::XMLReader &reader, const char * TypeName, const char *PropName);
virtual void handleChangedPropertyType(Base::XMLReader &reader, const char * TypeName, Property * prop);
private:
// forbidden
PropertyContainer(const PropertyContainer&);
PropertyContainer& operator = (const PropertyContainer&);
protected:
DynamicProperty dynamicProps;
private:
std::string _propertyPrefix;
static PropertyData propertyData;
};
/// Property define
#define _ADD_PROPERTY(_name,_prop_, _defaultval_) \
do { \
this->_prop_.setValue _defaultval_;\
this->_prop_.setContainer(this); \
propertyData.addProperty(static_cast<App::PropertyContainer*>(this), _name, &this->_prop_); \
} while (0)
#define ADD_PROPERTY(_prop_, _defaultval_) \
_ADD_PROPERTY(#_prop_, _prop_, _defaultval_)
#define _ADD_PROPERTY_TYPE(_name,_prop_, _defaultval_, _group_,_type_,_Docu_) \
do { \
this->_prop_.setValue _defaultval_;\
this->_prop_.setContainer(this); \
propertyData.addProperty(static_cast<App::PropertyContainer*>(this), _name, &this->_prop_, (_group_),(_type_),(_Docu_)); \
} while (0)
#define ADD_PROPERTY_TYPE(_prop_, _defaultval_, _group_,_type_,_Docu_) \
_ADD_PROPERTY_TYPE(#_prop_,_prop_,_defaultval_,_group_,_type_,_Docu_)
#define PROPERTY_HEADER(_class_) \
TYPESYSTEM_HEADER(); \
protected: \
static const App::PropertyData * getPropertyDataPtr(void); \
virtual const App::PropertyData &getPropertyData(void) const; \
private: \
static App::PropertyData propertyData
/// Like PROPERTY_HEADER, but with overridden methods declared as such
#define PROPERTY_HEADER_WITH_OVERRIDE(_class_) \
TYPESYSTEM_HEADER_WITH_OVERRIDE(); \
protected: \
static const App::PropertyData * getPropertyDataPtr(void); \
virtual const App::PropertyData &getPropertyData(void) const override; \
private: \
static App::PropertyData propertyData
///
#define PROPERTY_SOURCE(_class_, _parentclass_) \
TYPESYSTEM_SOURCE_P(_class_)\
const App::PropertyData * _class_::getPropertyDataPtr(void){return &propertyData;} \
const App::PropertyData & _class_::getPropertyData(void) const{return propertyData;} \
App::PropertyData _class_::propertyData; \
void _class_::init(void){\
initSubclass(_class_::classTypeId, #_class_ , #_parentclass_, &(_class_::create) ); \
_class_::propertyData.parentPropertyData = _parentclass_::getPropertyDataPtr(); \
}
#define PROPERTY_SOURCE_ABSTRACT(_class_, _parentclass_) \
TYPESYSTEM_SOURCE_ABSTRACT_P(_class_)\
const App::PropertyData * _class_::getPropertyDataPtr(void){return &propertyData;} \
const App::PropertyData & _class_::getPropertyData(void) const{return propertyData;} \
App::PropertyData _class_::propertyData; \
void _class_::init(void){\
initSubclass(_class_::classTypeId, #_class_ , #_parentclass_, &(_class_::create) ); \
_class_::propertyData.parentPropertyData = _parentclass_::getPropertyDataPtr(); \
}
#define TYPESYSTEM_SOURCE_TEMPLATE(_class_) \
template<> Base::Type _class_::classTypeId = Base::Type::badType(); \
template<> Base::Type _class_::getClassTypeId(void) { return _class_::classTypeId; } \
template<> Base::Type _class_::getTypeId(void) const { return _class_::classTypeId; } \
template<> void * _class_::create(void){\
return new _class_ ();\
}
#define PROPERTY_SOURCE_TEMPLATE(_class_, _parentclass_) \
TYPESYSTEM_SOURCE_TEMPLATE(_class_)\
template<> App::PropertyData _class_::propertyData = App::PropertyData(); \
template<> const App::PropertyData * _class_::getPropertyDataPtr(void){return &propertyData;} \
template<> const App::PropertyData & _class_::getPropertyData(void) const{return propertyData;} \
template<> void _class_::init(void){\
initSubclass(_class_::classTypeId, #_class_ , #_parentclass_, &(_class_::create) ); \
_class_::propertyData.parentPropertyData = _parentclass_::getPropertyDataPtr(); \
}
} // namespace App
#endif // APP_PROPERTYCONTAINER_H
/***************************************************************************
* Copyright (c) 2005 Jürgen Riegel <juergen.riegel@web.de> *
* *
* 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 APP_PROPERTYCONTAINER_H
#define APP_PROPERTYCONTAINER_H
#include <map>
#include <cstring>
#include <Base/Persistence.h>
#include "DynamicProperty.h"
namespace Base {
class Writer;
}
namespace App
{
class Property;
class PropertyContainer;
class DocumentObject;
class Extension;
enum PropertyType
{
Prop_None = 0, /*!< No special property type */
Prop_ReadOnly = 1, /*!< Property is read-only in the editor */
Prop_Transient = 2, /*!< Property content won't be saved to file, but still saves name, type and status */
Prop_Hidden = 4, /*!< Property won't appear in the editor */
Prop_Output = 8, /*!< Modified property doesn't touch its parent container */
Prop_NoRecompute = 16,/*!< Modified property doesn't touch its container for recompute */
Prop_NoPersist = 32,/*!< Property won't be saved to file at all */
};
struct AppExport PropertyData
{
struct PropertySpec
{
const char * Name;
const char * Group;
const char * Docu;
short Offset, Type;
inline PropertySpec(const char *name, const char *group, const char *doc, short offset, short type)
:Name(name),Group(group),Docu(doc),Offset(offset),Type(type)
{}
};
//purpose of this struct is to be constructible from all acceptable container types and to
//be able to return the offset to a property from the accepted containers. This allows to use
//one function implementation for multiple container types without losing all type safety by
//accepting void*
struct OffsetBase
{
OffsetBase(const App::PropertyContainer* container) : m_container(container) {}//explicit bombs
OffsetBase(const App::Extension* container) : m_container(container) {}//explicit bombs
short int getOffsetTo(const App::Property* prop) const {
auto *pt = (const char*)prop;
auto *base = (const char *)m_container;
if(pt<base || pt>base+SHRT_MAX)
return -1;
return (short) (pt-base);
}
char* getOffset() const {return (char*) m_container;}
private:
const void* m_container;
};
// A multi index container for holding the property spec, with the following
// index,
// * a sequence, to preserve creation order
// * hash index on property name
// * hash index on property pointer offset
mutable bmi::multi_index_container<
PropertySpec,
bmi::indexed_by<
bmi::sequenced<>,
bmi::hashed_unique<
bmi::member<PropertySpec, const char*, &PropertySpec::Name>,
CStringHasher,
CStringHasher
>,
bmi::hashed_unique<
bmi::member<PropertySpec, short, &PropertySpec::Offset>
>
>
> propertyData;
mutable bool parentMerged = false;
const PropertyData* parentPropertyData;
void addProperty(OffsetBase offsetBase,const char* PropName, Property *Prop, const char* PropertyGroup= nullptr, PropertyType = Prop_None, const char* PropertyDocu= nullptr );
const PropertySpec *findProperty(OffsetBase offsetBase,const char* PropName) const;
const PropertySpec *findProperty(OffsetBase offsetBase,const Property* prop) const;
const char* getName (OffsetBase offsetBase,const Property* prop) const;
short getType (OffsetBase offsetBase,const Property* prop) const;
short getType (OffsetBase offsetBase,const char* name) const;
const char* getGroup (OffsetBase offsetBase,const char* name) const;
const char* getGroup (OffsetBase offsetBase,const Property* prop) const;
const char* getDocumentation(OffsetBase offsetBase,const char* name) const;
const char* getDocumentation(OffsetBase offsetBase,const Property* prop) const;
Property *getPropertyByName(OffsetBase offsetBase,const char* name) const;
void getPropertyMap(OffsetBase offsetBase,std::map<std::string,Property*> &Map) const;
void getPropertyList(OffsetBase offsetBase,std::vector<Property*> &List) const;
void getPropertyNamedList(OffsetBase offsetBase, std::vector<std::pair<const char*,Property*> > &List) const;
void merge(PropertyData *other=nullptr) const;
void split(PropertyData *other);
};
/** Base class of all classes with properties
*/
class AppExport PropertyContainer: public Base::Persistence
{
TYPESYSTEM_HEADER_WITH_OVERRIDE();
public:
/**
* A constructor.
* A more elaborate description of the constructor.
*/
PropertyContainer();
/**
* A destructor.
* A more elaborate description of the destructor.
*/
~PropertyContainer() override;
unsigned int getMemSize () const override;
virtual std::string getFullName() const {return std::string();}
/// find a property by its name
virtual Property *getPropertyByName(const char* name) const;
/// get the name of a property
virtual const char* getPropertyName(const Property* prop) const;
/// get all properties of the class (including properties of the parent)
virtual void getPropertyMap(std::map<std::string,Property*> &Map) const;
/// get all properties of the class (including properties of the parent)
virtual void getPropertyList(std::vector<Property*> &List) const;
/// get all properties with their names, may contain duplicates and aliases
virtual void getPropertyNamedList(std::vector<std::pair<const char*,Property*> > &List) const;
/// set the Status bit of all properties at once
void setPropertyStatus(unsigned char bit,bool value);
/// get the Type of a Property
virtual short getPropertyType(const Property* prop) const;
/// get the Type of a named Property
virtual short getPropertyType(const char *name) const;
/// get the Group of a Property
virtual const char* getPropertyGroup(const Property* prop) const;
/// get the Group of a named Property
virtual const char* getPropertyGroup(const char *name) const;
/// get the Group of a Property
virtual const char* getPropertyDocumentation(const Property* prop) const;
/// get the Group of a named Property
virtual const char* getPropertyDocumentation(const char *name) const;
/// check if the property is read-only
bool isReadOnly(const Property* prop) const;
/// check if the named property is read-only
bool isReadOnly(const char *name) const;
/// check if the property is hidden
bool isHidden(const Property* prop) const;
/// check if the named property is hidden
bool isHidden(const char *name) const;
virtual App::Property* addDynamicProperty(
const char* type, const char* name=nullptr,
const char* group=nullptr, const char* doc=nullptr,
short attr=0, bool ro=false, bool hidden=false);
DynamicProperty::PropData getDynamicPropertyData(const Property* prop) const {
return dynamicProps.getDynamicPropertyData(prop);
}
bool changeDynamicProperty(const Property *prop, const char *group, const char *doc) {
return dynamicProps.changeDynamicProperty(prop,group,doc);
}
virtual bool removeDynamicProperty(const char* name) {
return dynamicProps.removeDynamicProperty(name);
}
virtual std::vector<std::string> getDynamicPropertyNames() const {
return dynamicProps.getDynamicPropertyNames();
}
virtual App::Property *getDynamicPropertyByName(const char* name) const {
return dynamicProps.getDynamicPropertyByName(name);
}
virtual void onPropertyStatusChanged(const Property &prop, unsigned long oldStatus);
void Save (Base::Writer &writer) const override;
void Restore(Base::XMLReader &reader) override;
virtual void editProperty(const char * /*propName*/) {}
const char *getPropertyPrefix() const {
return _propertyPrefix.c_str();
}
void setPropertyPrefix(const char *prefix) {
_propertyPrefix = prefix;
}
friend class Property;
friend class DynamicProperty;
protected:
/// get called by the container when a property has changed
virtual void onChanged(const Property* /*prop*/){}
/// get called before the value is changed
virtual void onBeforeChange(const Property* /*prop*/){}
//void hasChanged(Property* prop);
static const PropertyData * getPropertyDataPtr();
virtual const PropertyData& getPropertyData() const;
virtual void handleChangedPropertyName(Base::XMLReader &reader, const char * TypeName, const char *PropName);
virtual void handleChangedPropertyType(Base::XMLReader &reader, const char * TypeName, Property * prop);
private:
// forbidden
PropertyContainer(const PropertyContainer&);
PropertyContainer& operator = (const PropertyContainer&);
protected:
DynamicProperty dynamicProps;
private:
std::string _propertyPrefix;
static PropertyData propertyData;
};
/// Property define
#define _ADD_PROPERTY(_name,_prop_, _defaultval_) \
do { \
this->_prop_.setValue _defaultval_;\
this->_prop_.setContainer(this); \
propertyData.addProperty(static_cast<App::PropertyContainer*>(this), _name, &this->_prop_); \
} while (0)
#define ADD_PROPERTY(_prop_, _defaultval_) \
_ADD_PROPERTY(#_prop_, _prop_, _defaultval_)
#define _ADD_PROPERTY_TYPE(_name,_prop_, _defaultval_, _group_,_type_,_Docu_) \
do { \
this->_prop_.setValue _defaultval_;\
this->_prop_.setContainer(this); \
propertyData.addProperty(static_cast<App::PropertyContainer*>(this), _name, &this->_prop_, (_group_),(_type_),(_Docu_)); \
} while (0)
#define ADD_PROPERTY_TYPE(_prop_, _defaultval_, _group_,_type_,_Docu_) \
_ADD_PROPERTY_TYPE(#_prop_,_prop_,_defaultval_,_group_,_type_,_Docu_)
#define PROPERTY_HEADER(_class_) \
TYPESYSTEM_HEADER(); \
protected: \
static const App::PropertyData * getPropertyDataPtr(void); \
virtual const App::PropertyData &getPropertyData(void) const; \
private: \
static App::PropertyData propertyData
/// Like PROPERTY_HEADER, but with overridden methods declared as such
#define PROPERTY_HEADER_WITH_OVERRIDE(_class_) \
TYPESYSTEM_HEADER_WITH_OVERRIDE(); \
protected: \
static const App::PropertyData * getPropertyDataPtr(void); \
virtual const App::PropertyData &getPropertyData(void) const override; \
private: \
static App::PropertyData propertyData
///
#define PROPERTY_SOURCE(_class_, _parentclass_) \
TYPESYSTEM_SOURCE_P(_class_)\
const App::PropertyData * _class_::getPropertyDataPtr(void){return &propertyData;} \
const App::PropertyData & _class_::getPropertyData(void) const{return propertyData;} \
App::PropertyData _class_::propertyData; \
void _class_::init(void){\
initSubclass(_class_::classTypeId, #_class_ , #_parentclass_, &(_class_::create) ); \
_class_::propertyData.parentPropertyData = _parentclass_::getPropertyDataPtr(); \
}
#define PROPERTY_SOURCE_ABSTRACT(_class_, _parentclass_) \
TYPESYSTEM_SOURCE_ABSTRACT_P(_class_)\
const App::PropertyData * _class_::getPropertyDataPtr(void){return &propertyData;} \
const App::PropertyData & _class_::getPropertyData(void) const{return propertyData;} \
App::PropertyData _class_::propertyData; \
void _class_::init(void){\
initSubclass(_class_::classTypeId, #_class_ , #_parentclass_, &(_class_::create) ); \
_class_::propertyData.parentPropertyData = _parentclass_::getPropertyDataPtr(); \
}
#define TYPESYSTEM_SOURCE_TEMPLATE(_class_) \
template<> Base::Type _class_::classTypeId = Base::Type::badType(); \
template<> Base::Type _class_::getClassTypeId(void) { return _class_::classTypeId; } \
template<> Base::Type _class_::getTypeId(void) const { return _class_::classTypeId; } \
template<> void * _class_::create(void){\
return new _class_ ();\
}
#define PROPERTY_SOURCE_TEMPLATE(_class_, _parentclass_) \
TYPESYSTEM_SOURCE_TEMPLATE(_class_)\
template<> App::PropertyData _class_::propertyData = App::PropertyData(); \
template<> const App::PropertyData * _class_::getPropertyDataPtr(void){return &propertyData;} \
template<> const App::PropertyData & _class_::getPropertyData(void) const{return propertyData;} \
template<> void _class_::init(void){\
initSubclass(_class_::classTypeId, #_class_ , #_parentclass_, &(_class_::create) ); \
_class_::propertyData.parentPropertyData = _parentclass_::getPropertyDataPtr(); \
}
} // namespace App
#endif // APP_PROPERTYCONTAINER_H
+430 -13
View File
@@ -40,7 +40,6 @@ using namespace std;
const PropertyQuantityConstraint::Constraints LengthStandard = {0.0,DBL_MAX,1.0};
const PropertyQuantityConstraint::Constraints AngleStandard = {-360,360,1.0};
//**************************************************************************
//**************************************************************************
// PropertyQuantity
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
@@ -129,7 +128,6 @@ const boost::any PropertyQuantity::getPathValue(const ObjectIdentifier & /*path*
return Quantity(_dValue, _Unit);
}
//**************************************************************************
//**************************************************************************
// PropertyQuantityConstraint
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
@@ -198,7 +196,10 @@ void PropertyQuantityConstraint::setPyObject(PyObject *value)
PropertyFloat::setValue(quant.getValue()); // clazy:exclude=skipped-base-method
}
//**************************************************************************
// ------------------------------------------------------
// now all properties
// ------------------------------------------------------
//**************************************************************************
// PropertyAcceleration
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
@@ -211,6 +212,16 @@ PropertyAcceleration::PropertyAcceleration()
}
//**************************************************************************
// PropertyAmountOfSubstance
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
TYPESYSTEM_SOURCE(App::PropertyAmountOfSubstance, App::PropertyQuantity)
PropertyAmountOfSubstance::PropertyAmountOfSubstance()
{
setUnit(Base::Unit::AmountOfSubstance);
}
//**************************************************************************
// PropertyAngle
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
@@ -223,7 +234,6 @@ PropertyAngle::PropertyAngle()
setConstraints(&AngleStandard);
}
//**************************************************************************
//**************************************************************************
// PropertyArea
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
@@ -237,18 +247,16 @@ PropertyArea::PropertyArea()
}
//**************************************************************************
//**************************************************************************
// PropertyDistance
// PropertyCompressiveStrength
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
TYPESYSTEM_SOURCE(App::PropertyDistance, App::PropertyQuantity)
TYPESYSTEM_SOURCE(App::PropertyCompressiveStrength, App::PropertyQuantity)
PropertyDistance::PropertyDistance()
PropertyCompressiveStrength::PropertyCompressiveStrength()
{
setUnit(Base::Unit::Length);
setUnit(Base::Unit::CompressiveStrength);
}
//**************************************************************************
//**************************************************************************
// PropertyCurrentDensity
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
@@ -261,6 +269,126 @@ PropertyCurrentDensity::PropertyCurrentDensity()
}
//**************************************************************************
// PropertyDensity
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
TYPESYSTEM_SOURCE(App::PropertyDensity, App::PropertyQuantity)
PropertyDensity::PropertyDensity()
{
setUnit(Base::Unit::Density);
}
//**************************************************************************
// PropertyDissipationRate
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
TYPESYSTEM_SOURCE(App::PropertyDissipationRate, App::PropertyQuantity)
PropertyDissipationRate::PropertyDissipationRate()
{
setUnit(Base::Unit::DissipationRate);
}
//**************************************************************************
// PropertyDistance
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
TYPESYSTEM_SOURCE(App::PropertyDistance, App::PropertyQuantity)
PropertyDistance::PropertyDistance()
{
setUnit(Base::Unit::Length);
}
//**************************************************************************
// PropertyDynamicViscosity
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
TYPESYSTEM_SOURCE(App::PropertyDynamicViscosity, App::PropertyQuantity)
PropertyDynamicViscosity::PropertyDynamicViscosity()
{
setUnit(Base::Unit::DynamicViscosity);
}
//**************************************************************************
// PropertyElectricalCapacitance
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
TYPESYSTEM_SOURCE(App::PropertyElectricalCapacitance, App::PropertyQuantity)
PropertyElectricalCapacitance::PropertyElectricalCapacitance()
{
setUnit(Base::Unit::ElectricalCapacitance);
}
//**************************************************************************
// PropertyElectricalInductance
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
TYPESYSTEM_SOURCE(App::PropertyElectricalInductance, App::PropertyQuantity)
PropertyElectricalInductance::PropertyElectricalInductance()
{
setUnit(Base::Unit::ElectricalInductance);
}
//**************************************************************************
// PropertyElectricalConductance
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
TYPESYSTEM_SOURCE(App::PropertyElectricalConductance, App::PropertyQuantity)
PropertyElectricalConductance::PropertyElectricalConductance()
{
setUnit(Base::Unit::ElectricalConductance);
}
//**************************************************************************
// PropertyElectricalConductivity
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
TYPESYSTEM_SOURCE(App::PropertyElectricalConductivity, App::PropertyQuantity)
PropertyElectricalConductivity::PropertyElectricalConductivity()
{
setUnit(Base::Unit::ElectricalConductivity);
}
//**************************************************************************
// PropertyElectricalResistance
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
TYPESYSTEM_SOURCE(App::PropertyElectricalResistance, App::PropertyQuantity)
PropertyElectricalResistance::PropertyElectricalResistance()
{
setUnit(Base::Unit::ElectricalResistance);
}
//**************************************************************************
// PropertyElectricCharge
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
TYPESYSTEM_SOURCE(App::PropertyElectricCharge, App::PropertyQuantity)
PropertyElectricCharge::PropertyElectricCharge()
{
setUnit(Base::Unit::ElectricCharge);
}
//**************************************************************************
// PropertyElectricCurrent
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
TYPESYSTEM_SOURCE(App::PropertyElectricCurrent, App::PropertyQuantity)
PropertyElectricCurrent::PropertyElectricCurrent()
{
setUnit(Base::Unit::ElectricCurrent);
}
//**************************************************************************
// PropertyElectricPotential
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
@@ -272,7 +400,6 @@ PropertyElectricPotential::PropertyElectricPotential()
setUnit(Base::Unit::ElectricPotential);
}
//**************************************************************************
//**************************************************************************
// PropertyFrequency
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
@@ -284,7 +411,6 @@ PropertyFrequency::PropertyFrequency()
setUnit(Base::Unit::Frequency);
}
//**************************************************************************
//**************************************************************************
// PropertyForce
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
@@ -297,6 +423,60 @@ PropertyForce::PropertyForce()
}
//**************************************************************************
// PropertyHeatFlux
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
TYPESYSTEM_SOURCE(App::PropertyHeatFlux, App::PropertyQuantity)
PropertyHeatFlux::PropertyHeatFlux()
{
setUnit(Base::Unit::HeatFlux);
}
//**************************************************************************
// PropertyInverseArea
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
TYPESYSTEM_SOURCE(App::PropertyInverseArea, App::PropertyQuantity)
PropertyInverseArea::PropertyInverseArea()
{
setUnit(Base::Unit::InverseArea);
}
//**************************************************************************
// PropertyInverseLength
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
TYPESYSTEM_SOURCE(App::PropertyInverseLength, App::PropertyQuantity)
PropertyInverseLength::PropertyInverseLength()
{
setUnit(Base::Unit::InverseLength);
}
//**************************************************************************
// PropertyInverseVolume
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
TYPESYSTEM_SOURCE(App::PropertyInverseVolume, App::PropertyQuantity)
PropertyInverseVolume::PropertyInverseVolume()
{
setUnit(Base::Unit::InverseVolume);
}
//**************************************************************************
// PropertyKinematicViscosity
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
TYPESYSTEM_SOURCE(App::PropertyKinematicViscosity, App::PropertyQuantity)
PropertyKinematicViscosity::PropertyKinematicViscosity()
{
setUnit(Base::Unit::KinematicViscosity);
}
//**************************************************************************
// PropertyLength
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
@@ -310,6 +490,49 @@ PropertyLength::PropertyLength()
}
//**************************************************************************
// PropertyLuminousIntensity
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
TYPESYSTEM_SOURCE(App::PropertyLuminousIntensity, App::PropertyQuantity)
PropertyLuminousIntensity::PropertyLuminousIntensity()
{
setUnit(Base::Unit::LuminousIntensity);
}
//**************************************************************************
// PropertyMagneticFieldStrength
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
TYPESYSTEM_SOURCE(App::PropertyMagneticFieldStrength, App::PropertyQuantity)
PropertyMagneticFieldStrength::PropertyMagneticFieldStrength()
{
setUnit(Base::Unit::MagneticFieldStrength);
}
//**************************************************************************
// PropertyMagneticFlux
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
TYPESYSTEM_SOURCE(App::PropertyMagneticFlux, App::PropertyQuantity)
PropertyMagneticFlux::PropertyMagneticFlux()
{
setUnit(Base::Unit::MagneticFlux);
}
//**************************************************************************
// PropertyMagneticFluxDensity
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
TYPESYSTEM_SOURCE(App::PropertyMagneticFluxDensity, App::PropertyQuantity)
PropertyMagneticFluxDensity::PropertyMagneticFluxDensity()
{
setUnit(Base::Unit::MagneticFluxDensity);
}
//**************************************************************************
// PropertyMagnetization
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
@@ -322,6 +545,16 @@ PropertyMagnetization::PropertyMagnetization()
}
//**************************************************************************
// PropertyMass
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
TYPESYSTEM_SOURCE(App::PropertyMass, App::PropertyQuantity)
PropertyMass::PropertyMass()
{
setUnit(Base::Unit::Mass);
}
//**************************************************************************
// PropertyPressure
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
@@ -334,6 +567,38 @@ PropertyPressure::PropertyPressure()
}
//**************************************************************************
// PropertyPower
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
TYPESYSTEM_SOURCE(App::PropertyPower, App::PropertyQuantity)
PropertyPower::PropertyPower()
{
setUnit(Base::Unit::Power);
}
//**************************************************************************
// PropertySpecificEnergy
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
TYPESYSTEM_SOURCE(App::PropertySpecificEnergy, App::PropertyQuantity)
PropertySpecificEnergy::PropertySpecificEnergy()
{
setUnit(Base::Unit::SpecificEnergy);
}
//**************************************************************************
// PropertySpecificHeat
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
TYPESYSTEM_SOURCE(App::PropertySpecificHeat, App::PropertyQuantity)
PropertySpecificHeat::PropertySpecificHeat()
{
setUnit(Base::Unit::SpecificHeat);
}
//**************************************************************************
// PropertySpeed
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
@@ -345,7 +610,6 @@ PropertySpeed::PropertySpeed()
setUnit(Base::Unit::Velocity);
}
//**************************************************************************
//**************************************************************************
// PropertyStiffness
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
@@ -358,6 +622,94 @@ PropertyStiffness::PropertyStiffness()
}
//**************************************************************************
// PropertyTemperature
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
TYPESYSTEM_SOURCE(App::PropertyTemperature, App::PropertyQuantity)
PropertyTemperature::PropertyTemperature()
{
setUnit(Base::Unit::Temperature);
}
//**************************************************************************
// PropertyThermalConductivity
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
TYPESYSTEM_SOURCE(App::PropertyThermalConductivity, App::PropertyQuantity)
PropertyThermalConductivity::PropertyThermalConductivity()
{
setUnit(Base::Unit::ThermalConductivity);
}
//**************************************************************************
// PropertyThermalExpansionCoefficient
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
TYPESYSTEM_SOURCE(App::PropertyThermalExpansionCoefficient, App::PropertyQuantity)
PropertyThermalExpansionCoefficient::PropertyThermalExpansionCoefficient()
{
setUnit(Base::Unit::ThermalExpansionCoefficient);
}
//**************************************************************************
// PropertyThermalTransferCoefficient
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
TYPESYSTEM_SOURCE(App::PropertyThermalTransferCoefficient, App::PropertyQuantity)
PropertyThermalTransferCoefficient::PropertyThermalTransferCoefficient()
{
setUnit(Base::Unit::ThermalTransferCoefficient);
}
//**************************************************************************
// PropertyTime
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
TYPESYSTEM_SOURCE(App::PropertyTime, App::PropertyQuantity)
PropertyTime::PropertyTime()
{
setUnit(Base::Unit::TimeSpan);
}
//**************************************************************************
// PropertyShearModulus
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
TYPESYSTEM_SOURCE(App::PropertyShearModulus, App::PropertyQuantity)
PropertyShearModulus::PropertyShearModulus()
{
setUnit(Base::Unit::ShearModulus);
}
//**************************************************************************
// PropertyStress
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
TYPESYSTEM_SOURCE(App::PropertyStress, App::PropertyQuantity)
PropertyStress::PropertyStress()
{
setUnit(Base::Unit::Stress);
}
//**************************************************************************
// PropertyUltimateTensileStrength
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
TYPESYSTEM_SOURCE(App::PropertyUltimateTensileStrength, App::PropertyQuantity)
PropertyUltimateTensileStrength::PropertyUltimateTensileStrength()
{
setUnit(Base::Unit::UltimateTensileStrength);
}
//**************************************************************************
// PropertyVacuumPermittivity
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
@@ -370,6 +722,16 @@ PropertyVacuumPermittivity::PropertyVacuumPermittivity()
}
//**************************************************************************
// PropertyVelocity
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
TYPESYSTEM_SOURCE(App::PropertyVelocity, App::PropertyQuantity)
PropertyVelocity::PropertyVelocity()
{
setUnit(Base::Unit::Velocity);
}
//**************************************************************************
// PropertyVolume
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
@@ -381,3 +743,58 @@ PropertyVolume::PropertyVolume()
setUnit(Base::Unit::Volume);
setConstraints(&LengthStandard);
}
//**************************************************************************
// PropertyVolumeFlowRate
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
TYPESYSTEM_SOURCE(App::PropertyVolumeFlowRate, App::PropertyQuantity)
PropertyVolumeFlowRate::PropertyVolumeFlowRate()
{
setUnit(Base::Unit::VolumeFlowRate);
}
//**************************************************************************
// PropertyVolumetricThermalExpansionCoefficient
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
TYPESYSTEM_SOURCE(App::PropertyVolumetricThermalExpansionCoefficient, App::PropertyQuantity)
PropertyVolumetricThermalExpansionCoefficient::PropertyVolumetricThermalExpansionCoefficient()
{
setUnit(Base::Unit::VolumetricThermalExpansionCoefficient);
}
//**************************************************************************
// PropertyWork
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
TYPESYSTEM_SOURCE(App::PropertyWork, App::PropertyQuantity)
PropertyWork::PropertyWork()
{
setUnit(Base::Unit::Work);
}
//**************************************************************************
// PropertyYieldStrength
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
TYPESYSTEM_SOURCE(App::PropertyYieldStrength, App::PropertyQuantity)
PropertyYieldStrength::PropertyYieldStrength()
{
setUnit(Base::Unit::YieldStrength);
}
//**************************************************************************
// PropertyYoungsModulus
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
TYPESYSTEM_SOURCE(App::PropertyYoungsModulus, App::PropertyQuantity)
PropertyYoungsModulus::PropertyYoungsModulus()
{
setUnit(Base::Unit::YoungsModulus);
}
+559 -11
View File
@@ -20,7 +20,6 @@
* *
***************************************************************************/
#ifndef APP_PROPERTYUNITS_H
#define APP_PROPERTYUNITS_H
@@ -29,11 +28,11 @@
#include "PropertyStandard.h"
namespace Base {
class Writer;
}
namespace App
{
@@ -119,6 +118,10 @@ protected:
const Constraints* _ConstStruct;
};
// ------------------------------------------------------
// now all properties
// ------------------------------------------------------
/** Acceleration property
* This is a property for representing acceleration. It is basically a float
* property. On the Gui it has a quantity like m/s^2.
@@ -132,6 +135,20 @@ public:
~PropertyAcceleration() override = default;
};
/** AmountOfSubstance property
* This is a property for representing number of molecules. It is basically a
* float property. On the Gui it has a quantity like mole.
*/
class AppExport PropertyAmountOfSubstance: public PropertyQuantity
{
TYPESYSTEM_HEADER();
public:
PropertyAmountOfSubstance(void);
virtual ~PropertyAmountOfSubstance()
{}
};
/** Angle property
* This is a property for representing angles. It basically a float
* property. On the Gui it has a quantity like RAD.
@@ -159,17 +176,18 @@ public:
~PropertyArea() override = default;
};
/** Distance property
* This is a property for representing distances. It is basically a float
* property. On the Gui it has a quantity like m or mm.
/** CompressiveStrength property
* This is a property for representing compressive strength. It is basically a
* float property. On the Gui it has a quantity like Pa.
*/
class AppExport PropertyDistance: public PropertyQuantity
class AppExport PropertyCompressiveStrength: public PropertyQuantity
{
TYPESYSTEM_HEADER_WITH_OVERRIDE();
TYPESYSTEM_HEADER();
public:
PropertyDistance();
~PropertyDistance() override = default;
PropertyCompressiveStrength(void);
virtual ~PropertyCompressiveStrength()
{}
};
/** CurrentDensity property
@@ -185,6 +203,161 @@ public:
~PropertyCurrentDensity() override = default;
};
/** Density property
* This is a property for representing density. It is basically a float
* property which must not be negative. On the Gui it has a quantity like
* kg/m^3.
*/
class AppExport PropertyDensity: public PropertyQuantity
{
TYPESYSTEM_HEADER();
public:
PropertyDensity(void);
virtual ~PropertyDensity()
{}
};
/** DissipationRate property
* This is a property for representing turbulent dissipation rate. It basically
* a float property. On the Gui it has a quantity like m^2/s^3.
*/
class AppExport PropertyDissipationRate: public PropertyQuantity
{
TYPESYSTEM_HEADER();
public:
PropertyDissipationRate(void);
virtual ~PropertyDissipationRate()
{}
};
/** Distance property
* This is a property for representing distances. It is basically a float
* property. On the Gui it has a quantity like m or mm.
*/
class AppExport PropertyDistance: public PropertyQuantity
{
TYPESYSTEM_HEADER_WITH_OVERRIDE();
public:
PropertyDistance();
~PropertyDistance() override = default;
};
/** DynamicViscosity property
* This is a property for representing dynamic viscosity. It is basically a float
* property which must not be negative. On the Gui it has a quantity like Pa*s.
*/
class AppExport PropertyDynamicViscosity: public PropertyQuantity
{
TYPESYSTEM_HEADER();
public:
PropertyDynamicViscosity(void);
virtual ~PropertyDynamicViscosity()
{}
};
/** ElectricalCapacitance property
* This is a property for representing capacitance. It is basically a float
* property. On the Gui it has a quantity like F.
*/
class AppExport PropertyElectricalCapacitance: public PropertyQuantity
{
TYPESYSTEM_HEADER();
public:
PropertyElectricalCapacitance(void);
virtual ~PropertyElectricalCapacitance()
{}
};
/** ElectricalConductance property
* This is a property for representing electrical conductance. It is basically a
* float property. On the Gui it has a quantity like S.
*/
class AppExport PropertyElectricalConductance: public PropertyQuantity
{
TYPESYSTEM_HEADER();
public:
PropertyElectricalConductance(void);
virtual ~PropertyElectricalConductance()
{}
};
/** ElectricalConductivity property
* This is a property for representing electrical conductivity. It is basically
* a float property. On the Gui it has a quantity like S/m.
*/
class AppExport PropertyElectricalConductivity: public PropertyQuantity
{
TYPESYSTEM_HEADER();
public:
PropertyElectricalConductivity(void);
virtual ~PropertyElectricalConductivity()
{}
};
/** ElectricalInductance property
* This is a property for representing electrical inductance. It is basically a
* float property. On the Gui it has a quantity like H.
*/
class AppExport PropertyElectricalInductance: public PropertyQuantity
{
TYPESYSTEM_HEADER();
public:
PropertyElectricalInductance(void);
virtual ~PropertyElectricalInductance()
{}
};
/** ElectricalResistance property
* This is a property for representing electrical resistance. It is basically a
* float property. On the Gui it has a quantity like Ohm.
*/
class AppExport PropertyElectricalResistance: public PropertyQuantity
{
TYPESYSTEM_HEADER();
public:
PropertyElectricalResistance(void);
virtual ~PropertyElectricalResistance()
{}
};
/** ElectricCharge property
* This is a property for representing electric charge. It is basically a float
* property. On the Gui it has a quantity like C.
*/
class AppExport PropertyElectricCharge: public PropertyQuantity
{
TYPESYSTEM_HEADER();
public:
PropertyElectricCharge(void);
virtual ~PropertyElectricCharge()
{}
};
/** ElectricCurrent property
* This is a property for representing electric currents. It is basically a
* float property. On the Gui it has a quantity like A.
*/
class AppExport PropertyElectricCurrent: public PropertyQuantity
{
TYPESYSTEM_HEADER();
public:
PropertyElectricCurrent(void);
virtual ~PropertyElectricCurrent()
{}
};
/** ElectricPotential property
* This is a property for electric potentials. It is basically a float
* property. On the Gui it has a quantity of Volt.
@@ -224,6 +397,76 @@ public:
~PropertyForce() override = default;
};
/** HeatFlux property
* This is a property for representing heat flux. It is basically a float
* property. On the Gui it has a quantity like W/m^2.
*/
class AppExport PropertyHeatFlux: public PropertyQuantity
{
TYPESYSTEM_HEADER();
public:
PropertyHeatFlux(void);
virtual ~PropertyHeatFlux()
{}
};
/** InverseArea property
* This is a property for representing the reciprocal of area. It is basically a float
* property which must not be negative. On the Gui it has a quantity like 1/m^2.
*/
class AppExport PropertyInverseArea: public PropertyQuantity
{
TYPESYSTEM_HEADER();
public:
PropertyInverseArea(void);
virtual ~PropertyInverseArea()
{}
};
/** InverseLength property
* This is a property for representing the reciprocal of length. It is basically a float
* property which must not be negative. On the Gui it has a quantity like 1/m.
*/
class AppExport PropertyInverseLength: public PropertyQuantity
{
TYPESYSTEM_HEADER();
public:
PropertyInverseLength(void);
virtual ~PropertyInverseLength()
{}
};
/** InverseVolume property
* This is a property for representing the reciprocal of volume. It is basically a float
* property. which must not be negative. On the Gui it has a quantity like 1/m^3.
*/
class AppExport PropertyInverseVolume: public PropertyQuantity
{
TYPESYSTEM_HEADER();
public:
PropertyInverseVolume(void);
virtual ~PropertyInverseVolume()
{}
};
/** KinematicViscosity property
* This is a property for representing kinematic viscosity. It is basically a float
* property which must not be negative. On the Gui it has a quantity like m^2/s.
*/
class AppExport PropertyKinematicViscosity: public PropertyQuantity
{
TYPESYSTEM_HEADER();
public:
PropertyKinematicViscosity(void);
virtual ~PropertyKinematicViscosity()
{}
};
/** Length property
* This is a property for representing lengths. It is basically a float
* property which must not be negative. On the Gui it has a quantity like m or mm.
@@ -237,6 +480,62 @@ public:
~PropertyLength() override = default;
};
/** LuminousIntensity property
* This is a property for representing luminous intensity. It is basically a
* float property. On the Gui it has a quantity like cd.
*/
class AppExport PropertyLuminousIntensity: public PropertyQuantity
{
TYPESYSTEM_HEADER();
public:
PropertyLuminousIntensity(void);
virtual ~PropertyLuminousIntensity()
{}
};
/** MagneticFieldStrength property
* This is a property for representing magnetic field strength. It is basically
* a float property. On the Gui it has a quantity like A/m.
*/
class AppExport PropertyMagneticFieldStrength: public PropertyQuantity
{
TYPESYSTEM_HEADER();
public:
PropertyMagneticFieldStrength(void);
virtual ~PropertyMagneticFieldStrength()
{}
};
/** MagneticFlux property
* This is a property for representing magnetic flux. It is basically a float
* property. On the Gui it has a quantity like Wb.
*/
class AppExport PropertyMagneticFlux: public PropertyQuantity
{
TYPESYSTEM_HEADER();
public:
PropertyMagneticFlux(void);
virtual ~PropertyMagneticFlux()
{}
};
/** MagneticFluxDensity property
* This is a property for representing magnetic flux density. It is basically a
* float property. On the Gui it has a quantity like G or T.
*/
class AppExport PropertyMagneticFluxDensity: public PropertyQuantity
{
TYPESYSTEM_HEADER();
public:
PropertyMagneticFluxDensity(void);
virtual ~PropertyMagneticFluxDensity()
{}
};
/** Magnetization property
* This is a property for representing magnetizations. It is basically a float
* property. On the Gui it has a quantity like A/m.
@@ -250,9 +549,23 @@ public:
~PropertyMagnetization() override = default;
};
/** Mass property
* This is a property for representing mass. It is basically a float
* property. On the Gui it has a quantity like kg.
*/
class AppExport PropertyMass: public PropertyQuantity
{
TYPESYSTEM_HEADER();
public:
PropertyMass(void);
virtual ~PropertyMass()
{}
};
/** Pressure property
* This is a property for representing acceleration. It is basically a float
* property. On the Gui it has a quantity like m/s^2.
* This is a property for representing pressure. It basically a float
* property. On the Gui it has a quantity like Pa.
*/
class AppExport PropertyPressure: public PropertyQuantity
{
@@ -263,6 +576,62 @@ public:
~PropertyPressure() override = default;
};
/** Power property
* This is a property for representing power. It is basically a float
* property. On the Gui it has a quantity like W.
*/
class AppExport PropertyPower: public PropertyQuantity
{
TYPESYSTEM_HEADER();
public:
PropertyPower(void);
virtual ~PropertyPower()
{}
};
/** ShearModulus property
* This is a property for representing shear modulus. It is basically a float
* property. On the Gui it has a quantity like Pa.
*/
class AppExport PropertyShearModulus: public PropertyQuantity
{
TYPESYSTEM_HEADER();
public:
PropertyShearModulus(void);
virtual ~PropertyShearModulus()
{}
};
/** SpecificEnergy property
* This is a property for representing specific energy. It is basically a float
* property. On the Gui it has a quantity like m^2/s^2 or J/kg.
*/
class AppExport PropertySpecificEnergy: public PropertyQuantity
{
TYPESYSTEM_HEADER();
public:
PropertySpecificEnergy(void);
virtual ~PropertySpecificEnergy()
{}
};
/** SpecificHeat property
* This is a property for representing specific heat capacity. It is basically a
* float property. On the Gui it has a quantity like J/kg/K.
*/
class AppExport PropertySpecificHeat: public PropertyQuantity
{
TYPESYSTEM_HEADER();
public:
PropertySpecificHeat(void);
virtual ~PropertySpecificHeat()
{}
};
/** Speed property
* This is a property for representing speed. It is basically a float
* property. On the Gui it has a quantity like m/s or km/h.
@@ -289,6 +658,102 @@ public:
~PropertyStiffness() override = default;
};
/** Stress property
* This is a property for representing . It is basically a float
* property. On the Gui it has a quantity like Pa.
*/
class AppExport PropertyStress: public PropertyQuantity
{
TYPESYSTEM_HEADER();
public:
PropertyStress(void);
virtual ~PropertyStress()
{}
};
/** Temperature property
* This is a property for representing temperatures. It is basically a float
* property which must not be negative. On the Gui it has a quantity like K.
*/
class AppExport PropertyTemperature: public PropertyQuantity
{
TYPESYSTEM_HEADER();
public:
PropertyTemperature(void);
virtual ~PropertyTemperature()
{}
};
/** ThermalConductivity property
* This is a property for representing thermal conductivity. It is basically a
* float property. On the Gui it has a quantity like W/m/K.
*/
class AppExport PropertyThermalConductivity: public PropertyQuantity
{
TYPESYSTEM_HEADER();
public:
PropertyThermalConductivity(void);
virtual ~PropertyThermalConductivity()
{}
};
/** ThermalExpansionCoefficient property
* This is a property for representing a coefficient of thermal expansion. It
* basically a float property. On the Gui it has a quantity like 1/K.
*/
class AppExport PropertyThermalExpansionCoefficient: public PropertyQuantity
{
TYPESYSTEM_HEADER();
public:
PropertyThermalExpansionCoefficient(void);
virtual ~PropertyThermalExpansionCoefficient()
{}
};
/** ThermalTransferCoefficient property
* This is a property for representing heat transfer coefficient. It is
* basically a float property. On the Gui it has a quantity like W/m^2/K.
*/
class AppExport PropertyThermalTransferCoefficient: public PropertyQuantity
{
TYPESYSTEM_HEADER();
public:
PropertyThermalTransferCoefficient(void);
virtual ~PropertyThermalTransferCoefficient()
{}
};
/** TimeSpan property
* This is a property for representing time intervals. It is basically a float
* property. On the Gui it has a quantity like s.
*/
class AppExport PropertyTime: public PropertyQuantity
{
TYPESYSTEM_HEADER();
public:
PropertyTime(void);
virtual ~PropertyTime(){}
};
/** UltimateTensileStrength property
* This is a property for representing ultimate tensile strength. It is
* basically a float property. On the Gui it has a quantity like Pa.
*/
class AppExport PropertyUltimateTensileStrength: public PropertyQuantity
{
TYPESYSTEM_HEADER();
public:
PropertyUltimateTensileStrength(void);
virtual ~PropertyUltimateTensileStrength(){}
};
/** VacuumPermittivity property
* This is a property for representing vacuum permittivity. It is basically a float
* property. On the Gui it has a quantity like s^4*A^2 / (m^3*kg).
@@ -302,6 +767,20 @@ public:
~PropertyVacuumPermittivity() override = default;
};
/** Velocity property
* This is a property for representing velocities. It is basically a float
* property. On the Gui it has a quantity like m/s.
*/
class AppExport PropertyVelocity: public PropertyQuantity
{
TYPESYSTEM_HEADER();
public:
PropertyVelocity(void);
virtual ~PropertyVelocity()
{}
};
/** Volume property
* This is a property for representing volumes. It is basically a float
* property which must not be negative. On the Gui it has a quantity like m^3 or mm^3.
@@ -315,6 +794,75 @@ public:
~PropertyVolume() override = default;
};
/** VolumeFlowRate property
* This is a property for representing volumetric flow rate. It is basically a
* float property. On the Gui it has a quantity like l/s.
*/
class AppExport PropertyVolumeFlowRate: public PropertyQuantity
{
TYPESYSTEM_HEADER();
public:
PropertyVolumeFlowRate(void);
virtual ~PropertyVolumeFlowRate()
{}
};
/** VolumetricThermalExpansionCoefficient property
* This is a property for representing . It is basically a float
* property. On the Gui it has a quantity like 1/K.
*/
class AppExport PropertyVolumetricThermalExpansionCoefficient: public PropertyQuantity
{
TYPESYSTEM_HEADER();
public:
PropertyVolumetricThermalExpansionCoefficient(void);
virtual ~PropertyVolumetricThermalExpansionCoefficient()
{}
};
/** Work property
* This is a property for representing work. It is basically a float
* property. On the Gui it has a quantity like Nm.
*/
class AppExport PropertyWork: public PropertyQuantity
{
TYPESYSTEM_HEADER();
public:
PropertyWork(void);
virtual ~PropertyWork(){}
};
/** YieldStrength property
* This is a property for representing yield strength. It is basically a float
* property. On the Gui it has a quantity like Pa.
*/
class AppExport PropertyYieldStrength: public PropertyQuantity
{
TYPESYSTEM_HEADER();
public:
PropertyYieldStrength(void);
virtual ~PropertyYieldStrength()
{}
};
/** YoungsModulus property
* This is a property for representing Young's modulus. It is basically a float
* property. On the Gui it has a quantity like Pa.
*/
class AppExport PropertyYoungsModulus: public PropertyQuantity
{
TYPESYSTEM_HEADER();
public:
PropertyYoungsModulus(void);
virtual ~PropertyYoungsModulus()
{}
};
}// namespace App
#endif// APP_PROPERTYUNITS_H
-1
View File
@@ -291,7 +291,6 @@ SET(FreeCADBase_HPP_SRCS
FileInfo.h
FileTemplate.h
FutureWatcherProgress.h
fdstream.hpp
GeometryPyCXX.h
Handle.h
InputSource.h
+19 -10
View File
@@ -833,34 +833,43 @@ ScaleType Matrix4D::hasScale(double tol) const
if (tol == 0.0)
tol = 1e-9;
// check if the absolute values are proportionally close or equal
auto closeAbs = [&](double a, double b) {
double c = fabs(a);
double d = fabs(b);
if (d>c) return (d-c)/d <= tol;
else if (c>d) return (c-d)/c <= tol;
return true;
};
// get column vectors
double dx = Vector3d(dMtrx4D[0][0],dMtrx4D[1][0],dMtrx4D[2][0]).Sqr();
double dy = Vector3d(dMtrx4D[0][1],dMtrx4D[1][1],dMtrx4D[2][1]).Sqr();
double dz = Vector3d(dMtrx4D[0][2],dMtrx4D[1][2],dMtrx4D[2][2]).Sqr();
double dx = getCol(0).Sqr();
double dy = getCol(1).Sqr();
double dz = getCol(2).Sqr();
double dxyz = sqrt(dx * dy * dz);
// get row vectors
double du = Vector3d(dMtrx4D[0][0],dMtrx4D[0][1],dMtrx4D[0][2]).Sqr();
double dv = Vector3d(dMtrx4D[1][0],dMtrx4D[1][1],dMtrx4D[1][2]).Sqr();
double dw = Vector3d(dMtrx4D[2][0],dMtrx4D[2][1],dMtrx4D[2][2]).Sqr();
double du = getRow(0).Sqr();
double dv = getRow(1).Sqr();
double dw = getRow(2).Sqr();
double duvw = sqrt(du * dv * dw);
double d3 = determinant3();
// This could be e.g. a projection, a shearing,... matrix
if (fabs(dxyz - d3) > tol && fabs(duvw - d3) > tol) {
if (!closeAbs(dxyz, d3) && !closeAbs(duvw, d3)) {
return ScaleType::Other;
}
if (fabs(duvw - d3) <= tol && (fabs(du - dv) > tol || fabs(dv - dw) > tol)) {
if (closeAbs(duvw, d3) && (!closeAbs(du, dv) || !closeAbs(dv, dw))) {
return ScaleType::NonUniformLeft;
}
if (fabs(dxyz - d3) <= tol && (fabs(dx - dy) > tol || fabs(dy - dz) > tol)) {
if (closeAbs(dxyz, d3) && (!closeAbs(dx, dy) || !closeAbs(dy, dz))) {
return ScaleType::NonUniformRight;
}
if (fabs(dx - 1.0) > tol) {
if (fabs(d3 - 1.0) > tol) {
return ScaleType::Uniform;
}
+16 -5
View File
@@ -67,9 +67,15 @@ int PlacementPy::PyInit(PyObject* args, PyObject* /*kwd*/)
PyErr_Clear();
if (PyArg_ParseTuple(args, "O!", &(Base::MatrixPy::Type), &o)) {
Base::Matrix4D mat = static_cast<Base::MatrixPy*>(o)->value();
getPlacementPtr()->fromMatrix(mat);
return 0;
try {
Base::Matrix4D mat = static_cast<Base::MatrixPy*>(o)->value();
getPlacementPtr()->fromMatrix(mat);
return 0;
}
catch (const Base::Exception& e) {
PyErr_SetString(e.getPyExceptionType(), e.what());
return -1;
}
}
PyErr_Clear();
@@ -342,8 +348,13 @@ void PlacementPy::setMatrix(Py::Object arg)
Py::Matrix mat;
if (!mat.accepts(arg.ptr()))
throw Py::TypeError("Expect type Matrix");
mat = arg;
getPlacementPtr()->fromMatrix(mat);
try {
mat = arg;
getPlacementPtr()->fromMatrix(mat);
}
catch (const Base::ValueError& e) {
throw Py::ValueError(e.what());
}
}
PyObject *PlacementPy::getCustomAttributes(const char* attr) const
+211 -193
View File
@@ -25,6 +25,7 @@
# ifdef FC_OS_WIN32
# define _USE_MATH_DEFINES
# endif // FC_OS_WIN32
# include <array>
#endif
#include "Quantity.h"
@@ -49,6 +50,7 @@
using namespace Base;
// ====== Static attributes =========================
// NOLINTNEXTLINE
int QuantityFormat::defaultDenominator = 8; // for 1/8"
@@ -71,165 +73,170 @@ QuantityFormat::QuantityFormat(QuantityFormat::NumberFormat format, int decimals
// ----------------------------------------------------------------------------
Quantity::Quantity()
: myValue{0.0}
{
this->_Value = 0.0;
}
Quantity::Quantity(const Quantity& that)
{
*this = that ;
}
Quantity::Quantity(double value, const Unit& unit)
: myValue{value}
, myUnit{unit}
{
this->_Unit = unit;
this->_Value = value;
}
Quantity::Quantity(double value, const QString& unit)
: myValue{0.0}
{
if (unit.isEmpty()) {
this->_Value = value;
this->_Unit = Unit();
this->myValue = value;
this->myUnit = Unit();
return;
}
try {
auto tmpQty = parse(unit);
this->_Unit = tmpQty.getUnit();
this->_Value = value * tmpQty.getValue();
this->myUnit = tmpQty.getUnit();
this->myValue = value * tmpQty.getValue();
}
catch (const Base::ParserError&) {
this->_Value = 0.0;
this->_Unit = Unit();
this->myValue = 0.0;
this->myUnit = Unit();
}
}
double Quantity::getValueAs(const Quantity &q)const
double Quantity::getValueAs(const Quantity& other)const
{
return _Value/q.getValue();
return myValue / other.getValue();
}
bool Quantity::operator ==(const Quantity& that) const
{
return (this->_Value == that._Value) && (this->_Unit == that._Unit);
return (this->myValue == that.myValue) && (this->myUnit == that.myUnit);
}
bool Quantity::operator !=(const Quantity& that) const
{
return !(*this == that);
}
bool Quantity::operator <(const Quantity& that) const
{
if (this->_Unit != that._Unit)
if (this->myUnit != that.myUnit) {
throw Base::UnitsMismatchError("Quantity::operator <(): quantities need to have same unit to compare");
}
return (this->_Value < that._Value) ;
return (this->myValue < that.myValue) ;
}
bool Quantity::operator >(const Quantity& that) const
{
if (this->_Unit != that._Unit)
if (this->myUnit != that.myUnit) {
throw Base::UnitsMismatchError("Quantity::operator >(): quantities need to have same unit to compare");
}
return (this->_Value > that._Value) ;
return (this->myValue > that.myValue) ;
}
bool Quantity::operator <=(const Quantity& that) const
{
if (this->_Unit != that._Unit)
if (this->myUnit != that.myUnit) {
throw Base::UnitsMismatchError("Quantity::operator <=(): quantities need to have same unit to compare");
}
return (this->_Value <= that._Value) ;
return (this->myValue <= that.myValue) ;
}
bool Quantity::operator >=(const Quantity& that) const
{
if (this->_Unit != that._Unit)
if (this->myUnit != that.myUnit) {
throw Base::UnitsMismatchError("Quantity::operator >=(): quantities need to have same unit to compare");
}
return (this->_Value >= that._Value) ;
return (this->myValue >= that.myValue) ;
}
Quantity Quantity::operator *(const Quantity &p) const
Quantity Quantity::operator *(const Quantity& other) const
{
return Quantity(this->_Value * p._Value,this->_Unit * p._Unit);
return Quantity(this->myValue * other.myValue, this->myUnit * other.myUnit);
}
Quantity Quantity::operator *(double p) const
Quantity Quantity::operator *(double factor) const
{
return Quantity(this->_Value * p,this->_Unit);
return Quantity(this->myValue * factor, this->myUnit);
}
Quantity Quantity::operator /(const Quantity &p) const
Quantity Quantity::operator /(const Quantity& other) const
{
return Quantity(this->_Value / p._Value,this->_Unit / p._Unit);
return Quantity(this->myValue / other.myValue, this->myUnit / other.myUnit);
}
Quantity Quantity::operator /(double p) const
Quantity Quantity::operator /(double factor) const
{
return Quantity(this->_Value / p,this->_Unit);
return Quantity(this->myValue / factor, this->myUnit);
}
Quantity Quantity::pow(const Quantity &p) const
Quantity Quantity::pow(const Quantity& other) const
{
if (!p._Unit.isEmpty())
if (!other.myUnit.isEmpty()) {
throw Base::UnitsMismatchError("Quantity::pow(): exponent must not have a unit");
}
return Quantity(
std::pow(this->_Value, p._Value),
this->_Unit.pow(static_cast<signed char>(p._Value))
std::pow(this->myValue, other.myValue),
this->myUnit.pow(static_cast<signed char>(other.myValue))
);
}
Quantity Quantity::pow(double p) const
Quantity Quantity::pow(double exp) const
{
return Quantity(
std::pow(this->_Value, p),
this->_Unit.pow((short)p)
std::pow(this->myValue, exp),
this->myUnit.pow(exp)
);
}
Quantity Quantity::operator +(const Quantity &p) const
Quantity Quantity::operator +(const Quantity& other) const
{
if (this->_Unit != p._Unit)
if (this->myUnit != other.myUnit) {
throw Base::UnitsMismatchError("Quantity::operator +(): Unit mismatch in plus operation");
return Quantity(this->_Value + p._Value,this->_Unit);
}
return Quantity(this->myValue + other.myValue, this->myUnit);
}
Quantity& Quantity::operator +=(const Quantity &p)
Quantity& Quantity::operator +=(const Quantity& other)
{
if (this->_Unit != p._Unit)
if (this->myUnit != other.myUnit) {
throw Base::UnitsMismatchError("Quantity::operator +=(): Unit mismatch in plus operation");
}
_Value += p._Value;
myValue += other.myValue;
return *this;
}
Quantity Quantity::operator -(const Quantity &p) const
Quantity Quantity::operator -(const Quantity& other) const
{
if (this->_Unit != p._Unit)
if (this->myUnit != other.myUnit) {
throw Base::UnitsMismatchError("Quantity::operator -(): Unit mismatch in minus operation");
return Quantity(this->_Value - p._Value,this->_Unit);
}
return Quantity(this->myValue - other.myValue,this->myUnit);
}
Quantity& Quantity::operator -=(const Quantity &p)
Quantity& Quantity::operator -=(const Quantity& other)
{
if (this->_Unit != p._Unit)
if (this->myUnit != other.myUnit) {
throw Base::UnitsMismatchError("Quantity::operator -=(): Unit mismatch in minus operation");
}
_Value -= p._Value;
myValue -= other.myValue;
return *this;
}
Quantity Quantity::operator -() const
{
return Quantity(-(this->_Value),this->_Unit);
}
Quantity& Quantity::operator = (const Quantity &New)
{
this->_Value = New._Value;
this->_Unit = New._Unit;
this->_Format = New._Format;
return *this;
return Quantity(-(this->myValue), this->myUnit);
}
QString Quantity::getUserString(double& factor, QString& unitString) const
@@ -245,13 +252,13 @@ QString Quantity::getUserString(UnitsSchema* schema, double &factor, QString &un
QString Quantity::getSafeUserString() const
{
auto retString = getUserString();
if(Q_LIKELY(this->_Value != 0))
if(Q_LIKELY(this->myValue != 0))
{
auto feedbackQty = parse(retString);
auto feedbackVal = feedbackQty.getValue();
if (feedbackVal == 0) {
retString = QStringLiteral("%1 %2")
.arg(this->_Value)
.arg(this->myValue)
.arg(this->getUnit().getString());
}
}
@@ -261,174 +268,174 @@ QString Quantity::getSafeUserString() const
/// true if it has a number without a unit
bool Quantity::isDimensionless() const
{
return isValid() && _Unit.isEmpty();
return isValid() && myUnit.isEmpty();
}
// true if it has a number and a valid unit
bool Quantity::isQuantity() const
{
return isValid() && !_Unit.isEmpty();
return isValid() && !myUnit.isEmpty();
}
// true if it has a number with or without a unit
bool Quantity::isValid() const
{
return !boost::math::isnan(_Value);
return !boost::math::isnan(myValue);
}
void Quantity::setInvalid()
{
_Value = std::numeric_limits<double>::quiet_NaN();
myValue = std::numeric_limits<double>::quiet_NaN();
}
// === Predefined types =====================================================
Quantity Quantity::NanoMetre (1.0e-6 ,Unit(1));
Quantity Quantity::MicroMetre (1.0e-3 ,Unit(1));
Quantity Quantity::MilliMetre (1.0 ,Unit(1));
Quantity Quantity::CentiMetre (10.0 ,Unit(1));
Quantity Quantity::DeciMetre (100.0 ,Unit(1));
Quantity Quantity::Metre (1.0e3 ,Unit(1));
Quantity Quantity::KiloMetre (1.0e6 ,Unit(1));
const Quantity Quantity::NanoMetre (1.0e-6 ,Unit(1));
const Quantity Quantity::MicroMetre (1.0e-3 ,Unit(1));
const Quantity Quantity::MilliMetre (1.0 ,Unit(1));
const Quantity Quantity::CentiMetre (10.0 ,Unit(1));
const Quantity Quantity::DeciMetre (100.0 ,Unit(1));
const Quantity Quantity::Metre (1.0e3 ,Unit(1));
const Quantity Quantity::KiloMetre (1.0e6 ,Unit(1));
Quantity Quantity::MilliLiter (1000.0 ,Unit(3));
Quantity Quantity::Liter (1.0e6 ,Unit(3));
const Quantity Quantity::MilliLiter (1000.0 ,Unit(3));
const Quantity Quantity::Liter (1.0e6 ,Unit(3));
Quantity Quantity::Hertz (1.0 ,Unit(0,0,-1));
Quantity Quantity::KiloHertz (1.0e3 ,Unit(0,0,-1));
Quantity Quantity::MegaHertz (1.0e6 ,Unit(0,0,-1));
Quantity Quantity::GigaHertz (1.0e9 ,Unit(0,0,-1));
Quantity Quantity::TeraHertz (1.0e12 ,Unit(0,0,-1));
const Quantity Quantity::Hertz (1.0 ,Unit(0,0,-1));
const Quantity Quantity::KiloHertz (1.0e3 ,Unit(0,0,-1));
const Quantity Quantity::MegaHertz (1.0e6 ,Unit(0,0,-1));
const Quantity Quantity::GigaHertz (1.0e9 ,Unit(0,0,-1));
const Quantity Quantity::TeraHertz (1.0e12 ,Unit(0,0,-1));
Quantity Quantity::MicroGram (1.0e-9 ,Unit(0,1));
Quantity Quantity::MilliGram (1.0e-6 ,Unit(0,1));
Quantity Quantity::Gram (1.0e-3 ,Unit(0,1));
Quantity Quantity::KiloGram (1.0 ,Unit(0,1));
Quantity Quantity::Ton (1.0e3 ,Unit(0,1));
const Quantity Quantity::MicroGram (1.0e-9 ,Unit(0,1));
const Quantity Quantity::MilliGram (1.0e-6 ,Unit(0,1));
const Quantity Quantity::Gram (1.0e-3 ,Unit(0,1));
const Quantity Quantity::KiloGram (1.0 ,Unit(0,1));
const Quantity Quantity::Ton (1.0e3 ,Unit(0,1));
Quantity Quantity::Second (1.0 ,Unit(0,0,1));
Quantity Quantity::Minute (60.0 ,Unit(0,0,1));
Quantity Quantity::Hour (3600.0 ,Unit(0,0,1));
const Quantity Quantity::Second (1.0 ,Unit(0,0,1));
const Quantity Quantity::Minute (60.0 ,Unit(0,0,1));
const Quantity Quantity::Hour (3600.0 ,Unit(0,0,1));
Quantity Quantity::Ampere (1.0 ,Unit(0,0,0,1));
Quantity Quantity::MilliAmpere (0.001 ,Unit(0,0,0,1));
Quantity Quantity::KiloAmpere (1000.0 ,Unit(0,0,0,1));
Quantity Quantity::MegaAmpere (1.0e6 ,Unit(0,0,0,1));
const Quantity Quantity::Ampere (1.0 ,Unit(0,0,0,1));
const Quantity Quantity::MilliAmpere (0.001 ,Unit(0,0,0,1));
const Quantity Quantity::KiloAmpere (1000.0 ,Unit(0,0,0,1));
const Quantity Quantity::MegaAmpere (1.0e6 ,Unit(0,0,0,1));
Quantity Quantity::Kelvin (1.0 ,Unit(0,0,0,0,1));
Quantity Quantity::MilliKelvin (0.001 ,Unit(0,0,0,0,1));
Quantity Quantity::MicroKelvin (0.000001 ,Unit(0,0,0,0,1));
const Quantity Quantity::Kelvin (1.0 ,Unit(0,0,0,0,1));
const Quantity Quantity::MilliKelvin (0.001 ,Unit(0,0,0,0,1));
const Quantity Quantity::MicroKelvin (0.000001 ,Unit(0,0,0,0,1));
Quantity Quantity::MilliMole (0.001 ,Unit(0,0,0,0,0,1));
Quantity Quantity::Mole (1.0 ,Unit(0,0,0,0,0,1));
const Quantity Quantity::MilliMole (0.001 ,Unit(0,0,0,0,0,1));
const Quantity Quantity::Mole (1.0 ,Unit(0,0,0,0,0,1));
Quantity Quantity::Candela (1.0 ,Unit(0,0,0,0,0,0,1));
const Quantity Quantity::Candela (1.0 ,Unit(0,0,0,0,0,0,1));
Quantity Quantity::Inch (25.4 ,Unit(1));
Quantity Quantity::Foot (304.8 ,Unit(1));
Quantity Quantity::Thou (0.0254 ,Unit(1));
Quantity Quantity::Yard (914.4 ,Unit(1));
Quantity Quantity::Mile (1609344.0 ,Unit(1));
const Quantity Quantity::Inch (25.4 ,Unit(1));
const Quantity Quantity::Foot (304.8 ,Unit(1));
const Quantity Quantity::Thou (0.0254 ,Unit(1));
const Quantity Quantity::Yard (914.4 ,Unit(1));
const Quantity Quantity::Mile (1609344.0 ,Unit(1));
Quantity Quantity::MilePerHour (447.04 ,Unit(1,0,-1));
Quantity Quantity::SquareFoot (92903.04 ,Unit(2));
Quantity Quantity::CubicFoot (28316846.592 ,Unit(3));
const Quantity Quantity::MilePerHour (447.04 ,Unit(1,0,-1));
const Quantity Quantity::SquareFoot (92903.04 ,Unit(2));
const Quantity Quantity::CubicFoot (28316846.592 ,Unit(3));
Quantity Quantity::Pound (0.45359237 ,Unit(0,1));
Quantity Quantity::Ounce (0.0283495231 ,Unit(0,1));
Quantity Quantity::Stone (6.35029318 ,Unit(0,1));
Quantity Quantity::Hundredweights (50.80234544 ,Unit(0,1));
const Quantity Quantity::Pound (0.45359237 ,Unit(0,1));
const Quantity Quantity::Ounce (0.0283495231 ,Unit(0,1));
const Quantity Quantity::Stone (6.35029318 ,Unit(0,1));
const Quantity Quantity::Hundredweights (50.80234544 ,Unit(0,1));
Quantity Quantity::PoundForce (4448.22 ,Unit(1,1,-2)); // lbf are ~= 4.44822 Newton
const Quantity Quantity::PoundForce (4448.22 ,Unit(1,1,-2)); // lbf are ~= 4.44822 Newton
Quantity Quantity::Newton (1000.0 ,Unit(1,1,-2)); // Newton (kg*m/s^2)
Quantity Quantity::MilliNewton (1.0 ,Unit(1,1,-2));
Quantity Quantity::KiloNewton (1e+6 ,Unit(1,1,-2));
Quantity Quantity::MegaNewton (1e+9 ,Unit(1,1,-2));
const Quantity Quantity::Newton (1000.0 ,Unit(1,1,-2)); // Newton (kg*m/s^2)
const Quantity Quantity::MilliNewton (1.0 ,Unit(1,1,-2));
const Quantity Quantity::KiloNewton (1e+6 ,Unit(1,1,-2));
const Quantity Quantity::MegaNewton (1e+9 ,Unit(1,1,-2));
Quantity Quantity::NewtonPerMeter (1.00 ,Unit(0,1,-2)); //Newton per meter (N/m or kg/s^2)
Quantity Quantity::MilliNewtonPerMeter (1e-3 ,Unit(0,1,-2));
Quantity Quantity::KiloNewtonPerMeter (1e3 ,Unit(0,1,-2));
Quantity Quantity::MegaNewtonPerMeter (1e6 ,Unit(0,1,-2));
const Quantity Quantity::NewtonPerMeter (1.00 ,Unit(0,1,-2)); //Newton per meter (N/m or kg/s^2)
const Quantity Quantity::MilliNewtonPerMeter (1e-3 ,Unit(0,1,-2));
const Quantity Quantity::KiloNewtonPerMeter (1e3 ,Unit(0,1,-2));
const Quantity Quantity::MegaNewtonPerMeter (1e6 ,Unit(0,1,-2));
Quantity Quantity::Pascal (0.001 ,Unit(-1,1,-2)); // Pascal (kg/m/s^2 or N/m^2)
Quantity Quantity::KiloPascal (1.00 ,Unit(-1,1,-2));
Quantity Quantity::MegaPascal (1000.0 ,Unit(-1,1,-2));
Quantity Quantity::GigaPascal (1e+6 ,Unit(-1,1,-2));
const Quantity Quantity::Pascal (0.001 ,Unit(-1,1,-2)); // Pascal (kg/m/s^2 or N/m^2)
const Quantity Quantity::KiloPascal (1.00 ,Unit(-1,1,-2));
const Quantity Quantity::MegaPascal (1000.0 ,Unit(-1,1,-2));
const Quantity Quantity::GigaPascal (1e+6 ,Unit(-1,1,-2));
Quantity Quantity::MilliBar (0.1 ,Unit(-1,1,-2));
Quantity Quantity::Bar (100.0 ,Unit(-1,1,-2)); // 1 bar = 100 kPa
const Quantity Quantity::MilliBar (0.1 ,Unit(-1,1,-2));
const Quantity Quantity::Bar (100.0 ,Unit(-1,1,-2)); // 1 bar = 100 kPa
Quantity Quantity::Torr (101.325/760.0 ,Unit(-1,1,-2)); // Torr is a defined fraction of Pascal (kg/m/s^2 or N/m^2)
Quantity Quantity::mTorr (0.101325/760.0,Unit(-1,1,-2)); // Torr is a defined fraction of Pascal (kg/m/s^2 or N/m^2)
Quantity Quantity::yTorr (0.000101325/760.0 ,Unit(-1,1,-2)); // Torr is a defined fraction of Pascal (kg/m/s^2 or N/m^2)
const Quantity Quantity::Torr (101.325/760.0 ,Unit(-1,1,-2)); // Torr is a defined fraction of Pascal (kg/m/s^2 or N/m^2)
const Quantity Quantity::mTorr (0.101325/760.0,Unit(-1,1,-2)); // Torr is a defined fraction of Pascal (kg/m/s^2 or N/m^2)
const Quantity Quantity::yTorr (0.000101325/760.0 ,Unit(-1,1,-2)); // Torr is a defined fraction of Pascal (kg/m/s^2 or N/m^2)
Quantity Quantity::PSI (6.894744825494,Unit(-1,1,-2)); // pounds/in^2
Quantity Quantity::KSI (6894.744825494,Unit(-1,1,-2)); // 1000 x pounds/in^2
Quantity Quantity::MPSI (6894744.825494,Unit(-1,1,-2)); // 1000 ksi
const Quantity Quantity::PSI (6.894744825494,Unit(-1,1,-2)); // pounds/in^2
const Quantity Quantity::KSI (6894.744825494,Unit(-1,1,-2)); // 1000 x pounds/in^2
const Quantity Quantity::MPSI (6894744.825494,Unit(-1,1,-2)); // 1000 ksi
Quantity Quantity::Watt (1e+6 ,Unit(2,1,-3)); // Watt (kg*m^2/s^3)
Quantity Quantity::MilliWatt (1e+3 ,Unit(2,1,-3));
Quantity Quantity::KiloWatt (1e+9 ,Unit(2,1,-3));
Quantity Quantity::VoltAmpere (1e+6 ,Unit(2,1,-3)); // VoltAmpere (kg*m^2/s^3)
const Quantity Quantity::Watt (1e+6 ,Unit(2,1,-3)); // Watt (kg*m^2/s^3)
const Quantity Quantity::MilliWatt (1e+3 ,Unit(2,1,-3));
const Quantity Quantity::KiloWatt (1e+9 ,Unit(2,1,-3));
const Quantity Quantity::VoltAmpere (1e+6 ,Unit(2,1,-3)); // VoltAmpere (kg*m^2/s^3)
Quantity Quantity::Volt (1e+6 ,Unit(2,1,-3,-1)); // Volt (kg*m^2/A/s^3)
Quantity Quantity::MilliVolt (1e+3 ,Unit(2,1,-3,-1));
Quantity Quantity::KiloVolt (1e+9 ,Unit(2,1,-3,-1));
const Quantity Quantity::Volt (1e+6 ,Unit(2,1,-3,-1)); // Volt (kg*m^2/A/s^3)
const Quantity Quantity::MilliVolt (1e+3 ,Unit(2,1,-3,-1));
const Quantity Quantity::KiloVolt (1e+9 ,Unit(2,1,-3,-1));
Quantity Quantity::MegaSiemens (1.0 ,Unit(-2,-1,3,2));
Quantity Quantity::KiloSiemens (1e-3 ,Unit(-2,-1,3,2));
Quantity Quantity::Siemens (1e-6 ,Unit(-2,-1,3,2)); // Siemens (A^2*s^3/kg/m^2)
Quantity Quantity::MilliSiemens (1e-9 ,Unit(-2,-1,3,2));
Quantity Quantity::MicroSiemens (1e-12 ,Unit(-2,-1,3,2));
const Quantity Quantity::MegaSiemens (1.0 ,Unit(-2,-1,3,2));
const Quantity Quantity::KiloSiemens (1e-3 ,Unit(-2,-1,3,2));
const Quantity Quantity::Siemens (1e-6 ,Unit(-2,-1,3,2)); // Siemens (A^2*s^3/kg/m^2)
const Quantity Quantity::MilliSiemens (1e-9 ,Unit(-2,-1,3,2));
const Quantity Quantity::MicroSiemens (1e-12 ,Unit(-2,-1,3,2));
Quantity Quantity::Ohm (1e+6 ,Unit(2,1,-3,-2)); // Ohm (kg*m^2/A^2/s^3)
Quantity Quantity::KiloOhm (1e+9 ,Unit(2,1,-3,-2));
Quantity Quantity::MegaOhm (1e+12 ,Unit(2,1,-3,-2));
const Quantity Quantity::Ohm (1e+6 ,Unit(2,1,-3,-2)); // Ohm (kg*m^2/A^2/s^3)
const Quantity Quantity::KiloOhm (1e+9 ,Unit(2,1,-3,-2));
const Quantity Quantity::MegaOhm (1e+12 ,Unit(2,1,-3,-2));
Quantity Quantity::Coulomb (1.0 ,Unit(0,0,1,1)); // Coulomb (A*s)
const Quantity Quantity::Coulomb (1.0 ,Unit(0,0,1,1)); // Coulomb (A*s)
Quantity Quantity::Tesla (1.0 ,Unit(0,1,-2,-1)); // Tesla (kg/s^2/A)
Quantity Quantity::Gauss (1e-4 ,Unit(0,1,-2,-1)); // 1 G = 1e-4 T
const Quantity Quantity::Tesla (1.0 ,Unit(0,1,-2,-1)); // Tesla (kg/s^2/A)
const Quantity Quantity::Gauss (1e-4 ,Unit(0,1,-2,-1)); // 1 G = 1e-4 T
Quantity Quantity::Weber (1e6 ,Unit(2,1,-2,-1)); // Weber (kg*m^2/s^2/A)
const Quantity Quantity::Weber (1e6 ,Unit(2,1,-2,-1)); // Weber (kg*m^2/s^2/A)
// disable Oersted because people need to input e.g. a field strength of
// 1 ampere per meter -> 1 A/m and not get the recalculation to Oersted
//Quantity Quantity::Oersted(0.07957747, Unit(-1, 0, 0, 1));// Oersted (A/m)
//const Quantity Quantity::Oersted(0.07957747, Unit(-1, 0, 0, 1));// Oersted (A/m)
Quantity Quantity::PicoFarad (1e-18 ,Unit(-2,-1,4,2));
Quantity Quantity::NanoFarad (1e-15 ,Unit(-2,-1,4,2));
Quantity Quantity::MicroFarad (1e-12 ,Unit(-2,-1,4,2));
Quantity Quantity::MilliFarad (1e-9 ,Unit(-2,-1,4,2));
Quantity Quantity::Farad (1e-6 ,Unit(-2,-1,4,2)); // Farad (s^4*A^2/m^2/kg)
const Quantity Quantity::PicoFarad (1e-18 ,Unit(-2,-1,4,2));
const Quantity Quantity::NanoFarad (1e-15 ,Unit(-2,-1,4,2));
const Quantity Quantity::MicroFarad (1e-12 ,Unit(-2,-1,4,2));
const Quantity Quantity::MilliFarad (1e-9 ,Unit(-2,-1,4,2));
const Quantity Quantity::Farad (1e-6 ,Unit(-2,-1,4,2)); // Farad (s^4*A^2/m^2/kg)
Quantity Quantity::NanoHenry (1e-3 ,Unit(2,1,-2,-2));
Quantity Quantity::MicroHenry (1.0 ,Unit(2,1,-2,-2));
Quantity Quantity::MilliHenry (1e+3 ,Unit(2,1,-2,-2));
Quantity Quantity::Henry (1e+6 ,Unit(2,1,-2,-2)); // Henry (kg*m^2/s^2/A^2)
const Quantity Quantity::NanoHenry (1e-3 ,Unit(2,1,-2,-2));
const Quantity Quantity::MicroHenry (1.0 ,Unit(2,1,-2,-2));
const Quantity Quantity::MilliHenry (1e+3 ,Unit(2,1,-2,-2));
const Quantity Quantity::Henry (1e+6 ,Unit(2,1,-2,-2)); // Henry (kg*m^2/s^2/A^2)
Quantity Quantity::Joule (1e+6 ,Unit(2,1,-2)); // Joule (kg*m^2/s^2)
Quantity Quantity::MilliJoule (1e+3 ,Unit(2,1,-2));
Quantity Quantity::KiloJoule (1e+9 ,Unit(2,1,-2));
Quantity Quantity::NewtonMeter (1e+6 ,Unit(2,1,-2)); // Joule (kg*m^2/s^2)
Quantity Quantity::VoltAmpereSecond (1e+6 ,Unit(2,1,-2)); // Joule (kg*m^2/s^2)
Quantity Quantity::WattSecond (1e+6 ,Unit(2,1,-2)); // Joule (kg*m^2/s^2)
Quantity Quantity::KiloWattHour (3.6e+12 ,Unit(2,1,-2)); // 1 kWh = 3.6e6 J
Quantity Quantity::ElectronVolt (1.602176634e-13 ,Unit(2,1,-2)); // 1 eV = 1.602176634e-19 J
Quantity Quantity::KiloElectronVolt (1.602176634e-10 ,Unit(2,1,-2));
Quantity Quantity::MegaElectronVolt (1.602176634e-7 ,Unit(2,1,-2));
Quantity Quantity::Calorie (4.1868e+6 ,Unit(2,1,-2)); // 1 cal = 4.1868 J
Quantity Quantity::KiloCalorie (4.1868e+9 ,Unit(2,1,-2));
const Quantity Quantity::Joule (1e+6 ,Unit(2,1,-2)); // Joule (kg*m^2/s^2)
const Quantity Quantity::MilliJoule (1e+3 ,Unit(2,1,-2));
const Quantity Quantity::KiloJoule (1e+9 ,Unit(2,1,-2));
const Quantity Quantity::NewtonMeter (1e+6 ,Unit(2,1,-2)); // Joule (kg*m^2/s^2)
const Quantity Quantity::VoltAmpereSecond (1e+6 ,Unit(2,1,-2)); // Joule (kg*m^2/s^2)
const Quantity Quantity::WattSecond (1e+6 ,Unit(2,1,-2)); // Joule (kg*m^2/s^2)
const Quantity Quantity::KiloWattHour (3.6e+12 ,Unit(2,1,-2)); // 1 kWh = 3.6e6 J
const Quantity Quantity::ElectronVolt (1.602176634e-13 ,Unit(2,1,-2)); // 1 eV = 1.602176634e-19 J
const Quantity Quantity::KiloElectronVolt (1.602176634e-10 ,Unit(2,1,-2));
const Quantity Quantity::MegaElectronVolt (1.602176634e-7 ,Unit(2,1,-2));
const Quantity Quantity::Calorie (4.1868e+6 ,Unit(2,1,-2)); // 1 cal = 4.1868 J
const Quantity Quantity::KiloCalorie (4.1868e+9 ,Unit(2,1,-2));
Quantity Quantity::KMH (277.778 ,Unit(1,0,-1)); // km/h
Quantity Quantity::MPH (447.04 ,Unit(1,0,-1)); // Mile/h
const Quantity Quantity::KMH (277.778 ,Unit(1,0,-1)); // km/h
const Quantity Quantity::MPH (447.04 ,Unit(1,0,-1)); // Mile/h
Quantity Quantity::AngMinute (1.0/60.0 ,Unit(0,0,0,0,0,0,0,1)); // angular minute
Quantity Quantity::AngSecond (1.0/3600.0 ,Unit(0,0,0,0,0,0,0,1)); // angular second
Quantity Quantity::Degree (1.0 ,Unit(0,0,0,0,0,0,0,1)); // degree (internal standard angle)
Quantity Quantity::Radian (180/M_PI ,Unit(0,0,0,0,0,0,0,1)); // radian
Quantity Quantity::Gon (360.0/400.0 ,Unit(0,0,0,0,0,0,0,1)); // gon
const Quantity Quantity::AngMinute (1.0/60.0 ,Unit(0,0,0,0,0,0,0,1)); // angular minute
const Quantity Quantity::AngSecond (1.0/3600.0 ,Unit(0,0,0,0,0,0,0,1)); // angular second
const Quantity Quantity::Degree (1.0 ,Unit(0,0,0,0,0,0,0,1)); // degree (internal standard angle)
const Quantity Quantity::Radian (180/M_PI ,Unit(0,0,0,0,0,0,0,1)); // radian
const Quantity Quantity::Gon (360.0/400.0 ,Unit(0,0,0,0,0,0,0,1)); // gon
@@ -437,31 +444,39 @@ Quantity Quantity::Gon (360.0/400.0 ,Unit(0,0,0,0,0,0,0,1)); // g
// include the Scanner and the Parser for the 'Quantity's
// NOLINTNEXTLINE
Quantity QuantResult;
/* helper function for tuning number strings with groups in a locale agnostic way... */
double num_change(char* yytext,char dez_delim,char grp_delim)
// NOLINTBEGIN
double num_change(char* yytext, char dez_delim, char grp_delim)
{
double ret_val;
char temp[40];
int i = 0;
for (char* c=yytext;*c!='\0';c++) {
double ret_val{};
const int num = 40;
std::array<char, num> temp{};
int iter = 0;
for (char* ch = yytext; *ch != '\0'; ch++) {
// skip group delimiter
if (*c==grp_delim) continue;
if (*ch == grp_delim)
continue;
// check for a dez delimiter other then dot
if (*c==dez_delim && dez_delim !='.')
temp[i++] = '.';
else
temp[i++] = *c;
if (*ch == dez_delim && dez_delim != '.') {
temp[iter++] = '.';
}
else {
temp[iter++] = *ch;
}
// check buffer overflow
if (i>39)
if (iter >= num)
return 0.0;
}
temp[i] = '\0';
ret_val = atof( temp );
temp[iter] = '\0';
ret_val = atof(temp.data());
return ret_val;
}
// NOLINTEND
#if defined(__clang__)
# pragma clang diagnostic push
@@ -491,16 +506,19 @@ void Quantity_yyerror(char *errorinfo)
namespace QuantityParser {
// NOLINTNEXTLINE
#define YYINITDEPTH 20
// show parser the lexer method
#define yylex QuantityLexer
int QuantityLexer();
// Parser, defined in QuantityParser.y
// NOLINTNEXTLINE
#include "QuantityParser.c"
#ifndef DOXYGEN_SHOULD_SKIP_THIS
// Scanner, defined in QuantityParser.l
// NOLINTNEXTLINE
#include "QuantityLexer.c"
#endif // DOXYGEN_SHOULD_SKIP_THIS
}
+149 -141
View File
@@ -27,12 +27,14 @@
#include "Unit.h"
#include <QString>
// NOLINTBEGIN
#ifndef DOUBLE_MAX
# define DOUBLE_MAX 1.7976931348623157E+308 /* max decimal value of a "double"*/
#endif
#ifndef DOUBLE_MIN
# define DOUBLE_MIN 2.2250738585072014E-308 /* min decimal value of a "double"*/
#endif
// NOLINTEND
namespace Base {
class UnitsSchema;
@@ -57,6 +59,7 @@ struct BaseExport QuantityFormat {
// Default denominator of minimum fractional inch. Only used in certain
// schemas.
// NOLINTNEXTLINE
static int defaultDenominator; // i.e 8 for 1/8"
static inline int getDefaultDenominator() {
@@ -75,7 +78,7 @@ struct BaseExport QuantityFormat {
denominator = denom;
}
QuantityFormat();
QuantityFormat(NumberFormat format, int decimals=-1);
explicit QuantityFormat(NumberFormat format, int decimals=-1);
inline char toFormat() const {
switch (format) {
case Fixed:
@@ -86,10 +89,11 @@ struct BaseExport QuantityFormat {
return 'g';
}
}
static inline NumberFormat toFormat(char c, bool* ok = nullptr) {
if (ok)
static inline NumberFormat toFormat(char ch, bool* ok = nullptr) {
if (ok) {
*ok = true;
switch (c) {
}
switch (ch) {
case 'f':
return Fixed;
case 'e':
@@ -97,8 +101,9 @@ struct BaseExport QuantityFormat {
case 'g':
return Default;
default:
if (ok)
if (ok) {
*ok = false;
}
return Default;
}
}
@@ -112,7 +117,8 @@ class BaseExport Quantity
public:
/// default constructor
Quantity();
Quantity(const Quantity&);
Quantity(const Quantity&) = default;
Quantity(Quantity&&) = default;
explicit Quantity(double value, const Unit& unit=Unit());
explicit Quantity(double value, const QString& unit);
/// Destruction
@@ -120,37 +126,39 @@ public:
/** Operators. */
//@{
Quantity operator *(const Quantity &p) const;
Quantity operator *(double p) const;
Quantity operator +(const Quantity &p) const;
Quantity& operator +=(const Quantity &p);
Quantity operator -(const Quantity &p) const;
Quantity& operator -=(const Quantity &p);
Quantity operator *(const Quantity &other) const;
Quantity operator *(double factor) const;
Quantity operator +(const Quantity &other) const;
Quantity& operator +=(const Quantity &other);
Quantity operator -(const Quantity &other) const;
Quantity& operator -=(const Quantity &other);
Quantity operator -() const;
Quantity operator /(const Quantity &p) const;
Quantity operator /(double p) const;
Quantity operator /(const Quantity &other) const;
Quantity operator /(double factor) const;
bool operator ==(const Quantity&) const;
bool operator !=(const Quantity&) const;
bool operator < (const Quantity&) const;
bool operator > (const Quantity&) const;
bool operator <= (const Quantity&) const;
bool operator >= (const Quantity&) const;
Quantity& operator =(const Quantity&);
Quantity& operator =(const Quantity&) = default;
Quantity& operator =(Quantity&&) = default;
Quantity pow(const Quantity&)const;
Quantity pow(double)const;
//@}
const QuantityFormat& getFormat() const {
return _Format;
return myFormat;
}
void setFormat(const QuantityFormat& f) {
_Format = f;
void setFormat(const QuantityFormat& fmt) {
myFormat = fmt;
}
/// transfer to user preferred unit/potence
QString getUserString(double &factor, QString &unitString) const;
QString getUserString() const { // to satisfy GCC
double dummy1;
QString dummy2;
return getUserString(dummy1,dummy2);
double dummy1{};
QString dummy2{};
return getUserString(dummy1, dummy2);
}
QString getUserString(UnitsSchema* schema, double &factor, QString &unitString) const;
QString getSafeUserString() const;
@@ -158,13 +166,13 @@ public:
static Quantity parse(const QString &string);
/// returns the unit of the quantity
const Unit & getUnit() const{return _Unit;}
const Unit & getUnit() const{return myUnit;}
/// set the unit of the quantity
void setUnit(const Unit &un){_Unit = un;}
void setUnit(const Unit &un){myUnit = un;}
/// get the Value of the quantity
double getValue() const{return _Value;}
double getValue() const{return myValue;}
/// set the value of the quantity
void setValue(double val){_Value = val;}
void setValue(double val){myValue = val;}
/** get the Value in a special unit given as quantity.
* One can use one of the predifeined quantity units in this class
*/
@@ -183,157 +191,157 @@ public:
/** Predefined Unit types. */
//@{
static Quantity NanoMetre;
static Quantity MicroMetre;
static Quantity CentiMetre;
static Quantity DeciMetre;
static Quantity Metre;
static Quantity MilliMetre;
static Quantity KiloMetre;
static const Quantity NanoMetre;
static const Quantity MicroMetre;
static const Quantity CentiMetre;
static const Quantity DeciMetre;
static const Quantity Metre;
static const Quantity MilliMetre;
static const Quantity KiloMetre;
static Quantity Liter;
static Quantity MilliLiter;
static const Quantity Liter;
static const Quantity MilliLiter;
static Quantity Hertz;
static Quantity KiloHertz;
static Quantity MegaHertz;
static Quantity GigaHertz;
static Quantity TeraHertz;
static const Quantity Hertz;
static const Quantity KiloHertz;
static const Quantity MegaHertz;
static const Quantity GigaHertz;
static const Quantity TeraHertz;
static Quantity MicroGram;
static Quantity MilliGram;
static Quantity Gram;
static Quantity KiloGram;
static Quantity Ton;
static const Quantity MicroGram;
static const Quantity MilliGram;
static const Quantity Gram;
static const Quantity KiloGram;
static const Quantity Ton;
static Quantity Second;
static Quantity Minute;
static Quantity Hour;
static const Quantity Second;
static const Quantity Minute;
static const Quantity Hour;
static Quantity Ampere;
static Quantity MilliAmpere;
static Quantity KiloAmpere;
static Quantity MegaAmpere;
static const Quantity Ampere;
static const Quantity MilliAmpere;
static const Quantity KiloAmpere;
static const Quantity MegaAmpere;
static Quantity Kelvin;
static Quantity MilliKelvin;
static Quantity MicroKelvin;
static const Quantity Kelvin;
static const Quantity MilliKelvin;
static const Quantity MicroKelvin;
static Quantity MilliMole;
static Quantity Mole;
static const Quantity MilliMole;
static const Quantity Mole;
static Quantity Candela;
static const Quantity Candela;
static Quantity Inch;
static Quantity Foot;
static Quantity Thou;
static Quantity Yard;
static const Quantity Inch;
static const Quantity Foot;
static const Quantity Thou;
static const Quantity Yard;
static Quantity Pound;
static Quantity Ounce;
static Quantity Stone;
static Quantity Hundredweights;
static Quantity Mile;
static const Quantity Pound;
static const Quantity Ounce;
static const Quantity Stone;
static const Quantity Hundredweights;
static const Quantity Mile;
static Quantity MilePerHour;
static Quantity SquareFoot;
static Quantity CubicFoot;
static const Quantity MilePerHour;
static const Quantity SquareFoot;
static const Quantity CubicFoot;
static Quantity PoundForce;
static const Quantity PoundForce;
static Quantity Newton;
static Quantity MilliNewton;
static Quantity KiloNewton;
static Quantity MegaNewton;
static const Quantity Newton;
static const Quantity MilliNewton;
static const Quantity KiloNewton;
static const Quantity MegaNewton;
static Quantity NewtonPerMeter;
static Quantity MilliNewtonPerMeter;
static Quantity KiloNewtonPerMeter;
static Quantity MegaNewtonPerMeter;
static const Quantity NewtonPerMeter;
static const Quantity MilliNewtonPerMeter;
static const Quantity KiloNewtonPerMeter;
static const Quantity MegaNewtonPerMeter;
static Quantity Pascal;
static Quantity KiloPascal;
static Quantity MegaPascal;
static Quantity GigaPascal;
static const Quantity Pascal;
static const Quantity KiloPascal;
static const Quantity MegaPascal;
static const Quantity GigaPascal;
static Quantity Bar;
static Quantity MilliBar;
static const Quantity Bar;
static const Quantity MilliBar;
static Quantity Torr;
static Quantity mTorr;
static Quantity yTorr;
static const Quantity Torr;
static const Quantity mTorr;
static const Quantity yTorr;
static Quantity PSI;
static Quantity KSI;
static Quantity MPSI;
static const Quantity PSI;
static const Quantity KSI;
static const Quantity MPSI;
static Quantity Watt;
static Quantity MilliWatt;
static Quantity KiloWatt;
static Quantity VoltAmpere;
static const Quantity Watt;
static const Quantity MilliWatt;
static const Quantity KiloWatt;
static const Quantity VoltAmpere;
static Quantity Volt;
static Quantity MilliVolt;
static Quantity KiloVolt;
static const Quantity Volt;
static const Quantity MilliVolt;
static const Quantity KiloVolt;
static Quantity MegaSiemens;
static Quantity KiloSiemens;
static Quantity Siemens;
static Quantity MilliSiemens;
static Quantity MicroSiemens;
static const Quantity MegaSiemens;
static const Quantity KiloSiemens;
static const Quantity Siemens;
static const Quantity MilliSiemens;
static const Quantity MicroSiemens;
static Quantity Ohm;
static Quantity KiloOhm;
static Quantity MegaOhm;
static const Quantity Ohm;
static const Quantity KiloOhm;
static const Quantity MegaOhm;
static Quantity Coulomb;
static const Quantity Coulomb;
static Quantity Tesla;
static Quantity Gauss;
static const Quantity Tesla;
static const Quantity Gauss;
static Quantity Weber;
static const Quantity Weber;
//static Quantity Oersted;
//static const Quantity Oersted;
static Quantity Farad;
static Quantity MilliFarad;
static Quantity MicroFarad;
static Quantity NanoFarad;
static Quantity PicoFarad;
static const Quantity Farad;
static const Quantity MilliFarad;
static const Quantity MicroFarad;
static const Quantity NanoFarad;
static const Quantity PicoFarad;
static Quantity Henry;
static Quantity MilliHenry;
static Quantity MicroHenry;
static Quantity NanoHenry;
static const Quantity Henry;
static const Quantity MilliHenry;
static const Quantity MicroHenry;
static const Quantity NanoHenry;
static Quantity Joule;
static Quantity MilliJoule;
static Quantity KiloJoule;
static Quantity NewtonMeter;
static Quantity VoltAmpereSecond;
static Quantity WattSecond;
static Quantity KiloWattHour;
static Quantity ElectronVolt;
static Quantity KiloElectronVolt;
static Quantity MegaElectronVolt;
static Quantity Calorie;
static Quantity KiloCalorie;
static const Quantity Joule;
static const Quantity MilliJoule;
static const Quantity KiloJoule;
static const Quantity NewtonMeter;
static const Quantity VoltAmpereSecond;
static const Quantity WattSecond;
static const Quantity KiloWattHour;
static const Quantity ElectronVolt;
static const Quantity KiloElectronVolt;
static const Quantity MegaElectronVolt;
static const Quantity Calorie;
static const Quantity KiloCalorie;
static Quantity KMH;
static Quantity MPH;
static const Quantity KMH;
static const Quantity MPH;
static Quantity Degree;
static Quantity Radian;
static Quantity Gon;
static Quantity AngMinute;
static Quantity AngSecond;
static const Quantity Degree;
static const Quantity Radian;
static const Quantity Gon;
static const Quantity AngMinute;
static const Quantity AngSecond;
//@}
protected:
double _Value;
Unit _Unit;
QuantityFormat _Format;
double myValue;
Unit myUnit;
QuantityFormat myFormat;
};
} // namespace Base
+35 -10
View File
@@ -220,32 +220,55 @@ void Rotation::setValue(const double q[4])
void Rotation::setValue(const Matrix4D & m)
{
double trace = (m[0][0] + m[1][1] + m[2][2]);
auto type = m.hasScale();
if (type == Base::ScaleType::Other) {
THROWM(Base::ValueError, "setValue(matrix): Could not determine the rotation.");
}
Matrix4D mc(m);
if (type != Base::ScaleType::NoScaling) {
mc.setCol(3, Vector3d(0.0, 0.0, 0.0));
if (type == Base::ScaleType::NonUniformRight) {
mc.transpose();
}
double sx = 1.0 / mc.getRow(0).Length();
double sy = 1.0 / mc.getRow(1).Length();
double sz = 1.0 / mc.getRow(2).Length();
mc.scale(sx, sy, sz);
if (type == Base::ScaleType::NonUniformRight) {
mc.transpose();
}
if (mc.determinant3() < 0.0) {
mc.scale(-1.0, -1.0, -1.0);
}
}
// Extract quaternion
double trace = (mc[0][0] + mc[1][1] + mc[2][2]);
if (trace > 0.0) {
double s = sqrt(1.0+trace);
this->quat[3] = 0.5 * s;
s = 0.5 / s;
this->quat[0] = ((m[2][1] - m[1][2]) * s);
this->quat[1] = ((m[0][2] - m[2][0]) * s);
this->quat[2] = ((m[1][0] - m[0][1]) * s);
this->quat[0] = ((mc[2][1] - mc[1][2]) * s);
this->quat[1] = ((mc[0][2] - mc[2][0]) * s);
this->quat[2] = ((mc[1][0] - mc[0][1]) * s);
}
else {
// Described in RotationIssues.pdf from <http://www.geometrictools.com>
//
// Get the max. element of the trace
unsigned short i = 0;
if (m[1][1] > m[0][0]) i = 1;
if (m[2][2] > m[i][i]) i = 2;
if (mc[1][1] > mc[0][0]) i = 1;
if (mc[2][2] > mc[i][i]) i = 2;
unsigned short j = (i+1)%3;
unsigned short k = (i+2)%3;
double s = sqrt((m[i][i] - (m[j][j] + m[k][k])) + 1.0);
double s = sqrt((mc[i][i] - (mc[j][j] + mc[k][k])) + 1.0);
this->quat[i] = s * 0.5;
s = 0.5 / s;
this->quat[3] = ((m[k][j] - m[j][k]) * s);
this->quat[j] = ((m[j][i] + m[i][j]) * s);
this->quat[k] = ((m[k][i] + m[i][k]) * s);
this->quat[3] = ((mc[k][j] - mc[j][k]) * s);
this->quat[j] = ((mc[j][i] + mc[i][j]) * s);
this->quat[k] = ((mc[k][i] + mc[i][k]) * s);
}
this->evaluateVector();
@@ -752,6 +775,8 @@ bool Rotation::isSame(const Rotation& q, double tol) const
// This term can be simplified to
// 2 - 2*(x1*y1 + ... + x4*y4) so that for the equality we have to check
// 1 - tol/2 <= x1*y1 + ... + x4*y4
// This simplification only work if both quats are normalized
// Is it safe to assume that?
// Because a quaternion (x1,x2,x3,x4) is equal to (-x1,-x2,-x3,-x4) we use the
// absolute value of the scalar product
double dot = q.quat[0]*quat[0]+q.quat[1]*quat[1]+q.quat[2]*quat[2]+q.quat[3]*quat[3];
+40 -17
View File
@@ -92,8 +92,14 @@ int RotationPy::PyInit(PyObject* args, PyObject* kwds)
PyErr_Clear();
if (PyArg_ParseTuple(args, "O!", &(Base::MatrixPy::Type), &o)) {
getRotationPtr()->setValue(static_cast<Base::MatrixPy*>(o)->value());
return 0;
try {
getRotationPtr()->setValue(static_cast<Base::MatrixPy*>(o)->value());
return 0;
}
catch (const Base::Exception& e) {
PyErr_SetString(e.getPyExceptionType(), e.what());
return -1;
}
}
PyErr_Clear();
@@ -134,12 +140,18 @@ int RotationPy::PyInit(PyObject* args, PyObject* kwds)
&a31, &a32, &a33, &a34,
&a41, &a42, &a43, &a44))
{
Matrix4D mtx(a11, a12, a13, a14,
a21, a22, a23, a24,
a31, a32, a33, a34,
a41, a42, a43, a44);
getRotationPtr()->setValue(mtx);
return 0;
try {
Matrix4D mtx(a11, a12, a13, a14,
a21, a22, a23, a24,
a31, a32, a33, a34,
a41, a42, a43, a44);
getRotationPtr()->setValue(mtx);
return 0;
}
catch (const Base::Exception& e) {
PyErr_SetString(e.getPyExceptionType(), e.what());
return -1;
}
}
// try read a 3x3 matrix
@@ -149,15 +161,20 @@ int RotationPy::PyInit(PyObject* args, PyObject* kwds)
&a21, &a22, &a23,
&a31, &a32, &a33))
{
Matrix4D mtx(a11, a12, a13, a14,
a21, a22, a23, a24,
a31, a32, a33, a34,
a41, a42, a43, a44);
getRotationPtr()->setValue(mtx);
return 0;
try {
Matrix4D mtx(a11, a12, a13, a14,
a21, a22, a23, a24,
a31, a32, a33, a34,
a41, a42, a43, a44);
getRotationPtr()->setValue(mtx);
return 0;
}
catch (const Base::Exception& e) {
PyErr_SetString(e.getPyExceptionType(), e.what());
return -1;
}
}
PyErr_Clear();
PyObject *v1, *v2;
if (PyArg_ParseTuple(args, "O!O!", &(Base::VectorPy::Type), &v1,
@@ -485,8 +502,14 @@ int RotationPy::setCustomAttributes(const char* attr, PyObject* obj)
{
if (strcmp(attr, "Matrix") == 0) {
if (PyObject_TypeCheck(obj, &(MatrixPy::Type))) {
this->getRotationPtr()->setValue(*static_cast<MatrixPy*>(obj)->getMatrixPtr());
return 1;
try {
this->getRotationPtr()->setValue(*static_cast<MatrixPy*>(obj)->getMatrixPtr());
return 1;
}
catch (const Base::Exception& e) {
PyErr_SetString(e.getPyExceptionType(), e.what());
return -1;
}
}
}
else if (strcmp(attr, "Axes") == 0) {
+167 -129
View File
@@ -22,6 +22,8 @@
#include "PreCompiled.h"
#ifndef _PreComp_
# include <cmath>
# include <limits>
# include <sstream>
#endif
@@ -32,6 +34,23 @@
using namespace Base;
static inline void checkPow(UnitSignature sig, double exp)
{
auto isInt = [](double value) {
return std::fabs(std::round(value) - value) < std::numeric_limits<double>::epsilon();
};
if (!isInt(sig.Length * exp) ||
!isInt(sig.Mass * exp) ||
!isInt(sig.Time * exp) ||
!isInt(sig.ElectricCurrent * exp) ||
!isInt(sig.ThermodynamicTemperature * exp) ||
!isInt(sig.AmountOfSubstance * exp) ||
!isInt(sig.LuminousIntensity * exp) ||
!isInt(sig.Angle * exp)) {
throw Base::UnitsMismatchError("pow() of unit not possible");
}
}
static inline void checkRange(const char * op, int length, int mass, int time, int electricCurrent,
int thermodynamicTemperature, int amountOfSubstance, int luminousIntensity, int angle)
{
@@ -52,7 +71,7 @@ static inline void checkRange(const char * op, int length, int mass, int time, i
( amountOfSubstance < -(1 << (UnitSignatureAmountOfSubstanceBits - 1)) ) ||
( luminousIntensity < -(1 << (UnitSignatureLuminousIntensityBits - 1)) ) ||
( angle < -(1 << (UnitSignatureAngleBits - 1)) ) )
throw Base::OverflowError((std::string("Unit underflow in ") + std::string(op)).c_str());
throw Base::UnderflowError((std::string("Unit underflow in ") + std::string(op)).c_str());
}
Unit::Unit(int8_t Length,
@@ -119,27 +138,28 @@ Unit::Unit(const QString& expr)
}
}
Unit Unit::pow(signed char exp) const
Unit Unit::pow(double exp) const
{
checkPow(Sig, exp);
checkRange("pow()",
Sig.Length * exp,
Sig.Mass * exp,
Sig.Time * exp,
Sig.ElectricCurrent * exp,
Sig.ThermodynamicTemperature * exp,
Sig.AmountOfSubstance * exp,
Sig.LuminousIntensity * exp,
Sig.Angle * exp);
static_cast<int>(Sig.Length * exp),
static_cast<int>(Sig.Mass * exp),
static_cast<int>(Sig.Time * exp),
static_cast<int>(Sig.ElectricCurrent * exp),
static_cast<int>(Sig.ThermodynamicTemperature * exp),
static_cast<int>(Sig.AmountOfSubstance * exp),
static_cast<int>(Sig.LuminousIntensity * exp),
static_cast<int>(Sig.Angle * exp));
Unit result;
result.Sig.Length = Sig.Length * exp;
result.Sig.Mass = Sig.Mass * exp;
result.Sig.Time = Sig.Time * exp;
result.Sig.ElectricCurrent = Sig.ElectricCurrent * exp;
result.Sig.ThermodynamicTemperature = Sig.ThermodynamicTemperature * exp;
result.Sig.AmountOfSubstance = Sig.AmountOfSubstance * exp;
result.Sig.LuminousIntensity = Sig.LuminousIntensity * exp;
result.Sig.Angle = Sig.Angle * exp;
result.Sig.Length = static_cast<int8_t>(Sig.Length * exp);
result.Sig.Mass = static_cast<int8_t>(Sig.Mass * exp);
result.Sig.Time = static_cast<int8_t>(Sig.Time * exp);
result.Sig.ElectricCurrent = static_cast<int8_t>(Sig.ElectricCurrent * exp);
result.Sig.ThermodynamicTemperature = static_cast<int8_t>(Sig.ThermodynamicTemperature * exp);
result.Sig.AmountOfSubstance = static_cast<int8_t>(Sig.AmountOfSubstance * exp);
result.Sig.LuminousIntensity = static_cast<int8_t>(Sig.LuminousIntensity * exp);
result.Sig.Angle = static_cast<int8_t>(Sig.Angle * exp);
return result;
}
@@ -426,36 +446,58 @@ QString Unit::getString() const
QString Unit::getTypeString() const
{
if (*this == Unit::Length)
return QString::fromLatin1("Length");
if (*this == Unit::Area)
return QString::fromLatin1("Area");
if (*this == Unit::Volume)
return QString::fromLatin1("Volume");
if (*this == Unit::Mass)
return QString::fromLatin1("Mass");
if (*this == Unit::Angle)
return QString::fromLatin1("Angle");
if (*this == Unit::Density)
return QString::fromLatin1("Density");
if (*this == Unit::TimeSpan)
return QString::fromLatin1("TimeSpan");
if (*this == Unit::Frequency)
return QString::fromLatin1("Frequency");
if (*this == Unit::Velocity)
return QString::fromLatin1("Velocity");
if (*this == Unit::Acceleration)
return QString::fromLatin1("Acceleration");
if (*this == Unit::Temperature)
return QString::fromLatin1("Temperature");
if (*this == Unit::AmountOfSubstance)
return QString::fromLatin1("AmountOfSubstance");
if (*this == Unit::Angle)
return QString::fromLatin1("Angle");
if (*this == Unit::AngleOfFriction)
return QString::fromLatin1("AngleOfFriction");
if (*this == Unit::Area)
return QString::fromLatin1("Area");
if (*this == Unit::CurrentDensity)
return QString::fromLatin1("CurrentDensity");
if (*this == Unit::Density)
return QString::fromLatin1("Density");
if (*this == Unit::DissipationRate)
return QString::fromLatin1("DissipationRate");
if (*this == Unit::DynamicViscosity)
return QString::fromLatin1("DynamicViscosity");
if (*this == Unit::ElectricalCapacitance)
return QString::fromLatin1("ElectricalCapacitance");
if (*this == Unit::ElectricalConductance)
return QString::fromLatin1("ElectricalConductance");
if (*this == Unit::ElectricalConductivity)
return QString::fromLatin1("ElectricalConductivity");
if (*this == Unit::ElectricalInductance)
return QString::fromLatin1("ElectricalInductance");
if (*this == Unit::ElectricalResistance)
return QString::fromLatin1("ElectricalResistance");
if (*this == Unit::ElectricCharge)
return QString::fromLatin1("ElectricCharge");
if (*this == Unit::ElectricCurrent)
return QString::fromLatin1("ElectricCurrent");
if (*this == Unit::ElectricPotential)
return QString::fromLatin1("ElectricPotential");
if (*this == Unit::ElectricCharge)
return QString::fromLatin1("ElectricCharge");
if (*this == Unit::Frequency)
return QString::fromLatin1("Frequency");
if (*this == Unit::Force)
return QString::fromLatin1("Force");
if (*this == Unit::HeatFlux)
return QString::fromLatin1("HeatFlux");
if (*this == Unit::InverseArea)
return QString::fromLatin1("InverseArea");
if (*this == Unit::InverseLength)
return QString::fromLatin1("InverseLength");
if (*this == Unit::InverseVolume)
return QString::fromLatin1("InverseVolume");
if (*this == Unit::KinematicViscosity)
return QString::fromLatin1("KinematicViscosity");
if (*this == Unit::Length)
return QString::fromLatin1("Length");
if (*this == Unit::LuminousIntensity)
return QString::fromLatin1("LuminousIntensity");
if (*this == Unit::MagneticFieldStrength)
return QString::fromLatin1("MagneticFieldStrength");
if (*this == Unit::MagneticFlux)
@@ -464,111 +506,107 @@ QString Unit::getTypeString() const
return QString::fromLatin1("MagneticFluxDensity");
if (*this == Unit::Magnetization)
return QString::fromLatin1("Magnetization");
if (*this == Unit::ElectricalCapacitance)
return QString::fromLatin1("ElectricalCapacitance");
if (*this == Unit::ElectricalInductance)
return QString::fromLatin1("ElectricalInductance");
if (*this == Unit::ElectricalConductance)
return QString::fromLatin1("ElectricalConductance");
if (*this == Unit::ElectricalResistance)
return QString::fromLatin1("ElectricalResistance");
if (*this == Unit::ElectricalConductivity)
return QString::fromLatin1("ElectricalConductivity");
if (*this == Unit::AmountOfSubstance)
return QString::fromLatin1("AmountOfSubstance");
if (*this == Unit::LuminousIntensity)
return QString::fromLatin1("LuminousIntensity");
if (*this == Unit::Mass)
return QString::fromLatin1("Mass");
if (*this == Unit::Pressure)
return QString::fromLatin1("Pressure");
if (*this == Unit::Force)
return QString::fromLatin1("Force");
if (*this == Unit::Work)
return QString::fromLatin1("Work");
if (*this == Unit::Power)
return QString::fromLatin1("Power");
if (*this == Unit::Stiffness)
return QString::fromLatin1("Stiffness");
if (*this == Unit::ShearModulus)
return QString::fromLatin1("ShearModulus");
if (*this == Unit::SpecificEnergy)
return QString::fromLatin1("SpecificEnergy");
if (*this == Unit::SpecificHeat)
return QString::fromLatin1("SpecificHeat");
if (*this == Unit::Stiffness)
return QString::fromLatin1("Stiffness");
if (*this == Unit::Stress)
return QString::fromLatin1("Stress");
if (*this == Unit::Temperature)
return QString::fromLatin1("Temperature");
if (*this == Unit::ThermalConductivity)
return QString::fromLatin1("ThermalConductivity");
if (*this == Unit::ThermalExpansionCoefficient)
return QString::fromLatin1("ThermalExpansionCoefficient");
if (*this == Unit::VolumetricThermalExpansionCoefficient)
return QString::fromLatin1("VolumetricThermalExpansionCoefficient");
if (*this == Unit::SpecificHeat)
return QString::fromLatin1("SpecificHeat");
if (*this == Unit::ThermalTransferCoefficient)
return QString::fromLatin1("ThermalTransferCoefficient");
if (*this == Unit::HeatFlux)
return QString::fromLatin1("HeatFlux");
if (*this == Unit::DynamicViscosity)
return QString::fromLatin1("DynamicViscosity");
if (*this == Unit::KinematicViscosity)
return QString::fromLatin1("KinematicViscosity");
if (*this == Unit::TimeSpan)
return QString::fromLatin1("TimeSpan");
if (*this == Unit::UltimateTensileStrength)
return QString::fromLatin1("UltimateTensileStrength");
if (*this == Unit::VacuumPermittivity)
return QString::fromLatin1("VacuumPermittivity");
if (*this == Unit::Velocity)
return QString::fromLatin1("Velocity");
if (*this == Unit::Volume)
return QString::fromLatin1("Volume");
if (*this == Unit::VolumeFlowRate)
return QString::fromLatin1("VolumeFlowRate");
if (*this == Unit::VolumetricThermalExpansionCoefficient)
return QString::fromLatin1("VolumetricThermalExpansionCoefficient");
if (*this == Unit::Work)
return QString::fromLatin1("Work");
if (*this == Unit::YieldStrength)
return QString::fromLatin1("YieldStrength");
if (*this == Unit::YoungsModulus)
return QString::fromLatin1("YoungsModulus");
return QString();
}
Unit Unit::Length(1);
Unit Unit::Area(2);
Unit Unit::Volume(3);
Unit Unit::Mass(0,1);
// SI base units
Unit Unit::AmountOfSubstance (0, 0, 0, 0, 0, 1);
Unit Unit::ElectricCurrent (0, 0, 0, 1);
Unit Unit::Length (1);
Unit Unit::LuminousIntensity (0, 0, 0, 0, 0, 0, 1);
Unit Unit::Mass (0, 1);
Unit Unit::Temperature (0, 0, 0, 0, 1);
Unit Unit::TimeSpan (0, 0, 1);
// Angle, deg
Unit Unit::Angle (0,0,0,0,0,0,0,1);
Unit Unit::AngleOfFriction (0,0,0,0,0,0,0,1);
Unit Unit::Density(-3,1);
Unit Unit::TimeSpan(0,0,1);
Unit Unit::Frequency(0,0,-1);
Unit Unit::Velocity(1,0,-1);
Unit Unit::Acceleration(1,0,-2);
Unit Unit::Temperature(0,0,0,0,1);
Unit Unit::CurrentDensity(-2,0,0,1);
Unit Unit::ElectricCurrent(0,0,0,1);
Unit Unit::ElectricPotential(2,1,-3,-1);
Unit Unit::ElectricCharge(0,0,1,1);
Unit Unit::MagneticFieldStrength(-1,0,0,1);
Unit Unit::MagneticFlux(2,1,-2,-1);
Unit Unit::MagneticFluxDensity(0,1,-2,-1);
Unit Unit::Magnetization(-1,0,0,1);
Unit Unit::ElectricalCapacitance(-2,-1,4,2);
Unit Unit::ElectricalInductance(2,1,-2,-2);
Unit Unit::ElectricalConductance(-2,-1,3,2);
Unit Unit::ElectricalResistance(2,1,-3,-2);
Unit Unit::ElectricalConductivity(-3,-1,3,2);
Unit Unit::AmountOfSubstance(0,0,0,0,0,1);
Unit Unit::LuminousIntensity(0,0,0,0,0,0,1);
// Pressure, kg/m*s^2 or N/m^2 or PSI or MPa
Unit Unit::CompressiveStrength (-1,1,-2);
Unit Unit::Pressure (-1,1,-2);
Unit Unit::ShearModulus (-1,1,-2);
Unit Unit::Stress (-1,1,-2);
Unit Unit::UltimateTensileStrength (-1,1,-2);
Unit Unit::YieldStrength (-1,1,-2);
Unit Unit::YoungsModulus (-1,1,-2);
// Stiffness [kg/s^-2]
Unit Unit::Stiffness (0,1,-2);
Unit Unit::Force (1,1,-2);
Unit Unit::Work (2,1,-2);
Unit Unit::Power (2,1,-3);
Unit Unit::SpecificEnergy (2,0,-2);
Unit Unit::ThermalConductivity (1,1,-3,0,-1);
Unit Unit::ThermalExpansionCoefficient (0,0,0,0,-1);
Unit Unit::VolumetricThermalExpansionCoefficient (0,0,0,0,-1);
Unit Unit::SpecificHeat (2,0,-2,0,-1);
Unit Unit::ThermalTransferCoefficient (0,1,-3,0,-1);
Unit Unit::HeatFlux (0,1,-3,0,0);
Unit Unit::DynamicViscosity (-1,1,-1); // SI unit: kg/m/s
Unit Unit::KinematicViscosity (2,0,-1); // SI unit: m^2/s, https://en.wikipedia.org/wiki/Viscosity#Kinematic_viscosity
Unit Unit::VacuumPermittivity (-3,-1,4,2); // SI unit: A²*s⁴/kg/m³ https://en.wikipedia.org/wiki/Permittivity#Vacuum_permittivity
// all other units
Unit Unit::Acceleration (1, 0, -2);
Unit Unit::Angle (0, 0, 0, 0, 0, 0, 0, 1);
Unit Unit::AngleOfFriction (0, 0, 0, 0, 0, 0, 0, 1);
Unit Unit::Area (2);
Unit Unit::CompressiveStrength (-1, 1, -2);
Unit Unit::CurrentDensity (-2, 0, 0, 1);
Unit Unit::Density (-3, 1);
Unit Unit::DissipationRate (2, 0, -3); // https://cfd-online.com/Wiki/Turbulence_dissipation_rate
Unit Unit::DynamicViscosity (-1, 1, -1);
Unit Unit::ElectricalCapacitance (-2, -1, 4, 2);
Unit Unit::ElectricalConductance (-2, -1, 3, 2);
Unit Unit::ElectricalConductivity (-3, -1, 3, 2);
Unit Unit::ElectricalInductance (2, 1, -2, -2);
Unit Unit::ElectricalResistance (2, 1, -3, -2);
Unit Unit::ElectricCharge (0, 0, 1, 1);
Unit Unit::ElectricPotential (2, 1, -3, -1);
Unit Unit::Force (1, 1, -2);
Unit Unit::Frequency (0, 0, -1);
Unit Unit::HeatFlux (0, 1, -3, 0, 0);
Unit Unit::InverseArea (-2, 0, 0);
Unit Unit::InverseLength (-1, 0, 0);
Unit Unit::InverseVolume (-3, 0, 0);
Unit Unit::KinematicViscosity (2, 0, -1);
Unit Unit::MagneticFieldStrength (-1,0,0,1);
Unit Unit::MagneticFlux (2,1,-2,-1);
Unit Unit::MagneticFluxDensity (0,1,-2,-1);
Unit Unit::Magnetization (-1,0,0,1);
Unit Unit::Pressure (-1,1,-2);
Unit Unit::Power (2, 1, -3);
Unit Unit::ShearModulus (-1,1,-2);
Unit Unit::SpecificEnergy (2, 0, -2);
Unit Unit::SpecificHeat (2, 0, -2, 0, -1);
Unit Unit::Stiffness (0, 1, -2);
Unit Unit::Stress (-1,1,-2);
Unit Unit::ThermalConductivity (1, 1, -3, 0, -1);
Unit Unit::ThermalExpansionCoefficient(0, 0, 0, 0, -1);
Unit Unit::ThermalTransferCoefficient (0, 1, -3, 0, -1);
Unit Unit::UltimateTensileStrength (-1,1,-2);
Unit Unit::VacuumPermittivity (-3, -1, 4, 2);
Unit Unit::Velocity (1, 0, -1);
Unit Unit::Volume (3);
Unit Unit::VolumeFlowRate (3, 0, -1);
Unit Unit::VolumetricThermalExpansionCoefficient(0, 0, 0, 0, -1);
Unit Unit::Work (2, 1, -2);
Unit Unit::YieldStrength (-1,1,-2);
Unit Unit::YoungsModulus (-1,1,-2);
+10 -2
View File
@@ -59,7 +59,9 @@ class BaseExport Unit
{
public:
/// default constructor
Unit(int8_t Length,int8_t Mass=0,int8_t Time=0,int8_t ElectricCurrent=0,int8_t ThermodynamicTemperature=0,int8_t AmountOfSubstance=0,int8_t LuminousIntensity=0,int8_t Angle=0);
explicit Unit(int8_t Length,int8_t Mass=0,int8_t Time=0,int8_t ElectricCurrent=0,
int8_t ThermodynamicTemperature=0, int8_t AmountOfSubstance=0,
int8_t LuminousIntensity=0, int8_t Angle=0);
Unit();
Unit(const Unit&);
explicit Unit(const QString& expr);
@@ -76,7 +78,7 @@ public:
bool operator ==(const Unit&) const;
bool operator !=(const Unit&that) const {return !(*this == that);}
Unit& operator =(const Unit&);
Unit pow(signed char exp)const;
Unit pow(double exp)const;
//@}
/// get the unit signature
const UnitSignature & getSignature()const {return Sig;}
@@ -148,6 +150,12 @@ public:
static Unit DynamicViscosity;
static Unit KinematicViscosity;
static Unit VacuumPermittivity;
static Unit VolumeFlowRate;
static Unit DissipationRate;
static Unit InverseLength;
static Unit InverseArea;
static Unit InverseVolume;
//@}
protected:
+107 -14
View File
@@ -49,34 +49,34 @@ QString UnitsSchemaInternal::schemaTranslate(const Quantity &quant, double &fact
// = 10e6 * kg*mm/s^3/K
// now do special treatment on all cases seems necessary:
if (unit == Unit::Length) { // Length handling ============================
if (UnitValue < 0.000000001) {// smaller than 0.001 nm -> scientific notation
if (unit == Unit::Length) {// Length handling ============================
if (UnitValue < 1e-6) {// smaller than 0.001 nm -> scientific notation
unitString = QString::fromLatin1("mm");
factor = 1.0;
}
else if(UnitValue < 0.001) {
else if (UnitValue < 1e-3) {
unitString = QString::fromLatin1("nm");
factor = 1e-6;
}
else if (UnitValue < 0.1) {
unitString = QString::fromUtf8("\xC2\xB5m");
factor = 0.001;
factor = 1e-3;
}
else if (UnitValue < 10000.0) {
else if (UnitValue < 1e4) {
unitString = QString::fromLatin1("mm");
factor = 1.0;
}
else if (UnitValue < 10000000.0) {
else if (UnitValue < 1e7) {
unitString = QString::fromLatin1("m");
factor = 1000.0;
factor = 1e3;
}
else if (UnitValue < 100000000000.0) {
else if (UnitValue < 1e10) {
unitString = QString::fromLatin1("km");
factor = 1e6;
}
else { // bigger than 1000 km -> scientific notation
unitString = QString::fromLatin1("mm");
factor = 1.0;
else {// bigger than 1000 km -> scientific notation
unitString = QString::fromLatin1("m");
factor = 1e3;
}
}
else if (unit == Unit::Area) {
@@ -419,7 +419,8 @@ QString UnitsSchemaInternal::schemaTranslate(const Quantity &quant, double &fact
factor = 1e-15;
}
else if (UnitValue < 1e-9) {
unitString = QString::fromUtf8("\xC2\xB5""F"); // \x reads everything to the end, therefore split
// \x reads everything to the end, therefore split
unitString = QString::fromUtf8("\xC2\xB5""F");
factor = 1e-12;
}
else if (UnitValue < 1e-6) {
@@ -480,8 +481,8 @@ QString UnitsSchemaInternal::schemaTranslate(const Quantity &quant, double &fact
factor = 1.0;
}
else if (unit == Unit::DynamicViscosity) {
unitString = QString::fromLatin1("kg/(mm*s)");
factor = 1.0;
unitString = QString::fromLatin1("Pa*s");
factor = 0.001;
}
else if (unit == Unit::KinematicViscosity) {
if (UnitValue < 1e3) {
@@ -493,6 +494,98 @@ QString UnitsSchemaInternal::schemaTranslate(const Quantity &quant, double &fact
factor = 1e6;
}
}
else if (unit == Unit::VolumeFlowRate) {
if (UnitValue < 1e3) {
unitString = QString::fromLatin1("mm^3/s");
factor = 1.0;
}
else if (UnitValue < 1e6) {
unitString = QString::fromLatin1("ml/s");
factor = 1e3;
}
else if (UnitValue < 1e9) {
unitString = QString::fromLatin1("l/s");
factor = 1e6;
}
else {
unitString = QString::fromLatin1("m^3/s");
factor = 1e9;
}
}
else if (unit == Unit::DissipationRate) {
unitString = QString::fromLatin1("m^2/s^3");
factor = 1e6;
}
else if (unit == Unit::InverseLength) {
if (UnitValue < 1e-6) {// smaller than 0.001 1/km -> scientific notation
unitString = QString::fromLatin1("1/m");
factor = 1e-3;
}
else if (UnitValue < 1e-3) {
unitString = QString::fromLatin1("1/km");
factor = 1e-6;
}
else if (UnitValue < 1.0) {
unitString = QString::fromLatin1("1/m");
factor = 1e-3;
}
else if (UnitValue < 1e3) {
unitString = QString::fromLatin1("1/mm");
factor = 1.0;
}
else if (UnitValue < 1e6) {
unitString = QString::fromUtf8("1/\xC2\xB5m");
factor = 1e3;
}
else if (UnitValue < 1e9) {
unitString = QString::fromLatin1("1/nm");
factor = 1e6;
}
else {// larger -> scientific notation
unitString = QString::fromLatin1("1/m");
factor = 1e-3;
}
}
else if (unit == Unit::InverseArea) {
if (UnitValue < 1e-12) {// smaller than 0.001 1/km^2 -> scientific notation
unitString = QString::fromLatin1("1/m^2");
factor = 1e-6;
}
else if (UnitValue < 1e-6) {
unitString = QString::fromLatin1("1/km^2");
factor = 1e-12;
}
else if (UnitValue < 1.0) {
unitString = QString::fromLatin1("1/m^2");
factor = 1e-6;
}
else if (UnitValue < 1e2) {
unitString = QString::fromLatin1("1/cm^2");
factor = 1e-2;
}
else {
unitString = QString::fromLatin1("1/mm^2");
factor = 1.0;
}
}
else if (unit == Unit::InverseVolume) {
if (UnitValue < 1e-6) {
unitString = QString::fromLatin1("1/m^3");
factor = 1e-9;
}
else if (UnitValue < 1e-3) {
unitString = QString::fromLatin1("1/l");
factor = 1e-6;
}
else if (UnitValue < 1.0) {
unitString = QString::fromLatin1("1/ml");
factor = 1e-3;
}
else {
unitString = QString::fromLatin1("1/mm^3");
factor = 1.0;
}
}
else {
// default action for all cases without special treatment:
unitString = quant.getUnit().getString();
+120 -23
View File
@@ -41,34 +41,34 @@ QString UnitsSchemaMKS::schemaTranslate(const Quantity &quant, double &factor, Q
Unit unit = quant.getUnit();
// now do special treatment on all cases seems necessary:
if (unit == Unit::Length) { // Length handling ============================
if (UnitValue < 0.000000001) {// smaller then 0.001 nm -> scientific notation
unitString = QString::fromLatin1("m");
factor = 1000.0;
}
else if(UnitValue < 0.001) {
unitString = QString::fromLatin1("nm");
factor = 0.000001;
}
else if(UnitValue < 0.1) {
unitString = QString::fromUtf8("\xC2\xB5m");
factor = 0.001;
}
else if(UnitValue < 100.0) {
if (unit == Unit::Length) {// Length handling ============================
if (UnitValue < 1e-6) {// smaller than 0.001 nm -> scientific notation
unitString = QString::fromLatin1("mm");
factor = 1.0;
}
else if(UnitValue < 10000000.0) {
unitString = QString::fromLatin1("m");
factor = 1000.0;
else if (UnitValue < 1e-3) {
unitString = QString::fromLatin1("nm");
factor = 1e-6;
}
else if(UnitValue < 100000000000.0 ) {
else if (UnitValue < 0.1) {
unitString = QString::fromUtf8("\xC2\xB5m");
factor = 1e-3;
}
else if (UnitValue < 1e4) {
unitString = QString::fromLatin1("mm");
factor = 1.0;
}
else if (UnitValue < 1e7) {
unitString = QString::fromLatin1("m");
factor = 1e3;
}
else if (UnitValue < 1e10) {
unitString = QString::fromLatin1("km");
factor = 1000000.0;
factor = 1e6;
}
else { // bigger then 1000 km -> scientific notation
else {// bigger than 1000 km -> scientific notation
unitString = QString::fromLatin1("m");
factor = 1000.0;
factor = 1e3;
}
}
else if (unit == Unit::Area) {
@@ -367,7 +367,8 @@ QString UnitsSchemaMKS::schemaTranslate(const Quantity &quant, double &factor, Q
factor = 1e-15;
}
else if (UnitValue < 1e-9) {
unitString = QString::fromUtf8("\xC2\xB5""F"); // \x reads everything to the end, therefore split
// \x reads everything to the end, therefore split
unitString = QString::fromUtf8("\xC2\xB5""F");
factor = 1e-12;
}
else if (UnitValue < 1e-6) {
@@ -470,13 +471,109 @@ QString UnitsSchemaMKS::schemaTranslate(const Quantity &quant, double &factor, Q
factor = 1000.0;
}
else if (unit == Unit::DynamicViscosity) {
unitString = QString::fromLatin1("kg/(m*s)");
unitString = QString::fromLatin1("Pa*s");
factor = 0.001;
}
else if (unit == Unit::KinematicViscosity) {
unitString = QString::fromLatin1("m^2/s");
factor = 1e6;
}
else if (unit == Unit::VolumeFlowRate) {
if (UnitValue < 1e-3) { // smaller than 0.001 mm^3/s -> scientific notation
unitString = QString::fromLatin1("m^3/s");
factor = 1e9;
}
else if (UnitValue < 1e3) {
unitString = QString::fromLatin1("mm^3/s");
factor = 1.0;
}
else if (UnitValue < 1e6) {
unitString = QString::fromLatin1("ml/s");
factor = 1e3;
}
else if (UnitValue < 1e9) {
unitString = QString::fromLatin1("l/s");
factor = 1e6;
}
else {
unitString = QString::fromLatin1("m^3/s");
factor = 1e9;
}
}
else if (unit == Unit::DissipationRate) {
unitString = QString::fromLatin1("m^2/s^3");
factor = 1e6;
}
else if (unit == Unit::InverseLength) {
if (UnitValue < 1e-6) {// smaller than 0.001 1/km -> scientific notation
unitString = QString::fromLatin1("1/m");
factor = 1e-3;
}
else if (UnitValue < 1e-3) {
unitString = QString::fromLatin1("1/km");
factor = 1e-6;
}
else if (UnitValue < 1.0) {
unitString = QString::fromLatin1("1/m");
factor = 1e-3;
}
else if (UnitValue < 1e3) {
unitString = QString::fromLatin1("1/mm");
factor = 1.0;
}
else if (UnitValue < 1e6) {
unitString = QString::fromUtf8("1/\xC2\xB5m");
factor = 1e3;
}
else if (UnitValue < 1e9) {
unitString = QString::fromLatin1("1/nm");
factor = 1e6;
}
else {// larger -> scientific notation
unitString = QString::fromLatin1("1/m");
factor = 1e-3;
}
}
else if (unit == Unit::InverseArea) {
if (UnitValue < 1e-12) {// smaller than 0.001 1/km^2 -> scientific notation
unitString = QString::fromLatin1("1/m^2");
factor = 1e-6;
}
else if (UnitValue < 1e-6) {
unitString = QString::fromLatin1("1/km^2");
factor = 1e-12;
}
else if (UnitValue < 1.0) {
unitString = QString::fromLatin1("1/m^2");
factor = 1e-6;
}
else if (UnitValue < 1e2) {
unitString = QString::fromLatin1("1/cm^2");
factor = 1e-2;
}
else {
unitString = QString::fromLatin1("1/mm^2");
factor = 1.0;
}
}
else if (unit == Unit::InverseVolume) {
if (UnitValue < 1e-6) {
unitString = QString::fromLatin1("1/m^3");
factor = 1e-9;
}
else if (UnitValue < 1e-3) {
unitString = QString::fromLatin1("1/l");
factor = 1e-6;
}
else if (UnitValue < 1.0) {
unitString = QString::fromLatin1("1/ml");
factor = 1e-3;
}
else {
unitString = QString::fromLatin1("1/mm^3");
factor = 1.0;
}
}
else {
// default action for all cases without special treatment:
unitString = quant.getUnit().getString();
-192
View File
@@ -1,192 +0,0 @@
/* The following code declares classes to read from and write to
* file descriptore or file handles.
*
* See
* http://www.josuttis.com/cppcode
* for details and the latest version.
*
* - open:
* - integrating BUFSIZ on some systems?
* - optimized reading of multiple characters
* - stream for reading AND writing
* - i18n
*
* (C) Copyright Nicolai M. Josuttis 2001.
* Permission to copy, use, modify, sell and distribute this software
* is granted provided this copyright notice appears in all copies.
* This software is provided "as is" without express or implied
* warranty, and with no claim as to its suitability for any purpose.
*
* Aug 05, 2001
*/
#ifndef BOOST_FDSTREAM_HPP
#define BOOST_FDSTREAM_HPP
#include <istream>
#include <ostream>
#include <streambuf>
// for EOF:
#include <cstdio>
// for memcpy():
#include <cstring>
// low-level read and write functions
#ifdef _MSC_VER
# include <io.h>
#else
# include <unistd.h>
//extern "C" {
// int write (int fd, const char* buf, int num);
// int read (int fd, char* buf, int num);
//}
#endif
// BEGIN namespace BOOST
namespace boost {
/************************************************************
* fdostream
* - a stream that writes on a file descriptor
************************************************************/
class fdoutbuf : public std::streambuf {
protected:
int fd; // file descriptor
public:
// constructor
fdoutbuf (int _fd) : fd(_fd) {
}
protected:
// write one character
int_type overflow (int_type c) override {
if (c != EOF) {
char z = c;
#ifdef _MSC_VER
if (_write (fd, &z, 1) != 1) {
#else
if (write (fd, &z, 1) != 1) {
#endif
return EOF;
}
}
return c;
}
// write multiple characters
std::streamsize xsputn (const char* s,
std::streamsize num) override {
#ifdef _MSC_VER
return _write(fd,s,num);
#else
return write(fd,s,num);
#endif
}
};
class fdostream : public std::ostream {
protected:
fdoutbuf buf;
public:
fdostream (int fd) : std::ostream(0), buf(fd) {
rdbuf(&buf);
}
};
/************************************************************
* fdistream
* - a stream that writes on a file descriptor
************************************************************/
class fdinbuf : public std::streambuf {
protected:
int fd; // file descriptor
protected:
/* data buffer:
* - at most, pbSize characters in putback area plus
* - at most, bufSize characters in ordinary read buffer
*/
static const int pbSize = 4; // size of putback area
static const int bufSize = 1024; // size of the data buffer
char buffer[bufSize+pbSize]; // data buffer
public:
/* constructor
* - initialize file descriptor
* - initialize empty data buffer
* - no putback area
* => force underflow()
*/
fdinbuf (int _fd) : fd(_fd) {
setg (buffer+pbSize, // beginning of putback area
buffer+pbSize, // read position
buffer+pbSize); // end position
}
protected:
// insert new characters into the buffer
int_type underflow () override {
#ifndef _MSC_VER
using std::memcpy;
#endif
// is read position before end of buffer?
if (gptr() < egptr()) {
return *gptr();
}
/* process size of putback area
* - use number of characters read
* - but at most size of putback area
*/
int numPutback;
numPutback = gptr() - eback();
if (numPutback > pbSize) {
numPutback = pbSize;
}
/* copy up to pbSize characters previously read into
* the putback area
*/
memcpy (buffer+(pbSize-numPutback), gptr()-numPutback,
numPutback);
// read at most bufSize new characters
int num;
#ifdef _MSC_VER
num = _read (fd, buffer+pbSize, bufSize);
#else
num = read (fd, buffer+pbSize, bufSize);
#endif
if (num <= 0) {
// ERROR or EOF
return EOF;
}
// reset buffer pointers
setg (buffer+(pbSize-numPutback), // beginning of putback area
buffer+pbSize, // read position
buffer+pbSize+num); // end of buffer
// return next character
return *gptr();
}
};
class fdistream : public std::istream {
protected:
fdinbuf buf;
public:
fdistream (int fd) : std::istream(0), buf(fd) {
rdbuf(&buf);
}
};
} // END namespace boost
#endif /*BOOST_FDSTREAM_HPP*/
+17 -1
View File
@@ -221,7 +221,7 @@ void Action::setToolTip(const QString & text, const QString & title)
_tooltip = text;
_title = title;
_action->setToolTip(createToolTip(text,
title.isEmpty() ? _action->text() : title,
title.isEmpty() ? _action->text() : title,
_action->font(),
_action->shortcut().toString(QKeySequence::NativeText),
command()));
@@ -461,6 +461,14 @@ void ActionGroup::addTo(QWidget *widget)
item->setMenuRole(action()->menuRole());
menu->setTitle(action()->text());
menu->addActions(groupAction()->actions());
QObject::connect(menu, &QMenu::aboutToShow, [this, menu]() {
Q_EMIT aboutToShow(menu);
});
QObject::connect(menu, &QMenu::aboutToHide, [this, menu]() {
Q_EMIT aboutToHide(menu);
});
}
else if (widget->inherits("QToolBar")) {
widget->addAction(action());
@@ -471,6 +479,14 @@ void ActionGroup::addTo(QWidget *widget)
auto menu = new QMenu(tb);
menu->addActions(acts);
tb->setMenu(menu);
QObject::connect(menu, &QMenu::aboutToShow, [this, menu]() {
Q_EMIT aboutToShow(menu);
});
QObject::connect(menu, &QMenu::aboutToHide, [this, menu]() {
Q_EMIT aboutToHide(menu);
});
}
else {
widget->addActions(groupAction()->actions()); // no drop-down
+6
View File
@@ -161,6 +161,12 @@ public Q_SLOTS:
void onActivated (QAction*);
void onHovered (QAction*);
Q_SIGNALS:
/// When drop down menu is enabled, the signal is triggered just before hiding the menu
void aboutToHide(QMenu*);
/// When drop down menu is enabled, the signal is triggered just before showing the menu
void aboutToShow(QMenu*);
private:
QActionGroup* _group;
bool _dropDown;
+2
View File
@@ -812,6 +812,7 @@ SET(View3D_CPP_SRCS
View3DInventorSelection.cpp
View3DInventorViewer.cpp
View3DInventorRiftViewer.cpp
View3DSettings.cpp
CoinRiftWidget.cpp
View3DPy.cpp
View3DViewerPy.cpp
@@ -833,6 +834,7 @@ SET(View3D_SRCS
View3DInventorViewer.h
View3DPy.h
View3DInventorRiftViewer.h
View3DSettings.h
CoinRiftWidget.h
View3DViewerPy.h
NaviCube.h
+33 -33
View File
@@ -30,6 +30,7 @@
#include "ui_DlgEditor.h"
#include "PythonEditor.h"
#include "Tools.h"
#include <App/Color.h>
using namespace Gui;
@@ -96,63 +97,63 @@ DlgSettingsEditorImp::DlgSettingsEditorImp( QWidget* parent )
d = new DlgSettingsEditorP();
QColor col;
col = qApp->palette().windowText().color();
unsigned int lText = (col.red() << 24) | (col.green() << 16) | (col.blue() << 8);
unsigned int lText = App::Color::asPackedRGB<QColor>(col);
d->colormap.push_back(QPair<QString, unsigned int>
(QString::fromLatin1(QT_TR_NOOP("Text")), lText));
col = Qt::cyan;
unsigned int lBookmarks = (col.red() << 24) | (col.green() << 16) | (col.blue() << 8);
unsigned int lBookmarks = App::Color::asPackedRGB<QColor>(QColor(Qt::cyan));
d->colormap.push_back(QPair<QString, unsigned int>
(QString::fromLatin1(QT_TR_NOOP("Bookmark")), lBookmarks));
col = Qt::red;
unsigned int lBreakpnts = (col.red() << 24) | (col.green() << 16) | (col.blue() << 8);
unsigned int lBreakpnts = App::Color::asPackedRGB<QColor>(QColor(Qt::red));
d->colormap.push_back(QPair<QString, unsigned int>
(QString::fromLatin1(QT_TR_NOOP("Breakpoint")), lBreakpnts));
col = Qt::blue;
unsigned int lKeywords = (col.red() << 24) | (col.green() << 16) | (col.blue() << 8);
unsigned int lKeywords = App::Color::asPackedRGB<QColor>(QColor(Qt::blue));
d->colormap.push_back(QPair<QString, unsigned int>
(QString::fromLatin1(QT_TR_NOOP("Keyword")), lKeywords));
col.setRgb(0, 170, 0);
unsigned int lComments = (col.red() << 24) | (col.green() << 16) | (col.blue() << 8);
unsigned int lComments = App::Color::asPackedRGB<QColor>(QColor(0, 170, 0));
d->colormap.push_back(QPair<QString, unsigned int>
(QString::fromLatin1(QT_TR_NOOP("Comment")), lComments));
col.setRgb(160, 160, 164);
unsigned int lBlockCom = (col.red() << 24) | (col.green() << 16) | (col.blue() << 8);
unsigned int lBlockCom = App::Color::asPackedRGB<QColor>(QColor(160, 160, 164));
d->colormap.push_back(QPair<QString, unsigned int>
(QString::fromLatin1(QT_TR_NOOP("Block comment")), lBlockCom));
col = Qt::blue;
unsigned int lNumbers = (col.red() << 24) | (col.green() << 16) | (col.blue() << 8);
unsigned int lNumbers = App::Color::asPackedRGB<QColor>(QColor(Qt::blue));
d->colormap.push_back(QPair<QString, unsigned int>
(QString::fromLatin1(QT_TR_NOOP("Number")), lNumbers));
col = Qt::red;
unsigned int lStrings = (col.red() << 24) | (col.green() << 16) | (col.blue() << 8);
unsigned int lStrings = App::Color::asPackedRGB<QColor>(QColor(Qt::red));
d->colormap.push_back(QPair<QString, unsigned int>
(QString::fromLatin1(QT_TR_NOOP("String")), lStrings));
col = Qt::red;
unsigned int lCharacter = (col.red() << 24) | (col.green() << 16) | (col.blue() << 8);
unsigned int lCharacter = App::Color::asPackedRGB<QColor>(QColor(Qt::red));
d->colormap.push_back(QPair<QString, unsigned int>
(QString::fromLatin1(QT_TR_NOOP("Character")), lCharacter));
col.setRgb(255, 170, 0);
unsigned int lClass = (col.red() << 24) | (col.green() << 16) | (col.blue() << 8);
unsigned int lClass = App::Color::asPackedRGB<QColor>(QColor(255, 170, 0));
d->colormap.push_back(QPair<QString, unsigned int>
(QString::fromLatin1(QT_TR_NOOP("Class name")), lClass));
col.setRgb(255, 170, 0);
unsigned int lDefine = (col.red() << 24) | (col.green() << 16) | (col.blue() << 8);
unsigned int lDefine = App::Color::asPackedRGB<QColor>(QColor(255, 170, 0));
d->colormap.push_back(QPair<QString, unsigned int>
(QString::fromLatin1(QT_TR_NOOP("Define name")), lDefine));
col.setRgb(160, 160, 164);
unsigned int lOperat = (col.red() << 24) | (col.green() << 16) | (col.blue() << 8);
unsigned int lOperat = App::Color::asPackedRGB<QColor>(QColor(160, 160, 164));
d->colormap.push_back(QPair<QString, unsigned int>
(QString::fromLatin1(QT_TR_NOOP("Operator")), lOperat));
col.setRgb(170, 170, 127);
unsigned int lPyOutput = (col.red() << 24) | (col.green() << 16) | (col.blue() << 8);
unsigned int lPyOutput = App::Color::asPackedRGB<QColor>(QColor(170, 170, 127));
d->colormap.push_back(QPair<QString, unsigned int>
(QString::fromLatin1(QT_TR_NOOP("Python output")), lPyOutput));
col = Qt::red;
unsigned int lPyError = (col.red() << 24) | (col.green() << 16) | (col.blue() << 8);
unsigned int lPyError = App::Color::asPackedRGB<QColor>(QColor(Qt::red));
d->colormap.push_back(QPair<QString, unsigned int>
(QString::fromLatin1(QT_TR_NOOP("Python error")), lPyError));
col.setRgb(224, 224, 224);
unsigned int lCLine = (col.red() << 24) | (col.green() << 16) | (col.blue() << 8);
unsigned int lCLine = App::Color::asPackedRGB<QColor>(QColor(224, 224, 224));
d->colormap.push_back(QPair<QString, unsigned int>
(QString::fromLatin1(QT_TR_NOOP("Current line highlight")), lCLine));
@@ -183,14 +184,14 @@ void DlgSettingsEditorImp::on_displayItems_currentItemChanged(QTreeWidgetItem *i
{
int index = ui->displayItems->indexOfTopLevelItem(item);
unsigned int col = d->colormap[index].second;
ui->colorButton->setColor(QColor((col >> 24) & 0xff, (col >> 16) & 0xff, (col >> 8) & 0xff));
ui->colorButton->setColor(App::Color::fromPackedRGB<QColor>(col));
}
/** Updates the color map if a color was changed */
void DlgSettingsEditorImp::on_colorButton_changed()
{
QColor col = ui->colorButton->color();
unsigned int lcol = (col.red() << 24) | (col.green() << 16) | (col.blue() << 8);
unsigned int lcol = App::Color::asPackedRGB<QColor>(col);
int index = ui->displayItems->indexOfTopLevelItem(ui->displayItems->currentItem());
d->colormap[index].second = lcol;
@@ -262,8 +263,7 @@ void DlgSettingsEditorImp::loadSettings()
auto col = static_cast<unsigned long>((*it).second);
col = hGrp->GetUnsigned((*it).first.toLatin1(), col);
(*it).second = static_cast<unsigned int>(col);
QColor color;
color.setRgb((col >> 24) & 0xff, (col >> 16) & 0xff, (col >> 8) & 0xff);
QColor color = App::Color::fromPackedRGB<QColor>(col);
pythonSyntax->setColor((*it).first, color);
}
+2
View File
@@ -74,6 +74,8 @@ DlgPreferencesImp::DlgPreferencesImp(QWidget* parent, Qt::WindowFlags fl)
int length = QtTools::horizontalAdvance(fm, longestGroupName());
ui->listBox->setFixedWidth(Base::clamp<int>(length + 20, 108, 120));
ui->listBox->setGridSize(QSize(108, 75));
// remove unused help button
setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
connect(ui->buttonBox, &QDialogButtonBox::clicked,
this, &DlgPreferencesImp::onButtonBoxClicked);
+5 -6
View File
@@ -57,6 +57,7 @@ DlgSettingsNavigation::DlgSettingsNavigation(QWidget* parent)
, q0(0), q1(0), q2(0), q3(1)
{
ui->setupUi(this);
ui->naviCubeButtonColor->setAllowTransparency(true);
retranslate();
}
@@ -93,6 +94,7 @@ void DlgSettingsNavigation::saveSettings()
ui->naviCubeToNearest->onSave();
ui->prefCubeSize->onSave();
ui->naviCubeFontSize->onSave();
ui->naviCubeButtonColor->onSave();
bool showNaviCube = ui->groupBoxNaviCube->isChecked();
hGrp->SetBool("ShowNaviCube", showNaviCube);
@@ -141,6 +143,7 @@ void DlgSettingsNavigation::loadSettings()
ui->naviCubeToNearest->onRestore();
ui->prefCubeSize->onRestore();
ui->naviCubeFontSize->onRestore();
ui->naviCubeButtonColor->onRestore();
ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath
("User parameter:BaseApp/Preferences/View");
@@ -187,7 +190,7 @@ void DlgSettingsNavigation::loadSettings()
// fill up font styles
hGrp = App::GetApplication().GetParameterGroupByPath(
"User parameter:BaseApp/Preferences/NaviCube");
QByteArray defaultSansserifFont = NaviCube::getDefaultSansserifFont().family().toLatin1();
std::string defaultSansserifFont = NaviCube::getDefaultSansserifFont().toStdString();
// we purposely allow all available fonts on the system
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
@@ -197,12 +200,8 @@ void DlgSettingsNavigation::loadSettings()
#endif
ui->naviCubeFontName->addItems(familyNames);
// if the parameter has not yet been set, do so immediately
// this assures it is set even if the user cancels the dialog
if (hGrp->GetASCII("FontString", "").empty())
hGrp->SetASCII("FontString", defaultSansserifFont.constData());
int indexFamilyNames = familyNames.indexOf(
QString::fromStdString(hGrp->GetASCII("FontString", defaultSansserifFont)));
QString::fromStdString(hGrp->GetASCII("FontString", defaultSansserifFont.c_str())));
if (indexFamilyNames < 0)
indexFamilyNames = 0;
ui->naviCubeFontName->setCurrentIndex(indexFamilyNames);
+50 -12
View File
@@ -6,8 +6,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>500</width>
<height>394</height>
<width>432</width>
<height>423</height>
</rect>
</property>
<property name="windowTitle">
@@ -117,7 +117,7 @@
</item>
</widget>
</item>
<item row="2" column="0" colspan="2">
<item row="1" column="0" colspan="2">
<widget class="Gui::PrefCheckBox" name="naviCubeToNearest">
<property name="toolTip">
<string>Rotates to nearest possible state when clicking a cube face</string>
@@ -136,14 +136,14 @@
</property>
</widget>
</item>
<item row="2" column="3">
<widget class="QLabel" name="TextLabel3">
<item row="1" column="3">
<widget class="QLabel" name="FontNameLabel">
<property name="text">
<string>Font name:</string>
</property>
</widget>
</item>
<item row="2" column="4">
<item row="1" column="4">
<widget class="Gui::PrefComboBox" name="naviCubeFontName">
<property name="toolTip">
<string>Font name of the navigation cube</string>
@@ -159,14 +159,14 @@
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="label_3">
<item row="2" column="0">
<widget class="QLabel" name="CubeSizeLabel">
<property name="text">
<string>Cube size</string>
</property>
</widget>
</item>
<item row="3" column="1">
<item row="2" column="1">
<widget class="Gui::PrefSpinBox" name="prefCubeSize">
<property name="toolTip">
<string>Size of the navigation cube</string>
@@ -194,14 +194,14 @@
</property>
</widget>
</item>
<item row="3" column="3">
<widget class="QLabel" name="TextLabel4">
<item row="2" column="3">
<widget class="QLabel" name="FontSizeLabel">
<property name="text">
<string>Font size:</string>
</property>
</widget>
</item>
<item row="3" column="4">
<item row="2" column="4">
<widget class="Gui::PrefSpinBox" name="naviCubeFontSize">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
@@ -232,6 +232,34 @@
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="ButtonColorLabel">
<property name="text">
<string>Button color</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="Gui::PrefColorButton" name="naviCubeButtonColor">
<property name="toolTip">
<string>color for all elements
around the cube</string>
</property>
<property name="color">
<color alpha="128">
<red>226</red>
<green>232</green>
<blue>239</blue>
</color>
</property>
<property name="prefEntry" stdset="0">
<cstring>ButtonColor</cstring>
</property>
<property name="prefPath" stdset="0">
<cstring>NaviCube</cstring>
</property>
</widget>
</item>
</layout>
</widget>
</item>
@@ -640,11 +668,21 @@ Mouse tilting is not disabled by this setting.</string>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>Gui::ColorButton</class>
<extends>QPushButton</extends>
<header>Gui/Widgets.h</header>
</customwidget>
<customwidget>
<class>Gui::PrefSpinBox</class>
<extends>QSpinBox</extends>
<header>Gui/PrefWidgets.h</header>
</customwidget>
<customwidget>
<class>Gui::PrefColorButton</class>
<extends>Gui::ColorButton</extends>
<header>Gui/PrefWidgets.h</header>
</customwidget>
<customwidget>
<class>Gui::PrefCheckBox</class>
<extends>QCheckBox</extends>
+2 -2
View File
@@ -21,7 +21,6 @@
***************************************************************************/
#include "PreCompiled.h"
#ifndef _PreComp_
# include <QPushButton>
#endif
@@ -45,7 +44,8 @@ DlgSettingsViewColor::DlgSettingsViewColor(QWidget* parent)
ui->setupUi(this);
ui->HighlightColor->setEnabled(ui->checkBoxPreselection->isChecked());
ui->SelectionColor->setEnabled(ui->checkBoxSelection->isChecked());
connect(ui->SwitchGradientColors, &QPushButton::pressed, this, &DlgSettingsViewColor::onSwitchGradientColorsPressed);
connect(ui->SwitchGradientColors, &QPushButton::pressed, this,
&DlgSettingsViewColor::onSwitchGradientColorsPressed);
}
/**
+13 -4
View File
@@ -78,6 +78,8 @@ DlgUnitsCalculator::DlgUnitsCalculator( QWidget* parent, Qt::WindowFlags fl )
<< Base::Unit::Area
<< Base::Unit::Density
<< Base::Unit::CurrentDensity
<< Base::Unit::DissipationRate
<< Base::Unit::DynamicViscosity
<< Base::Unit::ElectricalCapacitance
<< Base::Unit::ElectricalInductance
<< Base::Unit::ElectricalConductance
@@ -86,10 +88,13 @@ DlgUnitsCalculator::DlgUnitsCalculator( QWidget* parent, Qt::WindowFlags fl )
<< Base::Unit::ElectricCharge
<< Base::Unit::ElectricCurrent
<< Base::Unit::ElectricPotential
<< Base::Unit::Frequency
<< Base::Unit::Force
<< Base::Unit::Stiffness
<< Base::Unit::Frequency
<< Base::Unit::HeatFlux
<< Base::Unit::InverseArea
<< Base::Unit::InverseLength
<< Base::Unit::InverseVolume
<< Base::Unit::KinematicViscosity
<< Base::Unit::Length
<< Base::Unit::LuminousIntensity
<< Base::Unit::Mass
@@ -97,17 +102,21 @@ DlgUnitsCalculator::DlgUnitsCalculator( QWidget* parent, Qt::WindowFlags fl )
<< Base::Unit::MagneticFlux
<< Base::Unit::MagneticFluxDensity
<< Base::Unit::Magnetization
<< Base::Unit::Pressure
<< Base::Unit::Power
<< Base::Unit::Pressure
<< Base::Unit::SpecificEnergy
<< Base::Unit::SpecificHeat
<< Base::Unit::Stress
<< Base::Unit::Stiffness
<< Base::Unit::Temperature
<< Base::Unit::ThermalConductivity
<< Base::Unit::ThermalExpansionCoefficient
<< Base::Unit::ThermalTransferCoefficient
<< Base::Unit::TimeSpan
<< Base::Unit::VacuumPermittivity
<< Base::Unit::Velocity
<< Base::Unit::Volume
<< Base::Unit::VolumeFlowRate
<< Base::Unit::VolumetricThermalExpansionCoefficient
<< Base::Unit::Work;
for (QList<Base::Unit>::iterator it = units.begin(); it != units.end(); ++it) {
ui->unitsBox->addItem(it->getTypeString());
+5 -112
View File
@@ -810,132 +810,25 @@ void ExpressionCompleter::slotUpdate(const QString & prefix, int pos)
init();
// ExpressionParser::tokenize() only supports std::string but we need a tuple QString
// because due to UTF-8 encoding a std::string may be longer than a QString
// See https://forum.freecadweb.org/viewtopic.php?f=3&t=69931
auto tokenizeExpression = [](const QString& expr) {
std::vector<std::tuple<int, int, std::string>> result =
ExpressionParser::tokenize(expr.toStdString());
std::vector<std::tuple<int, int, QString>> tokens;
std::transform(result.cbegin(),
result.cend(),
std::back_inserter(tokens),
[&](const std::tuple<int, int, std::string>& item) {
return std::make_tuple(
get<0>(item),
QString::fromStdString(expr.toStdString().substr(0,get<1>(item))).size(),
QString::fromStdString(get<2>(item))
);
});
return tokens;
};
QString completionPrefix;
// Compute start; if prefix starts with =, start parsing from offset 1.
int start = (prefix.size() > 0 && prefix.at(0) == QChar::fromLatin1('=')) ? 1 : 0;
// Tokenize prefix
std::vector<std::tuple<int, int, QString> > tokens = tokenizeExpression(prefix.mid(start));
// No tokens
if (tokens.empty()) {
QString completionPrefix = tokenizer.perform(prefix, pos);
if (completionPrefix.isEmpty()) {
if (auto itemView = popup())
itemView->setVisible(false);
return;
}
prefixEnd = prefix.size();
// Pop those trailing tokens depending on the given position, which may be
// in the middle of a token, and we shall include that token.
for (auto it = tokens.begin(); it != tokens.end(); ++it) {
if (get<1>(*it) >= pos) {
// Include the immediately followed '.' or '#', because we'll be
// inserting these separators too, in ExpressionCompleteModel::pathFromIndex()
if (it != tokens.begin() && get<0>(*it) != '.' && get<0>(*it) != '#')
it = it - 1;
tokens.resize(it - tokens.begin() + 1);
prefixEnd = start + get<1>(*it) + (int)get<2>(*it).size();
break;
}
}
int trim = 0;
if (prefixEnd > pos)
trim = prefixEnd - pos;
// Extract last tokens that can be rebuilt to a variable
long i = static_cast<long>(tokens.size()) - 1;
// First, check if we have unclosing string starting from the end
bool stringing = false;
for (; i >= 0; --i) {
int token = get<0>(tokens[i]);
if (token == ExpressionParser::STRING) {
stringing = false;
break;
}
if (token == ExpressionParser::LT && i > 0
&& get<0>(tokens[i - 1]) == ExpressionParser::LT) {
--i;
stringing = true;
break;
}
}
// Not an unclosed string and the last character is a space
if (!stringing && !prefix.isEmpty() &&
prefixEnd > 0 && prefixEnd <= prefix.size() &&
prefix[prefixEnd-1] == QChar(32)) {
if (auto itemView = popup())
itemView->setVisible(false);
return;
}
if (!stringing) {
i = static_cast<long>(tokens.size()) - 1;
for (; i >= 0; --i) {
int token = get<0>(tokens[i]);
if (token != '.' &&
token != '#' &&
token != ExpressionParser::IDENTIFIER &&
token != ExpressionParser::STRING &&
token != ExpressionParser::UNIT)
break;
}
++i;
}
// Set prefix start for use when replacing later
if (i == static_cast<long>(tokens.size()))
prefixStart = prefixEnd;
else
prefixStart = start + get<1>(tokens[i]);
// Build prefix from tokens
while (i < static_cast<long>(tokens.size())) {
completionPrefix += get<2>(tokens[i]);
++i;
}
if (trim && trim < int(completionPrefix.size()))
completionPrefix.resize(completionPrefix.size() - trim);
FC_TRACE("Completion Prefix:" << completionPrefix.toUtf8().constData());
// Set completion prefix
setCompletionPrefix(completionPrefix);
if (!completionPrefix.isEmpty() && widget()->hasFocus()) {
if (widget()->hasFocus()) {
FC_TRACE("Complete on Prefix" << completionPrefix.toUtf8().constData());
complete();
FC_TRACE("Complete Done");
}
else {
if (auto itemView = popup())
itemView->setVisible(false);
else if (auto itemView = popup()) {
itemView->setVisible(false);
}
}
+4 -6
View File
@@ -28,6 +28,7 @@
#include <QObject>
#include <QPlainTextEdit>
#include <App/DocumentObserver.h>
#include <App/ExpressionTokenizer.h>
class QStandardItem;
@@ -52,12 +53,11 @@ public:
QObject *parent = nullptr, bool noProperty = false, bool checkInList = true);
void getPrefixRange(int &start, int &end) const {
start = prefixStart;
end = prefixEnd;
tokenizer.getPrefixRange(start, end);
}
void updatePrefixEnd(int end) {
prefixEnd = end;
tokenizer.updatePrefixEnd(end);
}
void setDocumentObject(const App::DocumentObject*, bool checkInList=true);
@@ -72,10 +72,8 @@ private:
QString pathFromIndex ( const QModelIndex & index ) const override;
QStringList splitPath ( const QString & input ) const override;
int prefixStart = 0;
int prefixEnd = 0;
App::DocumentObjectT currentObj;
App::ExpressionTokenizer tokenizer;
bool noProperty;
bool checkInList;
};
File diff suppressed because it is too large Load Diff
Binary file not shown.
File diff suppressed because it is too large Load Diff
Binary file not shown.
File diff suppressed because it is too large Load Diff
Binary file not shown.
File diff suppressed because it is too large Load Diff
Binary file not shown.
File diff suppressed because it is too large Load Diff
Binary file not shown.
File diff suppressed because it is too large Load Diff
Binary file not shown.
File diff suppressed because it is too large Load Diff
Binary file not shown.
File diff suppressed because it is too large Load Diff
Binary file not shown.
File diff suppressed because it is too large Load Diff
Binary file not shown.
File diff suppressed because it is too large Load Diff
Binary file not shown.
File diff suppressed because it is too large Load Diff
Binary file not shown.
File diff suppressed because it is too large Load Diff
Binary file not shown.
File diff suppressed because it is too large Load Diff
Binary file not shown.
File diff suppressed because it is too large Load Diff
Binary file not shown.
File diff suppressed because it is too large Load Diff
Binary file not shown.
File diff suppressed because it is too large Load Diff
Binary file not shown.
File diff suppressed because it is too large Load Diff
Binary file not shown.
File diff suppressed because it is too large Load Diff
Binary file not shown.
File diff suppressed because it is too large Load Diff
Binary file not shown.
File diff suppressed because it is too large Load Diff
Binary file not shown.
File diff suppressed because it is too large Load Diff
Binary file not shown.
File diff suppressed because it is too large Load Diff
Binary file not shown.
File diff suppressed because it is too large Load Diff
Binary file not shown.
File diff suppressed because it is too large Load Diff
Binary file not shown.
File diff suppressed because it is too large Load Diff
Binary file not shown.
File diff suppressed because it is too large Load Diff
Binary file not shown.
File diff suppressed because it is too large Load Diff
Binary file not shown.
File diff suppressed because it is too large Load Diff

Some files were not shown because too many files have changed in this diff Show More