]> OCCT Git - occt-copy.git/commitdiff
[ROBINS] Added commands loadlidar and savelidar to load and save LIDAR data as descri...
authorabv <abv@opencascade.com>
Sun, 24 Jun 2018 15:19:12 +0000 (18:19 +0300)
committerabv <abv@opencascade.com>
Fri, 21 Sep 2018 10:52:20 +0000 (13:52 +0300)
src/ViewerTest/ViewerTest_ObjectCommands.cxx

index 2b68f59f99f603afa78e51347c4d2edf2ecf40a1..c8c323d62c29821e2215ae70e27af08d66ac1cc6 100644 (file)
@@ -6248,6 +6248,170 @@ static int VNormals (Draw_Interpretor& theDI,
   return 0;
 }
 
+//=======================================================================
+//function : 
+//=======================================================================
+
+static bool LoadLidarData (const char* theScanFile, const char* thePosFile, std::vector<gp_Pnt>& theResult)
+{
+  FILE* aScanFile = fopen (theScanFile, "rb");
+  if (! aScanFile)
+  {
+    std::cerr << "Error: cannot open " << theScanFile << std::endl;
+    return false;
+  }
+  FILE* aPosFile = fopen (thePosFile, "rb");
+  if (! aPosFile)
+  {
+    fclose (aScanFile);
+    std::cerr << "Error: cannot open " << thePosFile << std::endl;
+    return false;
+  }
+
+  // prepare array of sin & cos values for conversion from polar coordinates 
+  // to cartesian ones; we take X directed along mid-range laser scan
+  const int aNbPointsPerLine = 1081;
+  double aStepDeg = 0.25;
+  double aStartDeg = -90. - 45.;
+  double aSinVal[aNbPointsPerLine], aCosVal[aNbPointsPerLine];
+  for (int i = 0; i < aNbPointsPerLine; i++)
+  {
+    double anAngle = (aStartDeg + i * aStepDeg) * M_PI / 180.;
+    aSinVal[i] = Sin (anAngle);
+    aCosVal[i] = Cos (anAngle);
+  }
+
+  // read both files synchronously
+  for (int nLine = 1; ; nLine++)
+  {
+    char aScanLine[1024 * 100];
+    bool hasScan = (fgets (aScanLine, sizeof(aScanLine), aScanFile) == aScanLine);
+    char aPosLine[1024];
+    bool hasPos = (fgets (aPosLine, sizeof(aPosLine), aPosFile) == aPosLine);
+    if (! hasPos || ! hasScan)
+    {
+      if (hasPos && strlen (aPosLine) > 0)
+        std::cerr << "Warning: Positions file contains more lines than scan file" << std::endl;
+      if (hasScan && strlen (aScanLine) > 0)
+        std::cerr << "Warning: Scan file contains more lines than positions file" << std::endl;
+      break;
+    }
+
+    // parse position line
+    char *aStr = aPosLine, *aNext = 0;
+    double aPosTime = Strtod (aStr, &aNext);
+    if (aNext == aStr)
+    {
+      std::cerr << "Warning: cannot fetch timestamp for position at line " << nLine << std::endl;
+    }
+
+    gp_Trsf aTrsf;
+    double aX = Strtod(aStr = aNext, &aNext);
+    double aY = Strtod(aStr = aNext, &aNext);
+    double aZ = Strtod(aStr = aNext, &aNext);
+    double aA = Strtod(aStr = aNext, &aNext);
+    double aB = Strtod(aStr = aNext, &aNext);
+    double aC = Strtod(aStr = aNext, &aNext);
+    if (aNext == aStr)
+    {
+      std::cerr << "Error: position line " << nLine << " contains less than 7 values, default positiomn will be used" << std::endl;
+    }
+    else {
+      gp_Quaternion aQ;
+//      aQ.SetEulerAngles(gp_Intrinsic_XYZ, aA, aB, aC);
+//      aQ.SetEulerAngles(gp_Intrinsic_ZYX, aA, aB, aC);
+      aQ.SetEulerAngles(gp_Intrinsic_ZYX, aC, aB, aA);
+      aTrsf.SetRotation(aQ);
+      aTrsf.SetTranslationPart(gp_Vec(aX, aY, aZ));
+    }
+
+    // parse scan line
+    aStr = aScanLine;
+    double aScanTime = Strtod (aStr, &aNext);
+    if (aNext == aStr)
+    {
+      std::cerr << "Warning: cannot fetch timestamp for scan line " << nLine << std::endl;
+    }
+    if (aPosTime && aScanTime && Abs (aPosTime - aScanTime) > 0.001)
+    {
+      std::cerr << "Warning: timestamps at scan and position data are differenr at line " << nLine << std::endl;
+      std::cerr << " - position timestamp: " << aPosTime << std::endl;
+      std::cerr << " - scanline timestamp: " << aScanTime << std::endl;
+    }
+
+    for (int i = 0; i < aNbPointsPerLine; i++)
+    {
+      double aDist = Strtod (aStr = aNext, &aNext);
+      if (aNext == aStr)
+      {
+        std::cerr << "Warning: scan line " << nLine << " contains only " << i << " values" << std::endl;
+        break;
+      }
+
+      // skip nans (no value), distances too small (local object on the drone),
+      // and distances greater than maximal valid range of LIDAR
+      if (std::isnan (aDist) || aDist < 0.5 || aDist > 30.)
+        continue;
+
+      // add a point 
+      gp_Pnt aPoint (aDist * aSinVal[i], aDist * aCosVal[i], 0.);
+      theResult.push_back (aPoint.Transformed (aTrsf));
+    }
+    while (IsSpace (*aNext)) aNext++;
+    if (*aNext)
+      std::cerr << "Warning: extra symbols at the end of the scan line " << nLine << std::endl;
+  }
+
+  fclose(aScanFile);
+  fclose(aPosFile);
+  return true;
+}
+
+std::vector<gp_Pnt> aLIDARPoints;
+
+static int LoadLIDAR (Draw_Interpretor& theDI, Standard_Integer  theArgNum, const char** theArgs)
+{
+  aLIDARPoints.clear();
+
+  if (theArgNum < 3)
+  {
+    std::cerr << "Use: " << theArgs[0] << " lidar_data_file positions_file" << std::endl;
+    return 1;
+  }
+
+  if (LoadLidarData (theArgs[1], theArgs[2], aLIDARPoints))
+  {
+    theDI << (int)aLIDARPoints.size() << " points loaded";
+  }
+
+  return 0;
+}
+
+static int SaveLIDAR (Draw_Interpretor& theDI, Standard_Integer  theArgNum, const char** theArgs)
+{
+  if (theArgNum < 2)
+  {
+    std::cerr << "Use: " << theArgs[0] << " ply_data_file " << std::endl;
+    return 1;
+  }
+
+  ofstream aFile (theArgs[1], std::ios_base::out);
+  aFile << "ply\nformat ascii 1.0\n";
+  aFile << "element vertex " << aLIDARPoints.size() << "\n";
+  aFile << "property float x\n";
+  aFile << "property float y\n";
+  aFile << "property float z\n";
+  aFile << "end_header\n";
+  for (unsigned int i = 0; i < aLIDARPoints.size(); i++)
+  {
+    const gp_Pnt& aPnt = aLIDARPoints[i];
+    aFile << aPnt.X() << " " << aPnt.Y() << " " << aPnt.Z() << "\n";
+  }
+  theDI << "Points saved to " << theArgs[1];
+
+  return 0;
+}
+
 //=======================================================================
 //function : ObjectsCommands
 //purpose  :
@@ -6605,4 +6769,7 @@ void ViewerTest::ObjectCommands(Draw_Interpretor& theCommands)
                    "\n\t\t:        [-useMesh] [-oriented {0}1}=0]"
                    "\n\t\t:  Displays/Hides normals calculated on shape geometry or retrieved from triangulation",
                    __FILE__, VNormals, group);
+
+  theCommands.Add ("loadlidar", "loadlidar scan_file positions_file", __FILE__, LoadLIDAR, group);
+  theCommands.Add ("savelidar", "savelidar ply_file", __FILE__, SaveLIDAR, group);
 }