drawstates.pro
12.5 KB
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
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
;+
; NAME:
; DRAWSTATES
;
; PURPOSE:
;
; Draws states in the USA in outline or as solid-color polygons
; from a state shapefile.
;
; AUTHOR:
;
; FANNING SOFTWARE CONSULTING
; David Fanning, Ph.D.
; 1645 Sheely Drive
; Fort Collins, CO 80526 USA
; Phone: 970-221-0438
; E-mail: david@idlcoyote.com
; Coyote's Guide to IDL Programming: http://www.idlcoyote.com
;
; CATEGORY:
; Utilities
;
; CALLING SEQUENCE:
;
; DrawStates, stateFile
;
; ARGUMENTS:
;
; stateFile: The name of the input shapefile containing state boundaries.
; If undefined, the "states.shp" file in the IDL distribution is used.
;
; KEYWORDS:
;
; ATTRIBUTE_NAME: The name of the attribute in the file that you wish to draw.
; By default, this is set to the attribute name "STATE_ABBR".
; (In some shapefiles, the attribute might be named "STATE".)
; If you are unsure of the attribute names in your shapefile,
; use the Coyote Library program SHAPEINFO to browse the file
; ahead of time.
;
; COLORS: The name of a color to draw the state outline or polygon in. This
; may be a string array of the same size as STATENAMES. Color names
; correspond to the colors available in cgColor. By default, "Sky Blue".
;
; FILL: Normally, the state outline is drawn. If this keyword is set,
; the polygon representing the state is filled with a solid color.
; May be a vector of the same size as STATENAMES.
;
; LINESTYLE: The normal LINESTYLE keyword index to choose plotting linestyles.
; By default, set to 0 and solid lines. May be a vector of the same
; size as STATENAMES.
;
; MINNUMVERTS: Set this keyword to the minimum number of vertices required to actually
; draw a polygon. In other words, to to drawn, a polygon must have at least
; this number of vertices. The default value is 3.
;
; STATENAMES: The names of the states you wish to draw. Normally, these are two-element
; state abbreviations, but this will depend upon the entity attributes in your
; shapefile. If this keyword is undefined, then all the states in the
; file will be drawn. If you are unsure of the entity names, use the
; Coyote Library program SHAPEINFO to browse the file ahead of time.
;
; THICK: The line thickness. By default, 1.0.
;
; RESTRICTIONS:
;
; It is assumed a map projection command has been issued and is in effect at
; the time this program is called.
;
; If STATENAMES is undefined, all states are drawn, but only a single value
; for COLORS, FILL, LINESTYLE, and THICK is allowed.
;
; Required Coyote Library programs:
;
; Error_Message
; cgColor
;
; EXAMPLE:
;
; cgDisplay, 700, 600
; Map_Set, 37.5, -117.5, /Albers, /IsoTropic, Limit=[30, -125, 45, -108], $
; Position=[0.05, 0.05, 0.95, 0.95], /NoErase
; DrawStates, Statenames=['CA', 'OR', 'WA', 'AZ', 'UT', 'ID'], Thick=1, $
; Colors=['firebrick', 'indian red', 'indian red', 'indian red', 'steel blue', 'indian red'], $
; Fill = [1,0,0,0,1,0]
; Map_Grid, LatDel = 2.0, LonDel = 2.0, /Box_Axes, Color=cgColor('charcoal')
;
; MODIFICATION HISTORY:
;
; Written by David W. Fanning, 2 April 2005.
; Added MINNUMVERTS keyword. Modifed the way entity pointers are cleaned up.
; Upgraded to use Coyote Graphics. 6 Oct 2011. DWF.
;-
;******************************************************************************************;
; Copyright (c) 2008, by Fanning Software Consulting, Inc. ;
; All rights reserved. ;
; ;
; Redistribution and use in source and binary forms, with or without ;
; modification, are permitted provided that the following conditions are met: ;
; ;
; * Redistributions of source code must retain the above copyright ;
; notice, this list of conditions and the following disclaimer. ;
; * Redistributions in binary form must reproduce the above copyright ;
; notice, this list of conditions and the following disclaimer in the ;
; documentation and/or other materials provided with the distribution. ;
; * Neither the name of Fanning Software Consulting, Inc. nor the names of its ;
; contributors may be used to endorse or promote products derived from this ;
; software without specific prior written permission. ;
; ;
; THIS SOFTWARE IS PROVIDED BY FANNING SOFTWARE CONSULTING, INC. ''AS IS'' AND ANY ;
; EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES ;
; OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT ;
; SHALL FANNING SOFTWARE CONSULTING, INC. BE LIABLE FOR ANY DIRECT, INDIRECT, ;
; INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED ;
; TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; ;
; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ;
; ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ;
; (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ;
; SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ;
;******************************************************************************************;
PRO DrawStates_DrawEntity, entity, COLOR=color, FILL=fill, LINESTYLE=linestyle, THICK=thick
; Error handling.
Catch, theError
IF theError NE 0 THEN BEGIN
ok = Error_Message()
IF Obj_Valid(shapefile) THEN Obj_Destroy, shapefile
IF Ptr_Valid(entities) THEN Heap_Free, entities
RETURN
ENDIF
; Drawing is going to be done based on the shape type.
CASE 1 OF
; Polygon shapes.
entity.shape_type EQ 5 OR $ ; Polygon.
entity.shape_type EQ 15 OR $ ; PolygonZ (ignoring Z)
entity.shape_type EQ 25: BEGIN ; PolygonM (ignoring M)
IF Ptr_Valid(entity.parts) THEN BEGIN
cuts = [*entity.parts, entity.n_vertices]
FOR j=0, entity.n_parts-1 DO BEGIN
CASE fill OF
0: cgPlotS, (*entity.vertices)[0, cuts[j]:cuts[j+1]-1], $
(*entity.vertices)[1, cuts[j]:cuts[j+1]-1], $
COLOR=color, LINESTYLE=linestyle, THICK=thick
1: cgColorFill, (*entity.vertices)[0, cuts[j]:cuts[j+1]-1], $
(*entity.vertices)[1, cuts[j]:cuts[j+1]-1], $
COLOR=color
ENDCASE
ENDFOR
ENDIF
ENDCASE ; Polygon shapes.
; Polyline shapes.
entity.shape_type EQ 3 OR $ ; PolyLine
entity.shape_type EQ 13 OR $ ; PolyLineZ (ignoring Z)
entity.shape_type EQ 23: BEGIN ; PolyLineM (ignoring M)
IF Ptr_Valid(entity.parts) THEN BEGIN
cuts = [*entity.parts, entity.n_vertices]
FOR j=0, entity.n_parts-1 DO BEGIN
CASE fill OF
0: cgPlotS, (*entity.vertices)[0, cuts[j]:cuts[j+1]-1], $
(*entity.vertices)[1, cuts[j]:cuts[j+1]-1], $
COLOR=color, LINESTYLE=linestyle, THICK=thick
1: cgColorFill, (*entity.vertices)[0, cuts[j]:cuts[j+1]-1], $
(*entity.vertices)[1, cuts[j]:cuts[j+1]-1], $
COLOR=color
ENDCASE
ENDFOR
ENDIF
ENDCASE ; Polyline shapes.
ELSE: ; All other shapes fall through and are silently ignored.
ENDCASE
END ;---------------------------------------------------------------------------------
PRO DrawStates, stateFile, $
ATTRIBUTE_NAME=attribute_name, $
COLORS=colors, $
FILL=fill, $
LINESTYLE=linestyle, $
MINNUMVERTS=minNumVerts, $
STATENAMES=statenames, $
THICK=thick
; Error handling.
Catch, theError
IF theError NE 0 THEN BEGIN
ok = Error_Message()
IF Obj_Valid(shapefile) THEN Obj_Destroy, shapefile
IF Ptr_Valid(entities) THEN Heap_Free, entities
RETURN
ENDIF
; Check parameters.
IF N_Elements(stateFile) EQ 0 THEN BEGIN
stateFile = Filepath(Subdirectory=['examples', 'data'], 'states.shp')
ENDIF
IF N_Elements(attribute_name) EQ 0 THEN attribute_name = 'STATE_ABBR' $
ELSE attribute_name = StrUpCase(attribute_name)
IF N_Elements(colors) EQ 0 THEN colors = 'Sky Blue'
IF N_Elements(fill) EQ 0 THEN fill = Keyword_Set(fill)
IF N_Elements(linestyle) EQ 0 THEN linestyle = 0
IF N_Elements(minNumVerts) EQ 0 THEN minNumVerts = 3
IF N_Elements(thick) EQ 0 THEN thick = 1.0
IF N_Elements(statenames) EQ 0 THEN statenames = 'ALL'
; Make sure arrays have the same number of elements.
IF N_Elements(statenames) NE 1 THEN BEGIN
numStates = N_Elements(statenames)
IF N_Elements(colors) EQ 1 THEN colors = Replicate(colors, numStates)
IF N_Elements(colors) NE numStates THEN $
Message, 'Number of COLORS does not match number of state names.'
IF N_Elements(fill) EQ 1 THEN fill = Replicate(fill, numStates)
IF N_Elements(fill) NE numStates THEN $
Message, 'Number of FILL values does not match number of state names.'
IF N_Elements(linestyle) EQ 1 THEN linestyle = Replicate(linestyle, numStates)
IF N_Elements(linestyle) NE numStates THEN $
Message, 'Number of LINESTYLE values does not match number of state names.'
IF N_Elements(thick) EQ 1 THEN thick = Replicate(thick, numStates)
IF N_Elements(thick) NE numStates THEN $
Message, 'Number of THICK values does not match number of state names.'
ENDIF
; Open the shape file and create the shape object.
shapefile = Obj_New('IDLffShape', stateFile)
IF Obj_Valid(shapefile) EQ 0 THEN $
Message, 'Unable to create shape file object. Returning...'
; Get the attribute names from the shape file.
shapefile -> GetProperty, ATTRIBUTE_NAMES=theNames
theNames = StrUpCase(StrTrim(theNames, 2))
; Find the attribute index.
attIndex = Where(theNames EQ attribute_name, count)
IF count EQ 0 THEN Message, 'Unable to find attribute ' + attribute_name + ' in file. Returning...'
; Get all the attribute pointers from the file. These are the entities.
entities = Ptr_New(/Allocate_Heap)
*entities = shapefile -> GetEntity(/All, /Attributes)
; Cycle through each entity and draw it, if required. Free each pointer
; as you go, because it take at least 10 times as long to free them with
; HEAP_FREE at the end if you don't do this!
FOR j=0,N_Elements(*entities)-1 DO BEGIN
thisEntity = (*entities)[j]
theState = StrUpCase(StrTrim((*thisEntity.attributes).(attIndex), 2))
index = Where(stateNames EQ theState, test)
IF stateNames[0] EQ 'ALL' THEN BEGIN
index = 0
test = 1
ENDIF
IF (test EQ 1) THEN BEGIN
IF N_Elements(*thisEntity.vertices) GE minNumVerts THEN BEGIN
DrawStates_DrawEntity, (*entities)[j], Color=(colors[index])[0], $
Fill=(fill[index])[0], LineStyle=(linestyle[index])[0], $
Thick=(thick[index])[0]
ENDIF
ENDIF
Ptr_Free, thisEntity.vertices
Ptr_Free, thisEntity.measure
Ptr_Free, thisEntity.parts
Ptr_Free, thisEntity.part_types
Ptr_Free, thisEntity.attributes
ENDFOR
; Clean up.
Obj_Destroy, shapefile
Ptr_Free, entities
END ;---------------------------------------------------------------------------------