-
Notifications
You must be signed in to change notification settings - Fork 481
/
Polygon.cs
178 lines (166 loc) · 6.28 KB
/
Polygon.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
//------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
//------------------------------------------------------------
namespace Microsoft.Azure.Cosmos.Spatial
{
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Runtime.Serialization;
using Newtonsoft.Json;
/// <summary>
/// <para>
/// Polygon geometry class in the Azure Cosmos DB service.
/// </para>
/// <para>
/// A polygon is represented by the set of "polygon rings". Each ring is closed line string.
/// First ring defines external ring. All subsequent rings define "holes" in the external ring.
/// </para>
/// <para>
/// Rings must be specified using Left Hand Rule: traversing the ring in the order of its points, should result
/// in internal area of the polygon being to the left side.
/// </para>
/// </summary>
/// <example>
/// This example shows how to define a polygon which covers small portion of the Earth:
/// <code language="c#">
/// <![CDATA[
/// var polygon = new Polygon(
/// new[]
/// {
/// new Position(20.0, 20.0),
/// new Position(30.0, 20.0),
/// new Position(30.0, 30.0),
/// new Position(20.0, 30.0)
/// new Position(20.0, 20.0)
/// });
/// ]]>
/// </code>
/// </example>
/// <example>
/// This example shows how to define a polygon which covers area more than one hemisphere:
/// (Notice that only order of coordinates was reversed).
/// <code language="c#">
/// <![CDATA[
/// var polygon = new Polygon(
/// new[]
/// {
/// new Position(20.0, 20.0),
/// new Position(20.0, 30.0),
/// new Position(30.0, 30.0),
/// new Position(30.0, 20.0)
/// new Position(20.0, 20.0)
/// });
/// ]]>
/// </code>
/// </example>
[DataContract]
public sealed class Polygon : Geometry, IEquatable<Polygon>
{
/// <summary>
/// Initializes a new instance of the <see cref="Polygon"/> class,
/// from external ring (the polygon contains no holes) in the Azure Cosmos DB service.
/// </summary>
/// <param name="externalRingPositions">
/// External polygon ring coordinates.
/// </param>
public Polygon(IList<Position> externalRingPositions)
: this(new[] { new LinearRing(externalRingPositions) }, new GeometryParams())
{
}
/// <summary>
/// Initializes a new instance of the <see cref="Polygon"/> class in the Azure Cosmos DB service.
/// </summary>
/// <param name="rings">
/// <para>
/// Polygon rings.
/// </para>
/// <para>
/// First ring is external ring. Following rings define 'holes' in the polygon.
/// </para>
/// </param>
public Polygon(IList<LinearRing> rings)
: this(rings, new GeometryParams())
{
}
/// <summary>
/// Initializes a new instance of the <see cref="Polygon"/> class in the Azure Cosmos DB service.
/// </summary>
/// <param name="rings">
/// Polygon rings.
/// </param>
/// <param name="geometryParams">
/// Additional geometry parameters.
/// </param>
public Polygon(IList<LinearRing> rings, GeometryParams geometryParams)
: base(GeometryType.Polygon, geometryParams)
{
if (rings == null)
{
throw new ArgumentNullException("rings");
}
this.Rings = new ReadOnlyCollection<LinearRing>(rings);
}
/// <summary>
/// Initializes a new instance of the <see cref="Polygon"/> class in the Azure Cosmos DB service.
/// </summary>
/// <remarks>
/// This constructor is used only during deserialization.
/// </remarks>
internal Polygon()
: base(GeometryType.Polygon, new GeometryParams())
{
}
/// <summary>
/// Gets the polygon rings in the Azure Cosmos DB service.
/// </summary>
/// <value>
/// Polygon rings.
/// </value>
[DataMember(Name = "coordinates")]
[JsonProperty("coordinates", Required = Required.Always, Order = 1)]
public ReadOnlyCollection<LinearRing> Rings { get; private set; }
/// <summary>
/// Determines whether the specified <see cref="Polygon" /> is equal to the current <see cref="Polygon" /> in the Azure Cosmos DB service.
/// </summary>
/// <returns>
/// true if the specified object is equal to the current object; otherwise, false.
/// </returns>
/// <param name="obj">The object to compare with the current object. </param>
public override bool Equals(object obj)
{
return this.Equals(obj as Polygon);
}
/// <summary>
/// Serves as a hash function for the <see cref="Polygon" /> type in the Azure Cosmos DB service.
/// </summary>
/// <returns>
/// A hash code for the current <see cref="Polygon"/>.
/// </returns>
public override int GetHashCode()
{
unchecked
{
return this.Rings.Aggregate(base.GetHashCode(), (current, value) => (current * 397) ^ value.GetHashCode());
}
}
/// <summary>
/// Determines if this <see cref="Polygon"/> is equal to the <paramref name="other" /> in the Azure Cosmos DB service.
/// </summary>
/// <param name="other"><see cref="Polygon"/> to compare to this <see cref="Polygon"/>.</param>
/// <returns><c>true</c> if objects are equal. <c>false</c> otherwise.</returns>
public bool Equals(Polygon other)
{
if (object.ReferenceEquals(null, other))
{
return false;
}
if (object.ReferenceEquals(this, other))
{
return true;
}
return base.Equals(other) && this.Rings.SequenceEqual(other.Rings);
}
}
}