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