Merge branch 'master' into removeGZstream
This commit is contained in:
+145
-70
@@ -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
@@ -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
@@ -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();
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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
|
||||
@@ -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;
|
||||
|
||||
@@ -256,6 +256,7 @@ public:
|
||||
TAN,
|
||||
TANH,
|
||||
SQRT,
|
||||
CBRT,
|
||||
COS,
|
||||
COSH,
|
||||
ATAN2,
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
|
||||
|
||||
@@ -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
@@ -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
@@ -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;
|
||||
|
||||
+650
-649
File diff suppressed because it is too large
Load Diff
+343
-343
@@ -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
@@ -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
@@ -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
|
||||
|
||||
@@ -291,7 +291,6 @@ SET(FreeCADBase_HPP_SRCS
|
||||
FileInfo.h
|
||||
FileTemplate.h
|
||||
FutureWatcherProgress.h
|
||||
fdstream.hpp
|
||||
GeometryPyCXX.h
|
||||
Handle.h
|
||||
InputSource.h
|
||||
|
||||
+19
-10
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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:
|
||||
|
||||
@@ -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
@@ -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();
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
+268
-257
File diff suppressed because it is too large
Load Diff
Binary file not shown.
+554
-542
File diff suppressed because it is too large
Load Diff
Binary file not shown.
+276
-264
File diff suppressed because it is too large
Load Diff
Binary file not shown.
+269
-257
File diff suppressed because it is too large
Load Diff
Binary file not shown.
+271
-259
File diff suppressed because it is too large
Load Diff
Binary file not shown.
+269
-257
File diff suppressed because it is too large
Load Diff
Binary file not shown.
+283
-273
File diff suppressed because it is too large
Load Diff
Binary file not shown.
+284
-274
File diff suppressed because it is too large
Load Diff
Binary file not shown.
+283
-270
File diff suppressed because it is too large
Load Diff
Binary file not shown.
+269
-257
File diff suppressed because it is too large
Load Diff
Binary file not shown.
+277
-265
File diff suppressed because it is too large
Load Diff
Binary file not shown.
+269
-257
File diff suppressed because it is too large
Load Diff
Binary file not shown.
+269
-257
File diff suppressed because it is too large
Load Diff
Binary file not shown.
+278
-266
File diff suppressed because it is too large
Load Diff
Binary file not shown.
+274
-262
File diff suppressed because it is too large
Load Diff
Binary file not shown.
+269
-257
File diff suppressed because it is too large
Load Diff
Binary file not shown.
+274
-262
File diff suppressed because it is too large
Load Diff
Binary file not shown.
+269
-257
File diff suppressed because it is too large
Load Diff
Binary file not shown.
+269
-257
File diff suppressed because it is too large
Load Diff
Binary file not shown.
+288
-276
File diff suppressed because it is too large
Load Diff
Binary file not shown.
+269
-257
File diff suppressed because it is too large
Load Diff
Binary file not shown.
+270
-258
File diff suppressed because it is too large
Load Diff
Binary file not shown.
+269
-257
File diff suppressed because it is too large
Load Diff
Binary file not shown.
+274
-262
File diff suppressed because it is too large
Load Diff
Binary file not shown.
+271
-259
File diff suppressed because it is too large
Load Diff
Binary file not shown.
+279
-267
File diff suppressed because it is too large
Load Diff
Binary file not shown.
+279
-267
File diff suppressed because it is too large
Load Diff
Binary file not shown.
+269
-257
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
Reference in New Issue
Block a user