1
2 ///////////////////////////////////////////////////////////
3 // //
4 // SAGA //
5 // //
6 // System for Automated Geoscientific Analyses //
7 // //
8 // Application Programming Interface //
9 // //
10 // Library: SAGA_API //
11 // //
12 //-------------------------------------------------------//
13 // //
14 // shapes_io.cpp //
15 // //
16 // Copyright (C) 2005 by Olaf Conrad //
17 // //
18 //-------------------------------------------------------//
19 // //
20 // This file is part of 'SAGA - System for Automated //
21 // Geoscientific Analyses'. //
22 // //
23 // This library is free software; you can redistribute //
24 // it and/or modify it under the terms of the GNU Lesser //
25 // General Public License as published by the Free //
26 // Software Foundation, either version 2.1 of the //
27 // License, or (at your option) any later version. //
28 // //
29 // This library is distributed in the hope that it will //
30 // be useful, but WITHOUT ANY WARRANTY; without even the //
31 // implied warranty of MERCHANTABILITY or FITNESS FOR A //
32 // PARTICULAR PURPOSE. See the GNU Lesser General Public //
33 // License for more details. //
34 // //
35 // You should have received a copy of the GNU Lesser //
36 // General Public License along with this program; if //
37 // not, see <http://www.gnu.org/licenses/>. //
38 // //
39 //-------------------------------------------------------//
40 // //
41 // contact: Olaf Conrad //
42 // Institute of Geography //
43 // University of Goettingen //
44 // Goldschmidtstr. 5 //
45 // 37077 Goettingen //
46 // Germany //
47 // //
48 // e-mail: oconrad@saga-gis.org //
49 // //
50 ///////////////////////////////////////////////////////////
51
52 //---------------------------------------------------------
53 #include "shapes.h"
54 #include "table_dbase.h"
55 #include "tool_library.h"
56 #include "data_manager.h"
57
58
59 ///////////////////////////////////////////////////////////
60 // //
61 // //
62 // //
63 ///////////////////////////////////////////////////////////
64
65 //---------------------------------------------------------
On_Reload(void)66 bool CSG_Shapes::On_Reload(void)
67 {
68 return( Create(Get_File_Name(false)) );
69 }
70
71 //---------------------------------------------------------
On_Delete(void)72 bool CSG_Shapes::On_Delete(void)
73 {
74 CSG_String File_Name = Get_File_Name(true);
75
76 SG_File_Delete(File_Name);
77
78 SG_File_Set_Extension(File_Name, "shp"); SG_File_Delete(File_Name); // shapes
79 SG_File_Set_Extension(File_Name, "shx"); SG_File_Delete(File_Name); // shape index
80 SG_File_Set_Extension(File_Name, "dbf"); SG_File_Delete(File_Name); // attributes
81 SG_File_Set_Extension(File_Name, "prj"); SG_File_Delete(File_Name); // projection
82 SG_File_Set_Extension(File_Name, "sbn"); SG_File_Delete(File_Name); // spatial index
83 SG_File_Set_Extension(File_Name, "sbx"); SG_File_Delete(File_Name); // spatial index
84 SG_File_Set_Extension(File_Name, "atx"); SG_File_Delete(File_Name); // attribute index
85 SG_File_Set_Extension(File_Name, "xml"); SG_File_Delete(File_Name); // metadata
86 SG_File_Set_Extension(File_Name, "cpg"); SG_File_Delete(File_Name); // code page
87 SG_File_Set_Extension(File_Name, "qix"); SG_File_Delete(File_Name); // quadtree spatial index
88
89 return( true );
90 }
91
92
93 ///////////////////////////////////////////////////////////
94 // //
95 // //
96 // //
97 ///////////////////////////////////////////////////////////
98
99 //---------------------------------------------------------
_Load_GDAL(const CSG_String & File_Name)100 bool CSG_Shapes::_Load_GDAL(const CSG_String &File_Name)
101 {
102 CSG_Data_Manager Data;
103
104 CSG_Tool *pTool = SG_Get_Tool_Library_Manager().Create_Tool("io_gdal", 3); // Import Shapes
105
106 if( pTool )
107 {
108 if( pTool->Settings_Push(&Data) && pTool->Set_Parameter("FILES", File_Name, PARAMETER_TYPE_FilePath) )
109 {
110 SG_UI_Msg_Lock(true);
111 pTool->Execute();
112 SG_UI_Msg_Lock(false);
113 }
114
115 SG_Get_Tool_Library_Manager().Delete_Tool(pTool);
116 }
117
118 //-----------------------------------------------------
119 CSG_Shapes *pShapes = Data.Get_Shapes()->Count() ? Data.Get_Shapes()->Get(0)->asShapes() : NULL;
120
121 if( !pShapes || !Create(*pShapes) )
122 {
123 return( false );
124 }
125
126 Get_MetaData () = pShapes->Get_MetaData ();
127 Get_Projection() = pShapes->Get_Projection();
128
129 //-----------------------------------------------------
130 if( SG_File_Cmp_Extension(File_Name, "gpkg" )
131 || SG_File_Cmp_Extension(File_Name, "GeoJSON") )
132 {
133 Set_File_Name(File_Name, true);
134 }
135 else
136 {
137 Set_File_Name(File_Name, false);
138 }
139
140 return( true );
141 }
142
143 //---------------------------------------------------------
_Save_GDAL(const CSG_String & File_Name,const CSG_String & Driver)144 bool CSG_Shapes::_Save_GDAL(const CSG_String &File_Name, const CSG_String &Driver)
145 {
146 bool bResult;
147
148 SG_RUN_TOOL(bResult, "io_gdal", 4, // Export Shapes
149 SG_TOOL_PARAMETER_SET("SHAPES", this)
150 && SG_TOOL_PARAMETER_SET("FORMAT", Driver)
151 && SG_TOOL_PARAMETER_SET("FILE" , File_Name)
152 );
153
154 return( bResult );
155 }
156
157
158 ///////////////////////////////////////////////////////////
159 // //
160 // //
161 // //
162 ///////////////////////////////////////////////////////////
163
164 //---------------------------------------------------------
_Load_ESRI(const CSG_String & File_Name)165 bool CSG_Shapes::_Load_ESRI(const CSG_String &File_Name)
166 {
167 int Type, iField, iPart, nParts, *Parts, iPoint, nPoints, iOffset;
168 double *pZ = NULL, *pM = NULL;
169 TSG_Point *pPoint;
170 CSG_Buffer File_Header(100), Record_Header(8), Content;
171 CSG_File fSHP;
172
173 //-----------------------------------------------------
174 // Open DBase File...
175
176 m_Encoding = SG_FILE_ENCODING_ANSI;
177
178 if( fSHP.Open(SG_File_Make_Path("", File_Name, "cpg")) )
179 {
180 CSG_String sLine;
181
182 if( fSHP.Read_Line(sLine) && sLine.Find("UTF-8") >= 0 )
183 {
184 m_Encoding = SG_FILE_ENCODING_UTF8;
185 }
186
187 fSHP.Close();
188 }
189
190 CSG_Table_DBase fDBF(m_Encoding);
191
192 if( !fDBF.Open_Read(SG_File_Make_Path("", File_Name, "dbf"), this, false) )
193 {
194 SG_UI_Msg_Add_Error(_TL("DBase file could not be opened."));
195
196 return( false );
197 }
198
199 fDBF.Move_First();
200
201 if( fDBF.Get_Field_Count() < 1 )
202 {
203 SG_UI_Msg_Add_Error(_TL("DBase file does not contain any attribute fields."));
204
205 return( false );
206 }
207
208 //-----------------------------------------------------
209 // Open Shapes File...
210
211 if( !fSHP.Open(SG_File_Make_Path("", File_Name, "shp"), SG_FILE_R, true) )
212 {
213 SG_UI_Msg_Add_Error(_TL("Shape file could not be opened."));
214
215 return( false );
216 }
217
218 //-----------------------------------------------------
219 // Read File Header (100 Bytes)...
220
221 if( fSHP.Read(File_Header.Get_Data(), sizeof(char), 100) != 100 )
222 {
223 SG_UI_Msg_Add_Error(_TL("corrupted file header"));
224
225 return( false );
226 }
227
228 if( File_Header.asInt( 0, true) != 9994 ) // Byte 00 -> File Code 9994 (Integer Big)...
229 {
230 SG_UI_Msg_Add_Error(_TL("invalid file code"));
231
232 return( false );
233 }
234
235 if( File_Header.asInt(28, false) != 1000 ) // Byte 28 -> Version 1000 (Integer Little)...
236 {
237 SG_UI_Msg_Add_Error(_TL("unsupported file version"));
238
239 return( false );
240 }
241
242 switch( Type = File_Header.asInt(32) ) // Byte 32 -> Shape Type (Integer Little)...
243 {
244 case 1: m_Type = SHAPE_TYPE_Point; m_Vertex_Type = SG_VERTEX_TYPE_XY; break; // Point
245 case 8: m_Type = SHAPE_TYPE_Points; m_Vertex_Type = SG_VERTEX_TYPE_XY; break; // MultiPoint
246 case 3: m_Type = SHAPE_TYPE_Line; m_Vertex_Type = SG_VERTEX_TYPE_XY; break; // PolyLine
247 case 5: m_Type = SHAPE_TYPE_Polygon; m_Vertex_Type = SG_VERTEX_TYPE_XY; break; // Polygon
248
249 case 11: m_Type = SHAPE_TYPE_Point; m_Vertex_Type = SG_VERTEX_TYPE_XYZM; break; // PointZ
250 case 18: m_Type = SHAPE_TYPE_Points; m_Vertex_Type = SG_VERTEX_TYPE_XYZM; break; // MultiPointZ
251 case 13: m_Type = SHAPE_TYPE_Line; m_Vertex_Type = SG_VERTEX_TYPE_XYZM; break; // PolyLineZ
252 case 15: m_Type = SHAPE_TYPE_Polygon; m_Vertex_Type = SG_VERTEX_TYPE_XYZM; break; // PolygonZ
253
254 case 21: m_Type = SHAPE_TYPE_Point; m_Vertex_Type = SG_VERTEX_TYPE_XYZ; break; // PointM
255 case 28: m_Type = SHAPE_TYPE_Points; m_Vertex_Type = SG_VERTEX_TYPE_XYZ; break; // MultiPointM
256 case 23: m_Type = SHAPE_TYPE_Line; m_Vertex_Type = SG_VERTEX_TYPE_XYZ; break; // PolyLineM
257 case 25: m_Type = SHAPE_TYPE_Polygon; m_Vertex_Type = SG_VERTEX_TYPE_XYZ; break; // PolygonM
258
259 default: // unsupported...
260 case 31: // unsupported: MultiPatch...
261 SG_UI_Msg_Add_Error(_TL("unsupported shape type."));
262
263 return( false );
264 }
265
266 //-----------------------------------------------------
267 // Load Shapes...
268
269 for(int iShape=0; iShape<fDBF.Get_Record_Count() && SG_UI_Process_Set_Progress(iShape, fDBF.Get_Record_Count()); iShape++)
270 {
271 if( fSHP.Read(Record_Header.Get_Data(0), sizeof(int), 2) != 2 ) // read record header
272 {
273 SG_UI_Msg_Add_Error(_TL("corrupted record header"));
274
275 return( false );
276 }
277
278 if( Record_Header.asInt(0, true) != iShape + 1 ) // record number
279 {
280 SG_UI_Msg_Add_Error(CSG_String::Format("%s (%d != %d)", _TL("corrupted shapefile."), Record_Header.asInt(0, true), iShape + 1));
281
282 return( false );
283 }
284
285 size_t Length = 2 * Record_Header.asInt(4, true); // content length as 16-bit words !!!
286
287 if( !Content.Set_Size(Length, false) )
288 {
289 SG_UI_Msg_Add_Error(_TL("memory allocation error."));
290
291 return( false );
292 }
293
294 if( fSHP.Read(Content.Get_Data(), sizeof(char), Length) != Length )
295 {
296 SG_UI_Msg_Add_Error(_TL("corrupted shapefile."));
297
298 return( false );
299 }
300
301 if( fDBF.isDeleted() )
302 {
303 continue; // nop
304 }
305
306 if( Content.asInt(0) != Type )
307 {
308 if( Content.asInt(0) == 0 )
309 {
310 // null shape is allowed !!!
311 }
312 else
313 {
314 SG_UI_Msg_Add_Error(_TL("corrupted shapefile."));
315
316 return( false );
317 }
318 }
319
320 //-------------------------------------------------
321 else
322 {
323 CSG_Shape *pShape = Add_Shape();
324
325 switch( m_Type )
326 {
327 default: break;
328
329 //---------------------------------------------
330 case SHAPE_TYPE_Point: ////////////////////////
331
332 pPoint = (TSG_Point *)Content.Get_Data(4);
333
334 pShape->Add_Point(pPoint->x, pPoint->y);
335
336 switch( m_Vertex_Type ) // read Z + M
337 {
338 default: break;
339 case SG_VERTEX_TYPE_XYZM: pShape->Set_M(Content.asDouble(28), 0);
340 case SG_VERTEX_TYPE_XYZ : pShape->Set_Z(Content.asDouble(20), 0);
341 }
342
343 break;
344
345 //---------------------------------------------
346 case SHAPE_TYPE_Points: ///////////////////////
347
348 nPoints = Content.asInt(36);
349 pPoint = (TSG_Point *)Content.Get_Data(40);
350
351 switch( m_Vertex_Type ) // read Z + M
352 {
353 default:
354 break;
355
356 case SG_VERTEX_TYPE_XYZ:
357 pZ = 56 + nPoints * 24 <= (int)Length ? (double *)Content.Get_Data(56 + nPoints * 16) : NULL; // [40 + nPoints * 16 + 2 * 8] + [nPoints * 8]
358 break;
359
360 case SG_VERTEX_TYPE_XYZM:
361 pZ = 56 + nPoints * 24 <= (int)Length ? (double *)Content.Get_Data(56 + nPoints * 16) : NULL; // [40 + nPoints * 16 + 2 * 8] + [nPoints * 8]
362 pM = 72 + nPoints * 32 <= (int)Length ? (double *)Content.Get_Data(72 + nPoints * 24) : NULL; // [40 + nPoints * 16 + 2 * 8] + [nPoints * 8 + 2 * 8] + [nPoints * 8]
363 break;
364 }
365
366 //-----------------------------------------
367 for(iPoint=0; iPoint<nPoints; iPoint++, pPoint++)
368 {
369 pShape->Add_Point(pPoint->x, pPoint->y);
370
371 if( pZ ) { pShape->Set_Z(*(pZ++), iPoint); }
372 if( pM ) { pShape->Set_M(*(pM++), iPoint); }
373 }
374
375 break;
376
377 //---------------------------------------------
378 case SHAPE_TYPE_Line : //////////////////////
379 case SHAPE_TYPE_Polygon: //////////////////////
380
381 nParts = Content.asInt(36);
382 nPoints = Content.asInt(40);
383 Parts = (int *)Content.Get_Data(44);
384 pPoint = (TSG_Point *)Content.Get_Data(44 + 4 * nParts);
385
386 switch( m_Vertex_Type ) // read Z + M
387 {
388 default:
389 break;
390
391 case SG_VERTEX_TYPE_XYZ:
392 pZ = 60 + nParts * 4 + nPoints * 24 <= (int)Length ? (double *)Content.Get_Data(60 + nParts * 4 + nPoints * 16) : NULL; // [44 + nParts * 4 + nPoints * 16 + 2 * 8] + [nPoints * 8]
393 break;
394
395 case SG_VERTEX_TYPE_XYZM:
396 pZ = 60 + nParts * 4 + nPoints * 24 <= (int)Length ? (double *)Content.Get_Data(60 + nParts * 4 + nPoints * 16) : NULL; // [44 + nParts * 4 + nPoints * 16 + 2 * 8] + [nPoints * 8]
397 pM = 76 + nParts * 4 + nPoints * 32 <= (int)Length ? (double *)Content.Get_Data(76 + nParts * 4 + nPoints * 24) : NULL; // [44 + nParts * 4 + nPoints * 16 + 2 * 8] + [nPoints * 8 + 2 * 8] + [nPoints * 8]
398 break;
399 }
400
401 //-----------------------------------------
402 iOffset = 0;
403
404 for(iPoint=0, iPart=0; iPoint<nPoints; iPoint++, pPoint++)
405 {
406 if( iPart < nParts - 1 && iPoint >= Parts[iPart + 1] )
407 {
408 iPart++;
409 iOffset = 0;
410 }
411
412 pShape->Add_Point(pPoint->x, pPoint->y, iPart);
413
414 if( pZ ) { pShape->Set_Z(*(pZ++), iOffset, iPart); }
415 if( pM ) { pShape->Set_M(*(pM++), iOffset, iPart); }
416
417 iOffset++;
418 }
419
420 break;
421 }
422
423 //---------------------------------------------
424 for(iField=0; iField<Get_Field_Count(); iField++)
425 {
426 switch( fDBF.Get_Field_Type(iField) )
427 {
428 default:
429 pShape->Set_Value(iField, fDBF.asString(iField));
430 break;
431
432 case DBF_FT_FLOAT:
433 case DBF_FT_NUMERIC:
434 {
435 double Value;
436
437 if( fDBF.asDouble(iField, Value) )
438 {
439 pShape->Set_Value(iField, Value);
440 }
441 else
442 {
443 pShape->Set_NoData(iField);
444 }
445 }
446 break;
447 }
448 }
449 }
450
451 fDBF.Move_Next();
452 }
453
454 //-----------------------------------------------------
455 Get_Projection().Load(SG_File_Make_Path("", File_Name, "prj"), SG_PROJ_FMT_WKT);
456
457 //-----------------------------------------------------
458 Load_MetaData(File_Name);
459
460 CSG_MetaData *pFields = Get_MetaData_DB().Get_Child("FIELDS");
461
462 if( pFields && pFields->Get_Children_Count() == Get_Field_Count() )
463 {
464 for(iField=0; iField<Get_Field_Count(); iField++)
465 {
466 Set_Field_Name(iField, pFields->Get_Content(iField));
467 }
468 }
469
470 Set_File_Name(File_Name, true);
471
472 //-----------------------------------------------------
473 return( true );
474 }
475
476
477 ///////////////////////////////////////////////////////////
478 // //
479 // //
480 // //
481 ///////////////////////////////////////////////////////////
482
483 //---------------------------------------------------------
484 #define Set_Content_Length(n) Record_Header.Set_Value(4, (int)(n), true);\
485 fSHP.Write(Record_Header.Get_Data(), sizeof(int), 2);\
486 fSHX.Write_Int(fSHP_Size, true);\
487 fSHX.Write_Int((n) , true);\
488 fSHP_Size += 4 + (n);\
489 fSHX_Size += 4;
490
491 //---------------------------------------------------------
_Save_ESRI(const CSG_String & File_Name)492 bool CSG_Shapes::_Save_ESRI(const CSG_String &File_Name)
493 {
494 int Type, fSHP_Size, fSHX_Size, iField, iPart, iPoint, nPoints;
495 TSG_Point Point;
496 CSG_Buffer File_Header(100), Record_Header(8), Content;
497 CSG_File fSHP, fSHX;
498
499 //-----------------------------------------------------
500 // Determine Shape Type...
501
502 switch( m_Type )
503 {
504 case SHAPE_TYPE_Point : Type = 1; break;
505 case SHAPE_TYPE_Points : Type = 8; break;
506 case SHAPE_TYPE_Line : Type = 3; break;
507 case SHAPE_TYPE_Polygon : Type = 5; break;
508 default: return( false );
509 }
510
511 TSG_Vertex_Type Vertex_Type = m_Vertex_Type == 0 ? SG_VERTEX_TYPE_XY : SG_VERTEX_TYPE_XYZM;
512
513 switch( Vertex_Type )
514 {
515 case SG_VERTEX_TYPE_XY : break;
516 case SG_VERTEX_TYPE_XYZ : Type += 20; break; // M
517 case SG_VERTEX_TYPE_XYZM: Type += 10; break; // Z (+M)
518 default: return( false );
519 }
520
521 //-----------------------------------------------------
522 // DBase File Access...
523
524 SG_File_Delete(SG_File_Make_Path("", File_Name, "cpg"));
525
526 if( m_Encoding == SG_FILE_ENCODING_UTF8 )
527 {
528 if( fSHP.Open(SG_File_Make_Path("", File_Name, "cpg"), SG_FILE_W, false) )
529 {
530 fSHP.Printf("UTF-8\n");
531
532 fSHP.Close();
533 }
534 }
535
536 CSG_Table_DBase fDBF(m_Encoding);
537
538 if( !fDBF.Open_Write(SG_File_Make_Path("", File_Name, "dbf"), this, false) )
539 {
540 return( false );
541 }
542
543 //-----------------------------------------------------
544 // Shape File Access...
545
546 if( !fSHX.Open(SG_File_Make_Path("", File_Name, "shx"), SG_FILE_W, true) )
547 {
548 SG_UI_Msg_Add_Error(_TL("index file could not be opened"));
549
550 return( false );
551 }
552
553 if( !fSHP.Open(SG_File_Make_Path("", File_Name, "shp"), SG_FILE_W, true) )
554 {
555 SG_UI_Msg_Add_Error(_TL("shape file could not be opened."));
556
557 return( false );
558 }
559
560 //-----------------------------------------------------
561 // Save Header...
562
563 Make_Clean(); // polygons: first == last point, inner rings > anti-clockwise...
564
565 Update();
566
567 File_Header.Set_Value( 0, 9994 , true ); // Byte 0 Integer Big File Code = 9994
568 File_Header.Set_Value( 4, 0 , true ); // Byte 4 Integer Big unused
569 File_Header.Set_Value( 8, 0 , true ); // Byte 8 Integer Big unused
570 File_Header.Set_Value(12, 0 , true ); // Byte 12 Integer Big unused
571 File_Header.Set_Value(16, 0 , true ); // Byte 16 Integer Big unused
572 File_Header.Set_Value(20, 0 , true ); // Byte 20 Integer Big unused
573 File_Header.Set_Value(24, 0 , true ); // Byte 24 Integer Big File Length
574 File_Header.Set_Value(28, 1000 , false); // Byte 28 Integer Little Version = 1000
575 File_Header.Set_Value(32, Type , false); // Byte 32 Integer Little Shape Type
576 File_Header.Set_Value(36, m_Extent.Get_XMin() , false); // Byte 36 Double Little Bounding Box Xmin
577 File_Header.Set_Value(44, m_Extent.Get_YMin() , false); // Byte 44 Double Little Bounding Box Ymin
578 File_Header.Set_Value(52, m_Extent.Get_XMax() , false); // Byte 52 Double Little Bounding Box Xmax
579 File_Header.Set_Value(60, m_Extent.Get_YMax() , false); // Byte 60 Double Little Bounding Box Ymax
580 File_Header.Set_Value(68, Get_ZMin() , false); // Byte 68 Double Little Bounding Box Zmin
581 File_Header.Set_Value(76, Get_ZMax() , false); // Byte 76 Double Little Bounding Box Zmax
582 File_Header.Set_Value(84, Get_MMin() , false); // Byte 84 Double Little Bounding Box Mmin
583 File_Header.Set_Value(92, Get_MMax() , false); // Byte 92 Double Little Bounding Box Mmax
584
585 fSHP.Write(File_Header.Get_Data(), sizeof(char), 100);
586 fSHX.Write(File_Header.Get_Data(), sizeof(char), 100);
587
588 fSHP_Size = 50; // file size measured in 16-bit words...
589 fSHX_Size = 50; // file size measured in 16-bit words...
590
591 //-----------------------------------------------------
592 // Save Shapes...
593
594 for(int iShape=0; iShape<Get_Count() && SG_UI_Process_Set_Progress(iShape, Get_Count()); iShape++)
595 {
596 CSG_Shape *pShape = Get_Shape(iShape);
597
598 //-------------------------------------------------
599 // geometries...
600
601 Record_Header.Set_Value(0, iShape + 1, true); // record number
602
603 for(iPart=0, nPoints=0; iPart<pShape->Get_Part_Count(); iPart++)
604 {
605 nPoints += pShape->Get_Point_Count(iPart); // total number of points in shape
606 }
607
608 //-------------------------------------------------
609 switch( m_Type ) // write content header
610 {
611 default: break;
612
613 //-------------------------------------------------
614 case SHAPE_TYPE_Point: ///////////////////////
615
616 switch( Vertex_Type )
617 {
618 case SG_VERTEX_TYPE_XY: Set_Content_Length(10); break;
619 case SG_VERTEX_TYPE_XYZ: Set_Content_Length(14); break;
620 case SG_VERTEX_TYPE_XYZM: Set_Content_Length(18); break;
621 }
622
623 fSHP.Write_Int (Type);
624
625 break;
626
627 //-------------------------------------------------
628 case SHAPE_TYPE_Points: ///////////////////////
629
630 switch( Vertex_Type )
631 {
632 case SG_VERTEX_TYPE_XY: Set_Content_Length(20 + 8 * nPoints); break;
633 case SG_VERTEX_TYPE_XYZ: Set_Content_Length(28 + 12 * nPoints); break;
634 case SG_VERTEX_TYPE_XYZM: Set_Content_Length(36 + 16 * nPoints); break;
635 }
636
637 fSHP.Write_Int (Type);
638 fSHP.Write_Double (pShape->Get_Extent().Get_XMin());
639 fSHP.Write_Double (pShape->Get_Extent().Get_YMin());
640 fSHP.Write_Double (pShape->Get_Extent().Get_XMax());
641 fSHP.Write_Double (pShape->Get_Extent().Get_YMax());
642 fSHP.Write_Int (nPoints);
643
644 break;
645
646 //-------------------------------------------------
647 case SHAPE_TYPE_Line: ///////////////////////
648 case SHAPE_TYPE_Polygon: ///////////////////////
649
650 switch( Vertex_Type )
651 {
652 case SG_VERTEX_TYPE_XY: Set_Content_Length(22 + 2 * pShape->Get_Part_Count() + 8 * nPoints); break;
653 case SG_VERTEX_TYPE_XYZ: Set_Content_Length(30 + 2 * pShape->Get_Part_Count() + 12 * nPoints); break;
654 case SG_VERTEX_TYPE_XYZM: Set_Content_Length(38 + 2 * pShape->Get_Part_Count() + 16 * nPoints); break;
655 }
656
657 fSHP.Write_Int (Type);
658 fSHP.Write_Double (pShape->Get_Extent().Get_XMin());
659 fSHP.Write_Double (pShape->Get_Extent().Get_YMin());
660 fSHP.Write_Double (pShape->Get_Extent().Get_XMax());
661 fSHP.Write_Double (pShape->Get_Extent().Get_YMax());
662 fSHP.Write_Int (pShape->Get_Part_Count());
663 fSHP.Write_Int (nPoints);
664
665 for(iPart=0, iPoint=0; iPart<pShape->Get_Part_Count(); iPoint+=pShape->Get_Point_Count(iPart++))
666 {
667 fSHP.Write_Int(iPoint);
668 }
669
670 break;
671 }
672
673 //-------------------------------------------------
674 switch( m_Type ) // write point data
675 {
676 default: break;
677
678 //-------------------------------------------------
679 case SHAPE_TYPE_Point: ///////////////////////
680
681 fSHP.Write(&(Point = pShape->Get_Point(0)), sizeof(TSG_Point));
682
683 //---------------------------------------------
684 if( Vertex_Type != SG_VERTEX_TYPE_XY )
685 {
686 fSHP.Write_Double(pShape->Get_Z(0));
687
688 if( Vertex_Type == SG_VERTEX_TYPE_XYZM )
689 {
690 fSHP.Write_Double(pShape->Get_M(0));
691 }
692 }
693
694 break;
695
696 //-------------------------------------------------
697 case SHAPE_TYPE_Points: ///////////////////////
698 case SHAPE_TYPE_Line: ///////////////////////
699 case SHAPE_TYPE_Polygon: ///////////////////////
700
701 for(iPart=0; iPart<pShape->Get_Part_Count(); iPart++)
702 {
703 for(iPoint=0; iPoint<pShape->Get_Point_Count(iPart); iPoint++)
704 {
705 fSHP.Write(&(Point = pShape->Get_Point(iPoint, iPart)), sizeof(TSG_Point));
706 }
707 }
708
709 //---------------------------------------------
710 if( Vertex_Type != SG_VERTEX_TYPE_XY )
711 {
712 fSHP.Write_Double(pShape->Get_ZMin());
713 fSHP.Write_Double(pShape->Get_ZMax());
714
715 for(iPart=0; iPart<pShape->Get_Part_Count(); iPart++)
716 {
717 for(iPoint=0; iPoint<pShape->Get_Point_Count(iPart); iPoint++)
718 {
719 fSHP.Write_Double(pShape->Get_Z(iPoint, iPart));
720 }
721 }
722
723 if( Vertex_Type == SG_VERTEX_TYPE_XYZM )
724 {
725 fSHP.Write_Double(pShape->Get_MMin());
726 fSHP.Write_Double(pShape->Get_MMax());
727
728 for(iPart=0; iPart<pShape->Get_Part_Count(); iPart++)
729 {
730 for(iPoint=0; iPoint<pShape->Get_Point_Count(iPart); iPoint++)
731 {
732 fSHP.Write_Double(pShape->Get_M(iPoint, iPart));
733 }
734 }
735 }
736 }
737 }
738
739 //-------------------------------------------------
740 // attributes...
741
742 fDBF.Add_Record();
743
744 for(iField=0; iField<Get_Field_Count(); iField++)
745 {
746 if( pShape->is_NoData(iField) )
747 {
748 fDBF.Set_NoData(iField);
749 }
750 else switch( fDBF.Get_Field_Type(iField) )
751 {
752 default:
753 fDBF.Set_Value(iField, pShape->asString(iField));
754 break;
755
756 case DBF_FT_FLOAT:
757 case DBF_FT_NUMERIC:
758 fDBF.Set_Value(iField, pShape->asDouble(iField));
759 break;
760 }
761 }
762
763 fDBF.Flush_Record();
764 }
765
766 //-----------------------------------------------------
767 // File Sizes...
768
769 fSHP.Seek(24);
770 fSHP.Write_Int(fSHP_Size, true);
771
772 fSHX.Seek(24);
773 fSHX.Write_Int(fSHX_Size, true);
774
775 //-----------------------------------------------------
776 Get_Projection().Save(SG_File_Make_Path("", File_Name, "prj"), SG_PROJ_FMT_WKT);
777
778 //-----------------------------------------------------
779 CSG_MetaData *pFields = Get_MetaData_DB().Get_Child("FIELDS");
780
781 if( !pFields )
782 {
783 pFields = Get_MetaData_DB().Add_Child("FIELDS");
784 }
785
786 pFields->Del_Children();
787
788 for(iField=0; iField<Get_Field_Count(); iField++)
789 {
790 pFields->Add_Child("FIELD", Get_Field_Name(iField))->Add_Property("TYPE", gSG_Data_Type_Identifier[Get_Field_Type(iField)]);
791 }
792
793 Get_MetaData().Del_Child("GDAL_DRIVER");
794
795 Save_MetaData(File_Name);
796
797 //-----------------------------------------------------
798 return( true );
799 }
800
801
802 ///////////////////////////////////////////////////////////
803 // //
804 // //
805 // //
806 ///////////////////////////////////////////////////////////
807
808 //---------------------------------------------------------
809