Salome HOME
Use discretization to write non-linear borders of LCM to SHP file // p.4
[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 <Handle_Geom_Curve.hxx>
39 #include <Handle_Geom_Line.hxx>
40 #include <Handle_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
60 #ifdef WIN32
61   #pragma warning( disable: 4996 )
62 #endif
63
64 //SHP->TFaces (Import) 
65 #define OSD_TIMER
66
67 HYDROData_ShapeFile::HYDROData_ShapeFile() : myHSHP(NULL)
68
69 }
70
71 HYDROData_ShapeFile::~HYDROData_ShapeFile()
72 {
73   Free();
74 }
75
76 void HYDROData_ShapeFile::Export(const QString& aFileName, 
77   NCollection_Sequence<Handle_HYDROData_PolylineXY> aPolyXYSeq,
78   NCollection_Sequence<Handle_HYDROData_Polyline3D> aPoly3DSeq,
79   QStringList& aNonExpList)
80 {
81   SHPHandle hSHPHandle;
82   if (!aPolyXYSeq.IsEmpty() && aPoly3DSeq.IsEmpty())
83   {
84     hSHPHandle = SHPCreate( aFileName.toAscii().data(), SHPT_ARC );        
85     for (int i = 1; i <= aPolyXYSeq.Size(); i++)
86       if (WriteObjectPolyXY(hSHPHandle, aPolyXYSeq(i)) != 1)
87         aNonExpList.append(aPolyXYSeq(i)->GetName());
88   }
89   else if (aPolyXYSeq.IsEmpty() && !aPoly3DSeq.IsEmpty())
90   {
91     hSHPHandle = SHPCreate( aFileName.toAscii().data(), SHPT_ARCZ );
92     for (int i = 1; i <= aPoly3DSeq.Size(); i++)
93       if (WriteObjectPoly3D(hSHPHandle, aPoly3DSeq(i)) != 1)
94         aNonExpList.append(aPoly3DSeq(i)->GetName());
95   }
96   if (hSHPHandle->nRecords > 0)
97     SHPClose( hSHPHandle );
98   else
99   {
100     SHPClose( hSHPHandle );
101     QString aFN = aFileName.simplified();
102     remove (aFN.toStdString().c_str());
103     remove ((aFN.simplified().replace( aFN.simplified().size() - 4, 4, ".shx")).toStdString().c_str());
104   }
105 }
106
107 void HYDROData_ShapeFile::Export(const QString& aFileName, const Handle_HYDROData_LandCoverMap& aLCM, 
108                                  QStringList& aNonExpList, bool bCheckLinear, bool bUseDiscr, double theDefl)
109 {
110   if (bCheckLinear && !aLCM->CheckLinear())
111     return;
112   //
113   SHPHandle hSHPHandle;
114   if ( !aLCM.IsNull() && !aLCM->IsEmpty())
115   {
116     hSHPHandle = SHPCreate( aFileName.toAscii().data(), SHPT_POLYGON );
117     HYDROData_LandCoverMap::Explorer It( aLCM );
118     for( ; It.More(); It.Next())
119     {
120       TopoDS_Face aFace = It.Face();
121       if (WriteObjectPolygon(hSHPHandle, aFace, bUseDiscr, theDefl) != 1)
122         aNonExpList.append(aLCM->GetName() + "_" +  QString::number(It.Index()));
123     }
124   }
125   if (hSHPHandle->nRecords > 0)
126     SHPClose( hSHPHandle );
127   else
128   {
129     SHPClose( hSHPHandle );
130     QString aFN = aFileName.simplified();
131     remove (aFN.toStdString().c_str());
132     remove ((aFN.simplified().replace( aFN.simplified().size() - 4, 4, ".shx")).toStdString().c_str());
133   }
134 }
135
136
137 int HYDROData_ShapeFile::WriteObjectPolyXY(SHPHandle theShpHandle, Handle_HYDROData_PolylineXY thePoly )
138 {
139   SHPObject     *aSHPObj;
140   std::vector<double> x, y;
141   std::vector<int> anPartStart;
142   
143   for (int i = 0; i < thePoly->NbSections(); i++)    
144     if (thePoly->GetSectionType(i) == HYDROData_IPolyline::SECTION_SPLINE)
145       return -1;
146
147   for (int i = 0; i < thePoly->NbSections(); i++)
148   {
149     anPartStart.push_back(x.size());
150     HYDROData_PolylineXY::PointsList aPointList = thePoly->GetPoints(i);
151     for (int j = 1; j <= aPointList.Size(); j++)
152     {
153       x.push_back( aPointList(j).X());
154       y.push_back( aPointList(j).Y()); 
155     }
156     if (thePoly->IsClosedSection(i))
157     {
158       x.push_back( aPointList(1).X());
159       y.push_back( aPointList(1).Y()); 
160     }
161   }
162     
163   aSHPObj = SHPCreateObject( SHPT_ARC, -1, thePoly->NbSections(), &anPartStart[0], NULL, x.size(), &x[0], &y[0], NULL, NULL );
164   SHPWriteObject( theShpHandle, -1, aSHPObj );
165   SHPDestroyObject( aSHPObj );
166   return 1;
167 }
168
169 int HYDROData_ShapeFile::WriteObjectPoly3D(SHPHandle theShpHandle, Handle_HYDROData_Polyline3D thePoly )
170 {
171   SHPObject     *aSHPObj;
172   std::vector<double> x, y, z;
173   std::vector<int> anPartStart;
174
175   for (int i = 0; i < thePoly->GetPolylineXY()->NbSections(); i++)    
176     if (thePoly->GetPolylineXY()->GetSectionType(i) == HYDROData_IPolyline::SECTION_SPLINE)
177       return -1;
178   
179   for (int i = 0; i < thePoly->GetPolylineXY()->NbSections(); i++)
180   {
181     anPartStart.push_back(x.size());
182     HYDROData_PolylineXY::PointsList aPointList = thePoly->GetPolylineXY()->GetPoints(i);
183     for (int j = 1; j <= aPointList.Size(); j++)
184     {
185       x.push_back( aPointList(j).X());
186       y.push_back( aPointList(j).Y()); 
187       z.push_back(thePoly->GetAltitudeObject()->GetAltitudeForPoint(gp_XY (aPointList(j).X(), aPointList(j).Y())));
188     }
189     if ( thePoly->GetPolylineXY()->IsClosedSection(i))
190     {
191       x.push_back( aPointList(1).X());
192       y.push_back( aPointList(1).Y()); 
193       z.push_back(thePoly->GetAltitudeObject()->GetAltitudeForPoint(gp_XY (aPointList(1).X(), aPointList(1).Y())));
194
195     }
196   }
197   
198   aSHPObj = SHPCreateObject( SHPT_ARCZ, -1, thePoly->GetPolylineXY()->NbSections(), &anPartStart[0], NULL, x.size(), &x[0], &y[0], &z[0], NULL );
199   SHPWriteObject( theShpHandle, -1, aSHPObj );
200   SHPDestroyObject( aSHPObj );
201   return 1;
202 }
203
204 int HYDROData_ShapeFile::WriteObjectPolygon(SHPHandle theShpHandle, const TopoDS_Shape& theInputShape,
205                                             bool bUseDiscr, double theDefl)
206 {
207   if (theInputShape.IsNull())
208     return 0;
209
210   if (theInputShape.ShapeType() == TopAbs_FACE)
211   {
212     ProcessFace(TopoDS::Face(theInputShape), theShpHandle, bUseDiscr, theDefl);
213   }
214   else if (theInputShape.ShapeType() == TopAbs_COMPOUND)
215   {
216     TopExp_Explorer Ex(theInputShape, TopAbs_FACE);
217     for (; Ex.More(); Ex.Next()) 
218     {
219       TopoDS_Face aF = TopoDS::Face(Ex.Current());   
220       if (aF.IsNull())
221         continue;
222       ProcessFace(aF, theShpHandle, bUseDiscr, theDefl);
223     }
224   }
225   else
226     return 0;
227
228   return 1;
229  
230 }
231
232 void HYDROData_ShapeFile::ProcessFace(const TopoDS_Face& theFace, SHPHandle theShpHandle,
233                                       bool bUseDiscr, double theDefl )
234 {
235   if (theFace.ShapeType() != TopAbs_FACE)
236      return;
237   SHPObject     *aSHPObj;
238   std::vector<double> x, y;
239   std::vector<int> anPartStart;
240   TopoDS_Wire OuterW = BRepTools::OuterWire(theFace);
241   NCollection_Sequence<TopoDS_Wire> aWires;
242
243   //write an outer wire first
244   aWires.Append(OuterW); 
245   TopExp_Explorer Ex(theFace, TopAbs_WIRE);  
246   for (; Ex.More(); Ex.Next()) 
247   {
248     TopoDS_Wire aW = TopoDS::Wire(Ex.Current());
249     if (aW.IsEqual(OuterW))
250       continue;
251     aWires.Append(aW); 
252   }
253
254   int NbWires = 0;
255   for (int k = 1; k <= aWires.Length(); k++) 
256   {
257     TopoDS_Wire aW = aWires(k);   
258     if (aW.IsNull())
259       continue;
260     NbWires++;
261     if (aW.Orientation() == TopAbs_INTERNAL)
262       //cant write internal wires/edges
263       continue; 
264     // Try to reorder edges
265     Handle(ShapeFix_Wire) aSFW = new ShapeFix_Wire( aW, theFace, Precision::Confusion() );
266     aSFW->ModifyTopologyMode() = Standard_False;
267     aSFW->ModifyGeometryMode() = Standard_False;
268     aSFW->FixReorder();
269     Handle(ShapeExtend_WireData) aSEWD = aSFW->WireData();
270     Standard_Integer nbE = aSEWD->NbEdges();
271     if (nbE == 0)
272       continue;
273     //
274     anPartStart.push_back(x.size());
275     NCollection_Sequence<gp_Pnt2d> aPnts;
276     for (Standard_Integer i = 1; i <= nbE; i++)
277     {
278       TopoDS_Edge E = aSEWD->Edge(i);
279       if (!bUseDiscr)
280       {
281         TopoDS_Vertex aV = TopExp::LastVertex(E, 1);
282         if (aV.IsNull())
283           continue;
284         gp_Pnt P = BRep_Tool::Pnt(aV);
285         aPnts.Append(gp_Pnt2d(P.X(), P.Y()));
286       }
287       else
288       {
289         BRepAdaptor_Curve Cur( E );
290         GCPnts_QuasiUniformDeflection Discr( Cur, theDefl );
291         if( !Discr.IsDone() )
292           continue; //skip edge?
293         double NewDefl = theDefl/2.0;
294         while (Discr.NbPoints() < 2)
295         {
296           Discr.Initialize(Cur, NewDefl);
297           NewDefl = NewDefl/2.0;
298         }
299         //
300         if (E.Orientation() == TopAbs_FORWARD)
301         {
302           for( int i = 1; i <= Discr.NbPoints(); i++ )
303           {
304             gp_Pnt P = Discr.Value( i );
305             aPnts.Append(gp_Pnt2d(P.X(), P.Y()));
306           }
307         }
308         else
309         {
310           for( int i = Discr.NbPoints(); i > 0; i-- )
311           {
312             gp_Pnt P = Discr.Value( i );
313             aPnts.Append(gp_Pnt2d(P.X(), P.Y()));
314           }
315         }
316       }
317     }
318     NCollection_Sequence<gp_Pnt2d> aNPnts;
319     aNPnts.Append(aPnts.First());
320     for (int j = 1; j <= aPnts.Size() - 1; j++)
321     {
322       if (!aPnts(j).IsEqual(aPnts(j + 1), Precision::Confusion())) 
323         aNPnts.Append(aPnts(j + 1));
324     }
325
326     //assume that the orientation of external wire & internal wires is correct
327     //so just write all points "as-is"
328     //External wire will be written in clockwise direction
329     //any other wires (holes) - in anticlockwise direction
330     for (int j = 1; j <= aNPnts.Size(); j++)
331     { 
332       x.push_back( aNPnts(j).X());
333       y.push_back( aNPnts(j).Y()); 
334     }
335     //first point is same as the last one => closed polygon
336     x.push_back( aNPnts(1).X());
337     y.push_back( aNPnts(1).Y()); 
338
339   }
340   
341   aSHPObj = SHPCreateObject( SHPT_POLYGON, -1, NbWires, &anPartStart[0], NULL, x.size(), &x[0], &y[0], NULL, NULL );
342   SHPWriteObject( theShpHandle, -1, aSHPObj );
343   SHPDestroyObject( aSHPObj );
344
345 }
346
347 bool HYDROData_ShapeFile::Parse(SHPHandle theHandle, ShapeType theType, int& theShapeTypeOfFile)
348 {
349   int aShapeType;
350   mySHPObjects.clear();
351   SHPGetInfo( theHandle, NULL, &aShapeType, NULL, NULL );
352   theShapeTypeOfFile = aShapeType;
353   bool ToRead = (theType == ShapeType_Polyline && (aShapeType == 3 || aShapeType == 13 || aShapeType == 23)) ||
354    (theType == ShapeType_Polygon && aShapeType == 5);
355   if (ToRead) 
356   {
357     for (int i = 0; i < theHandle->nRecords; i++) 
358       mySHPObjects.push_back(SHPReadObject(theHandle, i));
359     return true;
360   }
361   else
362     return false;
363 }
364
365 void HYDROData_ShapeFile::ReadSHPPolygon(SHPObject* anObj, int i, TopoDS_Face& F)
366 {
367   if (!anObj)
368     return;
369   TopoDS_Wire W;
370   TopoDS_Edge E; 
371   int nParts = anObj->nParts;
372   gp_Pln pln(gp_Pnt(0,0,0), gp_Dir(0,0,1));
373
374   TopTools_SequenceOfShape aWires;
375   for ( int i = 0 ; i < nParts ; i++ )
376   { 
377     BRepBuilderAPI_MakeWire aBuilder;
378     int StartIndex = anObj->panPartStart[i];
379     int EndIndex;
380     if (i != nParts - 1)
381       EndIndex = anObj->panPartStart[i + 1];
382     else
383       EndIndex = anObj->nVertices;
384
385     NCollection_List<TopoDS_Vertex> aVertices;
386     gp_Pnt FP (anObj->padfX[StartIndex], anObj->padfY[StartIndex], 0);
387     TopoDS_Vertex V = BRepLib_MakeVertex(FP).Vertex();
388     aVertices.Append(V);
389       
390     for ( int k = StartIndex + 1; k < EndIndex; k++ )
391     {
392       gp_Pnt P1 (anObj->padfX[k - 1], anObj->padfY[k-1], 0); //prev point
393       gp_Pnt P2 (anObj->padfX[k], anObj->padfY[k], 0); //current point
394       if (P1.Distance(P2) < Precision::Confusion())
395         continue;
396       TopoDS_Vertex V = BRepLib_MakeVertex(P2).Vertex();
397       Handle_Geom_TrimmedCurve aTC = GC_MakeSegment(P1,P2).Value();
398       TopoDS_Edge E = BRepLib_MakeEdge(aTC, aVertices.Last(), V).Edge();
399       aVertices.Append(V);
400       aBuilder.Add(E);
401     }
402     
403     aBuilder.Build();
404     W = TopoDS::Wire(aBuilder.Shape());
405     W.Orientation(TopAbs_FORWARD);
406     BRepBuilderAPI_MakeFace aDB(pln, W);
407     TopoDS_Face aDummyFace = TopoDS::Face(aDB.Shape());
408     BRepTopAdaptor_FClass2d FClass(aDummyFace, Precision::PConfusion());
409     if ( i == 0 && FClass.PerformInfinitePoint() != TopAbs_OUT) 
410       W.Reverse();
411     if ( i > 0 && FClass.PerformInfinitePoint() != TopAbs_IN) 
412       W.Reverse();
413    
414     aWires.Append(W);
415   }
416   
417   BRepBuilderAPI_MakeFace aFBuilder(pln, TopoDS::Wire(aWires(1)));
418   for (int i = 2; i <= aWires.Length(); i++)
419     aFBuilder.Add(TopoDS::Wire(aWires(i)));
420   F = TopoDS::Face(aFBuilder.Shape());
421
422 }
423
424 int HYDROData_ShapeFile::ImportPolygons(const QString theFileName, QStringList& thePolygonsList, TopTools_SequenceOfShape& theFaces, int& theShapeTypeOfFile)
425 {
426   Free();
427   int Stat = TryOpenShapeFile(theFileName);
428   if (Stat != 0)
429     return Stat;
430   myHSHP = SHPOpen( theFileName.toAscii().data(), "rb" );
431   if (!Parse(myHSHP, HYDROData_ShapeFile::ShapeType_Polygon, theShapeTypeOfFile))
432     return 0;
433   for (size_t i = 0; i < mySHPObjects.size(); i++)
434     thePolygonsList.append("polygon_" + QString::number(i + 1));
435    
436   TopoDS_Face aF;
437   if (myHSHP->nShapeType == 5)
438   {
439 #ifdef OSD_TIMER
440     OSD_Timer timer;
441     timer.Start();
442 #endif
443     for (size_t i = 0; i < mySHPObjects.size(); i++) 
444     {
445        ReadSHPPolygon(mySHPObjects[i], i, aF);
446        theFaces.Append(aF);
447     }
448 #ifdef OSD_TIMER
449     timer.Stop();
450     timer.Show();
451 #endif
452     return 1;
453   }
454   else
455     return 0;
456 }
457
458 void HYDROData_ShapeFile::Free()
459 {  
460   for (size_t i = 0; i < mySHPObjects.size(); i++ )
461     free (mySHPObjects[i]);
462
463   mySHPObjects.clear();
464   if (myHSHP != NULL)
465   {
466     SHPClose(myHSHP);
467     myHSHP = NULL; 
468   }
469 }
470
471
472 void HYDROData_ShapeFile::ReadSHPPolyXY(Handle(HYDROData_Document) theDocument, SHPObject* anObj, QString theFileName, 
473   int theInd, NCollection_Sequence<Handle_HYDROData_Entity>& theEntities)
474 {
475
476   Handle(HYDROData_PolylineXY) aPolylineXY = Handle(HYDROData_PolylineXY)::DownCast( theDocument->CreateObject( KIND_POLYLINEXY ) );
477   
478   int nParts = anObj->nParts;
479   for ( int i = 0 ; i < nParts ; i++ )
480   {
481     int StartIndex = anObj->panPartStart[i];
482     int EndIndex;
483     if (i != nParts - 1)
484       EndIndex = anObj->panPartStart[i + 1];
485     else
486       EndIndex = anObj->nVertices;
487
488     bool IsClosed = false;
489     HYDROData_PolylineXY::SectionType aSectType = HYDROData_PolylineXY::SECTION_POLYLINE; 
490     if (anObj->padfX[StartIndex] == anObj->padfX[EndIndex - 1] &&
491         anObj->padfY[StartIndex] == anObj->padfY[EndIndex - 1] )
492     {
493       IsClosed = true;
494       aPolylineXY->AddSection( TCollection_AsciiString( ("poly_section_" + QString::number(i)).data()->toAscii()), aSectType, true);
495     }
496     else
497       aPolylineXY->AddSection( TCollection_AsciiString( ("poly_section_" + QString::number(i)).data()->toAscii()), aSectType, false);
498     
499     if (IsClosed)
500       EndIndex--;
501     for ( int k = StartIndex; k < EndIndex ; k++ )
502     {
503       HYDROData_PolylineXY::Point aSectPoint;
504       aSectPoint.SetX( anObj->padfX[k] );
505       aSectPoint.SetY( anObj->padfY[k] );
506       aPolylineXY->AddPoint( i, aSectPoint );
507     }
508
509   }
510   
511   aPolylineXY->SetWireColor( HYDROData_PolylineXY::DefaultWireColor() );
512   aPolylineXY->SetName( theFileName + "_PolyXY_" + QString::number(theInd) );
513   
514   aPolylineXY->Update();
515   theEntities.Append(aPolylineXY);
516
517 }
518
519 void HYDROData_ShapeFile::ReadSHPPoly3D(Handle(HYDROData_Document) theDocument, SHPObject* anObj, QString theFileName, 
520   int theInd, NCollection_Sequence<Handle_HYDROData_Entity>& theEntities)
521 {
522   Handle(HYDROData_PolylineXY) aPolylineXY = Handle(HYDROData_PolylineXY)::DownCast( theDocument->CreateObject( KIND_POLYLINEXY ) );
523
524   Handle(HYDROData_Polyline3D) aPolylineObj = Handle(HYDROData_Polyline3D)::DownCast( theDocument->CreateObject( KIND_POLYLINE ) );
525
526   Handle(HYDROData_Bathymetry) aBath = Handle(HYDROData_Bathymetry)::DownCast( theDocument->CreateObject( KIND_BATHYMETRY ) );
527   HYDROData_Bathymetry::AltitudePoints aAPoints;
528
529   int nParts = anObj->nParts;
530   for ( int i = 0 ; i < nParts ; i++ )
531   {
532     //bool aSectClosure = true;
533     int StartIndex = anObj->panPartStart[i];
534     int EndIndex;
535     if (i != nParts - 1)
536       EndIndex = anObj->panPartStart[i + 1];
537     else
538       EndIndex = anObj->nVertices;
539
540     bool IsClosed = false;
541     HYDROData_PolylineXY::SectionType aSectType = HYDROData_PolylineXY::SECTION_POLYLINE; 
542     if (anObj->padfX[StartIndex] == anObj->padfX[EndIndex - 1] &&
543         anObj->padfY[StartIndex] == anObj->padfY[EndIndex - 1] &&
544         anObj->padfZ[StartIndex] == anObj->padfZ[EndIndex - 1])
545     {
546       IsClosed = true;
547       aPolylineXY->AddSection( TCollection_AsciiString( ("poly_section_" + QString::number(i)).data()->toAscii()), aSectType, true );
548     }
549     else
550       aPolylineXY->AddSection( TCollection_AsciiString( ("poly_section_" + QString::number(i)).data()->toAscii()), aSectType, false  );
551     
552     if (IsClosed)
553       EndIndex--;
554     for ( int k = StartIndex ; k < EndIndex ; k++ )
555     {
556       HYDROData_PolylineXY::Point aSectPoint;
557       aSectPoint.SetX( anObj->padfX[k] );
558       aSectPoint.SetY( anObj->padfY[k] );
559       aPolylineXY->AddPoint( i, aSectPoint );
560       aAPoints.Append(gp_XYZ (anObj->padfX[k], anObj->padfY[k], anObj->padfZ[k]));
561     }
562   }
563
564
565   QString aBathName = theFileName + "_bath_" + QString::number(theInd);
566   QString aPolyXYName = theFileName + "_polyXY_" + QString::number(theInd);
567   QString aPoly3DName = theFileName + "_poly3D_" + QString::number(theInd);
568
569   aPolylineXY->SetName( aPolyXYName );
570   aPolylineXY->SetWireColor(HYDROData_PolylineXY::DefaultWireColor());
571   aPolylineXY->Update();
572   
573   aBath->SetAltitudePoints(aAPoints);
574   aBath->SetName( aBathName );
575
576   aPolylineObj->SetPolylineXY (aPolylineXY, false);
577   aPolylineObj->SetAltitudeObject(aBath);
578
579   aPolylineObj->SetBorderColor( aPolylineObj->DefaultBorderColor() );
580   aPolylineObj->SetName( aPoly3DName );
581   
582   aPolylineObj->Update();
583   theEntities.Append(aPolylineXY);
584   theEntities.Append(aPolylineObj);
585
586 }
587
588
589
590 int HYDROData_ShapeFile::ImportPolylines(Handle(HYDROData_Document) theDocument, const QString& theFileName, 
591   NCollection_Sequence<Handle_HYDROData_Entity>& theEntities, int& theShapeTypeOfFile)
592 {
593   //Free();
594   int aStat = TryOpenShapeFile(theFileName);
595   if (aStat != 0)
596     return aStat;
597
598   HYDROData_Iterator anIter( theDocument );
599   int anInd = 0;
600   QStringList anExistingNames;
601   std::vector<int> anAllowedIndexes;
602   for( ; anIter.More(); anIter.Next() )
603     anExistingNames.push_back(anIter.Current()->GetName());
604
605   SHPHandle aHSHP;
606   aHSHP = SHPOpen( theFileName.toAscii().data(), "rb" );
607   
608   QFileInfo aFileInfo(theFileName);
609   QString aBaseFileName = aFileInfo.baseName();
610
611   if (!Parse(aHSHP, HYDROData_ShapeFile::ShapeType_Polyline, theShapeTypeOfFile))
612     return 0;
613   if (aHSHP->nShapeType == 3 || aHSHP->nShapeType == 23)
614   {
615     anInd = 0;
616     for (;anAllowedIndexes.size() < mySHPObjects.size();)
617     {
618       if (!anExistingNames.contains(aBaseFileName + "_PolyXY_" + QString::number(anInd)))
619       {
620         anAllowedIndexes.push_back(anInd);
621         anInd++;
622       }
623       else
624         anInd++;
625     }
626     
627     for (size_t i = 0; i < mySHPObjects.size(); i++ )
628     {
629       ReadSHPPolyXY(theDocument, mySHPObjects[i], aBaseFileName, anAllowedIndexes[i], theEntities);
630     }
631     aStat = 1;
632   }
633   else if (aHSHP->nShapeType == 13)
634   {
635     anInd = 0;
636     for (;anAllowedIndexes.size() < mySHPObjects.size();)
637     {
638       if (!anExistingNames.contains(aBaseFileName + "_PolyXY_" + QString::number(anInd)) &&
639           !anExistingNames.contains(aBaseFileName + "_Poly3D_" + QString::number(anInd)) &&
640           !anExistingNames.contains(aBaseFileName + "_Bath_" + QString::number(anInd)))
641       {
642         anAllowedIndexes.push_back(anInd);
643         anInd++;
644       }
645       else
646         anInd++;
647     }
648     for (size_t i = 0; i < mySHPObjects.size(); i++ )
649       ReadSHPPoly3D(theDocument, mySHPObjects[i], aBaseFileName, anAllowedIndexes[i], theEntities);
650     aStat = 1;
651   }
652   else  
653   {
654     aStat = 0;
655   }
656   
657   for (size_t i = 0; i < mySHPObjects.size(); i++ )
658     free (mySHPObjects[i]);
659
660   mySHPObjects.clear();
661   SHPClose(aHSHP);
662   return aStat;
663 }
664
665 QString HYDROData_ShapeFile::GetShapeTypeName(int theType)
666 {
667   switch (theType)
668   {
669     case 0:
670       return "null shape";
671     case 1:
672       return "point (unsupported by HYDRO)";
673     case 3:
674       return "arc/polyline (supported by HYDRO)";
675     case 5:
676       return "polygon (supported by HYDRO)";
677     case 8:
678       return "multipoint (unsupported by HYDRO)";
679     case 11:
680       return "pointZ (unsupported by HYDRO)";
681     case 13:
682       return "arcZ/polyline (supported by HYDRO)";
683     case 15:
684       return "polygonZ (unsupported by HYDRO)";
685     case 18:
686       return "multipointZ (unsupported by HYDRO)";
687     case 21:
688       return "pointM (unsupported by HYDRO)";
689     case 23:
690       return "arcM/polyline (supported by HYDRO)";
691     case 25:
692       return "polygonM (unsupported by HYDRO)";
693     case 28:
694       return "multipointM (unsupported by HYDRO)";
695     case 31:
696       return "multipatch (unsupported by HYDRO)";
697     default:
698       return "unknown";
699   }
700 }
701
702 int HYDROData_ShapeFile::TryOpenShapeFile(QString theFileName)
703 {
704   QString aSHPfile = theFileName.simplified();
705   QString aSHXfile = theFileName.simplified().replace( theFileName.simplified().size() - 4, 4, ".shx");
706   FILE* pFileSHP = NULL;
707   pFileSHP = fopen (aSHPfile.toAscii().data(), "r");
708   FILE* pFileSHX = NULL;
709   pFileSHX = fopen (aSHXfile.toAscii().data(), "r");
710
711   if (pFileSHP == NULL || pFileSHX == NULL)
712   {
713     if (pFileSHP == NULL)
714       return -1;
715     if (pFileSHX == NULL)
716       return -2;
717   }
718   
719   fclose (pFileSHP);
720   fclose (pFileSHX);
721   return 0;
722 }
723
724
725 bool HYDROData_ShapeFile::CheckDBFFileExisting(const QString& theSHPFilePath, QString& thePathToDBFFile)
726 {
727   QString aSHPfile = theSHPFilePath.simplified();
728   QString aDBFfile = theSHPFilePath.simplified().replace( theSHPFilePath.simplified().size() - 4, 4, ".dbf");
729   FILE* pFileDBF = NULL;
730   pFileDBF = fopen (aDBFfile.toAscii().data(), "r");
731
732   if (pFileDBF == NULL)
733   {
734     return false;
735   }
736   
737   fclose (pFileDBF);
738   thePathToDBFFile = aDBFfile;
739   return true;
740 }
741
742
743 bool HYDROData_ShapeFile::DBF_OpenDBF(const QString& thePathToDBFFile)
744 {
745   myHDBF = DBFOpen( thePathToDBFFile.toAscii().data(), "r" );
746   if(myHDBF != NULL)
747     return true;
748   else
749     return false;
750 }
751
752 int HYDROData_ShapeFile::DBF_GetNbFields()
753 {
754   if(myHDBF == NULL)
755     return 0;
756   return DBFGetFieldCount(myHDBF);
757 }
758
759 void HYDROData_ShapeFile::DBF_CloseDBF()
760 {
761   if(myHDBF != NULL)
762      DBFClose( myHDBF );
763 }
764
765 QStringList HYDROData_ShapeFile::DBF_GetFieldList()
766 {
767   QStringList FieldList;
768   int   nWidth, nDecimals;
769   char chField[12];
770
771   for( int i = 0; i < DBFGetFieldCount(myHDBF); i++ )
772   {
773       DBFFieldType eType;
774       eType = DBFGetFieldInfo( myHDBF, i, chField, &nWidth, &nDecimals );
775       FieldList.append(QString(chField));
776   }
777
778   return FieldList;
779 }
780
781 void HYDROData_ShapeFile::DBF_GetFieldTypeList(std::vector<DBF_FieldType>& FTVect)
782 {
783   int   nWidth, nDecimals;
784   char chField[12];
785   DBF_FieldType FT;
786   for( int i = 0; i < DBFGetFieldCount(myHDBF); i++ )
787   {
788     DBFFieldType eType;
789     eType = DBFGetFieldInfo( myHDBF, i, chField, &nWidth, &nDecimals );
790     if( eType == FTString )
791       FT = DBF_FieldType_String;
792     else if( eType == FTInteger )
793       FT = DBF_FieldType_Integer;
794     else if( eType == FTDouble )
795       FT = DBF_FieldType_Double;
796     else if( eType == FTInvalid )
797       FT = DBF_FieldType_Invalid;
798
799     FTVect.push_back(FT);
800   }
801
802 }
803
804 int HYDROData_ShapeFile::DBF_GetNbRecords()
805 {
806   if(myHDBF == NULL)
807     return 0;
808   return DBFGetRecordCount(myHDBF);
809 }
810
811 void HYDROData_ShapeFile::DBF_GetAttributeList(int theIndexOfField, std::vector<DBF_AttrValue>& theAttrV)
812 {
813   int nWidth, nDecimals;
814   char chField[12];
815   
816   for( int i = 0; i < DBFGetRecordCount(myHDBF); i++ )
817   {      
818     DBFFieldType eType;
819     DBF_AttrValue anAttr;
820     eType = DBFGetFieldInfo( myHDBF, theIndexOfField, chField, &nWidth, &nDecimals );
821
822     if( DBFIsAttributeNULL( myHDBF, i, theIndexOfField ) )
823     {
824       anAttr.myIsNull = true;
825       DBF_FieldType FT = DBF_FieldType_None;
826       if( eType == FTString )
827         FT = DBF_FieldType_String;
828       else if( eType == FTInteger )
829         FT = DBF_FieldType_Integer;
830       else if( eType == FTDouble )
831         FT = DBF_FieldType_Double;
832       else if( eType == FTInvalid )
833         FT = DBF_FieldType_Invalid;
834       anAttr.myFieldType = FT;
835     }
836     else
837     {
838       switch( eType )
839       {
840         case FTString:
841         {
842           const char* chAttr = DBFReadStringAttribute( myHDBF, i, theIndexOfField );
843           anAttr.myIsNull = false;
844           anAttr.myFieldType = DBF_FieldType_String;
845           anAttr.myRawValue = chAttr;
846           anAttr.myStrVal = QString(chAttr);
847           break;
848         }
849        
850         case FTInteger:
851         {
852           int iAttr = DBFReadIntegerAttribute( myHDBF, i, theIndexOfField );
853           anAttr.myIsNull = false;
854           anAttr.myFieldType = DBF_FieldType_Integer;
855           anAttr.myRawValue = DBFReadStringAttribute( myHDBF, i, theIndexOfField );
856           anAttr.myIntVal = iAttr;
857           break;
858         }
859           
860         case FTDouble:
861         {
862           double dAttr = DBFReadDoubleAttribute( myHDBF, i, theIndexOfField );
863           anAttr.myIsNull = false;
864           anAttr.myFieldType = DBF_FieldType_Double;
865           anAttr.myRawValue = DBFReadStringAttribute( myHDBF, i, theIndexOfField );
866           anAttr.myDoubleVal = dAttr;
867           break;
868         }
869         default:
870           break;
871       }
872     }
873     theAttrV.push_back(anAttr);
874   }
875
876 }
877
878 bool HYDROData_ShapeFile::DBF_WriteFieldAndValues(const QString& theFileName, const QString& theFieldName, DBF_FieldType theType, const std::vector<DBF_AttrValue>& theAttrV, bool bUseRawValue)
879 {
880   // Check that given field type is equal to field types of attributes values
881   for (size_t i = 0; i < theAttrV.size(); i++)
882   {
883     if (theAttrV[i].myFieldType != theType)
884       return false;
885   }
886
887   DBFHandle     hDBF;
888   hDBF = DBFCreate( theFileName.toStdString().c_str() );
889   if( hDBF == NULL )
890           return false;
891   
892   if (theType != DBF_FieldType_String && theType != DBF_FieldType_Integer && theType != DBF_FieldType_Double) 
893   {
894     DBFClose( hDBF );
895     return false; //cant handle any other cases
896   }
897
898   int nWidth = 20;
899   switch( theType )
900   {
901     case DBF_FieldType_String:
902     {
903       DBFAddField (hDBF, theFieldName.toStdString().c_str(), FTString, nWidth, 0);
904       break;
905     }
906    
907     case DBF_FieldType_Integer:
908     {
909       DBFAddField (hDBF, theFieldName.toStdString().c_str(), FTInteger, nWidth, 0);
910       break;
911     }
912       
913     case DBF_FieldType_Double:
914     {
915       DBFAddField (hDBF, theFieldName.toStdString().c_str(), FTDouble, nWidth, 0);
916       break;
917     }
918     default:
919       break;
920   }
921
922   if (DBFGetFieldCount( hDBF ) != 1) 
923   {
924     DBFClose( hDBF );
925     return false;
926   }
927   if (DBFGetRecordCount( hDBF ) != 0)
928   {
929     DBFClose( hDBF );
930     return false;
931   }
932   int stat = -1;
933
934   if (bUseRawValue)
935   {
936     for (size_t i = 0; i < theAttrV.size(); i++)
937     {
938       if (!theAttrV[i].myIsNull)
939         stat = DBFWriteStringAttribute(hDBF, (int)i, 0, theAttrV[i].myRawValue.c_str());
940       else
941         stat = DBFWriteNULLAttribute(hDBF, (int)i, 0 );
942
943       if (stat != 1)
944       {
945         DBFClose( hDBF );
946         return false;
947       }
948     }
949   }
950   else
951   {
952     for (size_t i = 0; i < theAttrV.size(); i++)
953     {
954       if (!theAttrV[i].myIsNull)
955         switch( theType )
956         {
957           case DBF_FieldType_String:
958           {
959             stat = DBFWriteStringAttribute(hDBF, (int)i, 0, theAttrV[i].myStrVal.toStdString().c_str());
960             break;
961           }
962          
963           case DBF_FieldType_Integer:
964           {
965             stat = DBFWriteIntegerAttribute(hDBF, (int)i, 0, theAttrV[i].myIntVal);
966             break;
967           }
968             
969           case DBF_FieldType_Double:
970           {
971             stat = DBFWriteDoubleAttribute(hDBF, (int)i, 0, theAttrV[i].myDoubleVal);
972             break;
973           }
974           default:
975             break;
976         }
977       else
978         stat = DBFWriteNULLAttribute(hDBF, (int)i, 0 );
979
980       if (stat != 1)
981       {
982         DBFClose( hDBF );
983         return false;
984       }
985     }
986   }
987
988   DBFClose( hDBF );
989   return true;
990
991 }
992