Salome HOME
updated copyright message
[modules/shaper.git] / src / GeomAlgoAPI / GeomAlgoAPI_ShapeInfo.cpp
1 // Copyright (C) 2014-2023  CEA, EDF
2 //
3 // This library is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU Lesser General Public
5 // License as published by the Free Software Foundation; either
6 // version 2.1 of the License, or (at your option) any later version.
7 //
8 // This library is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11 // Lesser General Public License for more details.
12 //
13 // You should have received a copy of the GNU Lesser General Public
14 // License along with this library; if not, write to the Free Software
15 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
16 //
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
18 //
19
20 #include "GeomAlgoAPI_ShapeInfo.h"
21 #include "GeomAlgoAPI_BoundingBox.h"
22
23 #include <GeomAPI_Circ.h>
24 #include <GeomAPI_Ellipse.h>
25 #include <GeomAPI_Wire.h>
26 #include <GeomAPI_Pln.h>
27 #include <GeomAPI_Sphere.h>
28 #include <GeomAPI_Cone.h>
29 #include <GeomAPI_Cylinder.h>
30 #include <GeomAPI_Torus.h>
31 #include <GeomAPI_Shell.h>
32 #include <GeomAPI_Box.h>
33
34 #include <Precision.hxx>
35
36 #include <sstream>
37
38 std::string GeomAlgoAPI_ShapeInfo::html(Translator* theTranslator)
39 {
40   Values aVal(TYPE_HTML);
41   if (theTranslator)
42     aVal.setTranslator(theTranslator);
43   processShape(aVal);
44   return aVal.html();
45 }
46
47 std::list<GeomAlgoAPI_InfoValue> GeomAlgoAPI_ShapeInfo::values()
48 {
49   Values aVal(TYPE_VALS);
50   processShape(aVal);
51   return aVal.values();
52 }
53
54 void GeomAlgoAPI_ShapeInfo::processShape(GeomAlgoAPI_ShapeInfo::Values& theVals)
55 {
56   switch (myShape->shapeType()) {
57   case GeomAPI_Shape::VERTEX:
58   {
59     GeomPointPtr aPoint = myShape->vertex()->point();
60     setShapeType("Vertex");
61     theVals.addPoint("Coordinates", myShape->vertex()->point());
62     break;
63   }
64   case GeomAPI_Shape::EDGE:
65   {
66     GeomEdgePtr anEdge = myShape->edge();
67     processEdge(theVals, anEdge);
68     break;
69   }
70   case GeomAPI_Shape::FACE:
71   {
72     GeomFacePtr aFace = myShape->face();
73     processFace(theVals, aFace);
74     break;
75   }
76   case GeomAPI_Shape::SOLID: // nearly same as SHELL if it is only one sub
77   {
78     ListOfShape aShells = myShape->subShapes(GeomAPI_Shape::SHELL);
79     if (aShells.size() == 1)
80     {
81       GeomShapePtr aTmpShape = myShape;
82       myShape = aShells.front();
83       processShape(theVals);
84       myShape = aTmpShape;
85     }
86     if (myShapeType.empty() || myShapeType == "Shell")
87       setShapeType("Solid");
88     break;
89   }
90   case GeomAPI_Shape::SHELL:
91   {
92     GeomShellPtr aShell = myShape->shell();
93     if (GeomBoxPtr aBox = aShell->getParallelepiped())
94     {
95       if (aBox->isAxesAligned()) {
96         setShapeType("Box");
97       }
98       else {
99         setShapeType("Rotated Box");
100       }
101     }
102     else { // check single face
103       ListOfShape aFaces = myShape->subShapes(GeomAPI_Shape::FACE);
104       if (aFaces.size() == 1)
105       {
106         GeomFacePtr aFace = aFaces.front()->face();
107         processFace(theVals, aFace);
108       }
109       if (myShapeType.empty() || myShapeType == "Face")
110         setShapeType("Shell");
111     }
112     break;
113   }
114   case GeomAPI_Shape::WIRE:
115   {
116     theVals.addNamedValue("Closed", myShape->wire()->isClosed());
117
118     // check the wire is a polygon
119     std::list<GeomPointPtr> aPolygonPoints;
120     if (myShape->wire()->isPolygon(aPolygonPoints)) {
121       setShapeType("Polygon");
122       std::string aPointTr = theVals.translator()->translate("Point");
123       std::list<GeomPointPtr>::const_iterator aPtIt = aPolygonPoints.begin();
124       for (int aCornerIndex = 0; aPtIt != aPolygonPoints.end(); ++aPtIt) {
125         std::ostringstream aStr;
126         aStr << " " << (++aCornerIndex);
127         theVals.addPoint(aStr.str().c_str(), *aPtIt);
128       }
129     }
130     else // Common case
131       setShapeType("Wire");
132     break;
133   }
134   case GeomAPI_Shape::COMPSOLID:
135   case GeomAPI_Shape::COMPOUND:
136   {
137     setShapeType(myShape->shapeType() == GeomAPI_Shape::COMPSOLID ? "CompSolid" : "Compound");
138     double aXmin, aYmin, aZmin, aXmax, aYmax, aZmax;
139     if (myShape->computeSize(aXmin, aYmin, aZmin, aXmax, aYmax, aZmax))
140     {
141       theVals.addGroupName("Bounding box");
142       GeomPointPtr aMinPoint(new GeomAPI_Pnt(aXmin, aYmin, aZmin));
143       theVals.addPoint("Minimal corner", aMinPoint);
144       GeomPointPtr aMaxPoint(new GeomAPI_Pnt(aXmax, aYmax, aZmax));
145       theVals.addPoint("Maximal corner", aMaxPoint);
146     }
147     break;
148   }
149   default: // nothing to fill
150     break;
151   }
152 }
153
154 void GeomAlgoAPI_ShapeInfo::processEdge(Values& theVals, GeomEdgePtr theEdge)
155 {
156   setShapeType("Edge"); // Common case
157   if (theEdge->isDegenerated()) {
158     theVals.addNamedValue("Degenerated", true);
159     return;
160   }
161
162   GeomPointPtr aStartPnt = theEdge->firstPoint();
163   GeomPointPtr aEndPnt = theEdge->lastPoint();
164   bool addStartEndPoints = false;
165
166   if (theEdge->isLine()) {
167     setShapeType("Line segment");
168     addStartEndPoints = true;
169   }
170   else if (GeomCirclePtr aCircle = theEdge->circle()) {
171     addStartEndPoints = aStartPnt->distance(aEndPnt) >= Precision::Confusion();
172     setShapeType(addStartEndPoints ? "Arc of circle" : "Circle");
173     theVals.addPoint("Center", aCircle->center());
174     theVals.addDirection("Normal", aCircle->normal());
175     theVals.addGroupName("Dimensions");
176     theVals.addNamedValue("Radius", aCircle->radius());
177   }
178   else if (GeomEllipsePtr anEllipse = theEdge->ellipse()) {
179     addStartEndPoints = aStartPnt->distance(aEndPnt) >= Precision::Confusion();
180     setShapeType(addStartEndPoints ? "Arc of ellipse" : "Ellipse");
181     theVals.addPoint("Center", anEllipse->center());
182     theVals.addDirection("Normal", anEllipse->normal());
183     theVals.addGroupName("Dimensions");
184     theVals.addNamedValue("Major radius", anEllipse->majorRadius());
185     theVals.addNamedValue("Minor radius", anEllipse->minorRadius());
186   }
187
188   if (addStartEndPoints) {
189     theVals.addPoint("Start point", aStartPnt);
190     theVals.addPoint("End point", aEndPnt);
191   }
192 }
193
194 void GeomAlgoAPI_ShapeInfo::processFace(Values& theVals, GeomFacePtr theFace)
195 {
196   // Plane and planar face
197   if (GeomPlanePtr aPlane = theFace->getPlane()) {
198     bool isCommonCase = true;
199     // Check face bounded by circle or ellipse
200     std::list<GeomShapePtr> aSubs = theFace->subShapes(GeomAPI_Shape::EDGE);
201     if (aSubs.size() == 1) {
202       GeomEdgePtr anEdge = aSubs.front()->edge();
203       if (anEdge->isCircle() || anEdge->isEllipse()) {
204         processEdge(theVals, anEdge);
205         isCommonCase = false;
206         setShapeType("Disk");
207       }
208     }
209     else {
210       // Check face bounded by a single wire which is rectangle
211       aSubs = theFace->subShapes(GeomAPI_Shape::WIRE);
212       if (aSubs.size() == 1) {
213         std::list<GeomPointPtr> aCorners;
214         if (aSubs.front()->wire()->isRectangle(aCorners)) {
215           GeomPointPtr aBaseCorner = aCorners.front();
216           aCorners.pop_front();
217
218           double aWidth = aBaseCorner->distance(aCorners.front());
219           double aHeight = aBaseCorner->distance(aCorners.back());
220
221           setShapeType("Rectangle");
222           theVals.addPoint("Corner", aBaseCorner);
223           theVals.addDirection("Normal", aPlane->direction());
224           theVals.addGroupName("Dimensions");
225           theVals.addNamedValue("Width", aWidth);
226           theVals.addNamedValue("Height", aHeight);
227           isCommonCase = false;
228         }
229       }
230     }
231
232     if (isCommonCase) {
233       setShapeType("Plane");
234       theVals.addPoint("Origin", aPlane->location());
235       theVals.addDirection("Normal", aPlane->direction());
236     }
237   }
238   // Sphere
239   else if (GeomSpherePtr aSphere = theFace->getSphere()) {
240     setShapeType("Sphere");
241     theVals.addPoint("Center", aSphere->center());
242     theVals.addGroupName("Dimensions");
243     theVals.addNamedValue("Radius", aSphere->radius());
244   }
245   // Cylinder
246   else if (GeomCylinderPtr aCylinder = theFace->getCylinder())
247   {
248     setShapeType("Cylinder");
249     theVals.addPoint("Position", aCylinder->location());
250     theVals.addDirection("Axis", aCylinder->axis());
251     theVals.addGroupName("Dimensions");
252     theVals.addNamedValue("Radius", aCylinder->radius());
253     theVals.addNamedValue("Height", aCylinder->height());
254   }
255   // Cone
256   else if (GeomConePtr aCone = theFace->getCone()) {
257     setShapeType("Cone");
258     theVals.addPoint("Position", aCone->location());
259     theVals.addDirection("Axis", aCone->axis());
260     theVals.addGroupName("Dimensions");
261     theVals.addNamedValue("Radius 1", aCone->radius1());
262     theVals.addNamedValue("Radius 2", aCone->radius2());
263     theVals.addNamedValue("Height", aCone->height());
264
265   }
266   // Torus
267   else if (GeomTorusPtr aTorus = theFace->getTorus()) {
268     setShapeType("Torus");
269     theVals.addPoint("Center", aTorus->center());
270     theVals.addDirection("Axis", aTorus->direction());
271     theVals.addGroupName("Dimensions");
272     theVals.addNamedValue("Major radius", aTorus->majorRadius());
273     theVals.addNamedValue("Minor radius", aTorus->minorRadius());
274   }
275   // Common case
276   else
277     setShapeType("Face");
278 }
279
280 GeomAlgoAPI_ShapeInfo::Values::Values(const GeomAlgoAPI_ShapeInfo::InfoType theType)
281   : myType(theType)
282 {
283   static GeomAlgoAPI_ShapeInfo::Translator* kDefaultTr = new GeomAlgoAPI_ShapeInfo::Translator;
284   myTr = kDefaultTr;
285 }
286
287
288 GeomAlgoAPI_ShapeInfo::Values& GeomAlgoAPI_ShapeInfo::Values::operator<< (double theValue)
289 {
290   switch (myType)
291   {
292   case TYPE_HTML:
293   {
294     std::ostringstream aStr;
295     aStr << theValue;
296     myStr += aStr.str();
297     break;
298   }
299   case TYPE_VALS:
300     myVals.push_back(GeomAlgoAPI_InfoValue(theValue));
301     break;
302   }
303   return *this;
304 }
305
306 GeomAlgoAPI_ShapeInfo::Values& GeomAlgoAPI_ShapeInfo::Values::operator << (bool theValue)
307 {
308   switch (myType)
309   {
310   case TYPE_HTML:
311     myStr += myTr->translate(theValue ? "True" : "False");
312     break;
313   case TYPE_VALS:
314     myVals.push_back(GeomAlgoAPI_InfoValue(theValue));
315     break;
316   }
317   return *this;
318 }
319
320 GeomAlgoAPI_ShapeInfo::Values& GeomAlgoAPI_ShapeInfo::Values::operator<< (const char* theStr)
321 {
322   if (myType == TYPE_HTML)
323       myStr += myTr->translate(theStr);
324   return *this;
325 }
326
327 void GeomAlgoAPI_ShapeInfo::Values::addPoint(const char* theTitle, const GeomPointPtr& thePoint)
328 {
329   switch (myType)
330   {
331   case TYPE_HTML:
332   {
333     std::ostringstream aStr;
334     aStr << "<b>" << myTr->translate(theTitle) << "</b>"
335       << "<br> X: " << thePoint->x()
336       << "<br> Y: " << thePoint->y()
337       << "<br> Z: " << thePoint->z() << "<br>";
338     myStr += aStr.str();
339     break;
340   }
341   case TYPE_VALS:
342     myVals.push_back(GeomAlgoAPI_InfoValue(thePoint->x()));
343     myVals.push_back(GeomAlgoAPI_InfoValue(thePoint->y()));
344     myVals.push_back(GeomAlgoAPI_InfoValue(thePoint->z()));
345     break;
346   }
347 }
348
349 void GeomAlgoAPI_ShapeInfo::Values::addDirection(const char* theTitle, const GeomDirPtr& theDir)
350 {
351   switch (myType)
352   {
353   case TYPE_HTML:
354   {
355     std::ostringstream aStr;
356     aStr << "<b>" << myTr->translate(theTitle) << "</b>"
357       << "<br> DX: " << theDir->x()
358       << "<br> DY: " << theDir->y()
359       << "<br> DZ: " << theDir->z() << "<br>";
360     myStr += aStr.str();
361     break;
362   }
363   case TYPE_VALS:
364     myVals.push_back(GeomAlgoAPI_InfoValue(theDir->x()));
365     myVals.push_back(GeomAlgoAPI_InfoValue(theDir->y()));
366     myVals.push_back(GeomAlgoAPI_InfoValue(theDir->z()));
367     break;
368   }
369 }
370
371 void GeomAlgoAPI_ShapeInfo::Values::addNamedValue(const char* theName, const double theValue)
372 {
373   switch (myType)
374   {
375   case TYPE_HTML:
376   {
377     std::ostringstream aStr;
378     aStr << myTr->translate(theName) << ": " << theValue << "<br>";
379     myStr += aStr.str();
380     break;
381   }
382   case TYPE_VALS:
383     *this << theValue; // just value, no name
384     break;
385   }
386 }
387
388 void GeomAlgoAPI_ShapeInfo::Values::addNamedValue(const char* theName, const bool theValue)
389 {
390   switch (myType)
391   {
392   case TYPE_HTML:
393   {
394     std::ostringstream aStr;
395     aStr << myTr->translate(theName) << ": " << (theValue ? "True" : "False") << "<br>";
396     myStr += aStr.str();
397     break;
398   }
399   case TYPE_VALS:
400     *this << theValue; // just value, no name
401     break;
402   }
403 }
404
405 void GeomAlgoAPI_ShapeInfo::Values::addGroupName(const char* theName)
406 {
407   if (myType == TYPE_HTML)
408   {
409     myStr += "<b>" + myTr->translate(theName) + "</b>" + "<br>";
410   }
411 }