Salome HOME
improvements on importPolylines Python function
[modules/hydro.git] / src / HYDROData / HYDROData_ShapeFile.cxx
1 // Copyright (C) 2014-2015  EDF-R&D
2 // This library is free software; you can redistribute it and/or
3 // modify it under the terms of the GNU Lesser General Public
4 // License as published by the Free Software Foundation; either
5 // version 2.1 of the License, or (at your option) any later version.
6 //
7 // This library is distributed in the hope that it will be useful,
8 // but WITHOUT ANY WARRANTY; without even the implied warranty of
9 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
10 // Lesser General Public License for more details.
11 //
12 // You should have received a copy of the GNU Lesser General Public
13 // License along with this library; if not, write to the Free Software
14 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
15 //
16 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
17 //
18
19 #include <HYDROData_ShapeFile.h>
20 #include <HYDROData_PolylineXY.h>
21 #include <HYDROData_Polyline3D.h>
22 #include <HYDROData_Bathymetry.h>
23 #include <HYDROData_Profile.h>
24 #include <HYDROData_Iterator.h>
25 #include <HYDROData_LandCoverMap.h>
26
27 #include <QFile>
28 #include <QFileInfo>
29 #include <TopoDS.hxx>
30 #include <TopExp_Explorer.hxx>
31 #include <TopoDS_Wire.hxx>
32 #include <TopoDS_Vertex.hxx>
33 #include <TopoDS_Edge.hxx>
34 #include <TopoDS_Face.hxx>
35 #include <BRep_Tool.hxx>
36 #include <BRepTools.hxx>
37 #include <Precision.hxx>
38 #include <Geom_Curve.hxx>
39 #include <Geom_Line.hxx>
40 #include <Geom_TrimmedCurve.hxx>
41 #include <Geom_TrimmedCurve.hxx>
42 #include <BRepBuilderAPI_MakeEdge.hxx>
43 #include <BRepBuilderAPI_MakeWire.hxx>
44 #include <BRepBuilderAPI_MakeFace.hxx>
45 #include <gp_Pln.hxx>
46 #include <BRepLib.hxx>
47 #include <ShapeFix_Shape.hxx>
48 #include <TopTools_SequenceOfShape.hxx>
49 #include <QColor>
50 #include <BRepTopAdaptor_FClass2d.hxx>
51 #include <TopExp.hxx>
52 #include <OSD_Timer.hxx>
53 #include <BRepLib_MakeVertex.hxx>
54 #include <NCollection_List.hxx>
55 #include <GC_MakeSegment.hxx>
56 #include <BRep_Builder.hxx>
57 #include <BRepAdaptor_Curve.hxx>
58 #include <GCPnts_QuasiUniformDeflection.hxx>
59 #include <TopLoc_Location.hxx>
60 #include <Geom_Plane.hxx>
61 #include <NCollection_Array1.hxx>
62 #include <BRepBndLib.hxx>
63 #include <Bnd_Box.hxx>
64
65 #ifdef WIN32
66   #pragma warning( disable: 4996 )
67 #endif
68
69 //SHP->TFaces (Import)
70 #define OSD_TIMER
71
72 HYDROData_ShapeFile::HYDROData_ShapeFile() : myHSHP(NULL)
73 {
74 }
75
76 HYDROData_ShapeFile::~HYDROData_ShapeFile()
77 {
78   Free();
79 }
80
81 void HYDROData_ShapeFile::Export(Handle(HYDROData_Document) theDocument,
82                                  const QString& aFileName,
83                                  NCollection_Sequence<Handle(HYDROData_PolylineXY)> aPolyXYSeq,
84                                  NCollection_Sequence<Handle(HYDROData_Polyline3D)> aPoly3DSeq,
85                                  QStringList& aNonExpList)
86 {
87   SHPHandle hSHPHandle;
88   if (!aPolyXYSeq.IsEmpty() && aPoly3DSeq.IsEmpty())
89   {
90     hSHPHandle = SHPCreate( aFileName.toLatin1().data(), SHPT_ARC );
91     for (int i = 1; i <= aPolyXYSeq.Size(); i++)
92       if (WriteObjectPolyXY(theDocument, hSHPHandle, aPolyXYSeq(i)) != 1)
93         aNonExpList.append(aPolyXYSeq(i)->GetName());
94   }
95   else if (aPolyXYSeq.IsEmpty() && !aPoly3DSeq.IsEmpty())
96   {
97     hSHPHandle = SHPCreate( aFileName.toLatin1().data(), SHPT_ARCZ );
98     for (int i = 1; i <= aPoly3DSeq.Size(); i++)
99       if (WriteObjectPoly3D(theDocument, hSHPHandle, aPoly3DSeq(i)) != 1)
100         aNonExpList.append(aPoly3DSeq(i)->GetName());
101   }
102   if (hSHPHandle->nRecords > 0)
103     SHPClose( hSHPHandle );
104   else
105   {
106     SHPClose( hSHPHandle );
107     QString aFN = aFileName.simplified();
108     remove (aFN.toStdString().c_str());
109     remove ((aFN.simplified().replace( aFN.simplified().size() - 4, 4, ".shx")).toStdString().c_str());
110   }
111 }
112
113 void HYDROData_ShapeFile::Export(Handle(HYDROData_Document) theDocument,
114                                  const QString& aFileName,
115                                  const Handle(HYDROData_LandCoverMap)& aLCM,
116                                  QStringList& aNonExpList,
117                                  bool bCheckLinear, bool bUseDiscr, double theDefl)
118 {
119   if (bCheckLinear && !aLCM->CheckLinear())
120     return;
121   //
122   SHPHandle hSHPHandle = NULL;
123   if ( !aLCM.IsNull() && !aLCM->IsEmpty())
124   {
125     hSHPHandle = SHPCreate( aFileName.toLatin1().data(), SHPT_POLYGON );
126     HYDROData_LandCoverMap::Explorer It( aLCM );
127     for( ; It.More(); It.Next())
128     {
129       TopoDS_Face aFace = It.Face();
130       if (WriteObjectPolygon(theDocument, hSHPHandle, aFace, bUseDiscr, theDefl) != 1)
131         aNonExpList.append(aLCM->GetName() + "_" +  QString::number(It.Index()));
132     }
133   }
134   if (hSHPHandle && hSHPHandle->nRecords > 0)
135     SHPClose( hSHPHandle );
136   else
137   {
138     SHPClose( hSHPHandle );
139     QString aFN = aFileName.simplified();
140     remove (aFN.toStdString().c_str());
141     remove ((aFN.simplified().replace( aFN.simplified().size() - 4, 4, ".shx")).toStdString().c_str());
142   }
143 }
144
145
146 int HYDROData_ShapeFile::WriteObjectPolyXY(Handle(HYDROData_Document) theDocument,
147                                            SHPHandle theShpHandle,
148                                            Handle(HYDROData_PolylineXY) thePoly )
149 {
150   SHPObject     *aSHPObj;
151   std::vector<double> x, y;
152   std::vector<int> anPartStart;
153
154   for (int i = 0; i < thePoly->NbSections(); i++)
155     if (thePoly->GetSectionType(i) == HYDROData_IPolyline::SECTION_SPLINE)
156       return -1;
157
158   for (int i = 0; i < thePoly->NbSections(); i++)
159   {
160     anPartStart.push_back(x.size());
161     HYDROData_PolylineXY::PointsList aPointList = thePoly->GetPoints(i, true);
162     for (int j = 1; j <= aPointList.Size(); j++)
163     {
164       gp_XY P = aPointList(j);
165       //theDocument->Transform(P, false);
166       x.push_back( P.X());
167       y.push_back( P.Y());
168     }
169     if (thePoly->IsClosedSection(i))
170     {
171       gp_XY P = aPointList(1);
172       //theDocument->Transform(P, false);
173       x.push_back( P.X());
174       y.push_back( P.Y());
175     }
176   }
177
178   aSHPObj = SHPCreateObject (SHPT_ARC, -1, thePoly->NbSections(), &anPartStart[0], NULL, x.size(), &x[0], &y[0], NULL, NULL );
179   SHPWriteObject( theShpHandle, -1, aSHPObj );
180   SHPDestroyObject( aSHPObj );
181   return 1;
182 }
183
184 int HYDROData_ShapeFile::WriteObjectPoly3D(Handle(HYDROData_Document) theDocument,
185                                            SHPHandle theShpHandle,
186                                            Handle(HYDROData_Polyline3D) thePoly )
187 {
188   SHPObject *aSHPObj;
189   std::vector<double> x, y, z;
190   std::vector<int> anPartStart;
191   anPartStart.push_back(0); //one section only
192
193   if (thePoly->GetPolylineXY()->GetSectionType(0) == HYDROData_IPolyline::SECTION_SPLINE)
194     return -1;
195
196   HYDROData_Polyline3D::Polyline3DPoints aPointList3D = thePoly->GetProfilePoints3D(true);
197   for (int j = 1; j <= aPointList3D.Size(); j++)
198   {
199     const gp_XYZ& P = aPointList3D(j);
200     //theDocument->Transform(P, false);
201     x.push_back(P.X());
202     y.push_back(P.Y());
203     z.push_back(P.Z());
204   }
205   if ( thePoly->GetPolylineXY()->IsClosedSection(0))
206   {
207     const gp_XYZ& P = aPointList3D(1);
208     //theDocument->Transform(P, false);
209     x.push_back(P.X());
210     y.push_back(P.Y());
211     z.push_back(P.Z());
212   }
213
214   aSHPObj = SHPCreateObject( SHPT_ARCZ, -1, 1, &anPartStart[0], NULL, x.size(), &x[0], &y[0], &z[0], NULL );
215   SHPWriteObject( theShpHandle, -1, aSHPObj );
216   SHPDestroyObject( aSHPObj );
217   return 1;
218 }
219
220 int HYDROData_ShapeFile::WriteObjectPolygon(Handle(HYDROData_Document) theDocument,
221                                             SHPHandle theShpHandle,
222                                             const TopoDS_Shape& theInputShape,
223                                             bool bUseDiscr, double theDefl)
224 {
225   if (theInputShape.IsNull())
226     return 0;
227
228   if (theInputShape.ShapeType() == TopAbs_FACE)
229   {
230     ProcessFace(theDocument, TopoDS::Face(theInputShape), theShpHandle, bUseDiscr, theDefl);
231   }
232   else if (theInputShape.ShapeType() == TopAbs_COMPOUND)
233   {
234     TopExp_Explorer Ex(theInputShape, TopAbs_FACE);
235     for (; Ex.More(); Ex.Next())
236     {
237       TopoDS_Face aF = TopoDS::Face(Ex.Current());
238       if (aF.IsNull())
239         continue;
240       ProcessFace(theDocument, aF, theShpHandle, bUseDiscr, theDefl);
241     }
242   }
243   else
244     return 0;
245
246   return 1;
247
248 }
249
250 void HYDROData_ShapeFile::ProcessFace(Handle(HYDROData_Document) theDocument,
251                                       const TopoDS_Face& theFace,
252                                       SHPHandle theShpHandle,
253                                       bool bUseDiscr, double theDefl )
254 {
255   if (theFace.ShapeType() != TopAbs_FACE)
256      return;
257   SHPObject     *aSHPObj;
258   std::vector<double> x, y;
259   std::vector<int> anPartStart;
260   TopoDS_Wire OuterW = BRepTools::OuterWire(theFace);
261   NCollection_Sequence<TopoDS_Wire> aWires;
262
263   //write an outer wire first
264   aWires.Append(OuterW);
265   TopExp_Explorer Ex(theFace, TopAbs_WIRE);
266   for (; Ex.More(); Ex.Next())
267   {
268     TopoDS_Wire aW = TopoDS::Wire(Ex.Current());
269     if (aW.IsEqual(OuterW))
270       continue;
271     aWires.Append(aW);
272   }
273
274   int NbWires = 0;
275   for (int k = 1; k <= aWires.Length(); k++)
276   {
277     TopoDS_Wire aW = aWires(k);
278     if (aW.IsNull())
279       continue;
280     NbWires++;
281     if (aW.Orientation() == TopAbs_INTERNAL)
282       //cant write internal wires/edges
283       continue;
284     // Try to reorder edges
285     Handle(ShapeFix_Wire) aSFW = new ShapeFix_Wire( aW, theFace, Precision::Confusion() );
286     aSFW->ModifyTopologyMode() = Standard_False;
287     aSFW->ModifyGeometryMode() = Standard_False;
288     aSFW->FixReorder();
289     Handle(ShapeExtend_WireData) aSEWD = aSFW->WireData();
290     Standard_Integer nbE = aSEWD->NbEdges();
291     if (nbE == 0)
292       continue;
293     //
294     anPartStart.push_back(x.size());
295     NCollection_Sequence<gp_Pnt2d> aPnts;
296     for (Standard_Integer i = 1; i <= nbE; i++)
297     {
298       TopoDS_Edge E = aSEWD->Edge(i);
299       if (!bUseDiscr)
300       {
301         TopoDS_Vertex aV = TopExp::LastVertex(E, 1);
302         if (aV.IsNull())
303           continue;
304         gp_Pnt P = BRep_Tool::Pnt(aV);
305         aPnts.Append(gp_Pnt2d(P.X(), P.Y()));
306       }
307       else
308       {
309         BRepAdaptor_Curve Cur( E );
310         GCPnts_QuasiUniformDeflection Discr( Cur, theDefl );
311         if( !Discr.IsDone() )
312           continue; //skip edge?
313         double NewDefl = theDefl/2.0;
314         while (Discr.NbPoints() < 2)
315         {
316           Discr.Initialize(Cur, NewDefl);
317           NewDefl = NewDefl/2.0;
318         }
319         //
320         if (E.Orientation() == TopAbs_FORWARD)
321         {
322           for( int i = 1; i <= Discr.NbPoints(); i++ )
323           {
324             gp_Pnt P = Discr.Value( i );
325             aPnts.Append(gp_Pnt2d(P.X(), P.Y()));
326           }
327         }
328         else
329         {
330           for( int i = Discr.NbPoints(); i > 0; i-- )
331           {
332             gp_Pnt P = Discr.Value( i );
333             aPnts.Append(gp_Pnt2d(P.X(), P.Y()));
334           }
335         }
336       }
337     }
338     NCollection_Sequence<gp_Pnt2d> aNPnts;
339     aNPnts.Append(aPnts.First());
340     for (int j = 1; j <= aPnts.Size() - 1; j++)
341     {
342       if (!aPnts(j).IsEqual(aPnts(j + 1), Precision::Confusion()))
343         aNPnts.Append(aPnts(j + 1));
344     }
345
346     //assume that the orientation of external wire & internal wires is correct
347     //so just write all points "as-is"
348     //External wire will be written in clockwise direction
349     //any other wires (holes) - in anticlockwise direction
350     for (int j = aNPnts.Size(); j >= 1; j--)
351     {
352       gp_XY P = gp_XY(aNPnts(j).X(), aNPnts(j).Y());
353       theDocument->Transform(P, false);
354       x.push_back( P.X());
355       y.push_back( P.Y());
356     }
357     //first point is same as the last one => closed polygon
358     gp_XY P = gp_XY(aNPnts.Last().X(), aNPnts.Last().Y());
359     theDocument->Transform(P, false);
360     x.push_back( P.X());
361     y.push_back( P.Y());
362
363   }
364
365   aSHPObj = SHPCreateObject( SHPT_POLYGON, -1, NbWires, &anPartStart[0], NULL, x.size(), &x[0], &y[0], NULL, NULL );
366   SHPWriteObject( theShpHandle, -1, aSHPObj );
367   SHPDestroyObject( aSHPObj );
368
369 }
370
371 bool HYDROData_ShapeFile::Parse(SHPHandle theHandle, ShapeType theType)
372 {
373   int aShapeType;
374   mySHPObjects.clear();
375   SHPGetInfo( theHandle, NULL, &aShapeType, NULL, NULL );
376   //theShapeTypeOfFile = aShapeType;
377   bool ToRead = (theType == ShapeType_Polyline &&
378     (aShapeType == 3 || aShapeType == 13 || aShapeType == 23 || aShapeType == 5)) ||
379    (theType == ShapeType_Polygon && aShapeType == 5);
380   if (ToRead)
381   {
382     for (int i = 0; i < theHandle->nRecords; i++)
383       mySHPObjects.push_back(SHPReadObject(theHandle, i));
384     return true;
385   }
386   else
387     return false;
388 }
389
390 void HYDROData_ShapeFile::ReadSHPPolygon(Handle(HYDROData_Document) theDocument, SHPObject* anObj, int i, TopoDS_Face& F)
391 {
392   if (!anObj)
393     return;
394   TopoDS_Edge E;
395   int nParts = anObj->nParts;
396   Handle(Geom_Plane) aPlaneSur = new Geom_Plane(gp_Pnt(0,0,0), gp_Dir(0,0,1));
397
398   BRep_Builder BB;
399   BB.MakeFace(F);
400
401   NCollection_Sequence<TopoDS_Wire> allWires;
402
403   TopTools_SequenceOfShape aWires;
404   for ( int i = 0 ; i < nParts ; i++ )
405   {
406     BRepBuilderAPI_MakeWire aBuilder;
407     int StartIndex = anObj->panPartStart[i];
408     int EndIndex;
409     if (i != nParts - 1)
410       EndIndex = anObj->panPartStart[i + 1];
411     else
412       EndIndex = anObj->nVertices;
413
414     TopoDS_Wire W;
415     BB.MakeWire(W);
416
417     //First point is same as the last point
418     int NbPnts = EndIndex - StartIndex - 1;
419     NCollection_Array1<TopoDS_Vertex> VPoints(0, NbPnts);
420     int j = NbPnts;
421     for ( int k = StartIndex; k < EndIndex; k++ )
422     {
423       gp_Pnt P (anObj->padfX[k], anObj->padfY[k], 0);
424       theDocument->Transform(P, true);
425       VPoints.ChangeValue(j) = BRepLib_MakeVertex(P).Vertex();
426       j--;
427     }
428
429     for ( int k = 0; k < VPoints.Size() - 1; k++ )
430     {
431       gp_Pnt P1 = BRep_Tool::Pnt(VPoints(k));
432       gp_Pnt P2 = BRep_Tool::Pnt(VPoints(k + 1));
433       if (P1.Distance(P2) < Precision::Confusion())
434         continue;
435       Handle(Geom_TrimmedCurve) aTC = GC_MakeSegment(P1, P2).Value();
436       TopoDS_Edge E;
437       if ( k != VPoints.Size() - 2)
438         E = BRepLib_MakeEdge(aTC, VPoints(k), VPoints(k + 1)).Edge();
439       else
440         //the last edge => use first and last vertices
441         E = BRepLib_MakeEdge(aTC, VPoints.First(), VPoints.Value(VPoints.Upper() - 1)).Edge();
442       //Add edge to wire
443       //If SHP file is correct then the outer wire and the holes will have the correct orientations
444       W.Closed (Standard_True);
445       W.Orientation(TopAbs_FORWARD);
446       BB.Add(W, E);
447     }
448     allWires.Append(W);
449   }
450
451   int OutWIndex = -1;
452   if (allWires.Size() > 1)
453   {
454     NCollection_Sequence<Bnd_Box> BBs;
455     //try to find the largest bbox
456     for (int i = 1; i <= allWires.Size(); i++)
457     {
458       TopoDS_Wire W = allWires(i);
459       Bnd_Box BB;
460       BRepBndLib::AddClose(W, BB);
461       BBs.Append(BB);
462     }
463     for (int i = 1; i <= BBs.Size(); i++)
464     {
465       bool IsIn = false;
466       for (int j = 1; j <= BBs.Size(); j++)
467       {
468         if (i == j)
469           continue;
470         Standard_Real iXmax, iXmin, iYmax, iYmin, z0, z1;
471         Standard_Real jXmax, jXmin, jYmax, jYmin;
472         BBs(i).Get(iXmin, iYmin, z0, iXmax, iYmax, z1);
473         BBs(j).Get(jXmin, jYmin, z0, jXmax, jYmax, z1);
474         if (!(iXmin > jXmin &&
475             iYmin > jYmin &&
476             iXmax < jXmax &&
477             iYmax < jYmax))
478           IsIn = true;
479       }
480       if (IsIn)
481       {
482         OutWIndex = i;
483         break;
484       }
485     }
486   }
487   else
488     OutWIndex = 1; //one wire => no need to check
489
490   for (int i = 1; i <= allWires.Size(); i++)
491   {
492     TopoDS_Face DF;
493     BB.MakeFace(DF);
494     TopoDS_Wire W = allWires(i);
495     BB.Add(DF, W);
496     BB.UpdateFace(DF, aPlaneSur, TopLoc_Location(), Precision::Confusion());
497     //
498     BRepTopAdaptor_FClass2d FClass(DF, Precision::PConfusion());
499     if ( i == OutWIndex && FClass.PerformInfinitePoint() == TopAbs_IN)
500       W.Reverse();
501     if ( i != OutWIndex && FClass.PerformInfinitePoint() == TopAbs_OUT)
502       W.Reverse();
503     //
504     BB.Add(F, W);
505   }
506
507   //Add surface to the face
508   BB.UpdateFace(F, aPlaneSur, TopLoc_Location(), Precision::Confusion());
509   F.Closed(Standard_True);
510 }
511
512 int HYDROData_ShapeFile::ImportPolygons(Handle(HYDROData_Document) theDocument, const QString theFileName,
513   QStringList& thePolygonsList, TopTools_SequenceOfShape& theFaces)
514 {
515   Free();
516   int Stat = TryOpenShapeFile(theFileName);
517   if (Stat != 0)
518     return Stat;
519   myHSHP = SHPOpen( theFileName.toLatin1().data(), "rb" );
520   if (!Parse(myHSHP, HYDROData_ShapeFile::ShapeType_Polygon))
521     return 0;
522   for (size_t i = 0; i < mySHPObjects.size(); i++)
523     thePolygonsList.append("polygon_" + QString::number(i + 1));
524
525   TopoDS_Face aF;
526   if (myHSHP->nShapeType == 5)
527   {
528 #ifdef OSD_TIMER
529     OSD_Timer timer;
530     timer.Start();
531 #endif
532     for (size_t i = 0; i < mySHPObjects.size(); i++)
533     {
534        ReadSHPPolygon(theDocument, mySHPObjects[i], i, aF);
535        theFaces.Append(aF);
536     }
537 #ifdef OSD_TIMER
538     timer.Stop();
539     timer.Show();
540 #endif
541     return 1;
542   }
543   else
544     return 0;
545 }
546
547 void HYDROData_ShapeFile::Free()
548 {
549   for (size_t i = 0; i < mySHPObjects.size(); i++ )
550     free (mySHPObjects[i]);
551
552   mySHPObjects.clear();
553   if (myHSHP != NULL)
554   {
555     SHPClose(myHSHP);
556     myHSHP = NULL;
557   }
558 }
559
560
561 void HYDROData_ShapeFile::ReadSHPPolyXY(Handle(HYDROData_Document) theDocument, SHPObject* anObj, QString theFileName,
562   int theInd, NCollection_Sequence<Handle(HYDROData_Entity)>& theEntities, bool bReadAsPolyline)
563 {
564   Handle(HYDROData_PolylineXY) aPolylineXY = Handle(HYDROData_PolylineXY)::DownCast( theDocument->CreateObject( KIND_POLYLINEXY ) );
565
566   int nParts = anObj->nParts;
567   for ( int i = 0 ; i < nParts ; i++ )
568   {
569     int StartIndex = anObj->panPartStart[i];
570     int EndIndex;
571     if (i != nParts - 1)
572       EndIndex = anObj->panPartStart[i + 1];
573     else
574       EndIndex = anObj->nVertices;
575
576     HYDROData_PolylineXY::SectionType aSectType = HYDROData_PolylineXY::SECTION_POLYLINE;
577     if (!bReadAsPolyline)
578     {
579       bool IsClosed = false;
580       if (anObj->padfX[StartIndex] == anObj->padfX[EndIndex - 1] &&
581         anObj->padfY[StartIndex] == anObj->padfY[EndIndex - 1] )
582       {
583         IsClosed = true;
584         aPolylineXY->AddSection( TCollection_AsciiString( ("poly_section_" + QString::number(i)).data()->toLatin1()), aSectType, true);
585       }
586       else
587         aPolylineXY->AddSection( TCollection_AsciiString( ("poly_section_" + QString::number(i)).data()->toLatin1()), aSectType, false);
588
589       if (IsClosed)
590         EndIndex--;
591     }
592     else
593     {
594       //polygon; contours always closed
595       aPolylineXY->AddSection( TCollection_AsciiString( ("poly_section_" + QString::number(i)).data()->toLatin1()), aSectType, true);
596       EndIndex--;
597     }
598     for ( int k = StartIndex; k < EndIndex ; k++ )
599     {
600       HYDROData_PolylineXY::Point aSectPoint = gp_XY(anObj->padfX[k], anObj->padfY[k]);
601       theDocument->Transform(aSectPoint, true);
602       aPolylineXY->AddPoint( i, aSectPoint );
603     }
604
605   }
606
607   aPolylineXY->SetWireColor( HYDROData_PolylineXY::DefaultWireColor() );
608   aPolylineXY->SetName( theFileName + "_PolyXY_" + QString::number(theInd) );
609
610   aPolylineXY->Update();
611   theEntities.Append(aPolylineXY);
612 }
613
614
615 void HYDROData_ShapeFile::ReadSHPPoly3D(Handle(HYDROData_Document) theDocument, SHPObject* anObj,
616   const Handle(HYDROData_PolylineXY)& aPolylineXY,
617   NCollection_Sequence<Handle(HYDROData_Entity)>& theEntities)
618 {
619   Handle(HYDROData_Polyline3D) aPolylineObj = Handle(HYDROData_Polyline3D)::DownCast( theDocument->CreateObject( KIND_POLYLINE ) );
620   Handle(HYDROData_Bathymetry) aBath = Handle(HYDROData_Bathymetry)::DownCast( theDocument->CreateObject( KIND_BATHYMETRY ) );
621
622   HYDROData_Bathymetry::AltitudePoints aAPoints;
623
624   int nParts = anObj->nParts;
625   for ( int i = 0 ; i < nParts ; i++ )
626   {
627     //bool aSectClosure = true;
628     int StartIndex = anObj->panPartStart[i];
629     int EndIndex;
630     if (i != nParts - 1)
631       EndIndex = anObj->panPartStart[i + 1];
632     else
633       EndIndex = anObj->nVertices;
634
635     HYDROData_PolylineXY::SectionType aSectType = HYDROData_PolylineXY::SECTION_POLYLINE;
636     if (anObj->padfX[StartIndex] == anObj->padfX[EndIndex - 1] &&
637       anObj->padfY[StartIndex] == anObj->padfY[EndIndex - 1] &&
638       anObj->padfZ[StartIndex] == anObj->padfZ[EndIndex - 1])
639       EndIndex--;
640     for ( int k = StartIndex ; k < EndIndex ; k++ )
641     {
642       gp_XYZ xyz(anObj->padfX[k], anObj->padfY[k], anObj->padfZ[k]);
643       theDocument->Transform(xyz, true);
644       HYDROData_Bathymetry::AltitudePoint p;
645       p.X = xyz.X();
646       p.Y = xyz.Y();
647       p.Z = xyz.Z();
648       aAPoints.push_back(p);
649     }
650   }
651
652   QString PolyXYName = aPolylineXY->GetName();
653   QString aPoly3DName = PolyXYName, aBathyName = PolyXYName;
654   aPoly3DName.replace(PolyXYName.lastIndexOf("_PolyXY_"), 8, "_Poly3D_");
655   aBathyName.replace(PolyXYName.lastIndexOf("_Bath_"), 6, "_Poly3D_");
656
657   aBath->SetAltitudePoints(aAPoints);
658   aBath->SetName( aBathyName );
659
660   aPolylineObj->SetPolylineXY (aPolylineXY, false);
661   aPolylineObj->SetAltitudeObject(aBath);
662
663   aPolylineObj->SetBorderColor( aPolylineObj->DefaultBorderColor() );
664   aPolylineObj->SetName( aPoly3DName );
665
666   aPolylineObj->Update();
667
668   theEntities.Append(aPolylineObj);
669 }
670
671 /*
672 void HYDROData_ShapeFile::ReadSHPPoly3D(Handle(HYDROData_Document) theDocument, SHPObject* anObj, QString theFileName,
673   int theInd, bool XYOnly, NCollection_Sequence<Handle(HYDROData_Entity)>& theEntities)
674 {
675   Handle(HYDROData_PolylineXY) aPolylineXY = Handle(HYDROData_PolylineXY)::DownCast( theDocument->CreateObject( KIND_POLYLINEXY ) );
676
677   Handle(HYDROData_Polyline3D) aPolylineObj;
678   Handle(HYDROData_Bathymetry) aBath;
679   if (!XYOnly)
680   {
681     Handle(HYDROData_Polyline3D) aPolylineObj = Handle(HYDROData_Polyline3D)::DownCast( theDocument->CreateObject( KIND_POLYLINE ) );
682     Handle(HYDROData_Bathymetry) aBath = Handle(HYDROData_Bathymetry)::DownCast( theDocument->CreateObject( KIND_BATHYMETRY ) );
683   }
684
685   HYDROData_Bathymetry::AltitudePoints aAPoints;
686
687   int nParts = anObj->nParts;
688   for ( int i = 0 ; i < nParts ; i++ )
689   {
690     //bool aSectClosure = true;
691     int StartIndex = anObj->panPartStart[i];
692     int EndIndex;
693     if (i != nParts - 1)
694       EndIndex = anObj->panPartStart[i + 1];
695     else
696       EndIndex = anObj->nVertices;
697
698     bool IsClosed = false;
699     HYDROData_PolylineXY::SectionType aSectType = HYDROData_PolylineXY::SECTION_POLYLINE;
700     if (anObj->padfX[StartIndex] == anObj->padfX[EndIndex - 1] &&
701         anObj->padfY[StartIndex] == anObj->padfY[EndIndex - 1] &&
702         anObj->padfZ[StartIndex] == anObj->padfZ[EndIndex - 1])
703     {
704       IsClosed = true;
705       aPolylineXY->AddSection( TCollection_AsciiString( ("poly_section_" + QString::number(i)).data()->toLatin1()), aSectType, true );
706     }
707     else
708       aPolylineXY->AddSection( TCollection_AsciiString( ("poly_section_" + QString::number(i)).data()->toLatin1()), aSectType, false  );
709
710     if (IsClosed)
711       EndIndex--;
712     for ( int k = StartIndex ; k < EndIndex ; k++ )
713     {
714       HYDROData_PolylineXY::Point aSectPoint = gp_XY(anObj->padfX[k], anObj->padfY[k]);
715       theDocument->Transform(aSectPoint, true);
716       aPolylineXY->AddPoint( i, aSectPoint );
717       if (!XYOnly)
718       {
719         HYDROData_Bathymetry::AltitudePoint p;
720         p.X = aSectPoint.X();
721         p.Y = aSectPoint.Y();
722         p.Z = anObj->padfZ[k];
723         aAPoints.push_back(p);
724       }
725     }
726   }
727
728
729   QString aBathName = theFileName + "_bath_" + QString::number(theInd);
730   QString aPolyXYName = theFileName + "_polyXY_" + QString::number(theInd);
731   QString aPoly3DName = theFileName + "_poly3D_" + QString::number(theInd);
732
733   aPolylineXY->SetName( aPolyXYName );
734   aPolylineXY->SetWireColor(HYDROData_PolylineXY::DefaultWireColor());
735   aPolylineXY->Update();
736
737   if (!XYOnly)
738   {
739     aBath->SetAltitudePoints(aAPoints);
740     aBath->SetName( aBathName );
741
742     aPolylineObj->SetPolylineXY (aPolylineXY, false);
743     aPolylineObj->SetAltitudeObject(aBath);
744
745     aPolylineObj->SetBorderColor( aPolylineObj->DefaultBorderColor() );
746     aPolylineObj->SetName( aPoly3DName );
747
748     aPolylineObj->Update();
749   }
750
751   theEntities.Append(aPolylineXY);
752
753   if (!XYOnly)
754     theEntities.Append(aPolylineObj);
755
756 }*/
757
758 void HYDROData_ShapeFile::GetFreeIndices(std::vector<int>& theAllowedIndexes, QString strName, size_t theObjsSize,
759                                          QStringList theExistingNames, QString theBaseFileName)
760 {
761   int anInd = 0;
762   for (;theAllowedIndexes.size() < theObjsSize;)
763   {
764     if (!theExistingNames.contains(theBaseFileName + strName + QString::number(anInd)))
765     {
766       theAllowedIndexes.push_back(anInd);
767       anInd++;
768     }
769     else
770       anInd++;
771   }
772 }
773
774 int HYDROData_ShapeFile::OpenAndParse(const QString& theFileName)
775 {
776   //Free();
777   int aStat = TryOpenShapeFile(theFileName);
778   if (aStat != 0)
779     return aStat;
780
781   //SHPHandle aHSHP;
782   myHSHP = SHPOpen( theFileName.toLatin1().data(), "rb" );
783   if (myHSHP == NULL)
784     return -1;
785
786   if (!Parse(myHSHP, HYDROData_ShapeFile::ShapeType_Polyline))
787     return -1;
788
789   return 1;
790   //sh_type = aHSHP->nShapeType;
791 }
792
793 int HYDROData_ShapeFile::ImportPolylines(Handle(HYDROData_Document) theDocument,
794   const QString& theFileName,
795   NCollection_IndexedDataMap<Handle(HYDROData_Entity), SHPObject*>& theEntitiesToSHPObj,
796   ImportShapeType theShapeTypesToImport)
797 {
798   int aStat = -1;
799   int sh_type = myHSHP->nShapeType;
800   QFileInfo aFileInfo(theFileName);
801   QString aBaseFileName = aFileInfo.baseName();
802   HYDROData_Iterator anIter( theDocument );
803   int anInd = 0;
804   QStringList anExistingNames;
805   std::vector<int> anAllowedIndexes;
806   for( ; anIter.More(); anIter.Next() )
807     anExistingNames.push_back(anIter.Current()->GetName());
808
809   NCollection_Sequence<Handle(HYDROData_Entity)> Ents;
810   if ((theShapeTypesToImport == HYDROData_ShapeFile::ImportShapeType_All ||
811     theShapeTypesToImport == HYDROData_ShapeFile::ImportShapeType_Polyline)
812     && (sh_type == 3 || sh_type == 23))
813   {
814     size_t anObjsSize = mySHPObjects.size();
815     GetFreeIndices(anAllowedIndexes, "_PolyXY_", anObjsSize, anExistingNames, aBaseFileName);
816
817     for (size_t i = 0; i < mySHPObjects.size(); i++ )
818     {
819       ReadSHPPolyXY(theDocument, mySHPObjects[i], aBaseFileName, anAllowedIndexes[i], Ents, false);
820       for (int k=1;k<=Ents.Size();k++)
821         theEntitiesToSHPObj.Add(Ents(k), mySHPObjects[i]);
822     }
823     aStat = 1;
824   }
825   else if ((theShapeTypesToImport == HYDROData_ShapeFile::ImportShapeType_All ||
826     theShapeTypesToImport == HYDROData_ShapeFile::ImportShapeType_Polyline3D) && sh_type == 13)
827   {
828     anInd = 0;
829     for (;anAllowedIndexes.size() < mySHPObjects.size();)
830     {
831       if (!anExistingNames.contains(aBaseFileName + "_PolyXY_" + QString::number(anInd)) &&
832           !anExistingNames.contains(aBaseFileName + "_Poly3D_" + QString::number(anInd)) &&
833           !anExistingNames.contains(aBaseFileName + "_Bath_" + QString::number(anInd)))
834       {
835         anAllowedIndexes.push_back(anInd);
836         anInd++;
837       }
838       else
839         anInd++;
840     }
841     for (size_t i = 0; i < mySHPObjects.size(); i++ )
842     {
843       //ReadSHPPoly3D(theDocument, mySHPObjects[i], aBaseFileName, anAllowedIndexes[i], false, theEntities);
844       ReadSHPPolyXY(theDocument, mySHPObjects[i], aBaseFileName, anAllowedIndexes[i], Ents, false); //TODO check Z coord on closeness
845       for (int k=1;k<=Ents.Size();k++)
846         theEntitiesToSHPObj.Add(Ents(k), mySHPObjects[i]);
847     }
848     aStat = 1;
849   }
850   else if ((theShapeTypesToImport == HYDROData_ShapeFile::ImportShapeType_All ||
851     theShapeTypesToImport == HYDROData_ShapeFile::ImportShapeType_Polygon) && sh_type == 5)
852   {
853     //import polygon's contours as polylines
854     size_t anObjsSize = mySHPObjects.size();
855     GetFreeIndices(anAllowedIndexes, "_PolyXY_", anObjsSize, anExistingNames, aBaseFileName);
856
857     for (size_t i = 0; i < mySHPObjects.size(); i++ )
858     {
859       ReadSHPPolyXY(theDocument, mySHPObjects[i], aBaseFileName, anAllowedIndexes[i], Ents, true);
860       for (int k=1;k<=Ents.Size();k++)
861         theEntitiesToSHPObj.Add(Ents(k), mySHPObjects[i]);
862     }
863     aStat = 2;
864   }
865   else
866   {
867     aStat = 0;
868   }
869
870   return aStat;
871 }
872
873 int HYDROData_ShapeFile::GetShapeType() const
874 {
875   if (myHSHP != NULL)
876     return myHSHP->nShapeType;
877   else
878     return -1;
879 }
880
881 int HYDROData_ShapeFile::ImportPolylines3D(Handle(HYDROData_Document) theDocument,
882                                            NCollection_IndexedDataMap<Handle(HYDROData_Entity), SHPObject*> thePolyXYToObj,
883                                            NCollection_Sequence<Handle(HYDROData_Entity)>& theEntities,
884                                            ImportShapeType theShapeTypesToImport)
885 {
886   int aStat = -1;
887   int sh_type = myHSHP->nShapeType;
888   if ((theShapeTypesToImport == HYDROData_ShapeFile::ImportShapeType_All ||
889     theShapeTypesToImport == HYDROData_ShapeFile::ImportShapeType_Polyline3D) && sh_type == 13)
890   {
891     //for (size_t i = 0; i < mySHPObjects.size(); i++ )
892     for (int i = 1; i <= thePolyXYToObj.Extent(); i++ )
893     {
894       Handle(HYDROData_PolylineXY) aPolylineXY = Handle(HYDROData_PolylineXY)::DownCast( thePolyXYToObj.FindKey(i) );
895       ReadSHPPoly3D(theDocument, thePolyXYToObj(i), aPolylineXY, theEntities);
896     }
897     aStat = 1;
898   }
899   else
900     aStat = 0;
901
902   return aStat;
903 }
904
905
906 QString HYDROData_ShapeFile::GetShapeTypeName(int theType)
907 {
908   switch (theType)
909   {
910     case 0:
911       return "null shape";
912     case 1:
913       return "point (unsupported by HYDRO)";
914     case 3:
915       return "arc/polyline (supported by HYDRO)";
916     case 5:
917       return "polygon (supported by HYDRO)";
918     case 8:
919       return "multipoint (unsupported by HYDRO)";
920     case 11:
921       return "pointZ (unsupported by HYDRO)";
922     case 13:
923       return "arcZ/polyline (supported by HYDRO)";
924     case 15:
925       return "polygonZ (unsupported by HYDRO)";
926     case 18:
927       return "multipointZ (unsupported by HYDRO)";
928     case 21:
929       return "pointM (unsupported by HYDRO)";
930     case 23:
931       return "arcM/polyline (supported by HYDRO)";
932     case 25:
933       return "polygonM (unsupported by HYDRO)";
934     case 28:
935       return "multipointM (unsupported by HYDRO)";
936     case 31:
937       return "multipatch (unsupported by HYDRO)";
938     default:
939       return "unknown";
940   }
941 }
942
943 int HYDROData_ShapeFile::TryOpenShapeFile(QString theFileName)
944 {
945   QString aSHPfile = theFileName.simplified();
946   QString aSHXfile = theFileName.simplified().replace( theFileName.simplified().size() - 4, 4, ".shx");
947
948   QString anExt = theFileName.split('.', QString::SkipEmptyParts).back();
949   if (anExt.toLower() != "shp")
950     return -3;
951
952   FILE* pFileSHP = NULL;
953   pFileSHP = fopen (aSHPfile.toLatin1().data(), "r");
954   FILE* pFileSHX = NULL;
955   pFileSHX = fopen (aSHXfile.toLatin1().data(), "r");
956
957   if (pFileSHP == NULL || pFileSHX == NULL)
958   {
959     if (pFileSHP == NULL)
960       return -1;
961     if (pFileSHX == NULL)
962       return -2;
963   }
964
965   fclose (pFileSHP);
966   fclose (pFileSHX);
967   return 0;
968 }
969
970
971 bool HYDROData_ShapeFile::CheckDBFFileExisting(const QString& theSHPFilePath, QString& thePathToDBFFile)
972 {
973   QString aSHPfile = theSHPFilePath.simplified();
974   QString aDBFfile = theSHPFilePath.simplified().replace( theSHPFilePath.simplified().size() - 4, 4, ".dbf");
975   FILE* pFileDBF = NULL;
976   pFileDBF = fopen (aDBFfile.toLatin1().data(), "r");
977
978   if (pFileDBF == NULL)
979   {
980     return false;
981   }
982
983   fclose (pFileDBF);
984   thePathToDBFFile = aDBFfile;
985   return true;
986 }
987
988
989 bool HYDROData_ShapeFile::DBF_OpenDBF(const QString& thePathToDBFFile)
990 {
991   myHDBF = DBFOpen( thePathToDBFFile.toLatin1().data(), "r" );
992   if(myHDBF != NULL)
993     return true;
994   else
995     return false;
996 }
997
998 int HYDROData_ShapeFile::DBF_GetNbFields()
999 {
1000   if(myHDBF == NULL)
1001     return 0;
1002   return DBFGetFieldCount(myHDBF);
1003 }
1004
1005 void HYDROData_ShapeFile::DBF_CloseDBF()
1006 {
1007   if(myHDBF != NULL)
1008      DBFClose( myHDBF );
1009 }
1010
1011 QStringList HYDROData_ShapeFile::DBF_GetFieldList()
1012 {
1013   QStringList FieldList;
1014   int   nWidth, nDecimals;
1015   char chField[12];
1016
1017   for( int i = 0; i < DBFGetFieldCount(myHDBF); i++ )
1018   {
1019       DBFFieldType eType;
1020       eType = DBFGetFieldInfo( myHDBF, i, chField, &nWidth, &nDecimals );
1021       FieldList.append(QString(chField));
1022   }
1023
1024   return FieldList;
1025 }
1026
1027 void HYDROData_ShapeFile::DBF_GetFieldTypeList(std::vector<DBF_FieldType>& FTVect)
1028 {
1029   int nWidth, nDecimals;
1030   char chField[12];
1031   DBF_FieldType FT;
1032   for( int i = 0; i < DBFGetFieldCount(myHDBF); i++ )
1033   {
1034     DBFFieldType eType;
1035     eType = DBFGetFieldInfo( myHDBF, i, chField, &nWidth, &nDecimals );
1036     if( eType == FTString )
1037       FT = DBF_FieldType_String;
1038     else if( eType == FTInteger )
1039       FT = DBF_FieldType_Integer;
1040     else if( eType == FTDouble )
1041       FT = DBF_FieldType_Double;
1042     else if( eType == FTInvalid )
1043       FT = DBF_FieldType_Invalid;
1044
1045     FTVect.push_back(FT);
1046   }
1047
1048 }
1049
1050 int HYDROData_ShapeFile::DBF_GetNbRecords()
1051 {
1052   if(myHDBF == NULL)
1053     return 0;
1054   return DBFGetRecordCount(myHDBF);
1055 }
1056
1057 void HYDROData_ShapeFile::DBF_GetAttributeList(int theIndexOfField, std::vector<DBF_AttrValue>& theAttrV)
1058 {
1059   int nWidth, nDecimals;
1060   char chField[12];
1061
1062   for( int i = 0; i < DBFGetRecordCount(myHDBF); i++ )
1063   {
1064     DBFFieldType eType;
1065     DBF_AttrValue anAttr;
1066     eType = DBFGetFieldInfo( myHDBF, theIndexOfField, chField, &nWidth, &nDecimals );
1067
1068     if( DBFIsAttributeNULL( myHDBF, i, theIndexOfField ) )
1069     {
1070       anAttr.myIsNull = true;
1071       DBF_FieldType FT = DBF_FieldType_None;
1072       if( eType == FTString )
1073         FT = DBF_FieldType_String;
1074       else if( eType == FTInteger )
1075         FT = DBF_FieldType_Integer;
1076       else if( eType == FTDouble )
1077         FT = DBF_FieldType_Double;
1078       else if( eType == FTInvalid )
1079         FT = DBF_FieldType_Invalid;
1080       anAttr.myFieldType = FT;
1081     }
1082     else
1083     {
1084       switch( eType )
1085       {
1086         case FTString:
1087         {
1088           const char* chAttr = DBFReadStringAttribute( myHDBF, i, theIndexOfField );
1089           anAttr.myIsNull = false;
1090           anAttr.myFieldType = DBF_FieldType_String;
1091           anAttr.myRawValue = chAttr;
1092           anAttr.myStrVal = QString(chAttr);
1093           break;
1094         }
1095
1096         case FTInteger:
1097         {
1098           int iAttr = DBFReadIntegerAttribute( myHDBF, i, theIndexOfField );
1099           anAttr.myIsNull = false;
1100           anAttr.myFieldType = DBF_FieldType_Integer;
1101           anAttr.myRawValue = DBFReadStringAttribute( myHDBF, i, theIndexOfField );
1102           anAttr.myIntVal = iAttr;
1103           break;
1104         }
1105
1106         case FTDouble:
1107         {
1108           double dAttr = DBFReadDoubleAttribute( myHDBF, i, theIndexOfField );
1109           anAttr.myIsNull = false;
1110           anAttr.myFieldType = DBF_FieldType_Double;
1111           anAttr.myRawValue = DBFReadStringAttribute( myHDBF, i, theIndexOfField );
1112           anAttr.myDoubleVal = dAttr;
1113           break;
1114         }
1115         default:
1116           break;
1117       }
1118     }
1119     theAttrV.push_back(anAttr);
1120   }
1121
1122 }
1123
1124 bool HYDROData_ShapeFile::DBF_WriteFieldAndValues(const QString& theFileName, const QString& theFieldName, DBF_FieldType theType, const std::vector<DBF_AttrValue>& theAttrV, bool bUseRawValue)
1125 {
1126   // Check that given field type is equal to field types of attributes values
1127   for (size_t i = 0; i < theAttrV.size(); i++)
1128   {
1129     if (theAttrV[i].myFieldType != theType)
1130       return false;
1131   }
1132
1133   DBFHandle     hDBF;
1134   hDBF = DBFCreate( theFileName.toStdString().c_str() );
1135   if( hDBF == NULL )
1136           return false;
1137
1138   if (theType != DBF_FieldType_String && theType != DBF_FieldType_Integer && theType != DBF_FieldType_Double)
1139   {
1140     DBFClose( hDBF );
1141     return false; //cant handle any other cases
1142   }
1143
1144   int nWidth = 20;
1145   switch( theType )
1146   {
1147     case DBF_FieldType_String:
1148     {
1149       DBFAddField (hDBF, theFieldName.toStdString().c_str(), FTString, nWidth, 0);
1150       break;
1151     }
1152
1153     case DBF_FieldType_Integer:
1154     {
1155       DBFAddField (hDBF, theFieldName.toStdString().c_str(), FTInteger, nWidth, 0);
1156       break;
1157     }
1158
1159     case DBF_FieldType_Double:
1160     {
1161       DBFAddField (hDBF, theFieldName.toStdString().c_str(), FTDouble, nWidth, 0);
1162       break;
1163     }
1164     default:
1165       break;
1166   }
1167
1168   if (DBFGetFieldCount( hDBF ) != 1)
1169   {
1170     DBFClose( hDBF );
1171     return false;
1172   }
1173   if (DBFGetRecordCount( hDBF ) != 0)
1174   {
1175     DBFClose( hDBF );
1176     return false;
1177   }
1178   int stat = -1;
1179
1180   if (bUseRawValue)
1181   {
1182     for (size_t i = 0; i < theAttrV.size(); i++)
1183     {
1184       if (!theAttrV[i].myIsNull)
1185         stat = DBFWriteStringAttribute(hDBF, (int)i, 0, theAttrV[i].myRawValue.c_str());
1186       else
1187         stat = DBFWriteNULLAttribute(hDBF, (int)i, 0 );
1188
1189       if (stat != 1)
1190       {
1191         DBFClose( hDBF );
1192         return false;
1193       }
1194     }
1195   }
1196   else
1197   {
1198     for (size_t i = 0; i < theAttrV.size(); i++)
1199     {
1200       if (!theAttrV[i].myIsNull)
1201         switch( theType )
1202         {
1203           case DBF_FieldType_String:
1204           {
1205             stat = DBFWriteStringAttribute(hDBF, (int)i, 0, theAttrV[i].myStrVal.toStdString().c_str());
1206             break;
1207           }
1208
1209           case DBF_FieldType_Integer:
1210           {
1211             stat = DBFWriteIntegerAttribute(hDBF, (int)i, 0, theAttrV[i].myIntVal);
1212             break;
1213           }
1214
1215           case DBF_FieldType_Double:
1216           {
1217             stat = DBFWriteDoubleAttribute(hDBF, (int)i, 0, theAttrV[i].myDoubleVal);
1218             break;
1219           }
1220           default:
1221             break;
1222         }
1223       else
1224         stat = DBFWriteNULLAttribute(hDBF, (int)i, 0 );
1225
1226       if (stat != 1)
1227       {
1228         DBFClose( hDBF );
1229         return false;
1230       }
1231     }
1232   }
1233
1234   DBFClose( hDBF );
1235   return true;
1236
1237 }
1238