diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index 959211d..06d12ac 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -1,32 +1,41 @@ name: 'CI' -env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - on: - pull_request: #necessary to display "check" step in a PR - types: [labeled] - workflow_dispatch: #manual trigger + push: + branches: + - 'main' + pull_request: + types: [opened, synchronize, reopened] jobs: - tests: - if: github.event_name == 'workflow_dispatch' || (github.event_name == 'pull_request' && github.event.label.name == 'run-ci') + test: strategy: matrix: - os: [ ubuntu-latest, macos-latest, windows-latest ] - smalltalk: [ Pharo64-11, Pharo64-12, Pharo64-13 ] - ston: [ .smalltalkci.default.ston ] + smalltalk: [ Pharo64-11, Pharo64-12, Pharo64-13 ] #Pharo versions + os: [ ubuntu-latest, macos-latest, windows-latest ] #OS versions + ston: [ .smalltalkci.default.ston ] #Can use multiple .ston files runs-on: ${{ matrix.os }} - name: > - ${{ matrix.smalltalk }} • ${{ matrix.os }} + name: ${{ matrix.smalltalk }} on ${{ matrix.os }} steps: - - uses: actions/checkout@v3 - - - uses: hpi-swa/setup-smalltalkCI@v1 + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + - name: Setup smalltalkCI + uses: hpi-swa/setup-smalltalkCI@v1 with: smalltalk-image: ${{ matrix.smalltalk }} - - - name: Run ${{ matrix.ston == '.smalltalkci.default.ston' && 'Full' || 'Core' }} tests + - name: Load in new image and run tests run: smalltalkci -s ${{ matrix.smalltalk }} ${{ matrix.ston }} shell: bash - timeout-minutes: 30 \ No newline at end of file + timeout-minutes: 30 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + - name: Upload logs + if: ${{ failure() }} + uses: actions/upload-artifact@v4 + with: + name: Logs_${{ matrix.smalltalk }}_${{ matrix.os }}_${{ matrix.ston }} + path: | + *.fuel + PharoDebug.log + retention-days: 5 \ No newline at end of file diff --git a/.smalltalkci.default.ston b/.smalltalkci.default.ston index 9e25984..5b47b50 100644 --- a/.smalltalkci.default.ston +++ b/.smalltalkci.default.ston @@ -7,8 +7,6 @@ SmalltalkCISpec { } ], #testing : { - #include : { - #packages : [ 'GeoTools*-Tests' ] - } + #packages : [ 'GeoTools-Tests' ] } } diff --git a/src/GeoTools-Tests/GeodesicApproximativeFormulasTest.class.st b/src/GeoTools-Tests/GeodesicApproximativeFormulasTest.class.st new file mode 100644 index 0000000..39cd553 --- /dev/null +++ b/src/GeoTools-Tests/GeodesicApproximativeFormulasTest.class.st @@ -0,0 +1,14 @@ +" +A GeodesicVincentyFormulasTest is a test class for testing the behavior of GeodesicVincentyFormulas +" +Class { + #name : #GeodesicApproximativeFormulasTest, + #superclass : #GeodesicFormulasTest, + #category : #'GeoTools-Tests-Geodesic' +} + +{ #category : #accessing } +GeodesicApproximativeFormulasTest >> geodesicFormulasClass [ + + ^ GeodesicApproximativeFormulas +] diff --git a/src/GeoTools-Tests/GeodesicFormulasTest.class.st b/src/GeoTools-Tests/GeodesicFormulasTest.class.st new file mode 100644 index 0000000..ca05217 --- /dev/null +++ b/src/GeoTools-Tests/GeodesicFormulasTest.class.st @@ -0,0 +1,83 @@ +" +A GeodesicFormulasTest is a test class for testing the behavior of GeodesicFormulas +" +Class { + #name : #GeodesicFormulasTest, + #superclass : #TestCase, + #instVars : [ + 'geodesicFormulas' + ], + #category : #'GeoTools-Tests-Geodesic' +} + +{ #category : #testing } +GeodesicFormulasTest class >> isAbstract [ + + ^ self == GeodesicFormulasTest +] + +{ #category : #accessing } +GeodesicFormulasTest >> geodesicFormulasClass [ + + self subclassResponsibility +] + +{ #category : #running } +GeodesicFormulasTest >> intializeGeodesicFormulas [ + + geodesicFormulas := self geodesicFormulasClass new. +] + +{ #category : #running } +GeodesicFormulasTest >> setUp [ + + super setUp. + self intializeGeodesicFormulas. +] + +{ #category : #tests } +GeodesicFormulasTest >> testAbsoluteCoordinatesAlongGeodesicFromToAtFraction [ + + | coordinates | + coordinates := geodesicFormulas + absoluteCoordinatesAlongGeodesicFrom: + AbsoluteCoordinates zero + to: AbsoluteCoordinates zero + atFraction: 0.5. + + self assert: coordinates class identicalTo: AbsoluteCoordinates +] + +{ #category : #tests } +GeodesicFormulasTest >> testAbsoluteCoordinatesFromDistanceInMetersAzimuthInRadians [ + + | coordinates | + coordinates := geodesicFormulas + absoluteCoordinatesFrom: AbsoluteCoordinates zero + distanceInMeters: 1000 + azimuthInRadians: 0. + + self assert: coordinates class identicalTo: AbsoluteCoordinates +] + +{ #category : #tests } +GeodesicFormulasTest >> testAzimuthInRadiansFromTo [ + + | radians | + radians := geodesicFormulas + azimuthInRadiansFrom: AbsoluteCoordinates zero + to: AbsoluteCoordinates zero. + + self assert: radians equals: 0 +] + +{ #category : #tests } +GeodesicFormulasTest >> testDistanceInMetersFromTo [ + + | distance | + distance := geodesicFormulas + distanceInMetersFrom: AbsoluteCoordinates zero + to: AbsoluteCoordinates zero. + + self assert: distance equals: 0 +] diff --git a/src/GeoTools-Tests/GeodesicVincentyFormulasTest.class.st b/src/GeoTools-Tests/GeodesicVincentyFormulasTest.class.st new file mode 100644 index 0000000..bc7cd4b --- /dev/null +++ b/src/GeoTools-Tests/GeodesicVincentyFormulasTest.class.st @@ -0,0 +1,40 @@ +" +A GeodesicVincentyFormulasTest is a test class for testing the behavior of GeodesicVincentyFormulas +" +Class { + #name : #GeodesicVincentyFormulasTest, + #superclass : #GeodesicFormulasTest, + #category : #'GeoTools-Tests-Geodesic' +} + +{ #category : #accessing } +GeodesicVincentyFormulasTest >> geodesicFormulasClass [ + + ^ GeodesicVincentyFormulas +] + +{ #category : #tests } +GeodesicVincentyFormulasTest >> testIterationsLimit [ + + self assert: geodesicFormulas iterationsLimit equals: GeodesicVincentyFormulas defaultIterationsLimit. + self assert: geodesicFormulas iterationsLimit equals: 100. + + geodesicFormulas iterationsLimit: 1. + self assert: geodesicFormulas iterationsLimit equals: 1. + + geodesicFormulas iterationsLimit: nil. + self assert: geodesicFormulas iterationsLimit equals: GeodesicVincentyFormulas defaultIterationsLimit. +] + +{ #category : #tests } +GeodesicVincentyFormulasTest >> testPrecision [ + + self assert: geodesicFormulas precision equals: GeodesicVincentyFormulas defaultPrecision. + self assert: geodesicFormulas precision equals: 1e-12. + + geodesicFormulas precision: 1. + self assert: geodesicFormulas precision equals: 1. + + geodesicFormulas precision: nil. + self assert: geodesicFormulas precision equals: GeodesicVincentyFormulas defaultPrecision. +] diff --git a/src/GeoTools-Tests/WGS84Test.class.st b/src/GeoTools-Tests/WGS84Test.class.st index 4a17136..5557c75 100644 --- a/src/GeoTools-Tests/WGS84Test.class.st +++ b/src/GeoTools-Tests/WGS84Test.class.st @@ -43,3 +43,9 @@ WGS84Test >> testSemiMinorAxisInMeters [ self assert: WGS84 semiMinorAxisInMeters notNil ] + +{ #category : #running } +WGS84Test >> testWorldCircumferenceInMeters [ + + self assert: WGS84 worldCircumferenceInMeters equals: 4.007501668557849e7 +] diff --git a/src/GeoTools/GeodesicApproximativeFormulas.class.st b/src/GeoTools/GeodesicApproximativeFormulas.class.st index 7583a29..d6312db 100644 --- a/src/GeoTools/GeodesicApproximativeFormulas.class.st +++ b/src/GeoTools/GeodesicApproximativeFormulas.class.st @@ -4,6 +4,21 @@ Class { #category : #'GeoTools-Geodesic' } +{ #category : #tools } +GeodesicApproximativeFormulas >> absoluteCoordinatesAlongGeodesicFrom: aFromAbsoluteCoordinate to: aToAbsoluteCoordinate atFraction: aFraction [ + + | lat1 lon1 lat2 lon2 lat lon | + lat1 := aFromAbsoluteCoordinate latitudeInDegrees. + lon1 := aFromAbsoluteCoordinate longitudeInDegrees. + lat2 := aToAbsoluteCoordinate latitudeInDegrees. + lon2 := aToAbsoluteCoordinate longitudeInDegrees. + + lat := (lat1 + (lat2 - lat1)) * aFraction. + lon := (lon1 + (lon2 - lon1)) * aFraction. + + ^ AbsoluteCoordinates latitudeInDegrees: lat longitudeInDegrees: lon +] + { #category : #tools } GeodesicApproximativeFormulas >> absoluteCoordinatesFrom: anAbsoluteCoordinates distanceInMeters: aDistanceInM azimuthInRadians: anAzimuthInRadians [ @@ -36,3 +51,29 @@ GeodesicApproximativeFormulas >> absoluteCoordinatesFrom: anAbsoluteCoordinates ^ absoluteCoordinates ] + +{ #category : #tools } +GeodesicApproximativeFormulas >> azimuthInRadiansFrom: aFromAbsoluteCoordinate to: aToAbsoluteCoordinate [ + | lat1 lon1 lat2 lon2 dLon x y azimuth | + + lat1 := aFromAbsoluteCoordinate latitudeInRadians. + lon1 := aFromAbsoluteCoordinate longitudeInRadians. + lat2 := aToAbsoluteCoordinate latitudeInRadians. + lon2 := aToAbsoluteCoordinate longitudeInRadians. + + dLon := lon2 - lon1. + x := (dLon sin) * (lat2 cos). + y := ((lat2 sin) * (lat1 cos)) - ((lat1 sin) * (lat2 cos) * (dLon cos)). + + azimuth := y arcTan2: x. + + azimuth < 0 ifTrue: [ azimuth := azimuth + (2 * Float pi) ]. + + ^ azimuth +] + +{ #category : #tools } +GeodesicApproximativeFormulas >> distanceInMetersFrom: aFromAbsoluteCoordinate to: anEndAbsoluteCoordinate [ + + ^ self haversineDistanceFrom: aFromAbsoluteCoordinate to: anEndAbsoluteCoordinate +] diff --git a/src/GeoTools/GeodesicFormulas.class.st b/src/GeoTools/GeodesicFormulas.class.st index 2cc6737..3698b74 100644 --- a/src/GeoTools/GeodesicFormulas.class.st +++ b/src/GeoTools/GeodesicFormulas.class.st @@ -7,16 +7,7 @@ Class { { #category : #tools } GeodesicFormulas >> absoluteCoordinatesAlongGeodesicFrom: aFromAbsoluteCoordinate to: aToAbsoluteCoordinate atFraction: aFraction [ - | distance azimuth | - - (aFromAbsoluteCoordinate isValid and: [aToAbsoluteCoordinate isValid]) ifFalse: [ ^ nil ]. - (aFraction >= 1.0) ifTrue: [ ^ aToAbsoluteCoordinate copy ]. - (aFraction <= 0.0) ifTrue: [ ^ aFromAbsoluteCoordinate copy ]. - - distance := self distanceInMetersFrom: aFromAbsoluteCoordinate to: aToAbsoluteCoordinate. - azimuth := self azimuthInRadiansFrom: aFromAbsoluteCoordinate to: aToAbsoluteCoordinate. - - ^ self absoluteCoordinatesFrom: aFromAbsoluteCoordinate distanceInMeters: (distance * aFraction) azimuthInRadians: azimuth + self subclassResponsibility ] { #category : #tools } diff --git a/src/GeoTools/GeodesicVincentyFormulas.class.st b/src/GeoTools/GeodesicVincentyFormulas.class.st index ba7fbf6..5529831 100644 --- a/src/GeoTools/GeodesicVincentyFormulas.class.st +++ b/src/GeoTools/GeodesicVincentyFormulas.class.st @@ -23,6 +23,24 @@ GeodesicVincentyFormulas class >> defaultPrecision [ ^ 1e-12 ] +{ #category : #tools } +GeodesicVincentyFormulas >> absoluteCoordinatesAlongGeodesicFrom: aFromAbsoluteCoordinate to: aToAbsoluteCoordinate atFraction: aFraction [ + + | distance azimuth | + + (aFromAbsoluteCoordinate isValid and: [aToAbsoluteCoordinate isValid]) ifFalse: [ ^ nil ]. + (aFraction >= 1.0) ifTrue: [ ^ aToAbsoluteCoordinate copy ]. + (aFraction <= 0.0) ifTrue: [ ^ aFromAbsoluteCoordinate copy ]. + + distance := self distanceInMetersFrom: aFromAbsoluteCoordinate to: aToAbsoluteCoordinate. + azimuth := self azimuthInRadiansFrom: aFromAbsoluteCoordinate to: aToAbsoluteCoordinate. + + distance := distance * aFraction. + distance < self precision ifTrue:[ ^ aFromAbsoluteCoordinate copy ]. + + ^ self absoluteCoordinatesFrom: aFromAbsoluteCoordinate distanceInMeters: distance azimuthInRadians: azimuth +] + { #category : #tools } GeodesicVincentyFormulas >> absoluteCoordinatesFrom: anAbsoluteCoordinates distanceInMeters: aDistanceInM azimuthInRadians: anAzimuthInRadians [ | a f b lat1 lon1 alpha1 sinAlpha1 cosAlpha1 u1 sinU1 cosU1 sigma1 sinAlpha cosSqAlpha uSq A B sigma sigmaPrev iterLimit cosSigma sinSigma lat2 deltaSigma C L lon2 lambda cos2SigmaM tmp | @@ -56,6 +74,9 @@ GeodesicVincentyFormulas >> absoluteCoordinatesFrom: anAbsoluteCoordinates dista B := (uSq / 1024) * (256 + (uSq * (-128 + (uSq * (74 - (47 * uSq)))))). sigma := aDistanceInM / (b * A). + sinSigma := sigma sin. + cosSigma := sigma cos. + cos2SigmaM := ((2 * sigma1) + sigma) cos. sigmaPrev := 0.0. iterLimit := self iterationsLimit copy. @@ -289,13 +310,14 @@ GeodesicVincentyFormulas >> iterationsLimit: anObject [ { #category : #accessing } GeodesicVincentyFormulas >> precision [ + "Return the precision of computing in meters" ^ precision ifNil: [ precision := self class defaultPrecision ] ] { #category : #accessing } -GeodesicVincentyFormulas >> precision: anObject [ +GeodesicVincentyFormulas >> precision: aFloatInMeters [ - precision := anObject + precision := aFloatInMeters ] diff --git a/src/GeoTools/WGS84.class.st b/src/GeoTools/WGS84.class.st index 3ed57ea..db0fbff 100644 --- a/src/GeoTools/WGS84.class.st +++ b/src/GeoTools/WGS84.class.st @@ -72,6 +72,12 @@ WGS84 class >> semiMinorAxisInMeters [ ^ 6356752.314245 ] +{ #category : #properties } +WGS84 class >> worldCircumferenceInMeters [ + + ^ 2 * Float pi * self semiMajorAxisInMeters +] + { #category : #'see class side' } WGS84 >> seeClassSide [ ]