root/MGET/Branches/Jason/VisualStudioSolutions/vectorshp/vectorshp.cpp @ 905

Revision 905, 37.1 KB (checked in by jjr8, 16 months ago)

Added -u option to vectorshp.

Line 
1// vectorshp.cpp : Defines the entry point for the console application.
2//
3
4#include <iostream>
5#include <tchar.h>
6#include <math.h>
7#include <windows.h>
8
9#include "shapefil.h"
10
11const DWORD BUF_SIZE = 256*1024;
12
13enum DataType { Int8_DataType, Uint8_DataType, Int16_DataType, Uint16_DataType, Int32_DataType, Float_DataType, Double_DataType, };
14
15const int DataTypeSizes[] = {1, 1, 2, 2, 4, 4, 8 };
16
17static void PrintUsage()
18{
19    // Do not extend strings past column 91, so they come out properly
20    // in an 80-column CMD shell window.
21
22    printf("NAME\n");
23    printf("\n");
24    printf("     vectorshp - creates an ESRI shapefile of vectors from two 32-bit floating\n");
25    printf("                 point binary rasters that represent x and y components\n");
26    printf("\n");
27    printf("SYNOPSIS\n");
28    printf("\n");
29    printf("     vectorshp xbinary ybinary outfile datatype cols rows cellsize xllcorner\n");
30    printf("               yllcorner [options...]\n");
31    printf("\n");
32    printf("     xbinary     Binary raster representing the x components\n");
33    printf("     ybinary     Binary raster representing the y components\n");
34    printf("     outfile     Shapefile to create (must not exist already)\n");
35    printf("     datatype    Data type of the binary rasters, one of: int8, uint8, int16,\n");
36    printf("                 uint16, int32, float, or double\n");
37    printf("     cols        Number of columns in the binary files\n");
38    printf("     rows        Number of rows in the binary files\n");
39    printf("     cellsize    Cell size of the binary files\n");
40    printf("     xllcorner   X coordinate of the lower left corner of the binary files\n");
41    printf("     yllcorner   Y coordinate of the lower left corner of the binary files\n");
42    printf("\n");
43    printf("DESCRIPTION\n");
44    printf("\n");
45    printf("     vectorshp accepts as input two binary rasters having the same data type\n");
46    printf("     and dimensions. The first raster represents the X component of vectors\n");
47    printf("     and the second represents the Y component. vectorshp outputs an ESRI\n");
48    printf("     shapefile containing lines representing the vectors. The shapefile is\n");
49    printf("     useful for visualizing vector fields, like a quiver plot in matlab. In\n");
50    printf("     oceanography, vectorshp has been used to visualize geostrophic currents\n");
51    printf("     estimated from sea surface height data and sea surface winds estimated by\n");
52    printf("     the QuickSCAT satellite.\n");
53    printf("\n");
54    printf("     The output shapefile contains two attributes, Magnitude and Direction,\n");
55    printf("     which describe the vector in a polar coordinate system. Magnitude is in\n");
56    printf("     the units of the original X and Y components. Direction is in degrees,\n");
57    printf("     with 0 being due east, +90 due north, -90 due south, and +180 being due\n");
58    printf("     west.\n");
59    printf("\n");
60    printf("     The lines originate at the coordinates of the centers of the raster\n");
61    printf("     cells, allowing you to overlay the shapefile on the original rasters.\n");
62    printf("\n");
63    printf("     A special situation arises when your rasters are in a geographic\n");
64    printf("     projection but the vector components are in something other than degrees.\n");
65    printf("     For example, Aviso produces geostrophic current rasters projected in the\n");
66    printf("     Topex/Poseidon geographic projection with 0.25 degree cell size. The\n");
67    printf("     cells give current velocity in cm/s. You must consider three things when\n");
68    printf("     you create vector shapefiles.\n");
69    printf("\n");
70    printf("     First, the length of shapefile lines are computed as cm/s using simple\n");
71    printf("     Pythagorean math. They are not computed as degrees/s, even though the\n");
72    printf("     shapefile is in a geographic projection, not a cartesian projection\n");
73    printf("     such as Albers Equal Area. As a result, a 2 cm/s vector will span 2\n");
74    printf("     degrees. The current is clearly not moving at 2 degrees/s. If you want\n");
75    printf("     the lines to be scaled according to the projection, you must first\n");
76    printf("     project your input rasters to a cartesian system that uses the same\n");
77    printf("     units as the vector components (e.g. Albers Equal Area with cm units).\n");
78    printf("\n");
79    printf("     Second, depending on the cell size of and units of your rasters, the\n");
80    printf("     shapefile lines may be excessively long, resulting in a scrambled mess.\n");
81    printf("     Use the -s option to reduce the length of the lines. For example, for\n");
82    printf("     Aviso geostrophic currents, I typically use -s 0.01.\n");
83    printf("\n");
84    printf("     Finally, vectorshp does not define the ArcGIS projection of the\n");
85    printf("     shapefile. You must do this yourself (or wrap vectorshp in a\n");
86    printf("     geoprocessing script, as is done by Marine Geospatial Ecology Tools).\n");
87    printf("     After defining the projection and loading the shapefiles into ArcMap, you\n");
88    printf("     will get a warning saying the shapefile extends beyond the normal extent\n");
89    printf("     for geographic projections (+/-180 longitude, +/- 90 latitude). This is\n");
90    printf("     not a problem; it is expected.\n");
91    printf("\n");
92    printf("OPTIONS\n");
93    printf("\n");
94    printf("     -n val      Specifies that val is the \"NODATA\" value. Lines will not be\n");
95    printf("                 created if either the X or Y component has this value.\n");
96    printf("\n");
97    printf("     -s fac      Specifies that lines should be scaled by fac (for example,\n");
98    printf("                 -s 10 will create lines 10 times longer than normal). Use\n");
99    printf("                 this option to create vectors that can be overlaid on maps\n");
100    printf("                 without appearing too cluttered or too small to be visible.\n");
101    printf("                 The -s option does not affect the Magnitude attribute of the\n");
102    printf("                 lines; that attribute will still contain the unscaled values.\n");
103    printf("\n");
104    printf("     -u          Specifies that lengths of the lines should not be\n");
105    printf("                 proportional to the magnitude; instead, all lines will have\n");
106    printf("                 the same length. By default, this will be the cell size. If\n");
107    printf("                 the -s parameter is also specified, it scales this length\n");
108    printf("                 (e.g. -s 0.5 will create lines with a length of 1/2 of the\n");
109    printf("                 cell size. The -u parameter does not affect the Magnitude\n");
110    printf("                 attribute of the lines; that attribute will still contain the.\n");
111    printf("                 unscaled magnitude of each line.\n");
112    printf("\n");
113    printf("RELEASE HISTORY\n");
114    printf("\n");
115    printf("     1.1.0 (3-Feb-2012) - Added -u option.\n");
116    printf("     1.0.0 (2-Aug-2006) - Initial version.\n");
117    printf("\n");
118    printf("COPYRIGHT AND LICENSE\n");
119    printf("\n");
120    printf("     Copyright (c) 2012 Jason J. Roberts.\n");
121    printf("\n");
122    printf("     Compiled with portions of shapelib 1.2.10 Copyright (c) 1999, Frank\n");
123    printf("     Warmerdam.\n");
124    printf("\n");
125    printf("     Thanks Frank, and to your contributors, for a great library!\n");
126    printf("\n");
127    printf("     Permission is hereby granted, free of charge, to any person obtaining a\n");
128    printf("     copy of this software (the \"Software\"), to deal in the Software without\n");
129    printf("     restriction, including without limitation the rights to use, copy, modify,\n");
130    printf("     merge, publish, distribute, sublicense, and/or sell copies of the\n");
131    printf("     Software, and to permit persons to whom the Software is furnished to do\n");
132    printf("     so, subject to the following conditions:\n");
133    printf("\n");
134    printf("     The above copyright notice and this permission notice shall be included in\n");
135    printf("     all copies or substantial portions of the Software.\n");
136    printf("\n");
137    printf("     THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n");
138    printf("     IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n");
139    printf("     FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL\n");
140    printf("     THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n");
141    printf("     LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n");
142    printf("     FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\n");
143    printf("     DEALINGS IN THE SOFTWARE.\n");
144    printf("\n");
145    printf("CONTACT INFORMATION\n");
146    printf("\n");
147    printf("     Please email questions or feedback to jason.roberts@duke.edu.\n");
148}
149
150static bool ParseInteger(const char *pszStr, int *pValue)
151{
152    if (*pszStr == '\0')
153        return 0;
154
155    char *pEnd = "z";
156    int i = strtol(pszStr, &pEnd, 0);
157
158    if (*pEnd != '\0' || (i == LONG_MAX || i == LONG_MIN) && errno == ERANGE)
159        return false;
160
161    *pValue = i;
162
163    return true;
164}
165
166static bool ParseDouble(const char *pszStr, double *pValue)
167{
168    if (*pszStr == '\0')
169        return 0;
170
171    // Parse the value.
172
173    char *pEnd = "z";
174    double f = strtod(pszStr, &pEnd);
175
176    if (*pEnd != '\0' || (f == HUGE_VAL || f == -HUGE_VAL) && errno == ERANGE)
177        return false;
178
179    *pValue = f;
180
181    return true;
182}
183
184static bool ParseFloat(const char *pszStr, float *pValue)
185{
186    double d;
187
188    bool retval = ParseDouble(pszStr, &d);
189
190    *pValue = (float) d;
191
192    return retval;
193}
194
195static char *ParseCommandLineArguments(int argc, char *argv[], char **pXBinary, char **pYBinary, char **pOutFile, DataType *pDataType, int *pCols, int *pRows, double *pCellSize, double *pXLowerLeftCorner, double *pYLowerLeftCorner, int *pUseNoData, int *piNoDataValue, double *pdNoDataValue, double *pScaleFactor, int *pUniformLines)
196{
197    // Perform basic range checks.
198
199    if (argc < 10)
200        return "ERROR: Too few command line arguments specified.\n";
201
202    if (argc > 15)
203        return "ERROR: Too many command line arguments specified.\n";
204
205    // If the files are invalid, we will detect it when we fail to open them.
206
207    *pXBinary = argv[1];
208    *pYBinary = argv[2];
209    *pOutFile = argv[3];
210
211    // Extract the remaining arguments.
212
213    int iArgIndex = 4;
214
215    if (_stricmp(argv[iArgIndex], "int8") == 0)
216        *pDataType = Int8_DataType;
217    else if (_stricmp(argv[iArgIndex], "uint8") == 0)
218        *pDataType = Uint8_DataType;
219    else if (_stricmp(argv[iArgIndex], "int16") == 0)
220        *pDataType = Int16_DataType;
221    else if (_stricmp(argv[iArgIndex], "uint16") == 0)
222        *pDataType = Uint16_DataType;
223    else if (_stricmp(argv[iArgIndex], "int32") == 0)
224        *pDataType = Int32_DataType;
225    else if (_stricmp(argv[iArgIndex], "float") == 0)
226        *pDataType = Float_DataType;
227    else if (_stricmp(argv[iArgIndex], "double") == 0)
228        *pDataType = Double_DataType;
229    else
230        return "ERROR: An invalid data type was specified. The valid data types are int8, uint8, int16, uint16, int32, float and double.";
231    iArgIndex++;
232
233    if (!ParseInteger(argv[iArgIndex], pCols) || *pCols < 1)
234        return "ERROR: An invalid number of columns was specified. The number of columns must be an integer greater than or equal to 1 and less than or equal to 2147483647.";
235    iArgIndex++;
236
237    if (!ParseInteger(argv[iArgIndex], pRows) || *pRows < 1)
238        return "ERROR: An invalid number of rows was specified. The number of rows must be an integer greater than or equal to 1 and less than or equal to 2147483647.";
239    iArgIndex++;
240
241    if (!ParseDouble(argv[iArgIndex], pCellSize) || *pCellSize < 0.0)
242        return "ERROR: An invalid cell size was specified. The cell size must be the decimal representation of a double-precision (64-bit) floating point number greater than zero.";
243    iArgIndex++;
244
245    if (!ParseDouble(argv[iArgIndex], pXLowerLeftCorner))
246        return "ERROR: An invalid X coordinate of the lower-left corner was specified. The coordinate must be the decimal representation of a double-precision (64-bit) floating point number.";
247    iArgIndex++;
248
249    if (!ParseDouble(argv[iArgIndex], pYLowerLeftCorner))
250        return "ERROR: An invalid X coordinate of the lower-left corner was specified. The coordinate must be the decimal representation of a double-precision (64-bit) floating point number.";
251    iArgIndex++;
252
253    *pUseNoData = 0;
254    *pScaleFactor = 1.0;
255
256    while (iArgIndex < argc)
257    {
258        if (argv[iArgIndex][0] != '-' || argv[iArgIndex][1] == 0 || argv[iArgIndex][2] != 0 )
259            return "ERROR: Unrecognized command line argument.\n";
260
261        switch (argv[iArgIndex][1])
262        {
263            case 'n':
264            case 'N':
265                iArgIndex++;
266                if (*pDataType == Int8_DataType || *pDataType == Uint8_DataType || *pDataType == Int16_DataType || *pDataType == Uint16_DataType || *pDataType == Int32_DataType)
267                {
268                    if (!ParseInteger(argv[iArgIndex], piNoDataValue))
269                        return "ERROR: An invalid NODATA value was specified. The NODATA value must be an integer.";
270                    if (*pDataType == Int8_DataType && (*piNoDataValue < -128 || *piNoDataValue > 127))
271                        return "ERROR: An invalid NODATA value was specified. The NODATA value must be an integer between -128 and 127, inclusive.";
272                    if (*pDataType == Uint8_DataType && (*piNoDataValue < 0 || *piNoDataValue > 255))
273                        return "ERROR: An invalid NODATA value was specified. The NODATA value must be an integer between 0 and 255, inclusive.";
274                    if (*pDataType == Int16_DataType && (*piNoDataValue < -32768 || *piNoDataValue > 32767))
275                        return "ERROR: An invalid NODATA value was specified. The NODATA value must be an integer between -32768 and 32767, inclusive.";
276                    if (*pDataType == Uint16_DataType && (*piNoDataValue < 0 || *piNoDataValue > 65535))
277                        return "ERROR: An invalid NODATA value was specified. The NODATA value must be an integer between 0 and 65535, inclusive.";
278                    if (*pDataType == Int32_DataType && (*piNoDataValue < (0-2147483648) || *piNoDataValue > 2147483647))
279                        return "ERROR: An invalid NODATA value was specified. The NODATA value must be an integer between -2147483648 and 2147483647, inclusive.";
280                }
281                else
282                {
283                    if (!ParseDouble(argv[iArgIndex], pdNoDataValue))
284                        return "ERROR: An invalid NODATA value was specified. The NODATA value must be a decimal number.";
285                }
286                *pUseNoData = 1;
287                iArgIndex++;
288                break;
289
290            case 's':
291            case 'S':
292                iArgIndex++;
293                if (!ParseDouble(argv[iArgIndex], pScaleFactor) || *pScaleFactor <= 0.0)
294                    return "ERROR: An invalid scale factor was specified. The scale factor must be the decimal representation of a single-precision (32-bit) floating point number greater than zero.";
295                iArgIndex++;
296                break;
297
298            case 'u':
299            case 'U':
300                iArgIndex++;
301                *pUniformLines = 1;
302                break;
303
304            default:
305                return "ERROR: Unrecognized command line argument.\n";
306        }
307    }
308
309    // Return successfully.
310
311    return NULL;
312}
313
314int main(int argc, char *argv[])
315{
316    printf("vectorshp version 1.1.0 (3-Feb-2012)\n");
317    printf("\n");
318
319    // Parse the command line arguments.
320
321    if (argc == 1 || argc == 2 && argv[1][0] == '-' && argv[1][1] == '?' && argv[1][2] == 0)
322    {
323        PrintUsage();
324        return 1;
325    }
326
327    char *pszXBinary = NULL;
328    char *pszYBinary = NULL;
329    char *pszOutFile = NULL;
330    DataType iDataType = Int8_DataType;
331    int iCols = 0;
332    int iRows = 0;
333    double dCellSize = 0.0;
334    double dXLowerLeftCorner = 0.0;
335    double dYLowerLeftCorner = 0.0;
336    int bUseNoData = 0;
337    int iNoDataValue = 0;
338    double dNoDataValue = 0;
339    double dScaleFactor = 1.0;
340    int iUniformLines = 0;
341
342    char *pszErrorMessage = ParseCommandLineArguments(argc, argv, &pszXBinary, &pszYBinary, &pszOutFile, &iDataType, &iCols, &iRows, &dCellSize, &dXLowerLeftCorner, &dYLowerLeftCorner, &bUseNoData, &iNoDataValue, &dNoDataValue, &dScaleFactor, &iUniformLines);
343    if (pszErrorMessage != NULL)
344    {
345        printf(pszErrorMessage);
346        printf("\n");
347        printf("Type \"vectorshp -?\" for help.\n");
348        return 1;
349    }
350
351    // Make sure the output shapefile does not exist already.
352
353    size_t iLen = strlen(pszOutFile);
354
355    if (iLen >= 4 &&
356        pszOutFile[iLen - 4] == '.' &&
357        (pszOutFile[iLen - 3] == 's' || pszOutFile[iLen - 3] == 'S') &&
358        (pszOutFile[iLen - 2] == 'h' || pszOutFile[iLen - 2] == 'H') &&
359        (pszOutFile[iLen - 1] == 'p' || pszOutFile[iLen - 1] == 'P'))
360    {
361        char *pszNewOutFile = (char *) calloc(iLen - 3, 1);
362        if (pszNewOutFile == NULL)
363        {
364            printf("ERROR: Out of memory.\n");
365            return 1;
366        }
367        pszOutFile = strncpy(pszNewOutFile, pszOutFile, iLen - 4);
368    }
369
370    iLen = strlen(pszOutFile);
371    char *pszTemp = (char *) calloc(iLen + 5, 1);
372    if (pszTemp == NULL)
373    {
374        printf("ERROR: Out of memory.\n");
375        return 1;
376    }
377    strcpy(pszTemp, pszOutFile);
378    pszTemp[iLen] = '.';
379
380    pszTemp[iLen + 1] = 's';
381    pszTemp[iLen + 2] = 'h';
382    pszTemp[iLen + 3] = 'p';
383    FILE *pTempFile = fopen(pszTemp, "r");
384    if (pTempFile != NULL)
385    {
386        printf("ERROR: The file \"%s\" already exists. Please delete it or specify a different output file name.\n", pszTemp);
387        return 1;
388    }
389
390    pszTemp[iLen + 1] = 's';
391    pszTemp[iLen + 2] = 'h';
392    pszTemp[iLen + 3] = 'x';
393    pTempFile = fopen(pszTemp, "r");
394    if (pTempFile != NULL)
395    {
396        printf("ERROR: The file \"%s\" already exists. Please delete it or specify a different output file name.\n", pszTemp);
397        return 1;
398    }
399
400    pszTemp[iLen + 1] = 'd';
401    pszTemp[iLen + 2] = 'b';
402    pszTemp[iLen + 3] = 'f';
403    pTempFile = fopen(pszTemp, "r");
404    if (pTempFile != NULL)
405    {
406        printf("ERROR: The file \"%s\" already exists. Please delete it or specify a different output file name.\n", pszTemp);
407        return 1;
408    }
409
410    // Open the binary files file for reading.
411
412    HANDLE hXFile = CreateFile(pszXBinary, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL + FILE_FLAG_SEQUENTIAL_SCAN, 0);
413
414    if (hXFile == INVALID_HANDLE_VALUE)
415    {
416        DWORD dwError = GetLastError();
417        LPSTR lpMsgBuf = NULL;
418        FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, dwError, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR) &lpMsgBuf, 0, NULL);
419        if (lpMsgBuf != NULL)
420            printf("ERROR: Failed to open file \"%s\" for reading. The operating system returned error %d: %s\n", pszXBinary, dwError, lpMsgBuf);
421        else
422            printf("ERROR: Failed to open file \"%s\" for reading.\n", pszXBinary);
423        return 1;
424    }
425
426    printf("Opened \"%s\" for reading.\n", pszXBinary);
427
428    HANDLE hYFile = CreateFile(pszYBinary, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL + FILE_FLAG_SEQUENTIAL_SCAN, 0);
429
430    if (hYFile == INVALID_HANDLE_VALUE)
431    {
432        DWORD dwError = GetLastError();
433        LPSTR lpMsgBuf = NULL;
434        FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, dwError, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR) &lpMsgBuf, 0, NULL);
435        if (lpMsgBuf != NULL)
436            printf("ERROR: Failed to open file \"%s\" for reading. The operating system returned error %d: %s\n", pszYBinary, dwError, lpMsgBuf);
437        else
438            printf("ERROR: Failed to open file \"%s\" for reading.\n", pszYBinary);
439        return 1;
440    }
441
442    printf("Opened \"%s\" for reading.\n", pszYBinary);
443
444    // Verify that the binary files are the right sizes.
445
446    LONGLONG liExpectedSize = (LONGLONG) iCols * (LONGLONG) iRows * (LONGLONG) DataTypeSizes[iDataType];
447    LARGE_INTEGER liFileSize;
448
449    if (!GetFileSizeEx(hXFile, &liFileSize))
450    {
451        DWORD dwError = GetLastError();
452        LPSTR lpMsgBuf = NULL;
453        FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, dwError, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR) &lpMsgBuf, 0, NULL);
454        if (lpMsgBuf != NULL)
455            printf("ERROR: Failed to retrieve the size of the file \"%s\". The operating system returned error %d: %s\n", pszXBinary, dwError, lpMsgBuf);
456        else
457            printf("ERROR: Failed to retrieve the size of the file \"%s\".\n", pszXBinary);
458        return 1;
459    }
460
461    if (liFileSize.QuadPart != liExpectedSize)
462    {
463        printf("ERROR: The size of file \"%s\" is %I64i bytes, but it was expected to be %I64i bytes, given that it has %i columns, %i rows, and its data type requires %i bytes. Please check your parameters.\n", pszXBinary, liFileSize.QuadPart, liExpectedSize, iCols, iRows, DataTypeSizes[iDataType]);
464        return 1;
465    }
466
467    if (!GetFileSizeEx(hYFile, &liFileSize))
468    {
469        DWORD dwError = GetLastError();
470        LPSTR lpMsgBuf = NULL;
471        FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, dwError, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR) &lpMsgBuf, 0, NULL);
472        if (lpMsgBuf != NULL)
473            printf("ERROR: Failed to retrieve the size of the file \"%s\". The operating system returned error %d: %s\n", pszYBinary, dwError, lpMsgBuf);
474        else
475            printf("ERROR: Failed to retrieve the size of the file \"%s\".\n", pszYBinary);
476        return 1;
477    }
478
479    if (liFileSize.QuadPart != liExpectedSize)
480    {
481        printf("ERROR: The size of file \"%s\" is %I64i bytes, but it was expected to be %I64i bytes, given that it has %i columns, %i rows, and its data type requires %i bytes. Please check your parameters.\n", pszYBinary, liFileSize.QuadPart, liExpectedSize, iCols, iRows, DataTypeSizes[iDataType]);
482        return 1;
483    }
484
485    // Create the output shapefile.
486
487    printf("Writing lines to output shapefile \"%s\"...\n", pszOutFile);
488
489    errno = 0;
490    SHPHandle hOutShapeFile = NULL;
491
492    hOutShapeFile = SHPCreate(pszOutFile, SHPT_ARC);
493
494    if (hOutShapeFile == NULL)
495    {
496        if (errno != 0)
497            printf("ERROR: Failed to create the output shapefile \"%s\". The shapelib.dll function SHPCreate() failed. On exit of that function, the global error number was set to %d: %s\n", pszOutFile, errno, strerror(errno));
498        else
499            printf("ERROR: Failed to create the output shapefile \"%s\". The shapelib.dll function SHPCreate() failed. Unfortunately that function does not return any detailed error information, and the global error number was set to zero (no error).\n", pszOutFile);
500        return 1;
501    }
502
503    // Create the output DBF file.
504
505    DBFHandle hOutDBFFile = DBFCreate(pszOutFile);
506    if (hOutDBFFile == NULL)
507    {
508        if (errno != 0)
509            printf("ERROR: Failed to create the output DBF file \"%s.dbf\". The shapelib.dll function DBFCreate() failed. On exit of that function, the global error number was set to %d: %s\n", pszOutFile, errno, strerror(errno));
510        else
511            printf("ERROR: Failed to create the output DBF file \"%s.dbf\". The shapelib.dll function DBFCreate() failed. Unfortunately that function does not return any detailed error information, and the global error number was set to zero (no error).\n", pszOutFile);
512        SHPClose(hOutShapeFile);
513        return 1;
514    }
515
516    DBFAddField(hOutDBFFile, "Magnitude", FTDouble, 19, 11);
517    DBFAddField(hOutDBFFile, "Direction", FTDouble, 19, 11);
518
519    // Read cells from the binary files and write lines to the shapefile.
520   
521    BYTE pXReadBuf[BUF_SIZE];
522    BYTE pYReadBuf[BUF_SIZE];
523    DWORD dwBytesToRead = sizeof(pXReadBuf);
524    DWORD dwBytesRead = 0;
525    DWORD dwReadIndex = 0;
526
527    for (INT32 row = 0; row < iRows; row++)
528    {
529        for (INT32 col = 0; col < iCols; col++)
530        {
531            // If we exhausted the read buffers, refill them from the binary
532            // files.
533
534            if (dwReadIndex >= dwBytesRead)
535            {
536                if (!ReadFile(hXFile, pXReadBuf, dwBytesToRead, &dwBytesRead, NULL))
537                {
538                    DWORD dwError = GetLastError();
539                    LPSTR lpMsgBuf = NULL;
540                    FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, dwError, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR) &lpMsgBuf, 0, NULL);
541                    if (lpMsgBuf != NULL)
542                        printf("ERROR: Failed to read from the file \"%s\". The operating system returned error %d: %s\n", pszXBinary, dwError, lpMsgBuf);
543                    else
544                        printf("ERROR: Failed to read from the file \"%s\".\n", pszXBinary);
545                    SHPClose(hOutShapeFile);
546                    DBFClose(hOutDBFFile);
547                    return 1;
548                }
549                if (dwBytesRead == 0)
550                {
551                    printf("ERROR: Reached the end of file \"%s\" prematurely. It is too small for the number of columns and rows and the data type specified.\n", pszXBinary);
552                    SHPClose(hOutShapeFile);
553                    DBFClose(hOutDBFFile);
554                    return 1;
555                }
556
557                DWORD dwBytesRead2 = 0;
558                if (!ReadFile(hYFile, pYReadBuf, dwBytesRead, &dwBytesRead2, NULL))
559                {
560                    DWORD dwError = GetLastError();
561                    LPSTR lpMsgBuf = NULL;
562                    FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, dwError, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR) &lpMsgBuf, 0, NULL);
563                    if (lpMsgBuf != NULL)
564                        printf("ERROR: Failed to read from the file \"%s\". The operating system returned error %d: %s\n", pszYBinary, dwError, lpMsgBuf);
565                    else
566                        printf("ERROR: Failed to read from the file \"%s\".\n", pszYBinary);
567                    SHPClose(hOutShapeFile);
568                    DBFClose(hOutDBFFile);
569                    return 1;
570                }
571                if (dwBytesRead2 == 0)
572                {
573                    printf("ERROR: Reached the end of file \"%s\" prematurely. It is too small for the number of columns and rows and the data type specified.\n", pszYBinary);
574                    SHPClose(hOutShapeFile);
575                    DBFClose(hOutDBFFile);
576                    return 1;
577                }
578                if (dwBytesRead2 != dwBytesRead)
579                {
580                    printf("ERROR: Reached the end of file \"%s\" prematurely. It is not the same size as file \"%s\".\n", pszYBinary, pszXBinary);
581                    SHPClose(hOutShapeFile);
582                    DBFClose(hOutDBFFile);
583                    return 1;
584                }
585
586                dwReadIndex = 0;
587            }
588
589            // Only create a line if neither cell is NODATA.
590
591            bool bNoData = false;
592
593            if (bUseNoData)
594                switch (iDataType)
595                {
596                    case Int8_DataType:
597                        bNoData = ((INT32) *((INT8 *) (pXReadBuf + dwReadIndex))) == iNoDataValue || ((INT32) *((INT8 *) (pYReadBuf + dwReadIndex))) == iNoDataValue;
598                        break;
599
600                    case Uint8_DataType:
601                        bNoData = ((INT32) *((UINT8 *) (pXReadBuf + dwReadIndex))) == iNoDataValue || ((INT32) *((UINT8 *) (pYReadBuf + dwReadIndex))) == iNoDataValue;
602                        break;
603
604                    case Int16_DataType:
605                        bNoData = ((INT32) *((INT16 *) (pXReadBuf + dwReadIndex))) == iNoDataValue || ((INT32) *((INT16 *) (pYReadBuf + dwReadIndex))) == iNoDataValue;
606                        break;
607
608                    case Uint16_DataType:
609                        bNoData = ((INT32) *((UINT16 *) (pXReadBuf + dwReadIndex))) == iNoDataValue || ((INT32) *((UINT16 *) (pYReadBuf + dwReadIndex))) == iNoDataValue;
610                        break;
611
612                    case Int32_DataType:
613                        bNoData = *((INT32 *) (pXReadBuf + dwReadIndex)) == iNoDataValue || *((INT32 *) (pYReadBuf + dwReadIndex)) == iNoDataValue;
614                        break;
615
616                    case Float_DataType:
617                        bNoData = ((DOUBLE) *((FLOAT *) (pXReadBuf + dwReadIndex))) == dNoDataValue || ((DOUBLE) *((FLOAT *) (pYReadBuf + dwReadIndex))) == dNoDataValue;
618                        break;
619
620                    case Double_DataType:
621                        bNoData = *((DOUBLE *) (pXReadBuf + dwReadIndex)) == dNoDataValue || *((DOUBLE *) (pYReadBuf + dwReadIndex)) == dNoDataValue;
622                        break;
623
624                    default:
625                        printf("ERROR: Programming error in this tool. Invalid DataType. Please contact the author of this tool for assistance.\n");
626                        SHPClose(hOutShapeFile);
627                        DBFClose(hOutDBFFile);
628                        return 1;
629                }
630
631            if (!bNoData)
632            {
633                // Calculate the starting coordinates of the vector.
634
635                double dXStart = dXLowerLeftCorner + dCellSize * (double) col + dCellSize / 2;
636                double dYStart = dYLowerLeftCorner + dCellSize * (double) (iRows - row - 1) + dCellSize / 2;
637
638                // Calculate the ending coordinates of the vector.
639
640                double dXEnd = dXStart;
641                double dYEnd = dYStart;
642
643                switch (iDataType)
644                {
645                    case Int8_DataType:
646                        dXEnd += ((DOUBLE) *((INT8 *) (pXReadBuf + dwReadIndex))) * dScaleFactor;
647                        dYEnd += ((DOUBLE) *((INT8 *) (pYReadBuf + dwReadIndex))) * dScaleFactor;
648                        break;
649
650                    case Uint8_DataType:
651                        dXEnd += ((DOUBLE) *((UINT8 *) (pXReadBuf + dwReadIndex))) * dScaleFactor;
652                        dYEnd += ((DOUBLE) *((UINT8 *) (pYReadBuf + dwReadIndex))) * dScaleFactor;
653                        break;
654
655                    case Int16_DataType:
656                        dXEnd += ((DOUBLE) *((INT16 *) (pXReadBuf + dwReadIndex))) * dScaleFactor;
657                        dYEnd += ((DOUBLE) *((INT16 *) (pYReadBuf + dwReadIndex))) * dScaleFactor;
658                        break;
659
660                    case Uint16_DataType:
661                        dXEnd += ((DOUBLE) *((UINT16 *) (pXReadBuf + dwReadIndex))) * dScaleFactor;
662                        dYEnd += ((DOUBLE) *((UINT16 *) (pYReadBuf + dwReadIndex))) * dScaleFactor;
663                        break;
664
665                    case Int32_DataType:
666                        dXEnd += ((DOUBLE) *((INT32 *) (pXReadBuf + dwReadIndex))) * dScaleFactor;
667                        dYEnd += ((DOUBLE) *((INT32 *) (pYReadBuf + dwReadIndex))) * dScaleFactor;
668                        break;
669
670                    case Float_DataType:
671                        dXEnd += ((DOUBLE) *((FLOAT *) (pXReadBuf + dwReadIndex))) * dScaleFactor;
672                        dYEnd += ((DOUBLE) *((FLOAT *) (pYReadBuf + dwReadIndex))) * dScaleFactor;
673                        break;
674
675                    case Double_DataType:
676                        dXEnd += *((DOUBLE *) (pXReadBuf + dwReadIndex)) * dScaleFactor;
677                        dYEnd += *((DOUBLE *) (pYReadBuf + dwReadIndex)) * dScaleFactor;
678                        break;
679
680                    default:
681                        printf("ERROR: Programming error in this tool. Invalid DataType. Please contact the author of this tool for assistance.\n");
682                        SHPClose(hOutShapeFile);
683                        DBFClose(hOutDBFFile);
684                        return 1;
685                }
686
687                // Write the vector to the shapefile.
688
689                double dMagnitude = sqrt(pow((dXEnd - dXStart) / dScaleFactor, 2) + pow((dYEnd - dYStart) / dScaleFactor, 2));
690                double dDirection = atan2(dYEnd - dYStart, dXEnd - dXStart) / 3.1415926535897931 * 180.0;
691
692                double fX[2] = {dXStart, dXEnd};
693                double fY[2] = {dYStart, dYEnd};
694
695                if (iUniformLines)
696                {
697                    double dLineLength = dCellSize * dScaleFactor;
698                    fX[1] = dXStart + (dXEnd - dXStart) * (dLineLength / dMagnitude);
699                    fY[1] = dYStart + (dYEnd - dYStart) * (dLineLength / dMagnitude);
700
701                    //if (dXEnd >= dXStart)
702                    //    fX[1] = dXStart + sqrt(pow(dMagnitude, 2) - pow(dYStart - dYEnd, 2)) * dCellSize * dScaleFactor;
703                    //else
704                    //    fX[1] = dXStart - sqrt(pow(dMagnitude, 2) - pow(dYStart - dYEnd, 2)) * dCellSize * dScaleFactor;
705
706                    //if (dYEnd >= dYStart)
707                    //    fY[1] = dYStart + sqrt(pow(dMagnitude, 2) - pow(dXStart - dXEnd, 2)) * dCellSize * dScaleFactor;
708                    //else
709                    //    fY[1] = dYStart - sqrt(pow(dMagnitude, 2) - pow(dXStart - dXEnd, 2)) * dCellSize * dScaleFactor;
710                }
711
712                SHPObject *shpObj = SHPCreateObject(SHPT_ARC, -1, 0, NULL, NULL, 2, &fX[0], &fY[0], NULL, NULL);
713
714                int iShapeID = SHPWriteObject(hOutShapeFile, -1, shpObj);
715                if (iShapeID == -1)
716                {
717                    if (errno != 0)
718                        printf("ERROR: Failed to write line to output shapefile \"%s\". The shapelib.dll function SHPWriteObject() failed. On exit of that function, the global error number was set to %d: %s\n", pszOutFile, errno, strerror(errno));
719                    else
720                        printf("ERROR: Failed to write line to output shapefile \"%s\". The shapelib.dll function SHPWriteObject() failed. Unfortunately that function does not return any detailed error information, and the global error number was set to zero (no error).\n", pszOutFile);
721                    SHPClose(hOutShapeFile);
722                    DBFClose(hOutDBFFile);
723                    return 1;
724                }
725
726                SHPDestroyObject(shpObj);
727
728                // Write attributes to the DBF file.
729
730
731                if (!DBFWriteDoubleAttribute(hOutDBFFile, iShapeID, 0, dMagnitude) ||
732                    !DBFWriteDoubleAttribute(hOutDBFFile, iShapeID, 1, dDirection))
733                {
734                    if (errno != 0)
735                        printf("ERROR: Failed to write an attribute to the output DBF file \"%s.dbf\". The shapelib.dll function DBFWriteDoubleAttribute() failed. On exit of that function, the global error number was set to %d: %s\n", pszOutFile, errno, strerror(errno));
736                    else
737                        printf("ERROR: Failed to write an attribute to the output DBF file \"%s.dbf\". The shapelib.dll function DBFWriteDoubleAttribute() failed. Unfortunately that function does not return any detailed error information, and the global error number was set to zero (no error).\n", pszOutFile);
738                    SHPClose(hOutShapeFile);
739                    DBFClose(hOutDBFFile);
740                    return 1;
741                }
742            }
743
744            // Go on to the next cell.
745
746            switch (iDataType)
747            {
748                case Int8_DataType:
749                case Uint8_DataType:
750                    dwReadIndex++;
751                    break;
752
753                case Int16_DataType:
754                case Uint16_DataType:
755                    dwReadIndex += 2;
756                    break;
757
758                case Int32_DataType:
759                case Float_DataType:
760                    dwReadIndex += 4;
761                    break;
762
763                case Double_DataType:
764                    dwReadIndex += 8;
765                    break;
766
767                default:
768                    printf("ERROR: Programming error in this tool. Invalid DataType. Please contact the author of this tool for assistance.\n");
769                    SHPClose(hOutShapeFile);
770                    DBFClose(hOutDBFFile);
771                    return 1;
772            }
773        }
774    }
775
776    // Close the files.
777
778    printf("Done.\n");
779
780    CloseHandle(hXFile);
781    CloseHandle(hYFile);
782    SHPClose(hOutShapeFile);
783    DBFClose(hOutDBFFile);
784
785    // Return successfully.
786
787        return 0;
788}
Note: See TracBrowser for help on using the browser.