diff --git a/.clang-format b/.clang-format new file mode 100644 index 00000000..ba086c62 --- /dev/null +++ b/.clang-format @@ -0,0 +1,246 @@ +--- +Language: Cpp +# BasedOnStyle: LLVM +AccessModifierOffset: -2 +AlignAfterOpenBracket: Align +AlignArrayOfStructures: None +AlignConsecutiveAssignments: + Enabled: false + AcrossEmptyLines: false + AcrossComments: false + AlignCompound: false + AlignFunctionPointers: false + PadOperators: true +AlignConsecutiveBitFields: + Enabled: false + AcrossEmptyLines: false + AcrossComments: false + AlignCompound: false + AlignFunctionPointers: false + PadOperators: false +AlignConsecutiveDeclarations: + Enabled: false + AcrossEmptyLines: false + AcrossComments: false + AlignCompound: false + AlignFunctionPointers: false + PadOperators: false +AlignConsecutiveMacros: + Enabled: false + AcrossEmptyLines: false + AcrossComments: false + AlignCompound: false + AlignFunctionPointers: false + PadOperators: false +AlignConsecutiveShortCaseStatements: + Enabled: false + AcrossEmptyLines: false + AcrossComments: false + AlignCaseColons: false +AlignEscapedNewlines: Right +AlignOperands: Align +AlignTrailingComments: + Kind: Always + OverEmptyLines: 0 +AllowAllArgumentsOnNextLine: true +AllowAllParametersOfDeclarationOnNextLine: true +AllowBreakBeforeNoexceptSpecifier: Never +AllowShortBlocksOnASingleLine: Never +AllowShortCaseLabelsOnASingleLine: false +AllowShortCompoundRequirementOnASingleLine: true +AllowShortEnumsOnASingleLine: true +AllowShortFunctionsOnASingleLine: All +AllowShortIfStatementsOnASingleLine: Never +AllowShortLambdasOnASingleLine: All +AllowShortLoopsOnASingleLine: false +AlwaysBreakAfterDefinitionReturnType: None +AlwaysBreakAfterReturnType: None +AlwaysBreakBeforeMultilineStrings: false +AlwaysBreakTemplateDeclarations: Yes +AttributeMacros: + - __capability +BinPackArguments: true +BinPackParameters: true +BitFieldColonSpacing: Both +BraceWrapping: + AfterCaseLabel: false + AfterClass: false + AfterControlStatement: Never + AfterEnum: false + AfterExternBlock: false + AfterFunction: false + AfterNamespace: false + AfterObjCDeclaration: false + AfterStruct: false + AfterUnion: false + BeforeCatch: false + BeforeElse: false + BeforeLambdaBody: false + BeforeWhile: false + IndentBraces: false + SplitEmptyFunction: true + SplitEmptyRecord: true + SplitEmptyNamespace: true +BreakAdjacentStringLiterals: true +BreakAfterAttributes: Leave +BreakAfterJavaFieldAnnotations: false +BreakArrays: true +BreakBeforeBinaryOperators: None +BreakBeforeConceptDeclarations: Always +BreakBeforeBraces: Allman +BreakBeforeInlineASMColon: OnlyMultiline +BreakBeforeTernaryOperators: true +BreakConstructorInitializers: BeforeColon +BreakInheritanceList: BeforeColon +BreakStringLiterals: true +ColumnLimit: 120 +CommentPragmas: '^ IWYU pragma:' +CompactNamespaces: false +ConstructorInitializerIndentWidth: 4 +ContinuationIndentWidth: 4 +Cpp11BracedListStyle: true +DerivePointerAlignment: false +DisableFormat: false +EmptyLineAfterAccessModifier: Never +EmptyLineBeforeAccessModifier: LogicalBlock +ExperimentalAutoDetectBinPacking: false +FixNamespaceComments: true +ForEachMacros: + - foreach + - Q_FOREACH + - BOOST_FOREACH +IfMacros: + - KJ_IF_MAYBE +IncludeBlocks: Preserve +IncludeCategories: + - Regex: '^"(llvm|llvm-c|clang|clang-c)/' + Priority: 2 + SortPriority: 0 + CaseSensitive: false + - Regex: '^(<|"(gtest|gmock|isl|json)/)' + Priority: 3 + SortPriority: 0 + CaseSensitive: false + - Regex: '.*' + Priority: 1 + SortPriority: 0 + CaseSensitive: false +IncludeIsMainRegex: '(Test)?$' +IncludeIsMainSourceRegex: '' +IndentAccessModifiers: false +IndentCaseBlocks: false +IndentCaseLabels: true +IndentExternBlock: AfterExternBlock +IndentGotoLabels: true +IndentPPDirectives: None +IndentRequiresClause: true +IndentWidth: 4 +IndentWrappedFunctionNames: false +InsertBraces: false +InsertNewlineAtEOF: false +InsertTrailingCommas: None +IntegerLiteralSeparator: + Binary: 0 + BinaryMinDigits: 0 + Decimal: 0 + DecimalMinDigits: 0 + Hex: 0 + HexMinDigits: 0 +JavaScriptQuotes: Leave +JavaScriptWrapImports: true +KeepEmptyLinesAtTheStartOfBlocks: true +KeepEmptyLinesAtEOF: false +LambdaBodyIndentation: Signature +LineEnding: DeriveLF +MacroBlockBegin: '' +MacroBlockEnd: '' +MaxEmptyLinesToKeep: 1 +NamespaceIndentation: All +ObjCBinPackProtocolList: Auto +ObjCBlockIndentWidth: 2 +ObjCBreakBeforeNestedBlockParam: true +ObjCSpaceAfterProperty: false +ObjCSpaceBeforeProtocolList: true +PackConstructorInitializers: BinPack +PenaltyBreakAssignment: 2 +PenaltyBreakBeforeFirstCallParameter: 19 +PenaltyBreakComment: 300 +PenaltyBreakFirstLessLess: 120 +PenaltyBreakOpenParenthesis: 0 +PenaltyBreakScopeResolution: 500 +PenaltyBreakString: 1000 +PenaltyBreakTemplateDeclaration: 10 +PenaltyExcessCharacter: 1000000 +PenaltyIndentedWhitespace: 0 +PenaltyReturnTypeOnItsOwnLine: 60 +PointerAlignment: Right +PPIndentWidth: -1 +QualifierAlignment: Leave +ReferenceAlignment: Pointer +ReflowComments: true +RemoveBracesLLVM: false +RemoveParentheses: Leave +RemoveSemicolon: false +RequiresClausePosition: OwnLine +RequiresExpressionIndentation: OuterScope +SeparateDefinitionBlocks: Always +ShortNamespaceLines: 1 +SkipMacroDefinitionBody: false +SortIncludes: CaseSensitive +SortJavaStaticImport: Before +SortUsingDeclarations: LexicographicNumeric +SpaceAfterCStyleCast: false +SpaceAfterLogicalNot: false +SpaceAfterTemplateKeyword: true +SpaceAroundPointerQualifiers: Default +SpaceBeforeAssignmentOperators: true +SpaceBeforeCaseColon: false +SpaceBeforeCpp11BracedList: false +SpaceBeforeCtorInitializerColon: true +SpaceBeforeInheritanceColon: true +SpaceBeforeJsonColon: false +SpaceBeforeParens: ControlStatements +SpaceBeforeParensOptions: + AfterControlStatements: true + AfterForeachMacros: true + AfterFunctionDefinitionName: false + AfterFunctionDeclarationName: false + AfterIfMacros: true + AfterOverloadedOperator: false + AfterPlacementOperator: true + AfterRequiresInClause: false + AfterRequiresInExpression: false + BeforeNonEmptyParentheses: false +SpaceBeforeRangeBasedForLoopColon: true +SpaceBeforeSquareBrackets: false +SpaceInEmptyBlock: false +SpacesBeforeTrailingComments: 1 +SpacesInAngles: Never +SpacesInContainerLiterals: true +SpacesInLineCommentPrefix: + Minimum: 1 + Maximum: -1 +SpacesInParens: Custom +SpacesInParensOptions: + InCStyleCasts: false + InConditionalStatements: true + InEmptyParentheses: false + Other: true +SpacesInSquareBrackets: false +Standard: Latest +StatementAttributeLikeMacros: + - Q_EMIT +StatementMacros: + - Q_UNUSED + - QT_REQUIRE_VERSION +TabWidth: 8 +UseTab: Never +VerilogBreakBetweenInstancePorts: true +WhitespaceSensitiveMacros: + - BOOST_PP_STRINGIZE + - CF_SWIFT_NAME + - NS_SWIFT_NAME + - PP_STRINGIZE + - STRINGIZE +... + diff --git a/.github/workflows/conda_build.yaml b/.github/workflows/conda_build.yaml index 99dbc42f..f8b18878 100644 --- a/.github/workflows/conda_build.yaml +++ b/.github/workflows/conda_build.yaml @@ -104,4 +104,51 @@ jobs: uses: actions/upload-artifact@v4 with: path: conda_package/win-64/*.conda - name: conda_package_windows \ No newline at end of file + name: conda_package_windows + + Build-on-macOS: + + name: Build on macOS + + runs-on: macos-15 + + permissions: + contents: write + + env: + CONDA_PKG_DIR: ~/conda_pkgs_dir + GH_TOKEN: ${{ github.token }} + + steps: + + - name: Checkout + uses: actions/checkout@v4 + with: + submodules: true + + - name: Setup conda + uses: conda-incubator/setup-miniconda@v3 + with: + auto-update-conda: true + use-mamba: true + channels: conda-forge,defaults + auto-activate-base: true + activate-environment: "" + + - name: Add Custom Conda Channel + run: | + conda config --add channels https://jancaha.github.io/conda-channel + + - name: Install conda-build + run: | + conda install -n base conda-build conda-verify + + - name: Build library + run: | + conda build conda --output-folder conda_package --variant-config-files conda/variants/macOS.yaml + + - name: Upload artifact + uses: actions/upload-artifact@v4 + with: + path: conda_package/osx-arm64/*.conda + name: conda_package_macos diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 00000000..a73f0f06 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,16 @@ +repos: + - repo: local + + hooks: + + - id: version-update + name: 'Version update' + entry: './scripts/precommit/version_update.sh' + language: script + files: ^CMakeLists.txt + + - id: style-cpp + name: 'Style C++ code' + entry: './scripts/precommit/clang_format.sh' + language: script + files: ^src/.*|^tests/.*|^include/.*$ diff --git a/README.md b/README.md index 3a527a9f..9b19e714 100644 --- a/README.md +++ b/README.md @@ -113,7 +113,7 @@ apt-get -y install simplerasters viewshed viewshed-bin If you use the library, please cite it accordingly: ```bibtex -@Software{Caha2024, +@Software{CahaViewshed, author = {Jan Caha}, title = {viewshed ({C++ Viewshed library based on GDAL and Qt})}, year = {2024}, @@ -126,5 +126,6 @@ If you use the library, please cite it accordingly: ## Setup precommits ```bash -cp -r scripts/precommit/* .git/hooks/ +sudo apt-get install pre-commit +pre-commit install -f ``` diff --git a/clang-format.txt b/clang-format.txt deleted file mode 100644 index bf881c43..00000000 --- a/clang-format.txt +++ /dev/null @@ -1,17 +0,0 @@ -# https://clang.llvm.org/docs/ClangFormatStyleOptions.html -# https://zed0.co.uk/clang-format-configurator/ - ---- -BasedOnStyle: LLVM -AccessModifierOffset: '-2' -BreakBeforeBraces: Allman -AlwaysBreakTemplateDeclarations: Yes -ColumnLimit: 120 -IndentCaseLabels: 'true' -IndentWidth: '4' -NamespaceIndentation: All -PointerAlignment: Right -SeparateDefinitionBlocks: Always -SortIncludesOptions: CaseSensitive -SpacesInParentheses: true -... \ No newline at end of file diff --git a/conda/test_script.sh b/conda/test_script.sh index 11d2b344..12c87515 100755 --- a/conda/test_script.sh +++ b/conda/test_script.sh @@ -3,6 +3,13 @@ set -euo pipefail echo "Running Unix test..." +# change dynamic library extension based on OS - so for Linux, dylib for macOS +OS_NAME="$(uname -s)" +LIBRARY_EXTENSION="so" +if [[ "$OS_NAME" == "Darwin" ]]; then + LIBRARY_EXTENSION="dylib" +fi + # Function to check if a file exists check_file_exists() { local filepath="$1" @@ -25,8 +32,9 @@ run_and_check() { echo "✅ $bin -h ran successfully" fi } + # existence of files -check_file_exists "$PREFIX/lib/libviewshed.so" +check_file_exists "$PREFIX/lib/libviewshed.$LIBRARY_EXTENSION" check_file_exists "$PREFIX/lib/libviewshed.a" check_file_exists "$PREFIX/lib/cmake/Viewshed/ViewshedTargets.cmake" check_file_exists "$PREFIX/include/Viewshed/abstractviewshed.h" diff --git a/conda/variants/macOS.yaml b/conda/variants/macOS.yaml new file mode 100644 index 00000000..7b35e97f --- /dev/null +++ b/conda/variants/macOS.yaml @@ -0,0 +1,5 @@ +c_compiler: clang +cxx_compiler: clangxx + +c_compiler_version: 18 +cxx_compiler_version: 18 \ No newline at end of file diff --git a/include/viewshed/losnode.h b/include/viewshed/losnode.h index 743eee02..8ef7f090 100755 --- a/include/viewshed/losnode.h +++ b/include/viewshed/losnode.h @@ -49,9 +49,9 @@ namespace viewshed */ LoSNode( const int &pointRow, const int &pointCol, const CellEvent *e, const double &cellSize ); - bool operator==( const LoSNode &other ); - bool operator!=( const LoSNode &other ); - bool operator<( const LoSNode other ); + bool operator==( const LoSNode &other ) const; + bool operator!=( const LoSNode &other ) const; + bool operator<( const LoSNode other ) const; /** * @brief Extract value of ValueType at specified angle. @@ -60,7 +60,7 @@ namespace viewshed * @param valueType * @return double */ - double valueAtAngle( const double &angle, ValueType valueType = ValueType::Elevation ); + double valueAtAngle( const double &angle, ValueType valueType = ValueType::Elevation ) const; /** * @brief Extract value of ValueType at specific cell event position. @@ -69,31 +69,31 @@ namespace viewshed * @param valueType * @return double */ - double value( CellEventPositionType position, ValueType valueType = ValueType::Elevation ); + double value( CellEventPositionType position, ValueType valueType = ValueType::Elevation ) const; /** * @brief Shortcut call to obtain horizontal angle at center of raster cell that this LoSNode represents. * * @return double */ - double centreAngle(); + double centreAngle() const; /** * @brief Shortcut call to obtain elevation angle at center of raster cell that this LoSNode represents. * * @return double */ - double centreElevation(); + double centreElevation() const; /** * @brief Shortcut call to obtain distance angle at center of raster cell that this LoSNode represents. * * @return double */ - double centreDistance(); + double centreDistance() const; - double elevationAtAngle( const double &angle ); + double elevationAtAngle( const double &angle ) const; - double distanceAtAngle( const double &angle ); + double distanceAtAngle( const double &angle ) const; }; } // namespace viewshed diff --git a/scripts/precommit/clang_format.sh b/scripts/precommit/clang_format.sh new file mode 100755 index 00000000..38a5406f --- /dev/null +++ b/scripts/precommit/clang_format.sh @@ -0,0 +1,13 @@ +#!/bin/bash + +# Get list of staged files with relevant extensions +FILES=$(git diff --cached --name-only | grep -E '\.(cpp|hpp|cc|c|h)$') + +if [ -z "$FILES" ]; then + exit 0 +fi + +# Run clang-format on each staged file +for file in $FILES; do + [ -f "$file" ] && clang-format -i "$file" +done \ No newline at end of file diff --git a/scripts/precommit/conda_version.sh b/scripts/precommit/conda_version.sh deleted file mode 100755 index 9678b819..00000000 --- a/scripts/precommit/conda_version.sh +++ /dev/null @@ -1,41 +0,0 @@ -#!/bin/bash - -set -e # Exit on any error - -# Color codes for output -RED='\033[0;31m' -GREEN='\033[0;32m' -YELLOW='\033[1;33m' -BLUE='\033[0;34m' -NC='\033[0m' # No Color - -print_success() { - echo -e "${GREEN}[SUCCESS]${NC} $1" -} - -print_info() { - echo -e "${BLUE}[INFO]${NC} $1" -} - -print_error() { - echo -e "{RED}[ERROR]${NC} $1" -} - -echo "🔍 Running pre-commit checks..." - -VERSION=$(grep "project(" CMakeLists.txt | grep -E -o -e "[0-9\.]+") - -print_info "Project version: $VERSION" - -sed -i '/version: /c\ version: \"'$VERSION'\"' conda/meta.yaml - -CONDA_VERSION=$(grep "version: " conda/meta.yaml | grep -E -o -e "[0-9\.]+") - -if [[ "$CONDA_VERSION" != "$VERSION" ]]; then - print_error "${RED}[ERROR]${NC} Version mismatch between CMakeLists.txt and conda/meta.yaml" - exit 1 -fi - -print_success "All pre-commit checks passed! ✨" - -echo "🚀 Ready to commit!" diff --git a/scripts/precommit/pre-commit b/scripts/precommit/pre-commit deleted file mode 100755 index ccc403c7..00000000 --- a/scripts/precommit/pre-commit +++ /dev/null @@ -1,2 +0,0 @@ -#!/bin/bash -.git/hooks/conda_version.sh \ No newline at end of file diff --git a/scripts/precommit/version_update.sh b/scripts/precommit/version_update.sh new file mode 100755 index 00000000..e03076de --- /dev/null +++ b/scripts/precommit/version_update.sh @@ -0,0 +1,31 @@ +#!/bin/bash + +set -e # Exit on any error + +FILES=$(git diff --cached --name-only | grep -E '^CMakeLists.txt$') + +if [ -z "$FILES" ]; then + exit 0 +fi + +VERSION=$(grep "project(" CMakeLists.txt | grep -E -o -e "[0-9\.]+") + +echo -e "Project version: $VERSION" + +# update conda package version +CONDA_VERSION=$(grep "version: " conda/meta.yaml | grep -E -o -e "[0-9\.]+") + +if [[ "$CONDA_VERSION" != "$VERSION" ]]; then + sed -i '/version: /c\ version: \"'$VERSION'\"' conda/meta.yaml +fi + +# update README.md with the new version +README_VERSION=$(grep "version = " README.md | grep -E -o -e "[0-9\.]+") + +if [[ "$README_VERSION" != "$VERSION" ]]; then + YEAR=$(date +%Y) + ISO_DATE=$(date +%Y-%m-%d) + sed -i '/version = {/c\ version = {'$VERSION'}' README.md + sed -i '/year = {/c\ year = {'$YEAR'}' README.md + sed -i '/date = {/c\ date = {'$ISO_DATE'}' README.md +fi \ No newline at end of file diff --git a/src/library/structures/losnode.cpp b/src/library/structures/losnode.cpp index 7611fcbf..91e9cd52 100755 --- a/src/library/structures/losnode.cpp +++ b/src/library/structures/losnode.cpp @@ -68,7 +68,7 @@ LoSNode::LoSNode( const int &pointRow, const int &pointCol, const CellEvent *e, static_cast( pointRow ), static_cast( pointCol ), cellSize ); } -double LoSNode::value( CellEventPositionType position, ValueType valueType ) +double LoSNode::value( CellEventPositionType position, ValueType valueType ) const { switch ( valueType ) { @@ -91,7 +91,7 @@ double LoSNode::value( CellEventPositionType position, ValueType valueType ) } } -double LoSNode::valueAtAngle( const double &specificAngle, ValueType valueType ) +double LoSNode::valueAtAngle( const double &specificAngle, ValueType valueType ) const { if ( specificAngle == mAngle[CellEventPositionType::CENTER] ) return value( CellEventPositionType::CENTER, valueType ); @@ -131,13 +131,13 @@ double LoSNode::valueAtAngle( const double &specificAngle, ValueType valueType ) } } -double LoSNode::centreAngle() { return mAngle[CellEventPositionType::CENTER]; } +double LoSNode::centreAngle() const { return mAngle[CellEventPositionType::CENTER]; } -double LoSNode::centreElevation() { return mElevs[CellEventPositionType::CENTER]; } +double LoSNode::centreElevation() const { return mElevs[CellEventPositionType::CENTER]; } -double LoSNode::centreDistance() { return mDistances[CellEventPositionType::CENTER]; } +double LoSNode::centreDistance() const { return mDistances[CellEventPositionType::CENTER]; } -bool LoSNode::operator==( const LoSNode &other ) +bool LoSNode::operator==( const LoSNode &other ) const { if ( mRow == other.mRow && mCol == other.mCol ) return true; @@ -145,7 +145,7 @@ bool LoSNode::operator==( const LoSNode &other ) return false; } -bool LoSNode::operator!=( const LoSNode &other ) +bool LoSNode::operator!=( const LoSNode &other ) const { if ( mRow == other.mRow && mCol == other.mCol ) return false; @@ -153,11 +153,11 @@ bool LoSNode::operator!=( const LoSNode &other ) return true; } -bool LoSNode::operator<( const LoSNode other ) +bool LoSNode::operator<( const LoSNode other ) const { return mDistances[CellEventPositionType::CENTER] < other.mDistances[CellEventPositionType::CENTER]; } -double LoSNode::elevationAtAngle( const double &angle ) { return valueAtAngle( angle, ValueType::Elevation ); } +double LoSNode::elevationAtAngle( const double &angle ) const { return valueAtAngle( angle, ValueType::Elevation ); } -double LoSNode::distanceAtAngle( const double &angle ) { return valueAtAngle( angle, ValueType::Distance ); } +double LoSNode::distanceAtAngle( const double &angle ) const { return valueAtAngle( angle, ValueType::Distance ); }