|
1 // TODO breakAtDateLine? |
|
2 |
|
3 d3.geo.circle = function() { |
|
4 var origin = [0, 0], |
|
5 degrees = 90 - 1e-2, |
|
6 radians = degrees * d3_geo_radians, |
|
7 arc = d3.geo.greatArc().target(Object); |
|
8 |
|
9 function circle() { |
|
10 // TODO render a circle as a Polygon |
|
11 } |
|
12 |
|
13 function visible(point) { |
|
14 return arc.distance(point) < radians; |
|
15 } |
|
16 |
|
17 circle.clip = function(d) { |
|
18 arc.source(typeof origin === "function" ? origin.apply(this, arguments) : origin); |
|
19 return clipType(d); |
|
20 }; |
|
21 |
|
22 var clipType = d3_geo_type({ |
|
23 |
|
24 FeatureCollection: function(o) { |
|
25 var features = o.features.map(clipType).filter(Object); |
|
26 return features && (o = Object.create(o), o.features = features, o); |
|
27 }, |
|
28 |
|
29 Feature: function(o) { |
|
30 var geometry = clipType(o.geometry); |
|
31 return geometry && (o = Object.create(o), o.geometry = geometry, o); |
|
32 }, |
|
33 |
|
34 Point: function(o) { |
|
35 return visible(o.coordinates) && o; |
|
36 }, |
|
37 |
|
38 MultiPoint: function(o) { |
|
39 var coordinates = o.coordinates.filter(visible); |
|
40 return coordinates.length && { |
|
41 type: o.type, |
|
42 coordinates: coordinates |
|
43 }; |
|
44 }, |
|
45 |
|
46 LineString: function(o) { |
|
47 var coordinates = clip(o.coordinates); |
|
48 return coordinates.length && (o = Object.create(o), o.coordinates = coordinates, o); |
|
49 }, |
|
50 |
|
51 MultiLineString: function(o) { |
|
52 var coordinates = o.coordinates.map(clip).filter(function(d) { return d.length; }); |
|
53 return coordinates.length && (o = Object.create(o), o.coordinates = coordinates, o); |
|
54 }, |
|
55 |
|
56 Polygon: function(o) { |
|
57 var coordinates = o.coordinates.map(clip); |
|
58 return coordinates[0].length && (o = Object.create(o), o.coordinates = coordinates, o); |
|
59 }, |
|
60 |
|
61 MultiPolygon: function(o) { |
|
62 var coordinates = o.coordinates.map(function(d) { return d.map(clip); }).filter(function(d) { return d[0].length; }); |
|
63 return coordinates.length && (o = Object.create(o), o.coordinates = coordinates, o); |
|
64 }, |
|
65 |
|
66 GeometryCollection: function(o) { |
|
67 var geometries = o.geometries.map(clipType).filter(Object); |
|
68 return geometries.length && (o = Object.create(o), o.geometries = geometries, o); |
|
69 } |
|
70 |
|
71 }); |
|
72 |
|
73 function clip(coordinates) { |
|
74 var i = -1, |
|
75 n = coordinates.length, |
|
76 clipped = [], |
|
77 p0, |
|
78 p1, |
|
79 p2, |
|
80 d0, |
|
81 d1; |
|
82 |
|
83 while (++i < n) { |
|
84 d1 = arc.distance(p2 = coordinates[i]); |
|
85 if (d1 < radians) { |
|
86 if (p1) clipped.push(d3_geo_greatArcInterpolate(p1, p2)((d0 - radians) / (d0 - d1))); |
|
87 clipped.push(p2); |
|
88 p0 = p1 = null; |
|
89 } else { |
|
90 p1 = p2; |
|
91 if (!p0 && clipped.length) { |
|
92 clipped.push(d3_geo_greatArcInterpolate(clipped[clipped.length - 1], p1)((radians - d0) / (d1 - d0))); |
|
93 p0 = p1; |
|
94 } |
|
95 } |
|
96 d0 = d1; |
|
97 } |
|
98 |
|
99 if (p1 && clipped.length) { |
|
100 d1 = arc.distance(p2 = clipped[0]); |
|
101 clipped.push(d3_geo_greatArcInterpolate(p1, p2)((d0 - radians) / (d0 - d1))); |
|
102 } |
|
103 |
|
104 return resample(clipped); |
|
105 } |
|
106 |
|
107 // Resample coordinates, creating great arcs between each. |
|
108 function resample(coordinates) { |
|
109 var i = 0, |
|
110 n = coordinates.length, |
|
111 j, |
|
112 m, |
|
113 resampled = n ? [coordinates[0]] : coordinates, |
|
114 resamples, |
|
115 origin = arc.source(); |
|
116 |
|
117 while (++i < n) { |
|
118 resamples = arc.source(coordinates[i - 1])(coordinates[i]).coordinates; |
|
119 for (j = 0, m = resamples.length; ++j < m;) resampled.push(resamples[j]); |
|
120 } |
|
121 |
|
122 arc.source(origin); |
|
123 return resampled; |
|
124 } |
|
125 |
|
126 circle.origin = function(x) { |
|
127 if (!arguments.length) return origin; |
|
128 origin = x; |
|
129 return circle; |
|
130 }; |
|
131 |
|
132 circle.angle = function(x) { |
|
133 if (!arguments.length) return degrees; |
|
134 radians = (degrees = +x) * d3_geo_radians; |
|
135 return circle; |
|
136 }; |
|
137 |
|
138 // Precision is specified in degrees. |
|
139 circle.precision = function(x) { |
|
140 if (!arguments.length) return arc.precision(); |
|
141 arc.precision(x); |
|
142 return circle; |
|
143 }; |
|
144 |
|
145 return circle; |
|
146 } |