~ubuntu-branches/ubuntu/trusty/liblas/trusty-proposed

« back to all changes in this revision

Viewing changes to src/spatialreference.cpp

  • Committer: Package Import Robot
  • Author(s): Francesco Paolo Lovergine
  • Date: 2014-01-05 17:00:29 UTC
  • mfrom: (7.1.2 sid)
  • Revision ID: package-import@ubuntu.com-20140105170029-ddtp0j63x5jvck2u
Tags: 1.7.0+dfsg-2
Fixed missing linking of system boost component.
(closes: #733282)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/******************************************************************************
 
2
 * $Id: lasspatialreference.cpp 1104 2009-03-17 04:15:19Z hobu $
 
3
 *
 
4
 * Project:  libLAS - http://liblas.org - A BSD library for LAS format data.
 
5
 * Purpose:  LAS Spatial Reference class 
 
6
 * Author:   Howard Butler, hobu.inc@gmail.com
 
7
 *           Frank Warmerdam, warmerdam@pobox.com
 
8
 *
 
9
 ******************************************************************************
 
10
 * Copyright (c) 2009, Howard Butler
 
11
 *
 
12
 * All rights reserved.
 
13
 * 
 
14
 * Redistribution and use in source and binary forms, with or without 
 
15
 * modification, are permitted provided that the following 
 
16
 * conditions are met:
 
17
 * 
 
18
 *     * Redistributions of source code must retain the above copyright 
 
19
 *       notice, this list of conditions and the following disclaimer.
 
20
 *     * Redistributions in binary form must reproduce the above copyright 
 
21
 *       notice, this list of conditions and the following disclaimer in 
 
22
 *       the documentation and/or other materials provided 
 
23
 *       with the distribution.
 
24
 *     * Neither the name of the Martin Isenburg or Iowa Department 
 
25
 *       of Natural Resources nor the names of its contributors may be 
 
26
 *       used to endorse or promote products derived from this software 
 
27
 *       without specific prior written permission.
 
28
 * 
 
29
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
 
30
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
 
31
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 
 
32
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 
 
33
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 
 
34
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 
 
35
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 
 
36
 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 
 
37
 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 
 
38
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 
 
39
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY 
 
40
 * OF SUCH DAMAGE.
 
41
 ****************************************************************************/
 
42
 
 
43
 
 
44
// GDAL OSR
 
45
#ifdef HAVE_GDAL
 
46
 
 
47
// Supress inclusion of cpl_serv.h per #194, perhaps remove one day
 
48
// when libgeotiff 1.4.0+ is widely used
 
49
#define CPL_SERV_H_INCLUDED
 
50
 
 
51
#include <ogr_srs_api.h>
 
52
#include <cpl_port.h>
 
53
#include <geo_normalize.h>
 
54
#include <geovalues.h>
 
55
#include <ogr_spatialref.h>
 
56
#include <gdal.h>
 
57
#include <xtiffio.h>
 
58
#include <cpl_multiproc.h>
 
59
#endif
 
60
 
 
61
// GeoTIFF
 
62
#ifdef HAVE_LIBGEOTIFF
 
63
#include <geotiff.h>
 
64
#include <geo_simpletags.h>
 
65
#include <geo_normalize.h>
 
66
#include <geo_simpletags.h>
 
67
#include <geovalues.h>
 
68
#endif // HAVE_LIBGEOTIFF
 
69
 
 
70
#include <liblas/spatialreference.hpp>
 
71
#include <liblas/detail/private_utility.hpp>
 
72
#include <liblas/external/property_tree/xml_parser.hpp>
 
73
// boost
 
74
#include <boost/concept_check.hpp>
 
75
#include <boost/cstdint.hpp>
 
76
// std
 
77
#include <stdexcept>
 
78
#include <string>
 
79
#include <vector>
 
80
 
 
81
#ifdef HAVE_GDAL
 
82
#  include "cpl_conv.h"
 
83
#endif
 
84
 
 
85
using namespace boost;
 
86
 
 
87
namespace liblas {
 
88
 
 
89
SpatialReference::SpatialReference()
 
90
    : m_gtiff(0)
 
91
    , m_tiff(0)
 
92
{
 
93
    assert(0 == m_gtiff);
 
94
    assert(0 == m_tiff);
 
95
}
 
96
 
 
97
SpatialReference::SpatialReference(std::vector<VariableRecord> const& vlrs) 
 
98
    : m_gtiff(0)
 
99
    , m_tiff(0)
 
100
{
 
101
    SetVLRs(vlrs);
 
102
    GetGTIF();
 
103
}
 
104
 
 
105
SpatialReference::SpatialReference(SpatialReference const& other) 
 
106
    : m_gtiff(0)
 
107
    , m_tiff(0)
 
108
    , m_wkt(other.m_wkt)
 
109
{
 
110
    SetVLRs(other.GetVLRs());
 
111
    GetGTIF();
 
112
}
 
113
 
 
114
SpatialReference& SpatialReference::operator=(SpatialReference const& rhs)
 
115
{
 
116
    if (&rhs != this)
 
117
    {
 
118
        SetVLRs(rhs.GetVLRs());
 
119
        GetGTIF();
 
120
        m_wkt = rhs.m_wkt;
 
121
    }
 
122
    return *this;
 
123
}
 
124
 
 
125
bool SpatialReference::operator==(const SpatialReference& input) const
 
126
{
 
127
#ifdef HAVE_GDAL
 
128
 
 
129
    OGRSpatialReferenceH current = OSRNewSpatialReference(GetWKT(eCompoundOK, false).c_str());
 
130
    OGRSpatialReferenceH other = OSRNewSpatialReference(input.GetWKT(eCompoundOK, false).c_str());
 
131
 
 
132
    int output = OSRIsSame(current, other);
 
133
 
 
134
    OSRDestroySpatialReference( current );
 
135
    OSRDestroySpatialReference( other );
 
136
    
 
137
    return bool(output == 1);
 
138
    
 
139
#else
 
140
    boost::ignore_unused_variable_warning(input);
 
141
    throw std::runtime_error ("SpatialReference equality testing not available without GDAL+libgeotiff support");
 
142
#endif
 
143
 
 
144
}
 
145
 
 
146
SpatialReference::~SpatialReference() 
 
147
{
 
148
#ifdef HAVE_LIBGEOTIFF
 
149
    if (m_gtiff != 0)
 
150
    {
 
151
        GTIFFree(m_gtiff);
 
152
        m_gtiff = 0;
 
153
    }
 
154
    if (m_tiff != 0)
 
155
    {
 
156
        ST_Destroy(m_tiff);
 
157
        m_tiff = 0;
 
158
    }
 
159
#endif
 
160
}
 
161
 
 
162
/// Keep a copy of the VLRs that are related to GeoTIFF SRS information.
 
163
void SpatialReference::SetVLRs(std::vector<VariableRecord> const& vlrs)
 
164
{
 
165
    
 
166
    std::string const uid("LASF_Projection");
 
167
    
 
168
    // Wipe out any existing VLRs that might exist on the SpatialReference
 
169
    m_vlrs.clear();
 
170
    
 
171
    // We only copy VLR records from the list which are related to GeoTIFF keys.
 
172
    // They must have an id of "LASF_Projection" and a record id that's related.
 
173
    std::vector<VariableRecord>::const_iterator it;
 
174
    for (it = vlrs.begin(); it != vlrs.end(); ++it)
 
175
    {
 
176
        VariableRecord const& vlr = *it;
 
177
        if (IsGeoVLR(vlr))
 
178
        {
 
179
            m_vlrs.push_back(vlr);
 
180
        }
 
181
    }
 
182
}
 
183
 
 
184
void SpatialReference::AddVLR(VariableRecord const& vlr) 
 
185
{
 
186
    if (IsGeoVLR(vlr))
 
187
    {
 
188
        m_vlrs.push_back(vlr);
 
189
    }
 
190
}
 
191
 
 
192
bool SpatialReference::IsGeoVLR(VariableRecord const& vlr) const
 
193
{
 
194
    std::string const las_projid("LASF_Projection");
 
195
    std::string const liblas_id("liblas");
 
196
    
 
197
    // GTIFF_GEOKEYDIRECTORY == 34735
 
198
    if (las_projid == vlr.GetUserId(true).c_str() && 34735 == vlr.GetRecordId())
 
199
    {
 
200
        return true;
 
201
    }
 
202
    
 
203
    // GTIFF_DOUBLEPARAMS == 34736
 
204
    if (las_projid == vlr.GetUserId(true).c_str() && 34736 == vlr.GetRecordId())
 
205
    {
 
206
        return true;
 
207
    }
 
208
    
 
209
    // GTIFF_ASCIIPARAMS == 34737
 
210
    if (las_projid == vlr.GetUserId(true).c_str() && 34737 == vlr.GetRecordId())
 
211
    {
 
212
        return true;
 
213
    }
 
214
 
 
215
    // OGR_WKT?
 
216
    if (liblas_id == vlr.GetUserId(true).c_str() && 2112 == vlr.GetRecordId())
 
217
    {
 
218
        return true;
 
219
    }
 
220
 
 
221
    return false;
 
222
}
 
223
 
 
224
std::vector<VariableRecord> SpatialReference::GetVLRs() const
 
225
{
 
226
    return m_vlrs;
 
227
}
 
228
 
 
229
void SpatialReference::ClearVLRs( GeoVLRType eType )
 
230
 
 
231
{
 
232
    std::vector<VariableRecord>::iterator it;
 
233
    std::string const liblas_id("liblas");
 
234
    
 
235
    for (it = m_vlrs.begin(); it != m_vlrs.end(); )
 
236
    {
 
237
        VariableRecord const& vlr = *it;
 
238
        bool wipe = false;
 
239
 
 
240
        // for now we can assume all m_vlrs records are LASF_Projection.
 
241
        if( eType == eOGRWKT && 
 
242
            2112 == vlr.GetRecordId() && 
 
243
            liblas_id == vlr.GetUserId(true).c_str() )
 
244
            wipe = true;
 
245
 
 
246
        else if( eType == eGeoTIFF 
 
247
                 && (34735 == vlr.GetRecordId()
 
248
                     || 34736 == vlr.GetRecordId()
 
249
                     || 34737 == vlr.GetRecordId()) )
 
250
            wipe = true;
 
251
 
 
252
        if( wipe )
 
253
            it = m_vlrs.erase( it );
 
254
        else
 
255
            ++it;
 
256
    }
 
257
 
 
258
    if( eType == eOGRWKT )
 
259
        m_wkt = "";
 
260
    else if( eType == eGeoTIFF )
 
261
    {
 
262
#ifdef HAVE_LIBGEOTIFF
 
263
        if (m_gtiff != 0)
 
264
        {
 
265
            GTIFFree(m_gtiff);
 
266
            m_gtiff = 0;
 
267
        }
 
268
        if (m_tiff != 0)
 
269
        {
 
270
            ST_Destroy(m_tiff);
 
271
            m_tiff = 0;
 
272
        }
 
273
#endif
 
274
    }
 
275
}
 
276
 
 
277
void SpatialReference::ResetVLRs()
 
278
{
 
279
 
 
280
    m_vlrs.clear();
 
281
 
 
282
#ifdef HAVE_LIBGEOTIFF
 
283
 
 
284
    int ret = 0;
 
285
    short* kdata = 0;
 
286
    short kvalue = 0;
 
287
    double* ddata = 0;
 
288
    double dvalue = 0;
 
289
    uint8_t* adata = 0;
 
290
    uint8_t avalue = 0;
 
291
    int dtype = 0;
 
292
    int dcount = 0;
 
293
    int ktype = 0;
 
294
    int kcount = 0;
 
295
    int acount = 0;
 
296
    int atype =0;
 
297
    
 
298
    if (!m_tiff)
 
299
        throw std::invalid_argument("m_tiff was null, cannot reset VLRs without m_tiff");
 
300
 
 
301
    if (!m_gtiff)
 
302
        throw std::invalid_argument("m_gtiff was null, cannot reset VLRs without m_gtiff");
 
303
 
 
304
    //GTIFF_GEOKEYDIRECTORY == 34735
 
305
    ret = ST_GetKey(m_tiff, 34735, &kcount, &ktype, (void**)&kdata);
 
306
    if (ret)
 
307
    {    
 
308
        VariableRecord record;
 
309
        int i = 0;
 
310
        record.SetRecordId(34735);
 
311
        record.SetUserId("LASF_Projection");
 
312
        record.SetDescription("GeoTIFF GeoKeyDirectoryTag");
 
313
        std::vector<uint8_t> data;
 
314
 
 
315
        // Shorts are 2 bytes in length
 
316
        uint16_t length = 2 * static_cast<uint16_t>(kcount);
 
317
        record.SetRecordLength(length);
 
318
        
 
319
        // Copy the data into the data vector
 
320
        for (i = 0; i < kcount; i++)
 
321
        {
 
322
            kvalue = kdata[i];
 
323
            
 
324
            uint8_t* v = reinterpret_cast<uint8_t*>(&kvalue); 
 
325
            
 
326
            data.push_back(v[0]);
 
327
            data.push_back(v[1]);
 
328
        }
 
329
 
 
330
        record.SetData(data);
 
331
        m_vlrs.push_back(record);
 
332
    }
 
333
 
 
334
    // GTIFF_DOUBLEPARAMS == 34736
 
335
    ret = ST_GetKey(m_tiff, 34736, &dcount, &dtype, (void**)&ddata);
 
336
    if (ret)
 
337
    {    
 
338
        VariableRecord record;
 
339
        int i = 0;
 
340
        record.SetRecordId(34736);
 
341
        record.SetUserId("LASF_Projection");
 
342
        record.SetDescription("GeoTIFF GeoDoubleParamsTag");
 
343
        
 
344
        std::vector<uint8_t> data;
 
345
 
 
346
        // Doubles are 8 bytes in length
 
347
        uint16_t length = 8 * static_cast<uint16_t>(dcount);
 
348
        record.SetRecordLength(length);
 
349
        
 
350
        // Copy the data into the data vector
 
351
        for (i=0; i<dcount;i++)
 
352
        {
 
353
            dvalue = ddata[i];
 
354
            
 
355
            uint8_t* v =  reinterpret_cast<uint8_t*>(&dvalue);
 
356
            
 
357
            data.push_back(v[0]);
 
358
            data.push_back(v[1]);
 
359
            data.push_back(v[2]);
 
360
            data.push_back(v[3]);
 
361
            data.push_back(v[4]);
 
362
            data.push_back(v[5]);
 
363
            data.push_back(v[6]);
 
364
            data.push_back(v[7]);   
 
365
        }        
 
366
        record.SetData(data);
 
367
        m_vlrs.push_back(record);
 
368
    }
 
369
    
 
370
    // GTIFF_ASCIIPARAMS == 34737
 
371
    ret = ST_GetKey(m_tiff, 34737, &acount, &atype, (void**)&adata);
 
372
    if (ret) 
 
373
    {                    
 
374
         VariableRecord record;
 
375
         int i = 0;
 
376
         record.SetRecordId(34737);
 
377
         record.SetUserId("LASF_Projection");
 
378
         record.SetDescription("GeoTIFF GeoAsciiParamsTag");         
 
379
         std::vector<uint8_t> data;
 
380
 
 
381
         // whoa.  If the returned count was 0, it is because there 
 
382
         // was a bug in libgeotiff that existed before r1531 where it 
 
383
         // didn't calculate the string length for an ASCII geotiff tag.
 
384
         // We need to throw an exception in this case because we're
 
385
         // screwed, and if we don't we'll end up writing bad GeoTIFF keys.
 
386
         if (!acount)
 
387
         {
 
388
             throw std::runtime_error("GeoTIFF ASCII key with no returned size. " 
 
389
                                      "Upgrade your libgeotiff to a version greater "
 
390
                                      "than r1531 (libgeotiff 1.2.6)");
 
391
         }
 
392
 
 
393
         uint16_t length = static_cast<uint16_t>(acount);
 
394
         record.SetRecordLength(length);
 
395
         
 
396
         // Copy the data into the data vector
 
397
         for (i=0; i<acount;i++)
 
398
         {
 
399
             avalue = adata[i];
 
400
             uint8_t* v =  reinterpret_cast<uint8_t*>(&avalue);
 
401
             data.push_back(v[0]);
 
402
         }
 
403
         record.SetData(data);
 
404
 
 
405
        if (data.size() > (std::numeric_limits<boost::uint16_t>::max()))
 
406
        {
 
407
            std::ostringstream oss;
 
408
            std::vector<uint8_t>::size_type overrun = data.size() - static_cast<std::vector<uint8_t>::size_type>(std::numeric_limits<boost::uint16_t>::max());
 
409
            oss << "The size of the GeoTIFF GeoAsciiParamsTag, " << data.size() << ", is " << overrun 
 
410
                << " bytes too large to fit inside the maximum size of a VLR which is " 
 
411
                << (std::numeric_limits<boost::uint16_t>::max()) << " bytes.";
 
412
            throw std::runtime_error(oss.str());
 
413
 
 
414
        }
 
415
 
 
416
         m_vlrs.push_back(record);
 
417
    }
 
418
#endif // ndef HAVE_LIBGEOTIFF
 
419
 
 
420
 
 
421
    if( m_wkt == "" )
 
422
        m_wkt = GetWKT( eCompoundOK );
 
423
 
 
424
    // Add a WKT VLR if we have a WKT definition.
 
425
    if( m_wkt != "" )
 
426
    {
 
427
        VariableRecord wkt_record;
 
428
        std::vector<uint8_t> data;
 
429
        const uint8_t* wkt_bytes = reinterpret_cast<const uint8_t*>(m_wkt.c_str());
 
430
 
 
431
        wkt_record.SetRecordId( 2112 );
 
432
        wkt_record.SetUserId("liblas");
 
433
        wkt_record.SetDescription( "OGR variant of OpenGIS WKT SRS" );
 
434
 
 
435
        // Would you be surprised if this remarshalling of bytes
 
436
        // was annoying to me? FrankW
 
437
        while( *wkt_bytes != 0 )
 
438
            data.push_back( *(wkt_bytes++) );
 
439
 
 
440
        data.push_back( '\0' );
 
441
 
 
442
        if (data.size() > std::numeric_limits<boost::uint16_t>::max())
 
443
        {
 
444
            std::ostringstream oss;
 
445
            std::vector<uint8_t>::size_type overrun = data.size() - static_cast<std::vector<uint8_t>::size_type>(std::numeric_limits<boost::uint16_t>::max());
 
446
            oss << "The size of the wkt, " << data.size() << ", is " << overrun 
 
447
                << " bytes too large to fit inside the maximum size of a VLR which is " 
 
448
                << std::numeric_limits<boost::uint16_t>::max() << " bytes.";
 
449
            throw std::runtime_error(oss.str());
 
450
 
 
451
        }
 
452
 
 
453
 
 
454
        wkt_record.SetRecordLength( static_cast<boost::uint16_t>(data.size()) );
 
455
        wkt_record.SetData(data);
 
456
 
 
457
        // not to speak of this additional copy!
 
458
        m_vlrs.push_back( wkt_record );
 
459
    }
 
460
}
 
461
 
 
462
void SpatialReference::SetGTIF(GTIF* pgtiff, ST_TIFF* ptiff) 
 
463
{
 
464
    m_gtiff = (GTIF*)pgtiff;
 
465
    m_tiff = (ST_TIFF*)ptiff;
 
466
    ResetVLRs();
 
467
    m_gtiff = 0;
 
468
    m_tiff = 0;
 
469
}
 
470
const GTIF* SpatialReference::GetGTIF()
 
471
{
 
472
#ifndef HAVE_LIBGEOTIFF
 
473
    return 0;
 
474
#else
 
475
 
 
476
    // If we already have m_gtiff and m_tiff, that is because we have 
 
477
    // already called GetGTIF once before.  VLRs ultimately drive how the 
 
478
    // SpatialReference is defined, not the GeoTIFF keys.  
 
479
    if (m_tiff != 0 )
 
480
    {
 
481
        ST_Destroy(m_tiff);
 
482
        m_tiff = 0;
 
483
    }
 
484
 
 
485
    if (m_gtiff != 0 )
 
486
    {
 
487
        GTIFFree(m_gtiff);
 
488
        m_gtiff = 0;
 
489
    }
 
490
    
 
491
    m_tiff = ST_Create();
 
492
    std::string const uid("LASF_Projection");
 
493
    
 
494
    // Nothing is going to happen here if we don't have any VLRs describing
 
495
    // SRS information on the SpatialReference.  
 
496
    for (uint16_t i = 0; i < m_vlrs.size(); ++i)
 
497
    {
 
498
        VariableRecord record = m_vlrs[i];
 
499
        std::vector<uint8_t> data = record.GetData();
 
500
        if (uid == record.GetUserId(true).c_str() && 34735 == record.GetRecordId())
 
501
        {
 
502
            int count = data.size()/sizeof(int16_t);
 
503
            short *data_s = (short *) &(data[0]);
 
504
 
 
505
            // discard invalid "zero" geotags some software emits.
 
506
            while( count > 4 
 
507
                   && data_s[count-1] == 0
 
508
                   && data_s[count-2] == 0
 
509
                   && data_s[count-3] == 0
 
510
                   && data_s[count-4] == 0 )
 
511
            {
 
512
                count -= 4;
 
513
                data_s[3] -= 1;
 
514
            }
 
515
 
 
516
            ST_SetKey(m_tiff, record.GetRecordId(), count, STT_SHORT, data_s);
 
517
        }
 
518
 
 
519
        if (uid == record.GetUserId(true).c_str() && 34736 == record.GetRecordId())
 
520
        {
 
521
            int count = data.size() / sizeof(double);
 
522
            ST_SetKey(m_tiff, record.GetRecordId(), count, STT_DOUBLE, &(data[0]));
 
523
        }        
 
524
 
 
525
        if (uid == record.GetUserId(true).c_str() && 34737 == record.GetRecordId())
 
526
        {
 
527
            int count = data.size()/sizeof(uint8_t);
 
528
            ST_SetKey(m_tiff, record.GetRecordId(), count, STT_ASCII, &(data[0]));
 
529
        }
 
530
    }
 
531
 
 
532
    m_gtiff = GTIFNewSimpleTags(m_tiff);
 
533
    if (!m_gtiff) 
 
534
        throw std::runtime_error("The geotiff keys could not be read from VLR records");
 
535
    
 
536
    return m_gtiff;
 
537
#endif
 
538
}
 
539
 
 
540
std::string SpatialReference::GetWKT( WKTModeFlag mode_flag) const 
 
541
{
 
542
    return GetWKT(mode_flag, false);
 
543
}
 
544
 
 
545
/// Fetch the SRS as WKT
 
546
std::string SpatialReference::GetWKT(WKTModeFlag mode_flag , bool pretty) const 
 
547
{
 
548
#ifndef HAVE_GDAL
 
549
    boost::ignore_unused_variable_warning(mode_flag);
 
550
    boost::ignore_unused_variable_warning(pretty);
 
551
 
 
552
    // we don't have a way of making this pretty, or of stripping the compound wrapper.
 
553
    return m_wkt;
 
554
#else
 
555
 
 
556
    // If we already have Well Known Text then try return it, possibly
 
557
    // after some preprocessing.
 
558
    if( m_wkt != "" )
 
559
    {
 
560
        std::string result_wkt = m_wkt;
 
561
        
 
562
        if( (mode_flag == eHorizontalOnly 
 
563
             && strstr(result_wkt.c_str(),"COMPD_CS") != NULL)
 
564
            || pretty )
 
565
        {
 
566
            OGRSpatialReference* poSRS = (OGRSpatialReference*) OSRNewSpatialReference(result_wkt.c_str());
 
567
            char *pszWKT = NULL;
 
568
 
 
569
            if( mode_flag == eHorizontalOnly )
 
570
                poSRS->StripVertical();
 
571
 
 
572
            if (pretty) 
 
573
                poSRS->exportToPrettyWkt(&pszWKT, FALSE );
 
574
            else
 
575
                poSRS->exportToWkt( &pszWKT );
 
576
            
 
577
            OSRDestroySpatialReference( poSRS );
 
578
 
 
579
            result_wkt = pszWKT;
 
580
            CPLFree( pszWKT );
 
581
        }
 
582
 
 
583
        return result_wkt;
 
584
    }
 
585
 
 
586
    // Otherwise build WKT from GeoTIFF VLRs. 
 
587
 
 
588
    GTIFDefn sGTIFDefn;
 
589
    char* pszWKT = 0;
 
590
    if (!m_gtiff)
 
591
    {
 
592
        return std::string();
 
593
    }
 
594
 
 
595
    if (GTIFGetDefn(m_gtiff, &sGTIFDefn))
 
596
    {
 
597
        pszWKT = GTIFGetOGISDefn( m_gtiff, &sGTIFDefn );
 
598
 
 
599
        if (pretty) {
 
600
            OGRSpatialReference* poSRS = (OGRSpatialReference*) OSRNewSpatialReference(NULL);
 
601
            char *pszOrigWKT = pszWKT;
 
602
            poSRS->importFromWkt( &pszOrigWKT );
 
603
            
 
604
            CPLFree( pszWKT );
 
605
            pszWKT = NULL;
 
606
            poSRS->exportToPrettyWkt(&pszWKT, false);
 
607
            OSRDestroySpatialReference( poSRS );
 
608
 
 
609
        }
 
610
 
 
611
        // save this for future calls, etc.
 
612
        // m_wkt = std::string( pszWKT );
 
613
 
 
614
        // Older versions of GDAL lack StripVertical(), but should never
 
615
        // actually return COMPD_CS anyways.
 
616
#if (GDAL_VERSION_NUM >= 1700) && (GDAL_RELEASE_DATE >= 20100110)
 
617
        if( pszWKT 
 
618
            && mode_flag == eHorizontalOnly 
 
619
            && strstr(pszWKT,"COMPD_CS") != NULL )
 
620
        {
 
621
            OGRSpatialReference* poSRS = (OGRSpatialReference*) OSRNewSpatialReference(NULL);
 
622
            char *pszOrigWKT = pszWKT;
 
623
            poSRS->importFromWkt( &pszOrigWKT );
 
624
 
 
625
            CPLFree( pszWKT );
 
626
            pszWKT = NULL;
 
627
 
 
628
            poSRS->StripVertical();
 
629
            if (pretty) 
 
630
                poSRS->exportToPrettyWkt(&pszWKT, false);
 
631
            else
 
632
                poSRS->exportToWkt( &pszWKT );
 
633
            
 
634
            OSRDestroySpatialReference( poSRS );
 
635
        }
 
636
#else
 
637
        boost::ignore_unused_variable_warning(mode_flag);
 
638
#endif
 
639
 
 
640
        if (pszWKT)
 
641
        {
 
642
            std::string tmp(pszWKT);
 
643
            CPLFree(pszWKT);
 
644
            return tmp;
 
645
        }
 
646
    }
 
647
    return std::string();
 
648
#endif
 
649
}
 
650
 
 
651
void SpatialReference::SetFromUserInput(std::string const& v)
 
652
{
 
653
#ifdef HAVE_GDAL
 
654
 
 
655
    char* poWKT = 0;
 
656
    const char* input = v.c_str();
 
657
    
 
658
    // OGRSpatialReference* poSRS = (OGRSpatialReference*) OSRNewSpatialReference(NULL);
 
659
    OGRSpatialReference srs(NULL);
 
660
    if (OGRERR_NONE != srs.SetFromUserInput(const_cast<char *> (input)))
 
661
    {
 
662
        throw std::invalid_argument("could not import coordinate system into OSRSpatialReference SetFromUserInput");
 
663
    }
 
664
    
 
665
    srs.exportToWkt(&poWKT);
 
666
    
 
667
    std::string tmp(poWKT);
 
668
    CPLFree(poWKT);
 
669
    
 
670
    SetWKT(tmp);
 
671
#else
 
672
    boost::ignore_unused_variable_warning(v);
 
673
    throw std::runtime_error("GDAL is not available, SpatialReference could not be set from WKT");
 
674
#endif
 
675
}
 
676
 
 
677
void SpatialReference::SetWKT(std::string const& v)
 
678
{
 
679
    m_wkt = v;
 
680
 
 
681
    if (!m_gtiff)
 
682
    {
 
683
        GetGTIF(); 
 
684
    }
 
685
 
 
686
#ifdef HAVE_GDAL
 
687
    int ret = 0;
 
688
    ret = GTIFSetFromOGISDefn( m_gtiff, v.c_str() );
 
689
    if (!ret) 
 
690
    {
 
691
        throw std::invalid_argument("could not set m_gtiff from WKT");
 
692
    }
 
693
 
 
694
    ret = GTIFWriteKeys(m_gtiff);
 
695
    if (!ret) 
 
696
    {
 
697
        throw std::runtime_error("The geotiff keys could not be written");
 
698
    }
 
699
#else
 
700
    boost::ignore_unused_variable_warning(v);
 
701
#endif
 
702
 
 
703
    ResetVLRs();
 
704
}
 
705
 
 
706
void SpatialReference::SetVerticalCS(boost::int32_t verticalCSType, 
 
707
                                     std::string const& citation,
 
708
                                     boost::int32_t verticalDatum,
 
709
                                     boost::int32_t verticalUnits)
 
710
{
 
711
    if (!m_gtiff)
 
712
    {
 
713
        GetGTIF(); 
 
714
    }
 
715
 
 
716
#ifdef HAVE_LIBGEOTIFF
 
717
    if( verticalCSType != KvUserDefined && verticalCSType > 0 )
 
718
        GTIFKeySet( m_gtiff, VerticalCSTypeGeoKey, TYPE_SHORT, 1,
 
719
                    verticalCSType );
 
720
 
 
721
    if( citation != "" )
 
722
        GTIFKeySet( m_gtiff, VerticalCitationGeoKey, TYPE_ASCII, 0, 
 
723
                    citation.c_str() );                        
 
724
 
 
725
    if( verticalDatum > 0 && verticalDatum != KvUserDefined )
 
726
        GTIFKeySet( m_gtiff, VerticalDatumGeoKey, TYPE_SHORT, 1,
 
727
                    verticalDatum );
 
728
        
 
729
    if( verticalUnits > 0 && verticalUnits != KvUserDefined )
 
730
        GTIFKeySet( m_gtiff, VerticalUnitsGeoKey, TYPE_SHORT, 1,
 
731
                    verticalUnits );
 
732
 
 
733
    int ret = GTIFWriteKeys(m_gtiff);
 
734
    if (!ret) 
 
735
    {
 
736
        throw std::runtime_error("The geotiff keys could not be written");
 
737
    }
 
738
 
 
739
    // Clear WKT so it gets regenerated 
 
740
    m_wkt = std::string("");
 
741
    
 
742
    ResetVLRs();
 
743
#else
 
744
    boost::ignore_unused_variable_warning(citation);
 
745
    boost::ignore_unused_variable_warning(verticalUnits);
 
746
    boost::ignore_unused_variable_warning(verticalDatum);
 
747
    boost::ignore_unused_variable_warning(verticalCSType);
 
748
#endif /* def HAVE_LIBGEOTIFF */
 
749
}
 
750
                                         
 
751
std::string SpatialReference::GetProj4() const 
 
752
{
 
753
#ifdef HAVE_GDAL
 
754
    
 
755
    std::string wkt = GetWKT(eCompoundOK);
 
756
    const char* poWKT = wkt.c_str();
 
757
    
 
758
    OGRSpatialReference srs(NULL);
 
759
    if (OGRERR_NONE != srs.importFromWkt(const_cast<char **> (&poWKT)))
 
760
    {
 
761
        return std::string();
 
762
    }
 
763
    
 
764
    char* proj4 = 0;
 
765
    srs.exportToProj4(&proj4);
 
766
    std::string tmp(proj4);
 
767
    CPLFree(proj4);
 
768
    
 
769
    return tmp;
 
770
#endif
 
771
 
 
772
// if we have libgeotiff but not GDAL, we'll use the 
 
773
// simple method in libgeotiff
 
774
#if defined(HAVE_LIBGEOTIFF) && !defined(HAVE_GDAL)
 
775
 
 
776
    GTIFDefn defn;
 
777
 
 
778
    if (m_gtiff && GTIFGetDefn(m_gtiff, &defn)) 
 
779
    {
 
780
        char* proj4def = GTIFGetProj4Defn(&defn);
 
781
        std::string tmp(proj4def);
 
782
        GTIFFreeMemory( proj4def );
 
783
        return tmp;
 
784
    }
 
785
#endif
 
786
 
 
787
#ifndef HAVE_GDAL
 
788
    // By default or if we have neither GDAL nor proj.4, we can't do squat
 
789
    return std::string();
 
790
#endif
 
791
}
 
792
 
 
793
void SpatialReference::SetProj4(std::string const& v)
 
794
{
 
795
    if (!m_gtiff)
 
796
    {
 
797
        GetGTIF();
 
798
        ResetVLRs();
 
799
    }
 
800
   
 
801
#ifdef HAVE_GDAL
 
802
    char* poWKT = 0;
 
803
    const char* poProj4 = v.c_str();
 
804
 
 
805
    OGRSpatialReference srs(NULL);
 
806
    if (OGRERR_NONE != srs.importFromProj4(const_cast<char *>(poProj4)))
 
807
    {
 
808
        throw std::invalid_argument("could not import proj4 into OSRSpatialReference SetProj4");
 
809
    }
 
810
    
 
811
    srs.exportToWkt(&poWKT);
 
812
    
 
813
    std::string tmp(poWKT);
 
814
    CPLFree(poWKT);
 
815
        
 
816
    int ret = 0;
 
817
    ret = GTIFSetFromOGISDefn( m_gtiff, tmp.c_str() );
 
818
    if (!ret)
 
819
    {
 
820
        throw std::invalid_argument("could not set m_gtiff from Proj4");
 
821
    }
 
822
 
 
823
    ret = GTIFWriteKeys(m_gtiff);
 
824
    if (!ret) 
 
825
    {
 
826
        throw std::runtime_error("The geotiff keys could not be written");
 
827
    }
 
828
 
 
829
    GTIFDefn defn;
 
830
 
 
831
    if (m_gtiff && GTIFGetDefn(m_gtiff, &defn)) 
 
832
    {
 
833
        char* proj4def = GTIFGetProj4Defn(&defn);
 
834
        std::string tmp(proj4def);
 
835
        GTIFFreeMemory( proj4def );
 
836
    }
 
837
#else
 
838
    boost::ignore_unused_variable_warning(v);
 
839
#endif
 
840
 
 
841
// if we have libgeotiff but not GDAL, we'll use the 
 
842
// simple method in libgeotiff
 
843
#if defined(HAVE_LIBGEOTIFF) && !defined(HAVE_GDAL)
 
844
 
 
845
    int ret = 0;
 
846
    ret = GTIFSetFromProj4( m_gtiff, v.c_str());
 
847
    if (!ret) 
 
848
    {
 
849
        throw std::invalid_argument("PROJ.4 string is invalid or unsupported");
 
850
    }
 
851
 
 
852
    ret = GTIFWriteKeys(m_gtiff);
 
853
    if (!ret) 
 
854
    {
 
855
        throw std::runtime_error("The geotiff keys could not be written");
 
856
    }    
 
857
#endif
 
858
 
 
859
    ResetVLRs();
 
860
}
 
861
 
 
862
liblas::property_tree::ptree SpatialReference::GetPTree( ) const
 
863
{
 
864
    using liblas::property_tree::ptree;
 
865
    ptree srs;
 
866
 
 
867
#if defined(HAVE_GDAL)
 
868
    srs.put("proj4", GetProj4());
 
869
    srs.put("prettywkt", GetWKT(liblas::SpatialReference::eHorizontalOnly, true));
 
870
    srs.put("wkt", GetWKT(liblas::SpatialReference::eHorizontalOnly, false));
 
871
    srs.put("compoundwkt", GetWKT(eCompoundOK, false));
 
872
    srs.put("prettycompoundwkt", GetWKT(eCompoundOK, true));
 
873
    srs.put("gtiff", GetGTIFFText());
 
874
#endif
 
875
 
 
876
#if defined(HAVE_LIBGEOTIFF) && !defined(HAVE_GDAL)
 
877
 
 
878
    std::string message("Reference defined, but GDAL is not available for WKT support");
 
879
    srs.put("proj4", GetProj4());
 
880
    srs.put("prettywkt", message);
 
881
    srs.put("wkt", message);
 
882
    srs.put("compoundwkt", message);
 
883
    srs.put("prettycompoundwkt", message);
 
884
    srs.put("gtiff", GetGTIFFText());
 
885
#endif
 
886
 
 
887
#if !defined(HAVE_LIBGEOTIFF) && !defined(HAVE_GDAL)
 
888
 
 
889
    std::string message;
 
890
    if (m_vlrs.size() > 0 && m_wkt.size() == 0)
 
891
    {
 
892
        message = "Reference defined with VLR keys, but GeoTIFF and GDAL support are not available to produce definition";
 
893
    } else if (m_wkt.size() > 0)
 
894
    {
 
895
        message = "Reference defined with WKT, but GeoTIFF and GDAL support are not available to produce definition";
 
896
    } else
 
897
    {
 
898
        message = "None";
 
899
    }
 
900
 
 
901
    srs.put("proj4", message);
 
902
    srs.put("prettywkt", message);
 
903
    srs.put("wkt", message);
 
904
    srs.put("compoundwkt", message);
 
905
    srs.put("prettycompoundwkt", message);
 
906
    srs.put("gtiff", message);
 
907
#endif
 
908
    
 
909
    return srs;
 
910
    
 
911
}
 
912
 
 
913
std::string SpatialReference::GetGTIFFText() const
 
914
{
 
915
#ifndef HAVE_LIBGEOTIFF
 
916
    return std::string("");
 
917
#else
 
918
 
 
919
    if( m_gtiff == NULL )
 
920
        return std::string("");
 
921
 
 
922
    detail::geotiff_dir_printer geotiff_printer;
 
923
    GTIFPrint(m_gtiff, detail::libLASGeoTIFFPrint, &geotiff_printer);
 
924
    return geotiff_printer.output();
 
925
#endif
 
926
}
 
927
 
 
928
 
 
929
} // namespace liblas
 
930
 
 
931
std::ostream& operator<<(std::ostream& ostr, const liblas::SpatialReference& srs)
 
932
{
 
933
 
 
934
#ifdef HAVE_GDAL 
 
935
    liblas::property_tree::ptree tree;
 
936
    std::string name ("spatialreference");
 
937
    tree.put_child(name, srs.GetPTree());
 
938
    liblas::property_tree::write_xml(ostr, tree);
 
939
    return ostr;
 
940
 
 
941
#else
 
942
    boost::ignore_unused_variable_warning(ostr);
 
943
    boost::ignore_unused_variable_warning(srs);
 
944
    throw std::runtime_error("SpatialReference io operator<< is not available without GDAL+libgeotiff support");
 
945
#endif
 
946
}