diff --git a/BaselineOfOGC/BaselineOfOGC.class.st b/BaselineOfOGC/BaselineOfOGC.class.st index a3f0005..6bdf495 100644 --- a/BaselineOfOGC/BaselineOfOGC.class.st +++ b/BaselineOfOGC/BaselineOfOGC.class.st @@ -1,45 +1,45 @@ -Class { - #name : #BaselineOfOGC, - #superclass : #BaselineOf, - #category : #BaselineOfOGC -} - -{ #category : #baselines } -BaselineOfOGC >> baseline: spec [ - - - spec for: #'common' do: [ - self geometry: spec. - spec - package: #'OGC-Core'; - package: #'OGC-Core-Tests' with: [ - spec requires: #('OGC-Core' ) ]; - package: #'OGC-Viewer'; - package: #'OGC-Viewer-Tests'; - package: #'OGC-Geometry' with: [ - spec requires: #('OGC-Core' 'Geometry') ]; - package: #'OGC-Geometry-Tests' with: [ - spec requires: #('OGC-Core-Tests' 'OGC-Geometry') ]; - package: #'OGC-Spheric' with: [ - spec requires: #('OGC-Core' ) ]; - package: #'OGC-Spheric-Tests' with: [ - spec requires: #('OGC-Core-Tests' 'OGC-Spheric') ]. - spec - group: 'Core' with: #('OGC-Core' ); - group: 'Tests' with: #('OGC-Core-Tests'); - group: 'Geometric' with: #('OGC-Geometry' 'OGC-Geometry-Tests'); - group: 'Spheric' with: #('OGC-Spheric' 'OGC-Spheric-Tests'); - group: 'Visualisation' with: #('OGC-Viewer' 'OGC-Viewer-Tests'); - group: 'default' with: #('Core' 'Tests' 'Spheric' 'Visualisation'). - ] - -] - -{ #category : #accessing } -BaselineOfOGC >> geometry: spec [ - "For Geometric projection computation" - spec - baseline: 'Geometry' - with: [ - spec repository: 'github://pharo-contributions/Geometry:master/src' ] -] +Class { + #name : #BaselineOfOGC, + #superclass : #BaselineOf, + #category : #BaselineOfOGC +} + +{ #category : #baselines } +BaselineOfOGC >> baseline: spec [ + + + spec for: #'common' do: [ + self geometry: spec. + spec + package: #'OGC-Core'; + package: #'OGC-Core-Tests' with: [ + spec requires: #('OGC-Core' ) ]; + package: #'OGC-Viewer'; + package: #'OGC-Viewer-Tests'; + package: #'OGC-Geometry' with: [ + spec requires: #('OGC-Core' 'Geometry') ]; + package: #'OGC-Geometry-Tests' with: [ + spec requires: #('OGC-Core-Tests' 'OGC-Geometry') ]; + package: #'OGC-Spheric' with: [ + spec requires: #('OGC-Core' ) ]; + package: #'OGC-Spheric-Tests' with: [ + spec requires: #('OGC-Core-Tests' 'OGC-Spheric') ]. + spec + group: 'Core' with: #('OGC-Core' ); + group: 'Tests' with: #('OGC-Core-Tests'); + group: 'Geometric' with: #('OGC-Geometry' 'OGC-Geometry-Tests'); + group: 'Spheric' with: #('OGC-Spheric' 'OGC-Spheric-Tests'); + group: 'Visualisation' with: #('OGC-Viewer' 'OGC-Viewer-Tests'); + group: 'default' with: #('Core' 'Tests' 'Geometric' 'Visualisation'). + ] + +] + +{ #category : #accessing } +BaselineOfOGC >> geometry: spec [ + "For Geometric projection computation" + spec + baseline: 'Geometry' + with: [ + spec repository: 'github://pharo-contributions/Geometry:master/src' ] +] diff --git a/BaselineOfOGC/package.st b/BaselineOfOGC/package.st index e5e5ced..f182446 100644 --- a/BaselineOfOGC/package.st +++ b/BaselineOfOGC/package.st @@ -1 +1 @@ -Package { #name : #BaselineOfOGC } +Package { #name : #BaselineOfOGC } diff --git a/OGC-Core/ManifestOGCCore.class.st b/OGC-Core/ManifestOGCCore.class.st index b6e973d..2158095 100644 --- a/OGC-Core/ManifestOGCCore.class.st +++ b/OGC-Core/ManifestOGCCore.class.st @@ -1,8 +1,8 @@ -" -Implementation of Simple Feature Access Standard from OGC: https://www.ogc.org/standards/sfa -" -Class { - #name : #ManifestOGCCore, - #superclass : #PackageManifest, - #category : #'OGC-Core-Manifest' -} +" +Implementation of Simple Feature Access Standard from OGC: https://www.ogc.org/standards/sfa +" +Class { + #name : #ManifestOGCCore, + #superclass : #PackageManifest, + #category : #'OGC-Core-Manifest' +} diff --git a/OGC-Core/OGCCurve.class.st b/OGC-Core/OGCCurve.class.st index 4ae212b..e7506f1 100644 --- a/OGC-Core/OGCCurve.class.st +++ b/OGC-Core/OGCCurve.class.st @@ -1,118 +1,123 @@ -" -6.1.6 Curve - -6.1.6.1 Description - -A Curve is a 1-dimensional geometric object usually stored as a sequence of Points, with the subtype of Curve -specifying the form of the interpolation between Points. This standard defines only one subclass of Curve, -LineString, which uses linear interpolation between Points. -" -Class { - #name : #OGCCurve, - #superclass : #OGCGeometry, - #instVars : [ - 'points' - ], - #category : #'OGC-Core' -} - -{ #category : #accessing } -OGCCurve class >> geometryType [ - ^ 'Curve' -] - -{ #category : #'as yet unclassified' } -OGCCurve class >> withPoints: aCollectionOfPoints [ - ^ self new points: aCollectionOfPoints - -] - -{ #category : #testing } -OGCCurve >> = anotherCurve [ - ^ (self points) = (anotherCurve points) -] - -{ #category : #basic } -OGCCurve >> boundary [ - "The boundary of a non-closed Curve consists of its two end Points. The boundary of a closed Curve is empty." - self isClosed ifFalse: [ ^ self class withPoints: (OrderedCollection with: (self points allButLast last) with: self endPoint) ] ifTrue: [ ^ OGCEmptySet new ] -] - -{ #category : #accessing } -OGCCurve >> coordinates [ - ^ self points -] - -{ #category : #accessing } -OGCCurve >> coordinates: aCollection [ - self points: (aCollection collect: [ :each | OGCPoint xy: each ]) -] - -{ #category : #style } -OGCCurve >> defaultFillColor [ - ^ 'transparent' -] - -{ #category : #accessing } -OGCCurve >> dimension [ - "The inherent dimension of this geometric object, which must be less than or equal to the coordinate dimension." - ^ 1 -] - -{ #category : #accessing } -OGCCurve >> endPoint [ - ^ points last -] - -{ #category : #accessing } -OGCCurve >> isClosed [ - ^ self startPoint = self endPoint -] - -{ #category : #testing } -OGCCurve >> isLine [ - ^ points size = 2 -] - -{ #category : #testing } -OGCCurve >> isRing [ - ^ self isClosed & self isSimple -] - -{ #category : #basic } -OGCCurve >> isSimple [ - "A Curve is simple if it does not pass through the same Point twice with the possible exception of the two end -points" - | setSize | - setSize := points asSet size. - ^ (points size == setSize) ifFalse: [ (setSize == (points size - 1)) and: (self isClosed) ] -] - -{ #category : #accessing } -OGCCurve >> length [ - "The length of this Curve in its associated spatial reference" - self subclassResponsibility -] - -{ #category : #accessing } -OGCCurve >> points [ - ^ points -] - -{ #category : #accessing } -OGCCurve >> points: anObject [ - points := anObject -] - -{ #category : #basic } -OGCCurve >> rectangularEnvelope [ - " Returns the minimal rectangle which contains all features " - | allRectangularEnvelopes | - allRectangularEnvelopes := points collect: [ :aPoint | aPoint rectangularEnvelope ]. - ^ allRectangularEnvelopes reduce: [ :rect1 :rect2 | rect1 merge: rect2 ] -] - -{ #category : #accessing } -OGCCurve >> startPoint [ - ^ points first -] +" +###6.1.6 Curve +###6.1.6.1 Description + +A Curve is a 1-dimensional geometric object usually stored as a sequence of Points, with the subtype of Curve specifying the form of the interpolation between Points. +This standard defines only one subclass of Curve, LineString, which uses linear interpolation between Points. + +Points are stored in `points` instance variable as a sequence of `OGCPoint` + +I am an **abstract** class. + +Instanciation: +`OGCCurve class>>#withPoints:` +" +Class { + #name : #OGCCurve, + #superclass : #OGCGeometry, + #instVars : [ + 'points' + ], + #category : #'OGC-Core' +} + +{ #category : #accessing } +OGCCurve class >> geometryType [ + ^ 'Curve' +] + +{ #category : #'as yet unclassified' } +OGCCurve class >> withPoints: aCollectionOfPoints [ + ^ self new points: aCollectionOfPoints + +] + +{ #category : #testing } +OGCCurve >> = anotherCurve [ + ^ (self points) = (anotherCurve points) +] + +{ #category : #basic } +OGCCurve >> boundary [ + "The boundary of a non-closed Curve consists of its two end Points. The boundary of a closed Curve is empty." + self isClosed ifFalse: [ ^ self class withPoints: (OrderedCollection with: (self points allButLast last) with: self endPoint) ] ifTrue: [ ^ OGCEmptySet new ] +] + +{ #category : #accessing } +OGCCurve >> coordinates [ + ^ self points +] + +{ #category : #accessing } +OGCCurve >> coordinates: aCollection [ + self points: (aCollection collect: [ :each | OGCPoint xy: each ]) +] + +{ #category : #style } +OGCCurve >> defaultFillColor [ + ^ 'transparent' +] + +{ #category : #accessing } +OGCCurve >> dimension [ + "The inherent dimension of this geometric object, which must be less than or equal to the coordinate dimension." + ^ 1 +] + +{ #category : #accessing } +OGCCurve >> endPoint [ + ^ points last +] + +{ #category : #accessing } +OGCCurve >> isClosed [ + ^ self startPoint = self endPoint +] + +{ #category : #testing } +OGCCurve >> isLine [ + ^ points size = 2 +] + +{ #category : #testing } +OGCCurve >> isRing [ + ^ self isClosed & self isSimple +] + +{ #category : #basic } +OGCCurve >> isSimple [ + "A Curve is simple if it does not pass through the same Point twice with the possible exception of the two end +points" + | setSize | + setSize := points asSet size. + ^ (points size == setSize) ifFalse: [ (setSize == (points size - 1)) and: (self isClosed) ] +] + +{ #category : #accessing } +OGCCurve >> length [ + "The length of this Curve in its associated spatial reference" + self subclassResponsibility +] + +{ #category : #accessing } +OGCCurve >> points [ + ^ points +] + +{ #category : #accessing } +OGCCurve >> points: anObject [ + points := anObject +] + +{ #category : #basic } +OGCCurve >> rectangularEnvelope [ + " Returns the minimal rectangle which contains all features " + | allRectangularEnvelopes | + allRectangularEnvelopes := points collect: [ :aPoint | aPoint rectangularEnvelope ]. + ^ allRectangularEnvelopes reduce: [ :rect1 :rect2 | rect1 merge: rect2 ] +] + +{ #category : #accessing } +OGCCurve >> startPoint [ + ^ points first +] diff --git a/OGC-Core/OGCEmptySet.class.st b/OGC-Core/OGCEmptySet.class.st index c7c276e..1547aac 100644 --- a/OGC-Core/OGCEmptySet.class.st +++ b/OGC-Core/OGCEmptySet.class.st @@ -1,23 +1,23 @@ -" -I am a geometric object with isEmpty = true. -" -Class { - #name : #OGCEmptySet, - #superclass : #OGCGeometry, - #category : #'OGC-Core' -} - -{ #category : #accessing } -OGCEmptySet class >> geometryType [ - ^ 'Empty set' -] - -{ #category : #testing } -OGCEmptySet >> = anotherObject [ - ^ self isEmpty = anotherObject isEmpty -] - -{ #category : #basic } -OGCEmptySet >> isEmpty [ - ^ true -] +" +I am the empty OGCGeometry object, so `isEmpty = true` +" +Class { + #name : #OGCEmptySet, + #superclass : #OGCGeometry, + #category : #'OGC-Core' +} + +{ #category : #accessing } +OGCEmptySet class >> geometryType [ + ^ 'Empty set' +] + +{ #category : #testing } +OGCEmptySet >> = anotherObject [ + ^ self isEmpty = anotherObject isEmpty +] + +{ #category : #basic } +OGCEmptySet >> isEmpty [ + ^ true +] diff --git a/OGC-Core/OGCFeature.class.st b/OGC-Core/OGCFeature.class.st index 113cbc5..c298134 100644 --- a/OGC-Core/OGCFeature.class.st +++ b/OGC-Core/OGCFeature.class.st @@ -1,67 +1,80 @@ -Class { - #name : #OGCFeature, - #superclass : #OGCObject, - #instVars : [ - 'geometry', - 'properties', - 'id' - ], - #category : #'OGC-Core' -} - -{ #category : #style } -OGCFeature >> applyStyle: aStyleDictionary [ - self geometry applyStyle: aStyleDictionary -] - -{ #category : #style } -OGCFeature >> applyStyle: aStyleDictionary ifFeature: aBlock [ - " apply the given style to features which respect given block closure" - (aBlock value: self) ifTrue: [ self applyStyle: aStyleDictionary ] -] - -{ #category : #converting } -OGCFeature >> asFeaturesCollection [ - ^ OGCFeatureCollection new features: (Array with: self) -] - -{ #category : #'methods analysis' } -OGCFeature >> distance: anotherFeature [ - ^ self geometry distance: anotherFeature geometry -] - -{ #category : #accessing } -OGCFeature >> geometry [ - ^ geometry -] - -{ #category : #accessing } -OGCFeature >> geometry: anObject [ - geometry := anObject -] - -{ #category : #accessing } -OGCFeature >> id [ - ^ id -] - -{ #category : #accessing } -OGCFeature >> id: aStringIdOrInteger [ - id := aStringIdOrInteger -] - -{ #category : #accessing } -OGCFeature >> properties [ - ^ properties ifNil: [ ^ properties := Dictionary new ] -] - -{ #category : #accessing } -OGCFeature >> properties: aDictionary [ - properties := aDictionary -] - -{ #category : #basic } -OGCFeature >> rectangularEnvelope [ - " Returns the minimal rectangle which contains all features " - ^ self geometry rectangularEnvelope -] +" +I represent the ""Feature"" GeoJSON element. + +I contain: +- a geospatial geometry = `OGCGeometry` +- a dictionary of Properties +- (if needed) an id +" +Class { + #name : #OGCFeature, + #superclass : #OGCObject, + #instVars : [ + 'geometry', + 'properties', + 'id' + ], + #category : #'OGC-Core' +} + +{ #category : #accessing } +OGCFeature class >> geometry: aOGCGeometry [ + ^ self new geometry: aOGCGeometry +] + +{ #category : #style } +OGCFeature >> applyStyle: aStyleDictionary [ + self geometry applyStyle: aStyleDictionary +] + +{ #category : #style } +OGCFeature >> applyStyle: aStyleDictionary ifFeature: aBlock [ + " apply the given style to features which respect given block closure" + (aBlock value: self) ifTrue: [ self applyStyle: aStyleDictionary ] +] + +{ #category : #converting } +OGCFeature >> asFeaturesCollection [ + ^ OGCFeatureCollection new features: (Array with: self) +] + +{ #category : #'methods analysis' } +OGCFeature >> distance: anotherFeature [ + ^ self geometry distance: anotherFeature geometry +] + +{ #category : #accessing } +OGCFeature >> geometry [ + ^ geometry +] + +{ #category : #accessing } +OGCFeature >> geometry: anObject [ + geometry := anObject +] + +{ #category : #accessing } +OGCFeature >> id [ + ^ id +] + +{ #category : #accessing } +OGCFeature >> id: aStringIdOrInteger [ + id := aStringIdOrInteger +] + +{ #category : #accessing } +OGCFeature >> properties [ + ^ properties ifNil: [ ^ properties := Dictionary new ] +] + +{ #category : #accessing } +OGCFeature >> properties: aDictionary [ + properties := aDictionary +] + +{ #category : #basic } +OGCFeature >> rectangularEnvelope [ + " Returns the minimal rectangle which contains all features " + ^ self geometry rectangularEnvelope +] diff --git a/OGC-Core/OGCFeatureCollection.class.st b/OGC-Core/OGCFeatureCollection.class.st index aaf2358..d1a42e9 100644 --- a/OGC-Core/OGCFeatureCollection.class.st +++ b/OGC-Core/OGCFeatureCollection.class.st @@ -1,87 +1,123 @@ -Class { - #name : #OGCFeatureCollection, - #superclass : #OGCObject, - #instVars : [ - 'features', - 'properties' - ], - #category : #'OGC-Core' -} - -{ #category : #style } -OGCFeatureCollection >> applyStyle: aStyleDictionary [ - self features do: [ :aFeature | aFeature applyStyle: aStyleDictionary ] -] - -{ #category : #style } -OGCFeatureCollection >> applyStyle: aStyleDictionary ifFeature: aBlock [ - self features do: [ :eachFeature | eachFeature applyStyle: aStyleDictionary ifFeature: aBlock ] -] - -{ #category : #style } -OGCFeatureCollection >> applyStyleOn: aDataKey withFeatureData: aCSVArray withAssociateKey: aDataAssociateKey withColor: aColorName [ - ^ self applyStyleOn: aDataKey withFeatureData: aCSVArray withAssociateKey: aDataAssociateKey withEqualityCondition: [ :a :b | a = b ] withColor: aColorName -] - -{ #category : #style } -OGCFeatureCollection >> applyStyleOn: aDataKey withFeatureData: aCSVArray withAssociateKey: aDataAssociateKey withEqualityCondition: aBlock withColor: aColorName [ - | indexKey indexAssociateKey dataDictionary maxValue minValue | - " 1. organize data " - indexKey := aCSVArray first indexOf: aDataKey. - indexAssociateKey := aCSVArray first indexOf: aDataAssociateKey. - dataDictionary := Dictionary new. - aCSVArray allButFirst do: [ :aLine | dataDictionary at: (aLine at: indexAssociateKey) put: ((aLine at: indexKey) asNumber) ]. - " 2. fix colors " - maxValue := dataDictionary values max. - minValue := dataDictionary values min. - (minValue = maxValue) - ifTrue: [ - "all features have the same value" - self applyStyle: (self class createStyleDictionary: { aColorName . nil . nil . nil }) - ] - ifFalse: [ ]. - " 3. apply color based on value" - dataDictionary keysDo: [ :aDataKey_i | - | opacity_rate equalityBlock| - opacity_rate := (((dataDictionary at: aDataKey_i) - minValue)/(maxValue - minValue)) asFloat round:3. - equalityBlock := [ :aFeature | aBlock value: (aFeature properties at: aDataAssociateKey) value: (aDataKey_i) ]. - self applyStyle: (self class createStyleDictionary: { aColorName . opacity_rate . nil . nil }) ifFeature: equalityBlock . - " we add data to properties" - self features select: equalityBlock thenDo: [ :aFeature | aFeature properties at: (aDataKey) put: (dataDictionary at: aDataKey_i) ] - ]. -] - -{ #category : #converting } -OGCFeatureCollection >> asFeaturesCollection [ - ^ self -] - -{ #category : #accessing } -OGCFeatureCollection >> features [ - ^ features -] - -{ #category : #accessing } -OGCFeatureCollection >> features: aCollection [ - features := aCollection -] - -{ #category : #accessing } -OGCFeatureCollection >> initialize [ - super initialize. - features := OrderedCollection new. - properties := Dictionary new. -] - -{ #category : #accessing } -OGCFeatureCollection >> properties [ - ^ properties -] - -{ #category : #accessing } -OGCFeatureCollection >> rectangularEnvelope [ - " Returns the minimal rectangle which contains all features " - | allRectangularEnvelopes | - allRectangularEnvelopes := features collect: [ :aFeature | aFeature geometry rectangularEnvelope ]. - ^ allRectangularEnvelopes reduce: [ :rect1 :rect2 | rect1 merge: rect2 ] -] +" +I represent the GeoJSON element called FeatureCollection which gathers: +- a collection of `OGCFeature` objects +- a dictionary of Properties = information about me + +Instanciation: `OGCFeatureCollection class>>#features:` +" +Class { + #name : #OGCFeatureCollection, + #superclass : #OGCObject, + #instVars : [ + 'features', + 'properties' + ], + #category : #'OGC-Core' +} + +{ #category : #accessing } +OGCFeatureCollection class >> features: aCollectionOfFeatures [ + ^ self new features: aCollectionOfFeatures +] + +{ #category : #adding } +OGCFeatureCollection >> addFeaturePropertyKey: aKey withData: aDictionary withIdentityKey: anIdentityKey [ + " add a property to the properties of features, + based on a dictionary which uses a join key to identify concerned feature = identity key" + aDictionary keysAndValuesDo: [ :key :value | + | index | + index := self detectFeatureIndexWithPropertyKey: anIdentityKey andValue: key. + (self features at: index) properties add: (Association key: aKey value: value) ] +] + +{ #category : #style } +OGCFeatureCollection >> applyContinuousColorationOn: aDataKey withColor: aColorName [ + | maxValue minValue | + maxValue := (self features collect: [ :aFeature | (aFeature properties at: aDataKey) asNumber ]) max. + minValue := (self features collect: [ :aFeature | (aFeature properties at: aDataKey) asNumber ]) min. + (minValue = maxValue) + ifTrue: [ + "all features have the same value" + self applyStyle: (self class createStyleDictionary: { aColorName . nil . nil . nil }) + ] + ifFalse: [ + self features do: [ :aFeature | + | opacity_rate | + opacity_rate := (((aFeature properties at: aDataKey) - minValue)/(maxValue - minValue)) asFloat round:3. + self applyStyle: (self class createStyleDictionary: { aColorName . opacity_rate . nil . nil }) ifFeature: [ :each | each = aFeature ] + ] + ]. +] + +{ #category : #style } +OGCFeatureCollection >> applyContinuousColorationOn: aDataKey withFeatureData: aCSVArray withAssociateKey: aDataAssociateKey withColor: aColorName [ + ^ self applyContinuousColorationOn: aDataKey withFeatureData: aCSVArray withAssociateKey: aDataAssociateKey withEqualityCondition: [ :a :b | a = b ] withColor: aColorName +] + +{ #category : #style } +OGCFeatureCollection >> applyContinuousColorationOn: aDataKey withFeatureData: aCSVArray withAssociateKey: aDataAssociateKey withEqualityCondition: aBlock withColor: aColorName [ + | indexKey indexAssociateKey dataDictionary | + " 1. organize data " + indexKey := aCSVArray first indexOf: aDataKey. + indexAssociateKey := aCSVArray first indexOf: aDataAssociateKey. + dataDictionary := Dictionary new. + aCSVArray allButFirst do: [ :aLine | dataDictionary at: (aLine at: indexAssociateKey) put: ((aLine at: indexKey) asNumber) ]. + " 2. add data to properties" + dataDictionary keysDo: [ :aDataKey_i | + | equalityBlock| + equalityBlock := [ :aFeature | aBlock value: (aFeature properties at: aDataAssociateKey) value: (aDataKey_i) ]. + self features select: equalityBlock thenDo: [ :aFeature | aFeature properties at: (aDataKey) put: (dataDictionary at: aDataKey_i) ] + ]. + " 3. apply continuous coloration" + self applyContinuousColorationOn: aDataKey withColor: aColorName +] + +{ #category : #style } +OGCFeatureCollection >> applyStyle: aStyleDictionary [ + self features do: [ :aFeature | aFeature applyStyle: aStyleDictionary ] +] + +{ #category : #style } +OGCFeatureCollection >> applyStyle: aStyleDictionary ifFeature: aBlock [ + self features do: [ :eachFeature | eachFeature applyStyle: aStyleDictionary ifFeature: aBlock ] +] + +{ #category : #converting } +OGCFeatureCollection >> asFeaturesCollection [ + ^ self +] + +{ #category : #accessing } +OGCFeatureCollection >> detectFeatureIndexWithPropertyKey: aKey andValue: aValue [ + ^ self features detectIndex: [ :aFeature | aFeature properties includesAssociation: (Association key: aKey value: aValue) ] +] + +{ #category : #accessing } +OGCFeatureCollection >> features [ + ^ features +] + +{ #category : #accessing } +OGCFeatureCollection >> features: aCollection [ + features := aCollection +] + +{ #category : #accessing } +OGCFeatureCollection >> initialize [ + super initialize. + features := OrderedCollection new. + properties := Dictionary new. +] + +{ #category : #accessing } +OGCFeatureCollection >> properties [ + ^ properties +] + +{ #category : #accessing } +OGCFeatureCollection >> rectangularEnvelope [ + " Returns the minimal rectangle which contains all features " + | allRectangularEnvelopes | + allRectangularEnvelopes := features collect: [ :aFeature | aFeature geometry rectangularEnvelope ]. + ^ allRectangularEnvelopes reduce: [ :rect1 :rect2 | rect1 merge: rect2 ] +] diff --git a/OGC-Core/OGCGeometry.class.st b/OGC-Core/OGCGeometry.class.st index 12b712b..be6dc2d 100644 --- a/OGC-Core/OGCGeometry.class.st +++ b/OGC-Core/OGCGeometry.class.st @@ -1,321 +1,324 @@ -" -6.1.2 Geometry - -6.1.2.1 Description - -Geometry is the root class of the hierarchy. Geometry is an abstract (non-instantiable) class. -The instantiable subclasses of Geometry defined in this Standard are restricted to 0, 1 and -2-dimensional geometric objects that exist in 2, 3 or 4-dimensional coordinate space. -Geometry values in R2 have points with coordinate values for x and y. Geometry values in R3 have points with coordinate -values for x, y and z or for x, y and m. Geometry values in R4 have points with coordinate values for x, y, z and m. -The interpretation of the coordinates is subject to the coordinate reference systems associated to the point. All -coordinates within a geometry object should be in the same coordinate reference systems. Each coordinate shall -be unambiguously associated to a coordinate reference system either directly or through its containing geometry. -The z coordinate of a point is typically, but not necessarily, represents altitude or elevation. The m coordinate -represents a measurement. -All Geometry classes described in this standard are defined so that instances of Geometry are topologically -closed, i.e. all represented geometries include their boundary as point sets. This does not affect their -" -Class { - #name : #OGCGeometry, - #superclass : #OGCObject, - #instVars : [ - 'spatialReferenceSystem', - 'measureReferenceSystems', - 'style' - ], - #category : #'OGC-Core' -} - -{ #category : #accessing } -OGCGeometry class >> geometryType [ - self subclassResponsibility -] - -{ #category : #testing } -OGCGeometry class >> isAbstract [ - ^ self == OGCGeometry -] - -{ #category : #testing } -OGCGeometry >> = anotherGeometry [ - self subclassResponsibility -] - -{ #category : #basic } -OGCGeometry >> SRID [ - "Returns the Spatial Reference System ID for this geometric object. This will normally be a -foreign key to an index of reference systems stored in either the same or some other datastore." - self subclassResponsibility -] - -{ #category : #style } -OGCGeometry >> applyStyle: aStyleDictionary [ - aStyleDictionary keysDo: [ :aKey | self style at: aKey put: (aStyleDictionary at: aKey) ] -] - -{ #category : #converting } -OGCGeometry >> asFeature [ - ^ OGCFeature new geometry: self -] - -{ #category : #converting } -OGCGeometry >> asFeaturesCollection [ - | aFeature | - aFeature := OGCFeature new geometry: self. - ^ aFeature asFeaturesCollection -] - -{ #category : #basic } -OGCGeometry >> boundary [ - "Geometry — Returns the closure of the combinatorial boundary of this geometric object -(Reference [1], section 3.12.2). Because the result of this function is a closure, and hence topologically -closed, the resulting boundary can be represented using representational Geometry primitives (Reference [1], -section 3.12.2). The return type is integer, but is interpreted as Boolean, TRUE=1, FALSE=0." - self subclassResponsibility -] - -{ #category : #'methods analysis' } -OGCGeometry >> buffer: aDistance [ - "Returns a geometric object that represents all Points whose distance -from this geometric object is less than or equal to distance." - self subclassResponsibility -] - -{ #category : #testing } -OGCGeometry >> contains: anotherGeometry [ - self subclassResponsibility -] - -{ #category : #'methods analysis' } -OGCGeometry >> convexHull [ - "Returns a geometric object that represents the convex hull of this geometric -object. Convex hulls, being dependent on straight lines, can be accurately represented in linear interpolations -for any geometry restricted to linear interpolations." - self subclassResponsibility - -] - -{ #category : #accessing } -OGCGeometry >> coordinates [ - self subclassResponsibility -] - -{ #category : #accessing } -OGCGeometry >> coordinates: newCoordinates [ - self subclassResponsibility -] - -{ #category : #testing } -OGCGeometry >> crosses: anotherGeometry [ - self subclassResponsibility -] - -{ #category : #style } -OGCGeometry >> defaultFillColor [ - ^ 'red' -] - -{ #category : #style } -OGCGeometry >> defaultFillOpacity [ - ^ '0' -] - -{ #category : #style } -OGCGeometry >> defaultStrokeColor [ - ^ 'red' -] - -{ #category : #style } -OGCGeometry >> defaultStrokeWidth [ - ^ '2' -] - -{ #category : #'methods analysis' } -OGCGeometry >> difference: anotherGeometry [ - "Returns a geometric object that represents the Point -set difference of this geometric object with anotherGeometry." - self subclassResponsibility -] - -{ #category : #basic } -OGCGeometry >> dimension [ - "The inherent dimension of this geometric object, which must be less than or equal to the coordinate dimension." - self subclassResponsibility -] - -{ #category : #testing } -OGCGeometry >> disjoint: anotherGeometry [ - self subclassResponsibility -] - -{ #category : #'methods analysis' } -OGCGeometry >> distance: anotherGeometry [ - "Returns the shortest distance between any two Points in -the two geometric objects as calculated in the spatial reference system of this geometric object. Because the -geometries are closed, it is possible to find a point on each geometric object involved, such that the distance -between these 2 points is the returned distance between their geometric objects." - self subclassResponsibility -] - -{ #category : #basic } -OGCGeometry >> envelope [ - "The minimum bounding box for this Geometry, returned as a Geometry. The -polygon is defined by the corner points of the bounding box [(MINX, MINY), (MAXX, MINY), (MAXX, MAXY), -(MINX, MAXY), (MINX, MINY)]. Minimums for Z and M may be added. The simplest representation of an -Envelope is as two direct positions, one containing all the minimums, and another all the maximums. In some -cases, this coordinate will be outside the range of validity for the Spatial Reference System" - self subclassResponsibility -] - -{ #category : #basic } -OGCGeometry >> geometryType [ - "Returns the name of the instantiable subtype of Geometry of which this geometric object is an instantiable member" - ^ self class geometryType -] - -{ #category : #initialization } -OGCGeometry >> initialize [ - spatialReferenceSystem := OGCSphericSystem -] - -{ #category : #'methods analysis' } -OGCGeometry >> intersection: anotherGeometry [ - "Returns a geometric object that represents the -Point set intersection of this geometric object with anotherGeometry." - self subclassResponsibility -] - -{ #category : #testing } -OGCGeometry >> intersects: anotherGeometry [ - self subclassResponsibility -] - -{ #category : #basic } -OGCGeometry >> is3D [ - self subclassResponsibility -] - -{ #category : #basic } -OGCGeometry >> isEmpty [ - self subclassResponsibility -] - -{ #category : #basic } -OGCGeometry >> isMeasured [ - "Returns 1 (TRUE) if this geometric object has m coordinate values." - self subclassResponsibility -] - -{ #category : #basic } -OGCGeometry >> isSimple [ - "Returns 1 (TRUE) if this geometric object has no anomalous geometric points, such -as self intersection or self tangency. The description of each instantiable geometric class will include the -specific conditions that cause an instance of that class to be classified as not simple. The return type is -integer, but is interpreted as Boolean, TRUE=1, FALSE=0." - self subclassResponsibility -] - -{ #category : #testing } -OGCGeometry >> locateAlong: mValue [ - "Returns a derived geometry collection value that matches the -specified m coordinate value. See Subclause 6.1.2.6 “Measures on Geometry” for more details" - self subclassResponsibility -] - -{ #category : #testing } -OGCGeometry >> locateBetween: mStart and: mEnd [ - "Returns a derived geometry collection value -that matches the specified range of m coordinate values inclusively. See Subclause 6.1.2.6 “Measures on -Geometry” for more details." - self subclassResponsibility -] - -{ #category : #testing } -OGCGeometry >> overlaps: anotherGeometry [ - self subclassResponsibility -] - -{ #category : #basic } -OGCGeometry >> rectangularEnvelope [ - "Returns the minimal rectangle which contains the geometry" - self subclassResponsibility -] - -{ #category : #testing } -OGCGeometry >> relate: anotherGeometry [ - "Returns 1 (TRUE) if this -geometric object is spatially related to anotherGeometry by testing for intersections between the interior, -boundary and exterior of the two geometric objects as specified by the values in the intersectionPatternMatrix. -This returns FALSE if all the tested intersections are empty except exterior (this) intersect exterior (another)." - self subclassResponsibility -] - -{ #category : #accessing } -OGCGeometry >> spatialReferenceSystem [ - ^ spatialReferenceSystem -] - -{ #category : #accessing } -OGCGeometry >> style [ - ^ style ifNil: [ ^ style := Dictionary new ] -] - -{ #category : #accessing } -OGCGeometry >> style: aDictionaryWithStyleSpecs [ - style := aDictionaryWithStyleSpecs - -] - -{ #category : #style } -OGCGeometry >> styleFillColor [ - | color colorObject | - color := self style at: 'fill' ifAbsent: [ self defaultFillColor ]. - colorObject := (Color named: color) ifNil: [ Color named: self defaultFillColor ]. - ^ colorObject alpha: self styleFillOpacity -] - -{ #category : #style } -OGCGeometry >> styleFillOpacity [ - | fillOpacity | - fillOpacity := self style at: 'fill-opacity' ifAbsent: [ self defaultFillOpacity ]. - ^ (fillOpacity asNumber) ifNil: [ ^ self defaultFillOpacity asNumber ] -] - -{ #category : #style } -OGCGeometry >> styleStrokeColor [ - | color | - color := self style at: 'stroke' ifAbsent: [ self defaultStrokeColor ]. - ^ (Color named: color) ifNil: [ ^ Color named: self defaultStrokeColor ] -] - -{ #category : #style } -OGCGeometry >> styleStrokeWidth [ - | width | - width := self style at: 'stroke-width' ifAbsent: [ self defaultStrokeWidth ]. - ^ (width asNumber) ifNil: [ ^ self defaultStrokeWidth asNumber ] -] - -{ #category : #'methods analysis' } -OGCGeometry >> symDifference: anotherGeometry [ - "Returns a geometric object that represents the -Point set symmetric difference of this geometric object with anotherGeometry." - self subclassResponsibility -] - -{ #category : #testing } -OGCGeometry >> touches: anotherGeometry [ - self subclassResponsibility -] - -{ #category : #'methods analysis' } -OGCGeometry >> union: anotherGeometry [ - "Returns a geometric object that represents the Point set -union of this geometric object with anotherGeometry." - self subclassResponsibility -] - -{ #category : #testing } -OGCGeometry >> within: anotherGeometry [ - self subclassResponsibility -] +" +###6.1.2 Geometry +###6.1.2.1 Description + +**Geometry is the root class of the hierarchy.** + +Geometry is an **abstract** (non-instantiable) class. + +The instantiable subclasses of Geometry defined in this Standard are restricted to 0, 1 and 2-dimensional geometric objects that exist in 2, 3 or 4-dimensional coordinate space. +- Geometry values in R2 have points with coordinate values for x and y. +- Geometry values in R3 have points with coordinate values for x, y and z or for x, y and m. +- Geometry values in R4 have points with coordinate values for x, y, z and m. + +_Note: The z coordinate of a point is typically, but not necessarily, represents altitude or elevation. The m coordinate represents a **measurement** = `measureReferenceSystems` instance variable._ + +The interpretation of the coordinates is subject to the **coordinate reference systems** associated to the point = `spatialReferenceSystem` instance variable. +_All coordinates within a geometry object should be in the same coordinate reference systems. +Each coordinate shallbe unambiguously associated to a coordinate reference system either directly or through its containing geometry._ + +All Geometry classes described in this standard are defined so that instances of Geometry are topologically closed, i.e. all represented geometries include their boundary as point sets. This does not affect their +" +Class { + #name : #OGCGeometry, + #superclass : #OGCObject, + #instVars : [ + 'spatialReferenceSystem', + 'measureReferenceSystems', + 'style' + ], + #category : #'OGC-Core' +} + +{ #category : #accessing } +OGCGeometry class >> geometryType [ + self subclassResponsibility +] + +{ #category : #testing } +OGCGeometry class >> isAbstract [ + ^ self == OGCGeometry +] + +{ #category : #testing } +OGCGeometry >> = anotherGeometry [ + self subclassResponsibility +] + +{ #category : #basic } +OGCGeometry >> SRID [ + "Returns the Spatial Reference System ID for this geometric object. This will normally be a +foreign key to an index of reference systems stored in either the same or some other datastore." + self subclassResponsibility +] + +{ #category : #style } +OGCGeometry >> applyStyle: aStyleDictionary [ + aStyleDictionary keysDo: [ :aKey | self style at: aKey put: (aStyleDictionary at: aKey) ] +] + +{ #category : #converting } +OGCGeometry >> asFeature [ + ^ OGCFeature new geometry: self +] + +{ #category : #converting } +OGCGeometry >> asFeaturesCollection [ + | aFeature | + aFeature := OGCFeature new geometry: self. + ^ aFeature asFeaturesCollection +] + +{ #category : #basic } +OGCGeometry >> boundary [ + "Geometry — Returns the closure of the combinatorial boundary of this geometric object +(Reference [1], section 3.12.2). Because the result of this function is a closure, and hence topologically +closed, the resulting boundary can be represented using representational Geometry primitives (Reference [1], +section 3.12.2). The return type is integer, but is interpreted as Boolean, TRUE=1, FALSE=0." + self subclassResponsibility +] + +{ #category : #'methods analysis' } +OGCGeometry >> buffer: aDistance [ + "Returns a geometric object that represents all Points whose distance +from this geometric object is less than or equal to distance." + self subclassResponsibility +] + +{ #category : #testing } +OGCGeometry >> contains: anotherGeometry [ + self subclassResponsibility +] + +{ #category : #'methods analysis' } +OGCGeometry >> convexHull [ + "Returns a geometric object that represents the convex hull of this geometric +object. Convex hulls, being dependent on straight lines, can be accurately represented in linear interpolations +for any geometry restricted to linear interpolations." + self subclassResponsibility + +] + +{ #category : #accessing } +OGCGeometry >> coordinates [ + self subclassResponsibility +] + +{ #category : #accessing } +OGCGeometry >> coordinates: newCoordinates [ + self subclassResponsibility +] + +{ #category : #testing } +OGCGeometry >> crosses: anotherGeometry [ + self subclassResponsibility +] + +{ #category : #style } +OGCGeometry >> defaultFillColor [ + ^ 'red' +] + +{ #category : #style } +OGCGeometry >> defaultFillOpacity [ + ^ '0' +] + +{ #category : #style } +OGCGeometry >> defaultStrokeColor [ + ^ 'red' +] + +{ #category : #style } +OGCGeometry >> defaultStrokeWidth [ + ^ '2' +] + +{ #category : #'methods analysis' } +OGCGeometry >> difference: anotherGeometry [ + "Returns a geometric object that represents the Point +set difference of this geometric object with anotherGeometry." + self subclassResponsibility +] + +{ #category : #basic } +OGCGeometry >> dimension [ + "The inherent dimension of this geometric object, which must be less than or equal to the coordinate dimension." + self subclassResponsibility +] + +{ #category : #testing } +OGCGeometry >> disjoint: anotherGeometry [ + self subclassResponsibility +] + +{ #category : #'methods analysis' } +OGCGeometry >> distance: anotherGeometry [ + "Returns the shortest distance between any two Points in +the two geometric objects as calculated in the spatial reference system of this geometric object. Because the +geometries are closed, it is possible to find a point on each geometric object involved, such that the distance +between these 2 points is the returned distance between their geometric objects." + self subclassResponsibility +] + +{ #category : #basic } +OGCGeometry >> envelope [ + "The minimum bounding box for this Geometry, returned as a Geometry. The +polygon is defined by the corner points of the bounding box [(MINX, MINY), (MAXX, MINY), (MAXX, MAXY), +(MINX, MAXY), (MINX, MINY)]. Minimums for Z and M may be added. The simplest representation of an +Envelope is as two direct positions, one containing all the minimums, and another all the maximums. In some +cases, this coordinate will be outside the range of validity for the Spatial Reference System" + self subclassResponsibility +] + +{ #category : #basic } +OGCGeometry >> geometryType [ + "Returns the name of the instantiable subtype of Geometry of which this geometric object is an instantiable member" + ^ self class geometryType +] + +{ #category : #initialization } +OGCGeometry >> initialize [ + spatialReferenceSystem := OGCGeometricProjection +] + +{ #category : #'methods analysis' } +OGCGeometry >> intersection: anotherGeometry [ + "Returns a geometric object that represents the +Point set intersection of this geometric object with anotherGeometry." + self subclassResponsibility +] + +{ #category : #testing } +OGCGeometry >> intersects: anotherGeometry [ + self subclassResponsibility +] + +{ #category : #basic } +OGCGeometry >> is3D [ + self subclassResponsibility +] + +{ #category : #testing } +OGCGeometry >> isEmpty [ + self subclassResponsibility +] + +{ #category : #basic } +OGCGeometry >> isMeasured [ + "Returns 1 (TRUE) if this geometric object has m coordinate values." + self subclassResponsibility +] + +{ #category : #basic } +OGCGeometry >> isSimple [ + "Returns 1 (TRUE) if this geometric object has no anomalous geometric points, such +as self intersection or self tangency. The description of each instantiable geometric class will include the +specific conditions that cause an instance of that class to be classified as not simple. The return type is +integer, but is interpreted as Boolean, TRUE=1, FALSE=0." + self subclassResponsibility +] + +{ #category : #testing } +OGCGeometry >> locateAlong: mValue [ + "Returns a derived geometry collection value that matches the +specified m coordinate value. See Subclause 6.1.2.6 “Measures on Geometry” for more details" + self subclassResponsibility +] + +{ #category : #testing } +OGCGeometry >> locateBetween: mStart and: mEnd [ + "Returns a derived geometry collection value +that matches the specified range of m coordinate values inclusively. See Subclause 6.1.2.6 “Measures on +Geometry” for more details." + self subclassResponsibility +] + +{ #category : #testing } +OGCGeometry >> overlaps: anotherGeometry [ + self subclassResponsibility +] + +{ #category : #basic } +OGCGeometry >> rectangularEnvelope [ + "Returns the minimal rectangle which contains the geometry" + self subclassResponsibility +] + +{ #category : #testing } +OGCGeometry >> relate: anotherGeometry [ + "Returns 1 (TRUE) if this +geometric object is spatially related to anotherGeometry by testing for intersections between the interior, +boundary and exterior of the two geometric objects as specified by the values in the intersectionPatternMatrix. +This returns FALSE if all the tested intersections are empty except exterior (this) intersect exterior (another)." + self subclassResponsibility +] + +{ #category : #accessing } +OGCGeometry >> spatialReferenceSystem [ + ^ spatialReferenceSystem +] + +{ #category : #accessing } +OGCGeometry >> style [ + ^ style ifNil: [ ^ style := Dictionary new ] +] + +{ #category : #accessing } +OGCGeometry >> style: aDictionaryWithStyleSpecs [ + style := aDictionaryWithStyleSpecs + +] + +{ #category : #style } +OGCGeometry >> styleFillColor [ + | color colorObject | + color := self style at: 'fill' ifAbsent: [ self defaultFillColor ]. + colorObject := (Color named: color) ifNil: [ Color named: self defaultFillColor ]. + ^ colorObject alpha: self styleFillOpacity +] + +{ #category : #style } +OGCGeometry >> styleFillOpacity [ + | fillOpacity | + fillOpacity := self style at: 'fill-opacity' ifAbsent: [ self defaultFillOpacity ]. + ^ (fillOpacity asNumber) ifNil: [ ^ self defaultFillOpacity asNumber ] +] + +{ #category : #style } +OGCGeometry >> styleStrokeColor [ + | color | + color := self style at: 'stroke' ifAbsent: [ self defaultStrokeColor ]. + ^ (Color named: color) ifNil: [ ^ Color named: self defaultStrokeColor ] +] + +{ #category : #style } +OGCGeometry >> styleStrokeWidth [ + | width | + width := self style at: 'stroke-width' ifAbsent: [ self defaultStrokeWidth ]. + ^ (width asNumber) ifNil: [ ^ self defaultStrokeWidth asNumber ] +] + +{ #category : #'methods analysis' } +OGCGeometry >> symDifference: anotherGeometry [ + "Returns a geometric object that represents the +Point set symmetric difference of this geometric object with anotherGeometry." + self subclassResponsibility +] + +{ #category : #testing } +OGCGeometry >> touches: anotherGeometry [ + self subclassResponsibility +] + +{ #category : #'methods analysis' } +OGCGeometry >> union: anotherGeometry [ + "Returns a geometric object that represents the Point set +union of this geometric object with anotherGeometry." + self subclassResponsibility +] + +{ #category : #testing } +OGCGeometry >> within: anotherGeometry [ + self subclassResponsibility +] diff --git a/OGC-Core/OGCGeometryCollection.class.st b/OGC-Core/OGCGeometryCollection.class.st index ce9cd2a..eab5247 100644 --- a/OGC-Core/OGCGeometryCollection.class.st +++ b/OGC-Core/OGCGeometryCollection.class.st @@ -1,71 +1,85 @@ -" -6.1.3 GeometryCollection - -6.1.3.1 Description - -A GeometryCollection is a geometric object that is a collection of some number of geometric objects. -All the elements in a GeometryCollection shall be in the same Spatial Reference System. This is also the Spatial -Reference System for the GeometryCollection. -GeometryCollection places no other constraints on its elements. Subclasses of GeometryCollection may restrict -membership based on dimension and may also place other constraints on the degree of spatial overlap between -elements. -" -Class { - #name : #OGCGeometryCollection, - #superclass : #OGCGeometry, - #instVars : [ - 'geometries' - ], - #category : #'OGC-Core' -} - -{ #category : #testing } -OGCGeometryCollection class >> isAbstract [ - ^ self = OGCGeometryCollection -] - -{ #category : #testing } -OGCGeometryCollection >> = anotherMultiPoint [ - ^ self geometries asSet = anotherMultiPoint geometries asSet -] - -{ #category : #accessing } -OGCGeometryCollection >> coordinates [ - ^ geometries collect: #coordinates -] - -{ #category : #basic } -OGCGeometryCollection >> dimension [ - ^ geometries sorted: [ :e1 :e2 | e1 dimension > e2 dimension ] first -] - -{ #category : #accessing } -OGCGeometryCollection >> geometries [ - ^ geometries -] - -{ #category : #accessing } -OGCGeometryCollection >> geometries: anObject [ - geometries := anObject. - geometries do: [ :each | each style: self style ]. -] - -{ #category : #accessing } -OGCGeometryCollection >> geometryN: index [ - "Returns the Nth geometry in this GeometryCollection" - ^ geometries at: index -] - -{ #category : #accessing } -OGCGeometryCollection >> numGeometries [ - "cReturns the number of geometries in this GeometryCollection" - ^ geometries size -] - -{ #category : #basic } -OGCGeometryCollection >> rectangularEnvelope [ - " Returns the minimal rectangle which contains all features " - | allRectangularEnvelopes | - allRectangularEnvelopes := geometries collect: [ :aGeometry | aGeometry rectangularEnvelope ]. - ^ allRectangularEnvelopes reduce: [ :rect1 :rect2 | rect1 merge: rect2 ] -] +" +###6.1.3 GeometryCollection + +###6.1.3.1 Description + +A GeometryCollection is a geometric object that is **a collection of some number of geometric objects**. + +All the elements in a GeometryCollection shall be in the same Spatial Reference System. +This is also the Spatial Reference System for the GeometryCollection. + +GeometryCollection places no other constraints on its elements. +Subclasses of GeometryCollection may restrict membership based on dimension and may also place other constraints on the degree of spatial overlap between elements. +" +Class { + #name : #OGCGeometryCollection, + #superclass : #OGCGeometry, + #instVars : [ + 'geometries' + ], + #category : #'OGC-Core' +} + +{ #category : #accessing } +OGCGeometryCollection class >> geometries: aCollectionOfGeometries [ + | classToGenerate | + classToGenerate := self. + (aCollectionOfGeometries allSatisfy: [ :each | each class geometryType = 'LineString' ]) + ifTrue: [ classToGenerate := OGCMultiLineString ]. + (aCollectionOfGeometries allSatisfy: [ :each | each class geometryType = 'Point' ]) + ifTrue: [ classToGenerate := OGCMultiPoint ]. + (aCollectionOfGeometries allSatisfy: [ :each | each class geometryType = 'Polygon' ]) + ifTrue: [ classToGenerate := OGCMultiPolygon ]. + ^ classToGenerate new geometries: aCollectionOfGeometries +] + +{ #category : #testing } +OGCGeometryCollection class >> isAbstract [ + ^ self == OGCGeometryCollection +] + +{ #category : #testing } +OGCGeometryCollection >> = anotherMultiPoint [ + ^ self geometries asSet = anotherMultiPoint geometries asSet +] + +{ #category : #accessing } +OGCGeometryCollection >> coordinates [ + ^ geometries collect: #coordinates +] + +{ #category : #basic } +OGCGeometryCollection >> dimension [ + ^ geometries sorted: [ :e1 :e2 | e1 dimension > e2 dimension ] first +] + +{ #category : #accessing } +OGCGeometryCollection >> geometries [ + ^ geometries +] + +{ #category : #accessing } +OGCGeometryCollection >> geometries: anObject [ + geometries := anObject. + geometries do: [ :each | each style: self style ]. +] + +{ #category : #accessing } +OGCGeometryCollection >> geometryN: index [ + "Returns the Nth geometry in this GeometryCollection" + ^ geometries at: index +] + +{ #category : #accessing } +OGCGeometryCollection >> numGeometries [ + "cReturns the number of geometries in this GeometryCollection" + ^ geometries size +] + +{ #category : #basic } +OGCGeometryCollection >> rectangularEnvelope [ + " Returns the minimal rectangle which contains all features " + | allRectangularEnvelopes | + allRectangularEnvelopes := geometries collect: [ :aGeometry | aGeometry rectangularEnvelope ]. + ^ allRectangularEnvelopes reduce: [ :rect1 :rect2 | rect1 merge: rect2 ] +] diff --git a/OGC-Core/OGCIncorrectNumberOfPointsError.class.st b/OGC-Core/OGCIncorrectNumberOfPointsError.class.st index 949ddf0..579ad69 100644 --- a/OGC-Core/OGCIncorrectNumberOfPointsError.class.st +++ b/OGC-Core/OGCIncorrectNumberOfPointsError.class.st @@ -1,39 +1,39 @@ -" -Error used when too many points are given to instanciate a Line. -" -Class { - #name : #OGCIncorrectNumberOfPointsError, - #superclass : #Error, - #instVars : [ - 'size' - ], - #category : #'OGC-Core-Errors' -} - -{ #category : #signalling } -OGCIncorrectNumberOfPointsError class >> signalWith: anInteger [ - ^ self new - size: anInteger; - signal -] - -{ #category : #accessing } -OGCIncorrectNumberOfPointsError >> messageText [ - "Overwritten to initialiaze the message text to a standard text if it has not yet been set" - - ^ messageText ifNil: [ messageText := self standardMessageText ] -] - -{ #category : #accessing } -OGCIncorrectNumberOfPointsError >> size: anInteger [ - size := anInteger -] - -{ #category : #printing } -OGCIncorrectNumberOfPointsError >> standardMessageText [ - "Generate a standard textual description" - - ^ String streamContents: [ :stream | - stream print: size. - stream << ' points were given instead of 2 to define a Line' ] -] +" +Error used when too many points are given to instanciate a Line. +" +Class { + #name : #OGCIncorrectNumberOfPointsError, + #superclass : #Error, + #instVars : [ + 'size' + ], + #category : #'OGC-Core-Errors' +} + +{ #category : #signalling } +OGCIncorrectNumberOfPointsError class >> signalWith: anInteger [ + ^ self new + size: anInteger; + signal +] + +{ #category : #accessing } +OGCIncorrectNumberOfPointsError >> messageText [ + "Overwritten to initialiaze the message text to a standard text if it has not yet been set" + + ^ messageText ifNil: [ messageText := self standardMessageText ] +] + +{ #category : #accessing } +OGCIncorrectNumberOfPointsError >> size: anInteger [ + size := anInteger +] + +{ #category : #printing } +OGCIncorrectNumberOfPointsError >> standardMessageText [ + "Generate a standard textual description" + + ^ String streamContents: [ :stream | + stream print: size. + stream << ' points were given instead of 2 to define a Line' ] +] diff --git a/OGC-Core/OGCLine.class.st b/OGC-Core/OGCLine.class.st index 005863f..65a6f60 100644 --- a/OGC-Core/OGCLine.class.st +++ b/OGC-Core/OGCLine.class.st @@ -1,41 +1,36 @@ -" -6.1.7 LineString, Line, LinearRing - -6.1.7.1 Description - -A Line is a LineString with exactly 2 Points. -" -Class { - #name : #OGCLine, - #superclass : #OGCLineString, - #category : #'OGC-Core' -} - -{ #category : #'as yet unclassified' } -OGCLine class >> errorIncorrectNumberOfPoints: anInteger [ - OGCIncorrectNumberOfPointsError signalWith: anInteger -] - -{ #category : #accessing } -OGCLine class >> geometryType [ - ^ 'Line' -] - -{ #category : #'as yet unclassified' } -OGCLine class >> withPoints: aCollectionOfPoints [ - (aCollectionOfPoints size = 2) - ifTrue: [ ^ self new points: aCollectionOfPoints ] - ifFalse: [ self errorIncorrectNumberOfPoints: aCollectionOfPoints size] -] - -{ #category : #'methods analysis' } -OGCLine >> intersection: anotherGeometry [ - "Returns a geometric object that represents the -Point set intersection of this geometric object with anotherGeometry." - ^ spatialReferenceSystem intersection: anotherGeometry withLine: self -] - -{ #category : #accessing } -OGCLine >> length [ - ^ spatialReferenceSystem length: self -] +" +###6.1.7 LineString, Line, LinearRing + +###6.1.7.1 Description + +A Line is a LineString with exactly 2 Points = a segment. + +Instanciation: `OGCLine class>>#withPoints:` +" +Class { + #name : #OGCLine, + #superclass : #OGCLineString, + #category : #'OGC-Core' +} + +{ #category : #'as yet unclassified' } +OGCLine class >> errorIncorrectNumberOfPoints: anInteger [ + OGCIncorrectNumberOfPointsError signalWith: anInteger +] + +{ #category : #accessing } +OGCLine class >> geometryType [ + ^ 'Line' +] + +{ #category : #'as yet unclassified' } +OGCLine class >> withPoints: aCollectionOfPoints [ + (aCollectionOfPoints size = 2) + ifTrue: [ ^ self new points: aCollectionOfPoints ] + ifFalse: [ self errorIncorrectNumberOfPoints: aCollectionOfPoints size] +] + +{ #category : #accessing } +OGCLine >> length [ + ^ spatialReferenceSystem length: self +] diff --git a/OGC-Core/OGCLineString.class.st b/OGC-Core/OGCLineString.class.st index 70c6980..637a199 100644 --- a/OGC-Core/OGCLineString.class.st +++ b/OGC-Core/OGCLineString.class.st @@ -1,43 +1,53 @@ -" -6.1.7 LineString, Line, LinearRing - -6.1.7.1 Description - -A LineString is a Curve with linear interpolation between Points. Each consecutive pair of Points defines a Line -segment. -" -Class { - #name : #OGCLineString, - #superclass : #OGCCurve, - #category : #'OGC-Core' -} - -{ #category : #accessing } -OGCLineString class >> geometryType [ - ^ 'LineString' -] - -{ #category : #accessing } -OGCLineString >> length [ - ^ self length: points allButFirst withValue: 0 andStartedPoint: points first -] - -{ #category : #initialization } -OGCLineString >> length: aCollectionOfPoints withValue: aLength andStartedPoint: aPoint [ - ^ aCollectionOfPoints - ifEmpty: [ aLength ] - ifNotEmpty: - [ self length: aCollectionOfPoints allButFirst withValue: aLength + (aPoint distance: aCollectionOfPoints first) andStartedPoint: aCollectionOfPoints first ] -] - -{ #category : #access } -OGCLineString >> numPoints [ - "The number of Points in this LineString" - ^ points size -] - -{ #category : #access } -OGCLineString >> pointN: anInteger [ - "Returns the specified Point N in this LineString" - ^ points at: anInteger -] +" +###6.1.7 LineString, Line, LinearRing + +###6.1.7.1 Description + +A LineString is a Curve with linear interpolation between Points. +Each consecutive pair of Points defines a Line segment. +" +Class { + #name : #OGCLineString, + #superclass : #OGCCurve, + #instVars : [ + 'lines' + ], + #category : #'OGC-Core' +} + +{ #category : #accessing } +OGCLineString class >> geometryType [ + ^ 'LineString' +] + +{ #category : #'as yet unclassified' } +OGCLineString >> getLines [ + | resultLines | + resultLines := OrderedCollection new. + points allButLast doWithIndex: [ :point :index | resultLines add: (OGCLine withPoints: { point . (points at: (index + 1 ) ) }) ]. + ^ resultLines +] + +{ #category : #accessing } +OGCLineString >> length [ + | lengthLines | + lengthLines := (self lines collect: [ :aLine | aLine length ]). + ^ lengthLines ifNotEmpty: [ lengthLines sum ] ifEmpty: [ 0 ] +] + +{ #category : #accessing } +OGCLineString >> lines [ + ^ lines ifNil: [ lines := self getLines ] +] + +{ #category : #access } +OGCLineString >> numPoints [ + "The number of Points in this LineString" + ^ points size +] + +{ #category : #access } +OGCLineString >> pointN: anInteger [ + "Returns the specified Point N in this LineString" + ^ points at: anInteger +] diff --git a/OGC-Core/OGCLinearRing.class.st b/OGC-Core/OGCLinearRing.class.st index 55dc152..8fbdab0 100644 --- a/OGC-Core/OGCLinearRing.class.st +++ b/OGC-Core/OGCLinearRing.class.st @@ -1,32 +1,33 @@ -" -6.1.7 LineString, Line, LinearRing - -6.1.7.1 Description - -A LinearRing is a LineString that is both closed and simple. The Curve in Figure 2, item (c), is a closed LineString -that is a LinearRing. The Curve in Figure 2, item (d) is a closed LineString that is not a LinearRing. -" -Class { - #name : #OGCLinearRing, - #superclass : #OGCLineString, - #category : #'OGC-Core' -} - -{ #category : #accessing } -OGCLinearRing class >> geometryType [ - ^ 'LinearRing' -] - -{ #category : #'as yet unclassified' } -OGCLinearRing class >> notALinearRing: isClosed and: isSimple [ - OGCNotALinearRingError signal: isClosed and: isSimple -] - -{ #category : #'as yet unclassified' } -OGCLinearRing class >> withPoints: aCollectionOfPoints [ - | lineString | - lineString := self superclass withPoints: aCollectionOfPoints. - (lineString isRing) - ifTrue: [ ^ lineString ] - ifFalse: [ self notALinearRing: lineString isClosed and: lineString isSimple] -] +" +###6.1.7 LineString, Line, LinearRing + +###6.1.7.1 Description + +A LinearRing is **a LineString** that is: +- **closed**: my start point is equal to my end point +- **simple**: no intersection +" +Class { + #name : #OGCLinearRing, + #superclass : #OGCLineString, + #category : #'OGC-Core' +} + +{ #category : #accessing } +OGCLinearRing class >> geometryType [ + ^ 'LinearRing' +] + +{ #category : #'as yet unclassified' } +OGCLinearRing class >> notALinearRing: isClosed and: isSimple [ + OGCNotALinearRingError signal: isClosed and: isSimple +] + +{ #category : #'as yet unclassified' } +OGCLinearRing class >> withPoints: aCollectionOfPoints [ + | lineString | + lineString := self superclass withPoints: aCollectionOfPoints. + (lineString isRing) + ifTrue: [ ^ lineString ] + ifFalse: [ self notALinearRing: lineString isClosed and: lineString isSimple] +] diff --git a/OGC-Core/OGCMeasureReferenceSystem.class.st b/OGC-Core/OGCMeasureReferenceSystem.class.st index a802248..09af23c 100644 --- a/OGC-Core/OGCMeasureReferenceSystem.class.st +++ b/OGC-Core/OGCMeasureReferenceSystem.class.st @@ -1,9 +1,9 @@ -" -The m coordinate value allows the application environment to -associate some measure with the point values -" -Class { - #name : #OGCMeasureReferenceSystem, - #superclass : #OGCReferenceSystem, - #category : #'OGC-Core' -} +" +The m coordinate value allows the application environment to +associate some measure with the point values +" +Class { + #name : #OGCMeasureReferenceSystem, + #superclass : #OGCReferenceSystem, + #category : #'OGC-Core' +} diff --git a/OGC-Core/OGCMultiCurve.class.st b/OGC-Core/OGCMultiCurve.class.st index 75b0b75..613f7e1 100644 --- a/OGC-Core/OGCMultiCurve.class.st +++ b/OGC-Core/OGCMultiCurve.class.st @@ -1,48 +1,47 @@ -" -6.1.8 MultiCurve - -6.1.8.1 Description - -A MultiCurve is a 1-dimensional GeometryCollection whose elements are Curves as in Figure 3. - -MultiCurve is a non-instantiable class in this standard; it defines a set of methods for its subclasses and is -included for reasons of extensibility. -A MultiCurve is simple if and only if all of its elements are simple and the only intersections between any two -elements occur at Points that are on the boundaries of both elements. -The boundary of a MultiCurve is obtained by applying the “mod 2” union rule: A Point is in the boundary of a -MultiCurve if it is in the boundaries of an odd number of elements of the MultiCurve (Reference [1], section -3.12.3.2). -A MultiCurve is closed if all of its elements are closed. The boundary of a closed MultiCurve is always empty. -A MultiCurve is defined as topologically closed. -" -Class { - #name : #OGCMultiCurve, - #superclass : #OGCGeometryCollection, - #category : #'OGC-Core' -} - -{ #category : #accessing } -OGCMultiCurve class >> geometryType [ - ^ 'MultiCurve' -] - -{ #category : #testing } -OGCMultiCurve class >> isAbstract [ - ^ self == OGCMultiCurve -] - -{ #category : #basic } -OGCMultiCurve >> dimension [ - ^ 1 -] - -{ #category : #testing } -OGCMultiCurve >> isClosed [ - "A MultiCurve is closed if all of its elements are closed." - ^ self geometries allSatisfy: [ :each | each isClosed ] -] - -{ #category : #accessing } -OGCMultiCurve >> length [ - ^ self geometries sum: [ :each | each length ] -] +" +###6.1.8 MultiCurve + +###6.1.8.1 Description + +A MultiCurve is a 1-dimensional GeometryCollection whose elements are Curves. + +MultiCurve is a non-instantiable class in this standard: I am an **abstract** class. +It defines a set of methods for its subclasses and is included for reasons of extensibility. + +A MultiCurve is simple if and only if all of its elements are simple and the only intersections between any two elements occur at Points that are on the boundaries of both elements. +The boundary of a MultiCurve is obtained by applying the “mod 2” union rule: A Point is in the boundary of a MultiCurve if it is in the boundaries of an odd number of elements of the MultiCurve (Reference [1], section +3.12.3.2). +A MultiCurve is closed if all of its elements are closed. The boundary of a closed MultiCurve is always empty. +A MultiCurve is defined as topologically closed. +" +Class { + #name : #OGCMultiCurve, + #superclass : #OGCGeometryCollection, + #category : #'OGC-Core' +} + +{ #category : #accessing } +OGCMultiCurve class >> geometryType [ + ^ 'MultiCurve' +] + +{ #category : #testing } +OGCMultiCurve class >> isAbstract [ + ^ self == OGCMultiCurve +] + +{ #category : #basic } +OGCMultiCurve >> dimension [ + ^ 1 +] + +{ #category : #testing } +OGCMultiCurve >> isClosed [ + "A MultiCurve is closed if all of its elements are closed." + ^ self geometries allSatisfy: [ :each | each isClosed ] +] + +{ #category : #accessing } +OGCMultiCurve >> length [ + ^ self geometries sum: [ :each | each length ] +] diff --git a/OGC-Core/OGCMultiLineString.class.st b/OGC-Core/OGCMultiLineString.class.st index 5fdd0ce..2615bd1 100644 --- a/OGC-Core/OGCMultiLineString.class.st +++ b/OGC-Core/OGCMultiLineString.class.st @@ -1,21 +1,21 @@ -" -6.1.9 MultiLineString - -A MultiLineString is a MultiCurve whose elements are LineStrings. -" -Class { - #name : #OGCMultiLineString, - #superclass : #OGCMultiCurve, - #category : #'OGC-Core' -} - -{ #category : #accessing } -OGCMultiLineString class >> geometryType [ - ^ 'MultiLineString' -] - -{ #category : #accessing } -OGCMultiLineString >> coordinates: aCollection [ - geometries := aCollection collect: [ :each | - OGCLineString new coordinates: each ] -] +" +###6.1.9 MultiLineString + +A MultiLineString is a MultiCurve whose elements are LineStrings. +" +Class { + #name : #OGCMultiLineString, + #superclass : #OGCMultiCurve, + #category : #'OGC-Core' +} + +{ #category : #accessing } +OGCMultiLineString class >> geometryType [ + ^ 'MultiLineString' +] + +{ #category : #accessing } +OGCMultiLineString >> coordinates: aCollection [ + geometries := aCollection collect: [ :each | + OGCLineString new coordinates: each ] +] diff --git a/OGC-Core/OGCMultiPoint.class.st b/OGC-Core/OGCMultiPoint.class.st index 3622a25..cdfd232 100644 --- a/OGC-Core/OGCMultiPoint.class.st +++ b/OGC-Core/OGCMultiPoint.class.st @@ -1,56 +1,57 @@ -" -6.1.5 MultiPoint - -A MultiPoint is a 0-dimensional GeometryCollection. The elements of a MultiPoint are restricted to Points. The -Points are not connected or ordered in any semantically important way (see the discussion at -GeometryCollection). -A MultiPoint is simple if no two Points in the MultiPoint are equal (have identical coordinate values in X and Y). -Every MultiPoint is spatially equal under the definition in Clause 6.1.15.3 to a simple Multipoint. -The boundary of a MultiPoint is the empty set. -" -Class { - #name : #OGCMultiPoint, - #superclass : #OGCGeometryCollection, - #category : #'OGC-Core' -} - -{ #category : #accessing } -OGCMultiPoint class >> geometryType [ - ^ 'MultiPoint' -] - -{ #category : #'instance creation' } -OGCMultiPoint class >> withPoints: aBagOfPoints [ - ^ self new geometries: aBagOfPoints -] - -{ #category : #basic } -OGCMultiPoint >> boundary [ - ^ OGCEmptySet new -] - -{ #category : #accessing } -OGCMultiPoint >> dimension [ - "The inherent dimension of this geometric object, which must be less than or equal to the coordinate dimension." - ^ 0 -] - -{ #category : #basic } -OGCMultiPoint >> isSimple [ - "A MultiPoint is simple if no two Points in the MultiPoint are equal" - ^ (self geometries size == self geometries asSet size) -] - -{ #category : #testing } -OGCMultiPoint >> locateAlong: mValue [ - "Returns a derived geometry collection value that matches the -specified m coordinate value. See Subclause 6.1.2.6 “Measures on Geometry” for more details" - ^ self locateBetween: mValue and: mValue -] - -{ #category : #testing } -OGCMultiPoint >> locateBetween: mStart and: mEnd [ - | resultPoints | - resultPoints := self geometries select: [ :each | each m >= mStart and: each m<= mEnd ]. - ^ self class withPoints: resultPoints -] +" +###6.1.5 MultiPoint + +A MultiPoint is a 0-dimensional GeometryCollection. The elements of a MultiPoint are restricted to Points. + +The Points are not connected or ordered in any semantically important way (see the discussion at GeometryCollection). + +A MultiPoint is simple if no two Points in the MultiPoint are equal (have identical coordinate values in X and Y). +Every MultiPoint is spatially equal under the definition in Clause 6.1.15.3 to a simple Multipoint. +The boundary of a MultiPoint is the empty set. +" +Class { + #name : #OGCMultiPoint, + #superclass : #OGCGeometryCollection, + #category : #'OGC-Core' +} + +{ #category : #accessing } +OGCMultiPoint class >> geometryType [ + ^ 'MultiPoint' +] + +{ #category : #'instance creation' } +OGCMultiPoint class >> withPoints: aBagOfPoints [ + ^ self new geometries: aBagOfPoints +] + +{ #category : #basic } +OGCMultiPoint >> boundary [ + ^ OGCEmptySet new +] + +{ #category : #accessing } +OGCMultiPoint >> dimension [ + "The inherent dimension of this geometric object, which must be less than or equal to the coordinate dimension." + ^ 0 +] + +{ #category : #basic } +OGCMultiPoint >> isSimple [ + "A MultiPoint is simple if no two Points in the MultiPoint are equal" + ^ (self geometries size == self geometries asSet size) +] + +{ #category : #testing } +OGCMultiPoint >> locateAlong: mValue [ + "Returns a derived geometry collection value that matches the +specified m coordinate value. See Subclause 6.1.2.6 “Measures on Geometry” for more details" + ^ self locateBetween: mValue and: mValue +] + +{ #category : #testing } +OGCMultiPoint >> locateBetween: mStart and: mEnd [ + | resultPoints | + resultPoints := self geometries select: [ :each | each m >= mStart and: each m<= mEnd ]. + ^ self class withPoints: resultPoints +] diff --git a/OGC-Core/OGCMultiPolygon.class.st b/OGC-Core/OGCMultiPolygon.class.st index db4f6c8..43f8176 100644 --- a/OGC-Core/OGCMultiPolygon.class.st +++ b/OGC-Core/OGCMultiPolygon.class.st @@ -1,35 +1,35 @@ -" -6.1.14 MultiPolygon - -A MultiPolygon is a MultiSurface whose elements are Polygons. - -The assertions for MultiPolygons are as follows. -a) The interiors of 2 Polygons that are elements of a MultiPolygon may not intersect. -b) The boundaries of any 2 Polygons that are elements of a MultiPolygon may not “cross” and may touch at only a finite number of Points. -NOTE Crossing is prevented by assertion (a) above. -c) A MultiPolygon is defined as topologically closed. -d) A MultiPolygon may not have cut lines, spikes or punctures, a MultiPolygon is a regular closed Point set -e) The interior of a MultiPolygon with more than 1 Polygon is not connected; the number of connected -components of the interior of a MultiPolygon is equal to the number of Polygons in the MultiPolygon. -The boundary of a MultiPolygon is a set of closed Curves (LineStrings) corresponding to the boundaries of its -element Polygons. Each Curve in the boundary of the MultiPolygon is in the boundary of exactly 1 element -Polygon, and every Curve in the boundary of an element Polygon is in the boundary of the MultiPolygon. -The reader is referred to works by Worboys et al.([13], [14]) and Clementini et al. ([5], [6]) for the definition and -specification of MultiPolygons. -" -Class { - #name : #OGCMultiPolygon, - #superclass : #OGCMultiSurface, - #category : #'OGC-Core' -} - -{ #category : #accessing } -OGCMultiPolygon class >> geometryType [ - ^ 'MultiPolygon' -] - -{ #category : #accessing } -OGCMultiPolygon >> coordinates: aCollection [ - self geometries: (aCollection collect: [ :each | - OGCPolygon new coordinates: each ]) -] +" +###6.1.14 MultiPolygon + +A MultiPolygon is a MultiSurface whose elements are Polygons. + +The assertions for MultiPolygons are as follows. +a) The interiors of 2 Polygons that are elements of a MultiPolygon may not intersect. +b) The boundaries of any 2 Polygons that are elements of a MultiPolygon may not “cross” and may touch at only a finite number of Points. +NOTE Crossing is prevented by assertion (a) above. +c) A MultiPolygon is defined as topologically closed. +d) A MultiPolygon may not have cut lines, spikes or punctures, a MultiPolygon is a regular closed Point set +e) The interior of a MultiPolygon with more than 1 Polygon is not connected; the number of connected +components of the interior of a MultiPolygon is equal to the number of Polygons in the MultiPolygon. +The boundary of a MultiPolygon is a set of closed Curves (LineStrings) corresponding to the boundaries of its +element Polygons. Each Curve in the boundary of the MultiPolygon is in the boundary of exactly 1 element +Polygon, and every Curve in the boundary of an element Polygon is in the boundary of the MultiPolygon. +The reader is referred to works by Worboys et al.([13], [14]) and Clementini et al. ([5], [6]) for the definition and +specification of MultiPolygons. +" +Class { + #name : #OGCMultiPolygon, + #superclass : #OGCMultiSurface, + #category : #'OGC-Core' +} + +{ #category : #accessing } +OGCMultiPolygon class >> geometryType [ + ^ 'MultiPolygon' +] + +{ #category : #accessing } +OGCMultiPolygon >> coordinates: aCollection [ + self geometries: (aCollection collect: [ :each | + OGCPolygon new coordinates: each ]) +] diff --git a/OGC-Core/OGCMultiSurface.class.st b/OGC-Core/OGCMultiSurface.class.st index b77dc22..0eabb92 100644 --- a/OGC-Core/OGCMultiSurface.class.st +++ b/OGC-Core/OGCMultiSurface.class.st @@ -1,25 +1,25 @@ -" -6.1.13 MultiSurface - -6.1.13.1 Description - -A MultiSurface is a 2-dimensional GeometryCollection whose elements are Surfaces, all using coordinates from -the same coordinate reference system. The geometric interiors of any two Surfaces in a MultiSurface may not -intersect in the full coordinate system. The boundaries of any two coplanar elements in a MultiSurface may -intersect, at most, at a finite number of Points. If they were to meet along a curve, they could be merged into a -single surface. -MultiSurface is an instantiable class in this Standard, and may be used to represent heterogeneous surfaces -collections of polygons and polyhedral surfaces. It defines a set of methods for its subclasses. The subclass of -MultiSurface is MultiPolygon corresponding to a collection of Polygons only. Other collections shall use -MultiSurface. -" -Class { - #name : #OGCMultiSurface, - #superclass : #OGCGeometryCollection, - #category : #'OGC-Core' -} - -{ #category : #testing } -OGCMultiSurface class >> isAbstract [ - ^ self = OGCMultiSurface -] +" +###6.1.13 MultiSurface + +###6.1.13.1 Description + +A MultiSurface is a 2-dimensional GeometryCollection whose elements are Surfaces, all using coordinates from +the same coordinate reference system. The geometric interiors of any two Surfaces in a MultiSurface may not +intersect in the full coordinate system. The boundaries of any two coplanar elements in a MultiSurface may +intersect, at most, at a finite number of Points. If they were to meet along a curve, they could be merged into a +single surface. +MultiSurface is an instantiable class in this Standard, and may be used to represent heterogeneous surfaces +collections of polygons and polyhedral surfaces. It defines a set of methods for its subclasses. The subclass of +MultiSurface is MultiPolygon corresponding to a collection of Polygons only. Other collections shall use +MultiSurface. +" +Class { + #name : #OGCMultiSurface, + #superclass : #OGCGeometryCollection, + #category : #'OGC-Core' +} + +{ #category : #testing } +OGCMultiSurface class >> isAbstract [ + ^ self = OGCMultiSurface +] diff --git a/OGC-Core/OGCNotALinearRingError.class.st b/OGC-Core/OGCNotALinearRingError.class.st index fdb009b..6422963 100644 --- a/OGC-Core/OGCNotALinearRingError.class.st +++ b/OGC-Core/OGCNotALinearRingError.class.st @@ -1,51 +1,51 @@ -" -When a linear ring wants to be instantiate but is not simple or is not closed -" -Class { - #name : #OGCNotALinearRingError, - #superclass : #Error, - #instVars : [ - 'isSimple', - 'isClosed' - ], - #category : #'OGC-Core-Errors' -} - -{ #category : #signalling } -OGCNotALinearRingError class >> signal: answerIsClosed and: answerIsSimple [ - ^ self new - isSimple: answerIsClosed; - isClosed: answerIsClosed; - signal -] - -{ #category : #accessing } -OGCNotALinearRingError >> isClosed: aBoolean [ - isClosed := aBoolean -] - -{ #category : #accessing } -OGCNotALinearRingError >> isSimple: aBoolean [ - isSimple := aBoolean -] - -{ #category : #accessing } -OGCNotALinearRingError >> messageText [ - "Overwritten to initialiaze the message text to a standard text if it has not yet been set" - - ^ messageText ifNil: [ messageText := self standardMessageText ] -] - -{ #category : #printing } -OGCNotALinearRingError >> standardMessageText [ - "Generate a standard textual description" - | isClosedMessage isSimpleMessage | - isClosedMessage := isClosed - ifFalse: [ 'Is not closed as it must be. '] - ifTrue: [ '' ]. - isSimpleMessage := isSimple - ifFalse: [ 'Is not simple as it must be. ' ] - ifTrue: [ '' ]. - ^ String streamContents: [ :stream | - stream << isClosedMessage + isSimpleMessage ] -] +" +When a linear ring wants to be instantiate but is not simple or is not closed +" +Class { + #name : #OGCNotALinearRingError, + #superclass : #Error, + #instVars : [ + 'isSimple', + 'isClosed' + ], + #category : #'OGC-Core-Errors' +} + +{ #category : #signalling } +OGCNotALinearRingError class >> signal: answerIsClosed and: answerIsSimple [ + ^ self new + isSimple: answerIsClosed; + isClosed: answerIsClosed; + signal +] + +{ #category : #accessing } +OGCNotALinearRingError >> isClosed: aBoolean [ + isClosed := aBoolean +] + +{ #category : #accessing } +OGCNotALinearRingError >> isSimple: aBoolean [ + isSimple := aBoolean +] + +{ #category : #accessing } +OGCNotALinearRingError >> messageText [ + "Overwritten to initialiaze the message text to a standard text if it has not yet been set" + + ^ messageText ifNil: [ messageText := self standardMessageText ] +] + +{ #category : #printing } +OGCNotALinearRingError >> standardMessageText [ + "Generate a standard textual description" + | isClosedMessage isSimpleMessage | + isClosedMessage := isClosed + ifFalse: [ 'Is not closed as it must be. '] + ifTrue: [ '' ]. + isSimpleMessage := isSimple + ifFalse: [ 'Is not simple as it must be. ' ] + ifTrue: [ '' ]. + ^ String streamContents: [ :stream | + stream << isClosedMessage + isSimpleMessage ] +] diff --git a/OGC-Core/OGCObject.class.st b/OGC-Core/OGCObject.class.st index 4c61c3a..9600e9f 100644 --- a/OGC-Core/OGCObject.class.st +++ b/OGC-Core/OGCObject.class.st @@ -1,43 +1,48 @@ -Class { - #name : #OGCObject, - #superclass : #Object, - #category : #'OGC-Core' -} - -{ #category : #'as yet unclassified' } -OGCObject class >> createStyleDictionary: anArray [ - " return a dictionary which can be used as a style dictionary for a OGCGeometry, based on data given as the following array of strings : [ ] " - | styleDictionary keys | - styleDictionary := Dictionary new. - keys := { 'fill' . 'fill-opacity' . 'stroke' . 'stroke-width'}. - anArray withIndexDo: [ :each :i | each ifNotNil: [ styleDictionary at: (keys at: i) put: each asString ] ]. - ^ styleDictionary -] - -{ #category : #testing } -OGCObject class >> isAbstract [ - ^ self = OGCObject -] - -{ #category : #style } -OGCObject >> applyStyle: aStyleDictionary [ - " apply the given style (as a dictionary) to every elements" - self subclassResponsibility -] - -{ #category : #style } -OGCObject >> applyStyle: aStyleDictionary ifFeature: aBlock [ - " apply the given style to features which respect given block closure" - self subclassResponsibility -] - -{ #category : #converting } -OGCObject >> asFeaturesCollection [ - self subclassResponsibility -] - -{ #category : #basic } -OGCObject >> rectangularEnvelope [ - " return a rectangle which can contain all geometries" - self subclassResponsibility -] +Class { + #name : #OGCObject, + #superclass : #Object, + #category : #'OGC-Core' +} + +{ #category : #'as yet unclassified' } +OGCObject class >> createStyleDictionary: anArray [ + " return a dictionary which can be used as a style dictionary for a OGCGeometry, based on data given as the following array of strings : [ ] " + | styleDictionary keys | + styleDictionary := Dictionary new. + keys := { 'fill' . 'fill-opacity' . 'stroke' . 'stroke-width'}. + anArray withIndexDo: [ :each :i | each ifNotNil: [ styleDictionary at: (keys at: i) put: each asString ] ]. + ^ styleDictionary +] + +{ #category : #testing } +OGCObject class >> isAbstract [ + ^ self = OGCObject +] + +{ #category : #style } +OGCObject >> applyContinuousColorationOn: aDataKey withFeatureData: aCSVArray withAssociateKey: aDataAssociateKey withColor: aColorName [ + self subclassResponsibility +] + +{ #category : #style } +OGCObject >> applyStyle: aStyleDictionary [ + " apply the given style (as a dictionary) to every elements" + self subclassResponsibility +] + +{ #category : #style } +OGCObject >> applyStyle: aStyleDictionary ifFeature: aBlock [ + " apply the given style to features which respect given block closure" + self subclassResponsibility +] + +{ #category : #converting } +OGCObject >> asFeaturesCollection [ + self subclassResponsibility +] + +{ #category : #basic } +OGCObject >> rectangularEnvelope [ + " return a rectangle which can contain all geometries" + self subclassResponsibility +] diff --git a/OGC-Core/OGCPoint.class.st b/OGC-Core/OGCPoint.class.st index 6806882..8b103cf 100644 --- a/OGC-Core/OGCPoint.class.st +++ b/OGC-Core/OGCPoint.class.st @@ -1,231 +1,236 @@ -" -6.1.4 Point - -6.1.4.1 Description - -A Point is a 0-dimensional geometric object and represents a single location in coordinate space. A Point has an -x-coordinate value, a y-coordinate value. If called for by the associated Spatial Reference System, it may also -have coordinate values for z and m. -The boundary of a Point is the empty set. -" -Class { - #name : #OGCPoint, - #superclass : #OGCGeometry, - #instVars : [ - 'x', - 'y', - 'z', - 'm', - 'icon' - ], - #category : #'OGC-Core' -} - -{ #category : #accessing } -OGCPoint class >> geometryType [ - ^ 'Point' -] - -{ #category : #'instance creation' } -OGCPoint class >> latitude: latitude longitude: longitude [ - ^ self new - x: longitude; - y: latitude -] - -{ #category : #'instance creation' } -OGCPoint class >> x: xNumber y: yNumber [ - ^ self new - x: xNumber; - y: yNumber -] - -{ #category : #'instance creation' } -OGCPoint class >> x: xNumber y: yNumber m:mNumber [ - ^ self new - x: xNumber; - y: yNumber; - m: mNumber -] - -{ #category : #'instance creation' } -OGCPoint class >> xy: anArray [ - ^ self x: anArray first y: anArray second -] - -{ #category : #'instance creation' } -OGCPoint class >> xym: anArray [ - ^ self x: anArray first y: anArray second m: anArray last -] - -{ #category : #comparing } -OGCPoint >> = anOGCPoint [ - (self species == anOGCPoint species) ifFalse: [ ^ false ]. - ^ (x = anOGCPoint x) & (y = anOGCPoint y) & (z = anOGCPoint z) -] - -{ #category : #conversion } -OGCPoint >> asPoint [ - ^ x @ y -] - -{ #category : #basic } -OGCPoint >> boundary [ - "Geometry — Returns the closure of the combinatorial boundary of this geometric object -(Reference [1], section 3.12.2). Because the result of this function is a closure, and hence topologically -closed, the resulting boundary can be represented using representational Geometry primitives (Reference [1], -section 3.12.2). The return type is integer, but is interpreted as Boolean, TRUE=1, FALSE=0." - ^ OGCEmptySet new -] - -{ #category : #accessing } -OGCPoint >> coordinates [ - ^ Array braceWith: self x with: self y -] - -{ #category : #accessing } -OGCPoint >> coordinates: aCollection [ - "a point should only have two coordinates being numbers" - | coordinates | - coordinates := (aCollection first: 2) collect: #asNumber. - self x: coordinates first. - self y: coordinates second. -] - -{ #category : #accessing } -OGCPoint >> dimension [ - ^ 0 -] - -{ #category : #'methods analysis' } -OGCPoint >> distance: anotherGeometry [ - ^ spatialReferenceSystem distance: self toPoint: anotherGeometry -] - -{ #category : #comparing } -OGCPoint >> hash [ - ^ (x hash bitXor: y hash) bitXor: z hash -] - -{ #category : #testing } -OGCPoint >> is3D [ - ^ z notNil -] - -{ #category : #basic } -OGCPoint >> isMeasured [ - ^ m isNotNil -] - -{ #category : #accessing } -OGCPoint >> latitude [ - ^ self y -] - -{ #category : #accessing } -OGCPoint >> latitude: aNumberOrString [ - self y: aNumberOrString asNumber -] - -{ #category : #testing } -OGCPoint >> locateBetween: mStart and: mEnd [ - "Returns a derived geometry collection value -that matches the specified range of m coordinate values inclusively. See Subclause 6.1.2.6 “Measures on -Geometry” for more details." - ^ (m >= mStart and: m<= mEnd) - ifTrue: [ OGCMultiPoint withPoints: (Bag with: self) ] - ifFalse: [ OGCEmptySet new ] -] - -{ #category : #accessing } -OGCPoint >> longitude [ - ^ self x -] - -{ #category : #accessing } -OGCPoint >> longitude: aNumberOrString [ - self x: aNumberOrString asNumber -] - -{ #category : #accessing } -OGCPoint >> m [ - ^ m -] - -{ #category : #accessing } -OGCPoint >> m: aFloat [ - m := aFloat -] - -{ #category : #accessing } -OGCPoint >> max: anOGCPoint [ - - ^ OGCPoint - x: (x max: anOGCPoint x) - y: (y max: anOGCPoint y) -] - -{ #category : #accessing } -OGCPoint >> min: anOGCPoint [ - - ^ OGCPoint - x: (x min: anOGCPoint x) - y: (y min: anOGCPoint y) -] - -{ #category : #printing } -OGCPoint >> printOn: aStream [ - aStream << x asString << ',' << y asString. - z ifNotNil: [ - aStream << ',' << z asString ] -] - -{ #category : #geometry } -OGCPoint >> rectangularEnvelope [ - ^ x@y corner: x@y -] - -{ #category : #'truncation and round off' } -OGCPoint >> roundTo: grid [ - - | gridPoint | - gridPoint := grid asOGCPoint. - ^ OGCPoint - x: (x roundTo: gridPoint x) - y: (y roundTo: gridPoint y) -] - -{ #category : #geometry } -OGCPoint >> to: end1 intersects: start2 to: end2 [ - ^ self asPoint to: end1 intersects: start2 to: end2 -] - -{ #category : #accessing } -OGCPoint >> x [ - ^ x -] - -{ #category : #accessing } -OGCPoint >> x: aFloat [ - x:= aFloat -] - -{ #category : #accessing } -OGCPoint >> y [ - ^ y -] - -{ #category : #accessing } -OGCPoint >> y: aFloat [ - y:= aFloat -] - -{ #category : #accessing } -OGCPoint >> z [ - ^ z -] - -{ #category : #accessing } -OGCPoint >> z: aFloat [ - z := aFloat -] +" +###6.1.4 Point + +###6.1.4.1 Description + +A Point is a 0-dimensional geometric object and represents a single location in coordinate space. A Point has an +x-coordinate value, a y-coordinate value. If called for by the associated Spatial Reference System, it may also +have coordinate values for z and m. +The boundary of a Point is the empty set. +" +Class { + #name : #OGCPoint, + #superclass : #OGCGeometry, + #instVars : [ + 'x', + 'y', + 'z', + 'm', + 'icon' + ], + #category : #'OGC-Core' +} + +{ #category : #accessing } +OGCPoint class >> geometryType [ + ^ 'Point' +] + +{ #category : #'instance creation' } +OGCPoint class >> latitude: latitude longitude: longitude [ + ^ self new + x: longitude; + y: latitude +] + +{ #category : #'instance creation' } +OGCPoint class >> x: xNumber y: yNumber [ + ^ self new + x: xNumber; + y: yNumber +] + +{ #category : #'instance creation' } +OGCPoint class >> x: xNumber y: yNumber m:mNumber [ + ^ self new + x: xNumber; + y: yNumber; + m: mNumber +] + +{ #category : #'instance creation' } +OGCPoint class >> xy: anArray [ + ^ self x: anArray first y: anArray second +] + +{ #category : #'instance creation' } +OGCPoint class >> xym: anArray [ + ^ self x: anArray first y: anArray second m: anArray last +] + +{ #category : #comparing } +OGCPoint >> = anOGCPoint [ + (self species == anOGCPoint species) ifFalse: [ ^ false ]. + ^ (x = anOGCPoint x) & (y = anOGCPoint y) & (z = anOGCPoint z) +] + +{ #category : #conversion } +OGCPoint >> asPoint [ + ^ x @ y +] + +{ #category : #basic } +OGCPoint >> boundary [ + "Geometry — Returns the closure of the combinatorial boundary of this geometric object +(Reference [1], section 3.12.2). Because the result of this function is a closure, and hence topologically +closed, the resulting boundary can be represented using representational Geometry primitives (Reference [1], +section 3.12.2). The return type is integer, but is interpreted as Boolean, TRUE=1, FALSE=0." + ^ OGCEmptySet new +] + +{ #category : #accessing } +OGCPoint >> coordinates [ + ^ Array braceWith: self x with: self y +] + +{ #category : #accessing } +OGCPoint >> coordinates: aCollection [ + "a point should only have two coordinates being numbers" + | coordinates | + coordinates := (aCollection first: 2) collect: #asNumber. + self x: coordinates first. + self y: coordinates second. +] + +{ #category : #accessing } +OGCPoint >> dimension [ + ^ 0 +] + +{ #category : #'methods analysis' } +OGCPoint >> distance: anotherGeometry [ + ^ spatialReferenceSystem distance: self toPoint: anotherGeometry +] + +{ #category : #comparing } +OGCPoint >> hash [ + ^ (x hash bitXor: y hash) bitXor: z hash +] + +{ #category : #testing } +OGCPoint >> is3D [ + ^ z notNil +] + +{ #category : #testing } +OGCPoint >> isEmpty [ + ^ (x isNil) & (y isNil) & (z isNil) & (m isNil) +] + +{ #category : #basic } +OGCPoint >> isMeasured [ + ^ m isNotNil +] + +{ #category : #accessing } +OGCPoint >> latitude [ + ^ self y +] + +{ #category : #accessing } +OGCPoint >> latitude: aNumberOrString [ + self y: aNumberOrString asNumber +] + +{ #category : #testing } +OGCPoint >> locateBetween: mStart and: mEnd [ + "Returns a derived geometry collection value +that matches the specified range of m coordinate values inclusively. See Subclause 6.1.2.6 “Measures on +Geometry” for more details." + ^ (m >= mStart and: m<= mEnd) + ifTrue: [ OGCMultiPoint withPoints: (Bag with: self) ] + ifFalse: [ OGCEmptySet new ] +] + +{ #category : #accessing } +OGCPoint >> longitude [ + ^ self x +] + +{ #category : #accessing } +OGCPoint >> longitude: aNumberOrString [ + self x: aNumberOrString asNumber +] + +{ #category : #accessing } +OGCPoint >> m [ + ^ m +] + +{ #category : #accessing } +OGCPoint >> m: aFloat [ + m := aFloat +] + +{ #category : #accessing } +OGCPoint >> max: anOGCPoint [ + + ^ OGCPoint + x: (x max: anOGCPoint x) + y: (y max: anOGCPoint y) +] + +{ #category : #accessing } +OGCPoint >> min: anOGCPoint [ + + ^ OGCPoint + x: (x min: anOGCPoint x) + y: (y min: anOGCPoint y) +] + +{ #category : #printing } +OGCPoint >> printOn: aStream [ + aStream << x asString << ',' << y asString. + z ifNotNil: [ + aStream << ',' << z asString ] +] + +{ #category : #geometry } +OGCPoint >> rectangularEnvelope [ + ^ x@y corner: x@y +] + +{ #category : #'truncation and round off' } +OGCPoint >> roundTo: grid [ + + | gridPoint | + gridPoint := grid asOGCPoint. + ^ OGCPoint + x: (x roundTo: gridPoint x) + y: (y roundTo: gridPoint y) +] + +{ #category : #geometry } +OGCPoint >> to: end1 intersects: start2 to: end2 [ + ^ self asPoint to: end1 intersects: start2 to: end2 +] + +{ #category : #accessing } +OGCPoint >> x [ + ^ x +] + +{ #category : #accessing } +OGCPoint >> x: aFloat [ + x:= aFloat +] + +{ #category : #accessing } +OGCPoint >> y [ + ^ y +] + +{ #category : #accessing } +OGCPoint >> y: aFloat [ + y:= aFloat +] + +{ #category : #accessing } +OGCPoint >> z [ + ^ z +] + +{ #category : #accessing } +OGCPoint >> z: aFloat [ + z := aFloat +] diff --git a/OGC-Core/OGCPolygon.class.st b/OGC-Core/OGCPolygon.class.st index 798a9b6..5130121 100644 --- a/OGC-Core/OGCPolygon.class.st +++ b/OGC-Core/OGCPolygon.class.st @@ -1,116 +1,105 @@ -" -6.1.11 Polygon, Triangle - -6.1.11.1 Description - -A Polygon is a planar Surface defined by 1 exterior boundary and 0 or more interior boundaries. Each interior -boundary defines a hole in the Polygon. A Triangle is a polygon with 3 distinct, non-collinear vertices and no -interior boundary. -The exterior boundary LinearRing defines the “top” of the surface which is the side of the surface from which the -exterior boundary appears to traverse the boundary in a counter clockwise direction. The interior LinearRings will -have the opposite orientation, and appear as clockwise when viewed from the “top”, -The assertions for Polygons (the rules that define valid Polygons) are as follows: -a) Polygons are topologically closed; -b) The boundary of a Polygon consists of a set of LinearRings that make up its exterior and interior boundaries; -c) No two Rings in the boundary cross and the Rings in the boundary of a Polygon may intersect at a Point but -only as a tangent, e.g. -" -Class { - #name : #OGCPolygon, - #superclass : #OGCSurface, - #instVars : [ - 'interiorRings' - ], - #category : #'OGC-Core' -} - -{ #category : #accessing } -OGCPolygon class >> geometryType [ - ^ 'Polygon' -] - -{ #category : #testing } -OGCPolygon >> = anotherPolygon [ - ^ self class = anotherPolygon class and: - [ self interiorRings = anotherPolygon interiorRings - and: - [ self exteriorRing = anotherPolygon exteriorRing ] - ] -] - -{ #category : #accessing } -OGCPolygon >> addInteriorRing: anOGCLinearRing [ - anOGCLinearRing isClosed ifFalse: [ - Error signal: 'linear ring is not closed' ]. - self interiorRings add: anOGCLinearRing -] - -{ #category : #accessing } -OGCPolygon >> coordinates [ - ^ exteriorRing points collect: #coordinates -] - -{ #category : #accessing } -OGCPolygon >> coordinates: aCollection [ - (aCollection anySatisfy: [ :each | each class = Array ]) - ifTrue: [ - "coordinates contain an exterior ring and interior rings" - self addExteriorRing: (OGCLinearRing new coordinates: aCollection first). - aCollection allButFirst do: [ :each | - self addInteriorRing: (OGCLinearRing new coordinates: each) ] - ] - ifFalse: [ - "coordiniates only contain an exterior ring" - aCollection do: [ :each | - self addExteriorRing: (OGCLinearRing new coordinates: each) ] - ] -] - -{ #category : #style } -OGCPolygon >> defaultFillColor [ - ^ 'white' -] - -{ #category : #style } -OGCPolygon >> defaultFillOpacity [ - ^ '0.5' -] - -{ #category : #accessing } -OGCPolygon >> exteriorRing [ - "Returns the exterior ring of this Polygon as a LineString" - ^ exteriorRing -] - -{ #category : #accessing } -OGCPolygon >> exteriorRing: anObject [ - exteriorRing := anObject -] - -{ #category : #comparing } -OGCPolygon >> hash [ - ^ self interiorRings hash bitXor: self exteriorRing hash -] - -{ #category : #accessing } -OGCPolygon >> interiorRingN: anInteger [ - "Returns the Nth interior ring for this Polygon as a LineString." - ^ interiorRings at: anInteger -] - -{ #category : #accessing } -OGCPolygon >> interiorRings [ - ^ interiorRings ifNil: [ - interiorRings := OrderedCollection new ] -] - -{ #category : #accessing } -OGCPolygon >> interiorRings: anObject [ - interiorRings := anObject -] - -{ #category : #accessing } -OGCPolygon >> numInteriorRing [ - "Returns the number of interior rings in this Polygon" - ^ interiorRings size -] +" +###6.1.11 Polygon, Triangle + +###6.1.11.1 Description + +A Polygon is a planar Surface defined by 1 exterior boundary and 0 or more interior boundaries. Each interior +boundary defines a hole in the Polygon. A Triangle is a polygon with 3 distinct, non-collinear vertices and no +interior boundary. +The exterior boundary LinearRing defines the “top” of the surface which is the side of the surface from which the +exterior boundary appears to traverse the boundary in a counter clockwise direction. The interior LinearRings will +have the opposite orientation, and appear as clockwise when viewed from the “top”, +The assertions for Polygons (the rules that define valid Polygons) are as follows: +a) Polygons are topologically closed; +b) The boundary of a Polygon consists of a set of LinearRings that make up its exterior and interior boundaries; +c) No two Rings in the boundary cross and the Rings in the boundary of a Polygon may intersect at a Point but +only as a tangent, e.g. +" +Class { + #name : #OGCPolygon, + #superclass : #OGCSurface, + #instVars : [ + 'interiorRings' + ], + #category : #'OGC-Core' +} + +{ #category : #accessing } +OGCPolygon class >> geometryType [ + ^ 'Polygon' +] + +{ #category : #testing } +OGCPolygon >> = anotherPolygon [ + ^ self class = anotherPolygon class and: + [ self interiorRings = anotherPolygon interiorRings + and: + [ self exteriorRing = anotherPolygon exteriorRing ] + ] +] + +{ #category : #accessing } +OGCPolygon >> addInteriorRing: anOGCLinearRing [ + anOGCLinearRing isClosed ifFalse: [ + Error signal: 'linear ring is not closed' ]. + self interiorRings add: anOGCLinearRing +] + +{ #category : #accessing } +OGCPolygon >> coordinates [ + ^ exteriorRing points collect: #coordinates +] + +{ #category : #accessing } +OGCPolygon >> coordinates: aCollection [ + (aCollection anySatisfy: [ :each | each class = Array ]) + ifTrue: [ + "coordinates contain an exterior ring and interior rings" + self addExteriorRing: (OGCLinearRing new coordinates: aCollection first). + aCollection allButFirst do: [ :each | + self addInteriorRing: (OGCLinearRing new coordinates: each) ] + ] + ifFalse: [ + "coordiniates only contain an exterior ring" + aCollection do: [ :each | + self addExteriorRing: (OGCLinearRing new coordinates: each) ] + ] +] + +{ #category : #style } +OGCPolygon >> defaultFillColor [ + ^ 'white' +] + +{ #category : #style } +OGCPolygon >> defaultFillOpacity [ + ^ '0.5' +] + +{ #category : #comparing } +OGCPolygon >> hash [ + ^ self interiorRings hash bitXor: self exteriorRing hash +] + +{ #category : #accessing } +OGCPolygon >> interiorRingN: anInteger [ + "Returns the Nth interior ring for this Polygon as a LineString." + ^ interiorRings at: anInteger +] + +{ #category : #accessing } +OGCPolygon >> interiorRings [ + ^ interiorRings ifNil: [ + interiorRings := OrderedCollection new ] +] + +{ #category : #accessing } +OGCPolygon >> interiorRings: anObject [ + interiorRings := anObject +] + +{ #category : #accessing } +OGCPolygon >> numInteriorRing [ + "Returns the number of interior rings in this Polygon" + ^ interiorRings size +] diff --git a/OGC-Core/OGCPolyhedralSurface.class.st b/OGC-Core/OGCPolyhedralSurface.class.st index 534d995..f37344c 100644 --- a/OGC-Core/OGCPolyhedralSurface.class.st +++ b/OGC-Core/OGCPolyhedralSurface.class.st @@ -1,39 +1,39 @@ -" -A PolyhedralSurface is a contiguous collection of polygons, which share common boundary segments. For each -pair of polygons that “touch”, the common boundary shall be expressible as a finite collection of LineStrings. -" -Class { - #name : #OGCPolyhedralSurface, - #superclass : #OGCSurface, - #category : #'OGC-Core' -} - -{ #category : #accessing } -OGCPolyhedralSurface class >> geometryType [ - ^ 'PolyhedralSurface' -] - -{ #category : #'as yet unclassified' } -OGCPolyhedralSurface >> boundingPolygon: aPolygon [ - "Returns the collection of polygons MultiPolygon, in this surface that bounds the given polygon for any polygon in the surface" -] - -{ #category : #accessing } -OGCPolyhedralSurface >> coordinates [ - ^ exteriorRing collect: #coordinates -] - -{ #category : #'as yet unclassified' } -OGCPolyhedralSurface >> isClosed [ - " Returns 1 (True) if the polygon closes on itself, and thus has no boundary and encloses a solid" -] - -{ #category : #'as yet unclassified' } -OGCPolyhedralSurface >> numPatches [ - "Returns the number of including polygons" -] - -{ #category : #'as yet unclassified' } -OGCPolyhedralSurface >> patchesN: anInteger [ - "Returns a polygon in this surface, the order is arbitrary" -] +" +A PolyhedralSurface is a contiguous collection of polygons, which share common boundary segments. For each +pair of polygons that “touch”, the common boundary shall be expressible as a finite collection of LineStrings. +" +Class { + #name : #OGCPolyhedralSurface, + #superclass : #OGCSurface, + #category : #'OGC-Core' +} + +{ #category : #accessing } +OGCPolyhedralSurface class >> geometryType [ + ^ 'PolyhedralSurface' +] + +{ #category : #'as yet unclassified' } +OGCPolyhedralSurface >> boundingPolygon: aPolygon [ + "Returns the collection of polygons MultiPolygon, in this surface that bounds the given polygon for any polygon in the surface" +] + +{ #category : #accessing } +OGCPolyhedralSurface >> coordinates [ + ^ exteriorRing collect: #coordinates +] + +{ #category : #'as yet unclassified' } +OGCPolyhedralSurface >> isClosed [ + " Returns 1 (True) if the polygon closes on itself, and thus has no boundary and encloses a solid" +] + +{ #category : #'as yet unclassified' } +OGCPolyhedralSurface >> numPatches [ + "Returns the number of including polygons" +] + +{ #category : #'as yet unclassified' } +OGCPolyhedralSurface >> patchesN: anInteger [ + "Returns a polygon in this surface, the order is arbitrary" +] diff --git a/OGC-Core/OGCReferenceSystem.class.st b/OGC-Core/OGCReferenceSystem.class.st index b68ac96..a33e80c 100644 --- a/OGC-Core/OGCReferenceSystem.class.st +++ b/OGC-Core/OGCReferenceSystem.class.st @@ -1,25 +1,25 @@ -" -A reference system contains: -- exactly one spatial reference system -- one measure reference system if needed -" -Class { - #name : #OGCReferenceSystem, - #superclass : #Object, - #category : #'OGC-Core' -} - -{ #category : #accessing } -OGCReferenceSystem class >> axisName [ - self subclassResponsibility -] - -{ #category : #accessing } -OGCReferenceSystem class >> dimension [ - self subclassResponsibility -] - -{ #category : #testing } -OGCReferenceSystem class >> isAbstract [ - ^ true -] +" +A reference system contains: +- exactly one spatial reference system +- one measure reference system if needed +" +Class { + #name : #OGCReferenceSystem, + #superclass : #Object, + #category : #'OGC-Core' +} + +{ #category : #accessing } +OGCReferenceSystem class >> axisName [ + self subclassResponsibility +] + +{ #category : #accessing } +OGCReferenceSystem class >> dimension [ + self subclassResponsibility +] + +{ #category : #testing } +OGCReferenceSystem class >> isAbstract [ + ^ true +] diff --git a/OGC-Core/OGCSpatialReferenceSystem.class.st b/OGC-Core/OGCSpatialReferenceSystem.class.st index 0a8b609..45fd96c 100644 --- a/OGC-Core/OGCSpatialReferenceSystem.class.st +++ b/OGC-Core/OGCSpatialReferenceSystem.class.st @@ -1,10 +1,10 @@ -" -A spatial reference system (SRS) or coordinate reference system (CRS) is a coordinate-based local, regional or global system used to locate geographical entities. - -A SRS commonly defines a specific map projection, as well as transformations between different SRS. -" -Class { - #name : #OGCSpatialReferenceSystem, - #superclass : #OGCReferenceSystem, - #category : #'OGC-Core' -} +" +A spatial reference system (SRS) or coordinate reference system (CRS) is a coordinate-based local, regional or global system used to locate geographical entities. + +A SRS commonly defines a specific map projection, as well as transformations between different SRS. +" +Class { + #name : #OGCSpatialReferenceSystem, + #superclass : #OGCReferenceSystem, + #category : #'OGC-Core' +} diff --git a/OGC-Core/OGCSurface.class.st b/OGC-Core/OGCSurface.class.st index 69012df..2556ef3 100644 --- a/OGC-Core/OGCSurface.class.st +++ b/OGC-Core/OGCSurface.class.st @@ -1,60 +1,70 @@ -" -6.1.10 Surface - -6.1.10.1 Description - -A Surface is a 2-dimensional geometric object. -A simple Surface may consists of a single “patch” that is associated with one “exterior boundary” and 0 or more -“interior” boundaries. A single such Surface patch in 3-dimensional space is isometric to planar Surfaces, by a -simple affine rotation matrix that rotates the patch onto the plane z = 0. If the patch is not vertical, the projection -onto the same plane is an isomorphism, and can be represented as a linear transformation, i.e. an affine. -" -Class { - #name : #OGCSurface, - #superclass : #OGCGeometry, - #instVars : [ - 'exteriorRing' - ], - #category : #'OGC-Core' -} - -{ #category : #testing } -OGCSurface class >> isAbstract [ - ^ self == OGCSurface -] - -{ #category : #basic } -OGCSurface >> area [ - "The area of this Surface, as measured in the spatial reference system of this Surface." - self subclassResponsibility -] - -{ #category : #basic } -OGCSurface >> boundary [ - self subclassResponsibility -] - -{ #category : #basic } -OGCSurface >> centroid [ - "The mathematical centroid for this Surface as a Point. The result is not guaranteed to -be on this Surface." - self subclassResponsibility -] - -{ #category : #basic } -OGCSurface >> dimension [ - "The inherent dimension of this geometric object, which must be less than or equal to the coordinate dimension." - ^ 2 -] - -{ #category : #basic } -OGCSurface >> pointOnSurface [ - "A Point guaranteed to be on this Surface" - self subclassResponsibility -] - -{ #category : #basic } -OGCSurface >> rectangularEnvelope [ - " Returns [ minX, maxX, minY, maxY ] to define minimal rectangle which contains all features " - ^ exteriorRing rectangularEnvelope -] +" +###6.1.10 Surface + +###6.1.10.1 Description + +A Surface is a 2-dimensional geometric object. +A simple Surface may consists of a single “patch” that is associated with one “exterior boundary” and 0 or more +“interior” boundaries. A single such Surface patch in 3-dimensional space is isometric to planar Surfaces, by a +simple affine rotation matrix that rotates the patch onto the plane z = 0. If the patch is not vertical, the projection +onto the same plane is an isomorphism, and can be represented as a linear transformation, i.e. an affine. +" +Class { + #name : #OGCSurface, + #superclass : #OGCGeometry, + #instVars : [ + 'exteriorRing' + ], + #category : #'OGC-Core' +} + +{ #category : #testing } +OGCSurface class >> isAbstract [ + ^ self == OGCSurface +] + +{ #category : #basic } +OGCSurface >> area [ + "The area of this Surface, as measured in the spatial reference system of this Surface." + self subclassResponsibility +] + +{ #category : #basic } +OGCSurface >> boundary [ + self subclassResponsibility +] + +{ #category : #basic } +OGCSurface >> centroid [ + "The mathematical centroid for this Surface as a Point. The result is not guaranteed to +be on this Surface." + self subclassResponsibility +] + +{ #category : #basic } +OGCSurface >> dimension [ + "The inherent dimension of this geometric object, which must be less than or equal to the coordinate dimension." + ^ 2 +] + +{ #category : #accessing } +OGCSurface >> exteriorRing [ + ^ exteriorRing +] + +{ #category : #accessing } +OGCSurface >> exteriorRing: anObject [ + exteriorRing := anObject +] + +{ #category : #basic } +OGCSurface >> pointOnSurface [ + "A Point guaranteed to be on this Surface" + self subclassResponsibility +] + +{ #category : #basic } +OGCSurface >> rectangularEnvelope [ + " Returns [ minX, maxX, minY, maxY ] to define minimal rectangle which contains all features " + ^ exteriorRing rectangularEnvelope +] diff --git a/OGC-Core/OGCTIN.class.st b/OGC-Core/OGCTIN.class.st index e1be4cf..5214de6 100644 --- a/OGC-Core/OGCTIN.class.st +++ b/OGC-Core/OGCTIN.class.st @@ -1,8 +1,8 @@ -" -A TIN (triangulated irregular network) is a PolyhedralSurface consisting only of Triangle patches -" -Class { - #name : #OGCTIN, - #superclass : #OGCPolyhedralSurface, - #category : #'OGC-Core' -} +" +A TIN (triangulated irregular network) is a PolyhedralSurface consisting only of Triangle patches +" +Class { + #name : #OGCTIN, + #superclass : #OGCPolyhedralSurface, + #category : #'OGC-Core' +} diff --git a/OGC-Core/OGCTriangle.class.st b/OGC-Core/OGCTriangle.class.st index d98e8e4..75ceb23 100644 --- a/OGC-Core/OGCTriangle.class.st +++ b/OGC-Core/OGCTriangle.class.st @@ -1,29 +1,29 @@ -" -A Triangle is a polygon with 3 distinct, non-collinear vertices and no -interior boundary -" -Class { - #name : #OGCTriangle, - #superclass : #OGCPolygon, - #category : #'OGC-Core' -} - -{ #category : #accessing } -OGCTriangle class >> geometryType [ - ^ 'Triangle' -] - -{ #category : #'as yet unclassified' } -OGCTriangle class >> withExteriorRing: aLineString [ - ^ self new exteriorRing: aLineString -] - -{ #category : #basic } -OGCTriangle >> area [ - ^ spatialReferenceSystem area: self -] - -{ #category : #basic } -OGCTriangle >> boundary [ - ^ exteriorRing -] +" +A Triangle is a polygon with 3 distinct, non-collinear vertices and no +interior boundary +" +Class { + #name : #OGCTriangle, + #superclass : #OGCPolygon, + #category : #'OGC-Core' +} + +{ #category : #accessing } +OGCTriangle class >> geometryType [ + ^ 'Triangle' +] + +{ #category : #'as yet unclassified' } +OGCTriangle class >> withExteriorRing: aLineString [ + ^ self new exteriorRing: aLineString +] + +{ #category : #basic } +OGCTriangle >> area [ + ^ spatialReferenceSystem area: self +] + +{ #category : #basic } +OGCTriangle >> boundary [ + ^ exteriorRing +] diff --git a/OGC-Core/package.st b/OGC-Core/package.st index b689631..25b707b 100644 --- a/OGC-Core/package.st +++ b/OGC-Core/package.st @@ -1 +1 @@ -Package { #name : #'OGC-Core' } +Package { #name : #'OGC-Core' } diff --git a/OGC-Geometry-Tests/OGCGeometricIntersectionsTest.class.st b/OGC-Geometry-Tests/OGCGeometricIntersectionsTest.class.st new file mode 100644 index 0000000..ddd0cc8 --- /dev/null +++ b/OGC-Geometry-Tests/OGCGeometricIntersectionsTest.class.st @@ -0,0 +1,105 @@ +Class { + #name : #OGCGeometricIntersectionsTest, + #superclass : #TestCase, + #category : #'OGC-Geometry-Tests' +} + +{ #category : #tests } +OGCGeometricIntersectionsTest >> testLineIntersectionWithLine [ + | point1 point2 point3 point4 pointIntersection line1 line2 parallelLine1 parallelLine2 | + point1 := OGCPoint xy: #(-1 -1). + point2 := OGCPoint xy: #(1 1). + point3 := OGCPoint xy: #(-1 1). + point4 := OGCPoint xy: #(1 -1). + pointIntersection := OGCPoint xy: #(0 0). + line1 := OGCLine withPoints: { point1 . point2 }. + line2 := OGCLine withPoints: { point3 . point4 }. + parallelLine1 := OGCLine withPoints: { point1 . point4 }. + parallelLine2 := OGCLine withPoints: { point3 . point2 }. + " case secant lines" + self assert: (line1 intersection: line2) equals: pointIntersection. + " case paralell lines" + self assert: (parallelLine1 intersection: parallelLine2 ) equals: OGCEmptySet new. + " case mixed lines (?) " + + +] + +{ #category : #tests } +OGCGeometricIntersectionsTest >> testLineStringIntersectionWithLine [ + | p1 p2 p3 p4 p5 p6 p7 linestring line intersection1 intersection2 | + p1 := OGCPoint xy: { 0 . 0 }. + p2:= OGCPoint xy: { 3 . 0 }. + p3:= OGCPoint xy: { 1 . 1 }. + p4:= OGCPoint xy: { 1 . -1 }. + p5:= OGCPoint xy: { 2 . -1 }. + p6:= OGCPoint xy: { 2 . 1 }. + intersection1 := OGCPoint xy: { 1 . 0 }. + intersection2 := OGCPoint xy: { 2 . 0 }. + linestring := OGCLineString withPoints: { p3 . p4 . p5 . p6 }. + line := OGCLine withPoints: { p1 . p2 }. + self assert: (linestring intersection: line) equals: (OGCGeometryCollection geometries: { intersection1 . intersection2 }). + self assert: (line intersection: linestring) equals: (OGCGeometryCollection geometries: { intersection1 . intersection2 }). + p7 := OGCPoint xy: { 0 . -1 }. + self assert: (linestring intersection: (OGCLine withPoints: { p1 . p7 })) equals: OGCEmptySet new. + self assert: ((OGCLine withPoints: { p1 . p7 }) intersection: linestring) equals: OGCEmptySet new. +] + +{ #category : #tests } +OGCGeometricIntersectionsTest >> testLineStringIntersectionWithLineString [ + | pa1 pa2 pa3 pa4 pb1 pb2 pb3 pb4 lsa lsb intersect1 intersect2 intersect3 | + pa1 := OGCPoint xy: { 0 . -1 }. + pa2 := OGCPoint xy: { 2 . 1 }. + pa3 := OGCPoint xy: { 4 . -1 }. + pa4 := OGCPoint xy: { 6 . 1 }. + pb1 := (pa1 deepCopy) y: (pa1 y negated). + pb2 := (pa2 deepCopy) y: (pa2 y negated). + pb3 := (pa3 deepCopy) y: (pa3 y negated). + pb4 := (pa4 deepCopy) y: (pa4 y negated). + intersect1 := OGCPoint xy: { 1 . 0 }. + intersect2 := OGCPoint xy: { 3 . 0 }. + intersect3 := OGCPoint xy: { 5 . 0 }. + lsa := OGCLineString withPoints: { pa1 . pa2 . pa3 . pa4 }. + lsb := OGCLineString withPoints: { pb1 . pb2 . pb3 . pb4 }. + self assert: (lsa intersection: lsb) equals: (OGCGeometryCollection geometries: { intersect1 . intersect2 . intersect3 }). + +] + +{ #category : #tests } +OGCGeometricIntersectionsTest >> testLineStringIntersectionWithPoint [ + | p3 p4 p5 p6 p7 linestring intersection1 | + p3:= OGCPoint xy: { 1 . 1 }. + p4:= OGCPoint xy: { 1 . -1 }. + p5:= OGCPoint xy: { 2 . -1 }. + p6:= OGCPoint xy: { 2 . 1 }. + intersection1 := OGCPoint xy: { 1 . 0 }. + linestring := OGCLineString withPoints: { p3 . p4 . p5 . p6 }. + self assert: (linestring intersection: intersection1) equals: (intersection1). + self assert: (intersection1 intersection: linestring) equals: (intersection1). + p7 := OGCPoint xy: { 0 . -1 }. + self assert: (linestring intersection: p7) equals: OGCEmptySet new. + self assert: (p7 intersection: linestring) equals: OGCEmptySet new. +] + +{ #category : #tests } +OGCGeometricIntersectionsTest >> testPointIntersectionWithLine [ + | line point1 point2 point3 point4 | + point1 := OGCPoint xy: { 1 . 1 }. + point2 := OGCPoint xy: { 2 . 2 }. + point3 := OGCPoint xy: { 3 . 3 }. + point4 := OGCPoint xy: { -1 . -1 }. + line := OGCLine withPoints: { point1. point3 }. + self assert: (line intersection: point2) equals: point2. + self assert: (line intersection: point4) equals: OGCEmptySet new. + self assert: (point2 intersection: line) equals: point2. + self assert: (point4 intersection: line) equals: OGCEmptySet new. +] + +{ #category : #tests } +OGCGeometricIntersectionsTest >> testPointIntersectionWithPoint [ + | point1 point2 | + point1 := OGCPoint xy: { 1 . 1 }. + point2 := OGCPoint xy: { 2 . 2 }. + self assert: (point1 intersection: point2) equals: OGCEmptySet new. + self assert: (point1 intersection: point1) equals: point1 +] diff --git a/OGC-Geometry-Tests/OGCLineStringTest.extension.st b/OGC-Geometry-Tests/OGCLineStringTest.extension.st index 1dca24b..dc751bd 100644 --- a/OGC-Geometry-Tests/OGCLineStringTest.extension.st +++ b/OGC-Geometry-Tests/OGCLineStringTest.extension.st @@ -1,19 +1,19 @@ -Extension { #name : #OGCLineStringTest } - -{ #category : #'*OGC-Geometry-Tests' } -OGCLineStringTest >> testLength [ - | point1 point2 point3 point4 lineS points | - point1 := OGCPoint xy: #(0 0). - point2 := OGCPoint xy: #(3 0). - point3 := OGCPoint xy: #(3 5). - point4 := OGCPoint xy: #(10 5). - points := OrderedCollection with: point1. - points add: point2. - points add: point3. - points add: point4. - lineS := OGCLineString withPoints: points. - (point1 spatialReferenceSystem name = 'Geometric') - ifTrue: [ self assert: lineS length equals: 15 ] - - -] +Extension { #name : #OGCLineStringTest } + +{ #category : #'*OGC-Geometry-Tests' } +OGCLineStringTest >> testLength [ + | point1 point2 point3 point4 lineS points | + point1 := OGCPoint xy: #(0 0). + point2 := OGCPoint xy: #(3 0). + point3 := OGCPoint xy: #(3 5). + point4 := OGCPoint xy: #(10 5). + points := OrderedCollection with: point1. + points add: point2. + points add: point3. + points add: point4. + lineS := OGCLineString withPoints: points. + (point1 spatialReferenceSystem name = 'OGCGeometricProjection') + ifTrue: [ self assert: lineS length equals: 15 ] + + +] diff --git a/OGC-Geometry-Tests/package.st b/OGC-Geometry-Tests/package.st index e6b1b83..e923469 100644 --- a/OGC-Geometry-Tests/package.st +++ b/OGC-Geometry-Tests/package.st @@ -1 +1 @@ -Package { #name : #'OGC-Geometry-Tests' } +Package { #name : #'OGC-Geometry-Tests' } diff --git a/OGC-Geometry/ManifestOGCGeometry.class.st b/OGC-Geometry/ManifestOGCGeometry.class.st new file mode 100644 index 0000000..cacb175 --- /dev/null +++ b/OGC-Geometry/ManifestOGCGeometry.class.st @@ -0,0 +1,8 @@ +" +I provide analysis methods for a planar consideration of space. +" +Class { + #name : #ManifestOGCGeometry, + #superclass : #PackageManifest, + #category : #'OGC-Geometry-Manifest' +} diff --git a/OGC-Geometry/OGCGeometricProjection.class.st b/OGC-Geometry/OGCGeometricProjection.class.st index 43a8c29..e24b113 100644 --- a/OGC-Geometry/OGCGeometricProjection.class.st +++ b/OGC-Geometry/OGCGeometricProjection.class.st @@ -14,13 +14,6 @@ OGCGeometricProjection class >> distance: aGeometry toPoint: aPoint [ ^ aGeometry asGElement distanceTo: aPoint asGElement ] -{ #category : #'as yet unclassified' } -OGCGeometricProjection class >> intersection: aGeometry withLine: aLine [ - | result | - result := (aGeometry asGElement intersectionsWithLine: aLine asGElement). - (result size = 1) ifTrue: [ ^ result first asOGCElement ] ifFalse: [ ^ result ] -] - { #category : #initialization } OGCGeometricProjection class >> length: aLine [ " Return the distance between two points of a Line" diff --git a/OGC-Geometry/OGCLine.extension.st b/OGC-Geometry/OGCLine.extension.st index 0c32d2d..774ab68 100644 --- a/OGC-Geometry/OGCLine.extension.st +++ b/OGC-Geometry/OGCLine.extension.st @@ -4,3 +4,26 @@ Extension { #name : #OGCLine } OGCLine >> asGElement [ ^ GSegment with: points first asGElement with: points second asGElement ] + +{ #category : #'*OGC-Geometry' } +OGCLine >> intersection: anotherGeometry [ + ^ anotherGeometry intersectionWithLine: self +] + +{ #category : #'*OGC-Geometry' } +OGCLine >> intersectionWithLine: aLine [ + | result | + "3 possible cases: + - no intersection, + - same line equation -> answer is a OGCLine too, + - simple intersection -> just a OGCPoint of intersection " + result := self asGElement intersectionsWith: aLine asGElement . + result ifEmpty: [ ^ OGCEmptySet new ] ifNotEmpty: [ ^ result first asOGCElement ] +] + +{ #category : #'*OGC-Geometry' } +OGCLine >> intersectionWithPoint: aPoint [ + | result | + result := (aPoint asGElement intersectionsWithLine: self asGElement). + result ifEmpty: [ ^ OGCEmptySet new ] ifNotEmpty: [ ^ result first asOGCElement ] +] diff --git a/OGC-Geometry/OGCLineString.extension.st b/OGC-Geometry/OGCLineString.extension.st new file mode 100644 index 0000000..eaa6a91 --- /dev/null +++ b/OGC-Geometry/OGCLineString.extension.st @@ -0,0 +1,25 @@ +Extension { #name : #OGCLineString } + +{ #category : #'*OGC-Geometry' } +OGCLineString >> intersection: anotherGeometry [ + | allIntersections | + allIntersections := self lines collect: [ :aLine | aLine intersection: anotherGeometry ]. + allIntersections := (allIntersections asSet) reject: [:each | each class geometryType = 'Empty set' ]. + allIntersections + ifEmpty: [ ^ OGCEmptySet new ] + ifNotEmpty: [ + (allIntersections size = 1) + ifTrue: [ ^ allIntersections asArray first ] + ifFalse: [ ^ OGCGeometryCollection geometries: allIntersections ] + ] +] + +{ #category : #'*OGC-Geometry' } +OGCLineString >> intersectionWithLine: aLine [ + ^ self intersection: aLine +] + +{ #category : #'*OGC-Geometry' } +OGCLineString >> intersectionWithPoint: aPoint [ + ^ self intersection: aPoint +] diff --git a/OGC-Geometry/OGCPoint.extension.st b/OGC-Geometry/OGCPoint.extension.st index add04b1..e41fc3c 100644 --- a/OGC-Geometry/OGCPoint.extension.st +++ b/OGC-Geometry/OGCPoint.extension.st @@ -4,3 +4,20 @@ Extension { #name : #OGCPoint } OGCPoint >> asGElement [ ^ GPoint x: x y: y ] + +{ #category : #'*OGC-Geometry' } +OGCPoint >> intersection: anotherGeometry [ + ^ anotherGeometry intersectionWithPoint: self +] + +{ #category : #'*OGC-Geometry' } +OGCPoint >> intersectionWithLine: aLine [ + ^ aLine intersectionWithPoint: self +] + +{ #category : #'*OGC-Geometry' } +OGCPoint >> intersectionWithPoint: aPoint [ + | intersectionAnswer | + intersectionAnswer := (self asGElement ) intersectionsWithPoint: (aPoint asGElement ). + intersectionAnswer ifEmpty: [ ^ OGCEmptySet new ] ifNotEmpty: [ ^ intersectionAnswer first asOGCElement ] +] diff --git a/OGC-Geometry/OGCSurface.extension.st b/OGC-Geometry/OGCSurface.extension.st new file mode 100644 index 0000000..8333f81 --- /dev/null +++ b/OGC-Geometry/OGCSurface.extension.st @@ -0,0 +1,8 @@ +Extension { #name : #OGCSurface } + +{ #category : #'*OGC-Geometry' } +OGCSurface >> asGElement [ + | pointsToTransform | + pointsToTransform := (self exteriorRing points) allButLast . + ^ GPolygon vertices: (pointsToTransform collect: [ :aPoint | aPoint asGElement ]) +] diff --git a/OGC-Spheric/ManifestOGCSpheric.class.st b/OGC-Spheric/ManifestOGCSpheric.class.st new file mode 100644 index 0000000..7980d35 --- /dev/null +++ b/OGC-Spheric/ManifestOGCSpheric.class.st @@ -0,0 +1,10 @@ +" +I provide analysis methods for a spherical consideration of space. + +Earth is considered as a perfect sphere with a ray of 6372.795477598 km +" +Class { + #name : #ManifestOGCSpheric, + #superclass : #PackageManifest, + #category : #'OGC-Spheric-Manifest' +}