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