Procházet zdrojové kódy

Refactor project setup (part 1)

Johannes Kreutz před 3 roky
rodič
revize
b255346a69

+ 11 - 9
trackpoint-app/CMakeLists.txt

@@ -1,21 +1,23 @@
-CMAKE_MINIMUM_REQUIRED(VERSION 2.6)
-PROJECT(osgExample)
+CMAKE_MINIMUM_REQUIRED(VERSION 3.10)
+PROJECT(TrackpointApp VERSION 0.1)
 
-FIND_PACKAGE(OpenSceneGraph REQUIRED COMPONENTS osgViewer osgDB osgGA osgText osgUtil)
+CONFIGURE_FILE(trackpointapp.hpp.in trackpointapp.hpp)
+
+set(CMAKE_CXX_STANDARD 17)
+set(CMAKE_CXX_STANDARD_REQUIRED True)
 
-SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
+FIND_PACKAGE(OpenSceneGraph REQUIRED COMPONENTS osgViewer osgDB osgGA osgText osgUtil)
 
 INCLUDE_DIRECTORIES(
     ${OPENSCENEGRAPH_INCLUDE_DIRS}
 )
 
-ADD_EXECUTABLE(osgExample main.cpp)
-ADD_EXECUTABLE(osgTransform transforms.cpp)
+ADD_EXECUTABLE(TrackpointApp main.cpp)
 
-TARGET_LINK_LIBRARIES(osgExample
+TARGET_LINK_LIBRARIES(TrackpointApp
     ${OPENSCENEGRAPH_LIBRARIES}
 )
 
-TARGET_LINK_LIBRARIES(osgTransform
-    ${OPENSCENEGRAPH_LIBRARIES}
+TARGET_INCLUDE_DIRECTORIES(TrackpointApp PUBLIC
+    "${PROJECT_BINARY_DIR}"
 )

+ 277 - 30
trackpoint-app/main.cpp

@@ -1,42 +1,289 @@
-#include <osg/Referenced>
-#include <osg/Geometry>
-#include <osg/Geode>
-#include <osg/Array>
 #include <osgViewer/Viewer>
+#include <osg/ShapeDrawable>
+#include <osg/Geode>
+#include <osgDB/ReadFile>
+#include <osg/Group>
+#include <osg/Switch>
+#include <osg/MatrixTransform>
+#include <osg/Matrix>
+#include <osgGA/TrackballManipulator>
+#include <osgUtil/LineSegmentIntersector>
+#include <osgUtil/IntersectionVisitor>
+#include <osg/PolygonMode>
+#include <vector>
+#include <iostream>
+#include <fstream>
+#include <string>
+#include <math.h>
+
+const char* openScadBase =
+  "$fn = 100;\n"
+  "module optiTrackPointBase(translation, rotation) {\n"
+  "translate(translation) rotate(rotation) cylinder(10, 1, 1, false);\n"
+  "}\n";
+
+class TrackPoint {
+public:
+  TrackPoint(osg::Vec3 point, osg::Vec3 normal);
+  osg::ref_ptr<osg::MatrixTransform> getUppermostRoot();
+  osg::Vec3 getTranslation();
+  osg::Vec3 getRotation();
+
+protected:
+  osg::ref_ptr<osg::MatrixTransform> _translationGroup;
+  osg::ref_ptr<osg::MatrixTransform> _rotationGroup;
+  osg::ref_ptr<osg::MatrixTransform> _originFixGroup;
+
+private:
+  osg::Vec3 _origin;
+  osg::Vec3 _normal;
+  osg::Vec3 _trackOrigin;
+};
+
+TrackPoint::TrackPoint(osg::Vec3 point, osg::Vec3 normal) {
+  osg::ref_ptr<osg::Geode> geode = new osg::Geode;
+  osg::ref_ptr<osg::ShapeDrawable> cylinder = new osg::ShapeDrawable();
+  cylinder->setShape(new osg::Cylinder(osg::Vec3(0.0f, 0.0f, 0.0f), 1.0f, 10.0f));
+  cylinder->setColor(osg::Vec4(0.0f, 1.0f, 0.0f, 1.0f));
+  geode->addDrawable(cylinder.get());
+
+  _rotationGroup = new osg::MatrixTransform;
+  _rotationGroup->addChild(geode.get());
+  _rotationGroup->setMatrix(osg::Matrix::rotate(osg::Vec3f(0.0f, 0.0f, 1.0f), normal));
+
+  _originFixGroup = new osg::MatrixTransform;
+  _originFixGroup->addChild(_rotationGroup.get());
+  osg::Vec3f movementVector = normal.operator*(5.0f);
+  _originFixGroup->setMatrix(osg::Matrix::translate(movementVector));
+
+  _translationGroup = new osg::MatrixTransform;
+  _translationGroup->addChild(_originFixGroup.get());
+  _translationGroup->setMatrix(osg::Matrix::translate(point));
+
+  _origin = point;
+  _normal = normal;
+
+  osg::Vec3 shift = normal.operator*(10.0f);
+  _trackOrigin = shift.operator+(point);
+  printf("TrackPoint is at %lf %lf %lf\n", _trackOrigin.x(), _trackOrigin.y(), _trackOrigin.z());
+}
+
+osg::ref_ptr<osg::MatrixTransform> TrackPoint::getUppermostRoot() {
+  return _translationGroup.get();
+}
+
+osg::Vec3 TrackPoint::getTranslation() {
+  return _origin;
+}
+
+osg::Vec3 TrackPoint::getRotation() {
+  printf("YNorm: %lf %lf %lf\n", _normal.x(), _normal.y(), _normal.z());
+
+  osg::Vec3 start = osg::Vec3(0.0f, 0.0f, 1.0f);
+
+  // From https://en.wikipedia.org/wiki/Conversion_between_quaternions_and_Euler_angles
+  osg::Quat quat = osg::Quat(0.0f, 0.0f, 0.0f, 0.0f);
+  quat.makeRotate(start, _normal);
+
+  float sinr_cosp = 2 * (quat.w() * quat.x() + quat.y() * quat.z());
+  float cosr_cosp = 1 - 2 * (quat.x() * quat.x() + quat.y() * quat.y());
+  float xRotation = std::atan2(sinr_cosp, cosr_cosp) * 180.0 / M_PI;
+
+  float sinp = 2 * (quat.w() * quat.y() - quat.z() * quat.x());
+  float yRotation;
+  if (std::abs(sinp) >= 1) {
+    yRotation = std::copysign(M_PI / 2, sinp) * 180.0 / M_PI;
+  } else {
+    yRotation = std::asin(sinp) * 180.0 / M_PI;
+  }
+
+  float siny_cosp = 2 * (quat.w() * quat.z() + quat.x() * quat.y());
+  float cosy_cosp = 1 - 2 * (quat.y() * quat.y() + quat.z() * quat.z());
+  float zRotation = std::atan2(siny_cosp, cosy_cosp) * 180.0 / M_PI;
+
+  return osg::Vec3(xRotation, yRotation, zRotation);
+}
+
+class OpenScadRenderer {
+public:
+  void render(std::vector<TrackPoint*> points);
+};
+
+void OpenScadRenderer::render(std::vector<TrackPoint*> points) {
+  std::ofstream scadFile;
+  scadFile.open("/tmp/output.scad");
+  scadFile << openScadBase;
+  scadFile << "import(\"testbutton.stl\");\n";
+  for (TrackPoint* point: points) {
+    osg::Vec3 translation = point->getTranslation();
+    osg::Vec3 rotation = point->getRotation();
+    scadFile << "optiTrackPointBase([" << translation.x() << "," << translation.y() << "," << translation.z() << "], [" << rotation.x() << "," << rotation.y() << "," << rotation.z() << "]);\n";
+  }
+  scadFile.close();
+  system("openscad -o /tmp/output.stl /tmp/output.scad");
+}
+
+class StoreHandler {
+public:
+  void addTrackingPoint(osg::Vec3 point, osg::Vec3 normal);
+  StoreHandler(osg::ref_ptr<osg::Group> root);
+  std::vector<TrackPoint*> getPoints();
+
+protected:
+  std::vector<TrackPoint*> points;
+
+private:
+  osg::ref_ptr<osg::Group> _root;
+};
+
+void StoreHandler::addTrackingPoint(osg::Vec3 point, osg::Vec3 normal) {
+  TrackPoint* trackPoint = new TrackPoint(point, normal);
+  points.push_back(trackPoint);
+  _root->addChild(trackPoint->getUppermostRoot());
+}
+
+StoreHandler::StoreHandler(osg::ref_ptr<osg::Group> root) {
+  _root = root;
+}
+
+std::vector<TrackPoint*> StoreHandler::getPoints() {
+  return points;
+}
+
+StoreHandler* storeHandler;
+OpenScadRenderer* openScadRenderer;
+osg::ref_ptr<osg::Node> axesNode;
 
-int main(int argc, char** argv)
-{
-    // Create the geometry which will define the triangle
-    osg::ref_ptr<osg::Geometry> myTriangleGeometry = new osg::Geometry;
+class PickHandler: public osgGA::GUIEventHandler {
+public:
+  osg::Node* getOrCreateSelectionCylinder();
+  virtual bool handle(const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa);
+  void moveTo(osg::Vec3f position);
+  void rotateToNormalVector(osg::Vec3f normal);
+  void setVisibility(bool mode);
 
-    // Define the triangle's 3 vertices
-    osg::ref_ptr<osg::Vec3Array> vertices = new osg::Vec3Array;
-    vertices->push_back(osg::Vec3(0, 0, 0));
-    vertices->push_back(osg::Vec3(100, 0, 0));
-    vertices->push_back(osg::Vec3(0, 0, 100));
-    myTriangleGeometry->setVertexArray(vertices);
+protected:
+  osg::ref_ptr<osg::Switch> _selectionSwitch;
+  osg::ref_ptr<osg::MatrixTransform> _selectionTranslateGroup;
+  osg::ref_ptr<osg::MatrixTransform> _selectionRotateGroup;
+  osg::ref_ptr<osg::MatrixTransform> _selectionMoveToEndGroup;
+  bool isSelection = false;
+};
 
-    // You can give each vertex its own color, but let's just make it green for now
-    osg::ref_ptr<osg::Vec4Array> colors = new osg::Vec4Array;
-    colors->push_back(osg::Vec4(0, 1.0, 0, 1.0)); // RGBA for green
-    myTriangleGeometry->setColorArray(colors);
-    myTriangleGeometry->setColorBinding(osg::Geometry::BIND_OVERALL);
+osg::Node* PickHandler::getOrCreateSelectionCylinder() {
+  if (!_selectionTranslateGroup) {
+    osg::ref_ptr<osg::Geode> geode = new osg::Geode;
+    osg::ref_ptr<osg::ShapeDrawable> cylinder = new osg::ShapeDrawable();
+    cylinder->setShape(new osg::Cylinder(osg::Vec3(0.0f, 0.0f, 0.0f), 1.0f, 10.0f));
+    cylinder->setColor(osg::Vec4(1.0f, 0.0f, 0.0f, 0.2f));
+    geode->addDrawable(cylinder.get());
 
-    // Turn off lighting
-    myTriangleGeometry->getOrCreateStateSet()->setMode(GL_LIGHTING, osg::StateAttribute::OFF);
+    _selectionRotateGroup = new osg::MatrixTransform;
+    _selectionRotateGroup->addChild(geode.get());
 
-    // Turn on blending
-    myTriangleGeometry->getOrCreateStateSet()->setMode(GL_BLEND, osg::StateAttribute::ON);
+    _selectionMoveToEndGroup = new osg::MatrixTransform;
+    _selectionMoveToEndGroup->addChild(_selectionRotateGroup.get());
 
-    // Define the geometry type as 'triangles'
-    myTriangleGeometry->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::TRIANGLES, 0, vertices->size()));
+    _selectionTranslateGroup = new osg::MatrixTransform;
+    _selectionTranslateGroup->addChild(_selectionMoveToEndGroup.get());
 
-    // Finally, let's add our triangle to a geode
-    osg::ref_ptr<osg::Geode> myGeode = new osg::Geode;
-    myGeode->addDrawable(myTriangleGeometry);
+    _selectionSwitch = new osg::Switch;
+    _selectionSwitch->addChild(_selectionTranslateGroup.get());
+  }
+  return _selectionSwitch.get();
+}
+
+bool PickHandler::handle(const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa) {
+  if (ea.getModKeyMask()&osgGA::GUIEventAdapter::MODKEY_CTRL) {
+    isSelection = !isSelection;
+    setVisibility(false);
+  }
+  if (ea.getEventType() == osgGA::GUIEventAdapter::RELEASE && ea.getButton() == osgGA::GUIEventAdapter::LEFT_MOUSE_BUTTON && isSelection) {
+    osgViewer::Viewer* viewer = dynamic_cast<osgViewer::Viewer*>(&aa);
+    if (viewer) {
+      osg::ref_ptr<osgUtil::LineSegmentIntersector> intersector = new osgUtil::LineSegmentIntersector(osgUtil::Intersector::WINDOW, ea.getX(), ea.getY());
+      osgUtil::IntersectionVisitor iv(intersector.get());
+      iv.setTraversalMask(~0x1);
+      viewer->getCamera()->accept(iv);
+      if (intersector->containsIntersections()) {
+        for (const osgUtil::LineSegmentIntersector::Intersection result: intersector->getIntersections()) {
+          if (std::find(result.nodePath.begin(), result.nodePath.end(), axesNode) != result.nodePath.end()) {
+            moveTo(result.localIntersectionPoint);
+            rotateToNormalVector(result.localIntersectionNormal);
+            storeHandler->addTrackingPoint(result.localIntersectionPoint, result.localIntersectionNormal);
+            openScadRenderer->render(storeHandler->getPoints());
+            break;
+          }
+        }
+      }
+    }
+  }
+  if (ea.getEventType() == osgGA::GUIEventAdapter::MOVE && isSelection) {
+    osgViewer::Viewer* viewer = dynamic_cast<osgViewer::Viewer*>(&aa);
+    if (viewer) {
+      osg::ref_ptr<osgUtil::LineSegmentIntersector> intersector = new osgUtil::LineSegmentIntersector(osgUtil::Intersector::WINDOW, ea.getX(), ea.getY());
+      osgUtil::IntersectionVisitor iv(intersector.get());
+      iv.setTraversalMask(~0x1);
+      viewer->getCamera()->accept(iv);
+      if (intersector->containsIntersections()) {
+        for (const osgUtil::LineSegmentIntersector::Intersection result: intersector->getIntersections()) {
+          if (std::find(result.nodePath.begin(), result.nodePath.end(), axesNode) != result.nodePath.end()) {
+            moveTo(result.localIntersectionPoint);
+            rotateToNormalVector(result.localIntersectionNormal);
+            setVisibility(true);
+            break;
+          }
+        }
+      } else {
+        setVisibility(false);
+      }
+    }
+  }
+  return false;
+}
 
-    // And now we can create a viewer to look at our geode
+void PickHandler::moveTo(osg::Vec3f position) {
+  _selectionTranslateGroup->setMatrix(osg::Matrix::translate(position));
+}
+
+void PickHandler::rotateToNormalVector(osg::Vec3f normal) {
+  _selectionRotateGroup->setMatrix(osg::Matrix::rotate(osg::Vec3f(0.0f, 0.0f, 1.0f), normal));
+  osg::Vec3f movementVector = normal.operator*(5.0f);
+  _selectionMoveToEndGroup->setMatrix(osg::Matrix::translate(movementVector));
+}
+
+void PickHandler::setVisibility(bool mode) {
+  _selectionSwitch->setValue(0, mode);
+}
+
+int main(int argc, char** argv) {
+    // Root node of the scene
+    osg::ref_ptr<osg::Group> root = new osg::Group;
+
+    // Create the viewer
     osgViewer::Viewer viewer;
-    viewer.setSceneData(myGeode);
+    viewer.setSceneData(root);
+    viewer.realize();
+
+    // Add axesNode under root
+    axesNode = osgDB::readNodeFile("../../testdata/testbutton.stl");
+    if (!axesNode) {
+        printf("Origin node not loaded, model not found\n");
+        return 1;
+    }
+    root->addChild(axesNode);
+
+    // Attach a manipulator (it's usually done for us when we use viewer.run())
+    osg::ref_ptr<osgGA::TrackballManipulator> tm = new osgGA::TrackballManipulator;
+    viewer.setCameraManipulator(tm);
+
+    storeHandler = new StoreHandler(root);
+    openScadRenderer = new OpenScadRenderer();
+
+    osg::ref_ptr<PickHandler> picker = new PickHandler();
+    root->addChild(picker->getOrCreateSelectionCylinder());
+
+    viewer.addEventHandler(picker.get());
+
     return viewer.run();
 }

+ 3 - 0
trackpoint-app/trackpointapp.hpp.in

@@ -0,0 +1,3 @@
+// the configured options and settings for TrackpointApp
+#define TrackpointApp_VERSION_MAJOR @TrackpointApp_VERSION_MAJOR_VERSION_MAJOR@
+#define TrackpointApp_VERSION_MAJOR_VERSION_MINOR @TrackpointApp_VERSION_MAJOR_VERSION_MINOR@

+ 0 - 289
trackpoint-app/transforms.cpp

@@ -1,289 +0,0 @@
-#include <osgViewer/Viewer>
-#include <osg/ShapeDrawable>
-#include <osg/Geode>
-#include <osgDB/ReadFile>
-#include <osg/Group>
-#include <osg/Switch>
-#include <osg/MatrixTransform>
-#include <osg/Matrix>
-#include <osgGA/TrackballManipulator>
-#include <osgUtil/LineSegmentIntersector>
-#include <osgUtil/IntersectionVisitor>
-#include <osg/PolygonMode>
-#include <vector>
-#include <iostream>
-#include <fstream>
-#include <string>
-#include <math.h>
-
-const char* openScadBase =
-  "$fn = 100;\n"
-  "module optiTrackPointBase(translation, rotation) {\n"
-  "translate(translation) rotate(rotation) cylinder(10, 1, 1, false);\n"
-  "}\n";
-
-class TrackPoint {
-public:
-  TrackPoint(osg::Vec3 point, osg::Vec3 normal);
-  osg::ref_ptr<osg::MatrixTransform> getUppermostRoot();
-  osg::Vec3 getTranslation();
-  osg::Vec3 getRotation();
-
-protected:
-  osg::ref_ptr<osg::MatrixTransform> _translationGroup;
-  osg::ref_ptr<osg::MatrixTransform> _rotationGroup;
-  osg::ref_ptr<osg::MatrixTransform> _originFixGroup;
-
-private:
-  osg::Vec3 _origin;
-  osg::Vec3 _normal;
-  osg::Vec3 _trackOrigin;
-};
-
-TrackPoint::TrackPoint(osg::Vec3 point, osg::Vec3 normal) {
-  osg::ref_ptr<osg::Geode> geode = new osg::Geode;
-  osg::ref_ptr<osg::ShapeDrawable> cylinder = new osg::ShapeDrawable();
-  cylinder->setShape(new osg::Cylinder(osg::Vec3(0.0f, 0.0f, 0.0f), 1.0f, 10.0f));
-  cylinder->setColor(osg::Vec4(0.0f, 1.0f, 0.0f, 1.0f));
-  geode->addDrawable(cylinder.get());
-
-  _rotationGroup = new osg::MatrixTransform;
-  _rotationGroup->addChild(geode.get());
-  _rotationGroup->setMatrix(osg::Matrix::rotate(osg::Vec3f(0.0f, 0.0f, 1.0f), normal));
-
-  _originFixGroup = new osg::MatrixTransform;
-  _originFixGroup->addChild(_rotationGroup.get());
-  osg::Vec3f movementVector = normal.operator*(5.0f);
-  _originFixGroup->setMatrix(osg::Matrix::translate(movementVector));
-
-  _translationGroup = new osg::MatrixTransform;
-  _translationGroup->addChild(_originFixGroup.get());
-  _translationGroup->setMatrix(osg::Matrix::translate(point));
-
-  _origin = point;
-  _normal = normal;
-
-  osg::Vec3 shift = normal.operator*(10.0f);
-  _trackOrigin = shift.operator+(point);
-  printf("TrackPoint is at %lf %lf %lf\n", _trackOrigin.x(), _trackOrigin.y(), _trackOrigin.z());
-}
-
-osg::ref_ptr<osg::MatrixTransform> TrackPoint::getUppermostRoot() {
-  return _translationGroup.get();
-}
-
-osg::Vec3 TrackPoint::getTranslation() {
-  return _origin;
-}
-
-osg::Vec3 TrackPoint::getRotation() {
-  printf("YNorm: %lf %lf %lf\n", _normal.x(), _normal.y(), _normal.z());
-
-  osg::Vec3 start = osg::Vec3(0.0f, 0.0f, 1.0f);
-
-  // From https://en.wikipedia.org/wiki/Conversion_between_quaternions_and_Euler_angles
-  osg::Quat quat = osg::Quat(0.0f, 0.0f, 0.0f, 0.0f);
-  quat.makeRotate(start, _normal);
-
-  float sinr_cosp = 2 * (quat.w() * quat.x() + quat.y() * quat.z());
-  float cosr_cosp = 1 - 2 * (quat.x() * quat.x() + quat.y() * quat.y());
-  float xRotation = std::atan2(sinr_cosp, cosr_cosp) * 180.0 / M_PI;
-
-  float sinp = 2 * (quat.w() * quat.y() - quat.z() * quat.x());
-  float yRotation;
-  if (std::abs(sinp) >= 1) {
-    yRotation = std::copysign(M_PI / 2, sinp) * 180.0 / M_PI;
-  } else {
-    yRotation = std::asin(sinp) * 180.0 / M_PI;
-  }
-
-  float siny_cosp = 2 * (quat.w() * quat.z() + quat.x() * quat.y());
-  float cosy_cosp = 1 - 2 * (quat.y() * quat.y() + quat.z() * quat.z());
-  float zRotation = std::atan2(siny_cosp, cosy_cosp) * 180.0 / M_PI;
-
-  return osg::Vec3(xRotation, yRotation, zRotation);
-}
-
-class OpenScadRenderer {
-public:
-  void render(std::vector<TrackPoint*> points);
-};
-
-void OpenScadRenderer::render(std::vector<TrackPoint*> points) {
-  std::ofstream scadFile;
-  scadFile.open("/tmp/output.scad");
-  scadFile << openScadBase;
-  scadFile << "import(\"testbutton.stl\");\n";
-  for (TrackPoint* point: points) {
-    osg::Vec3 translation = point->getTranslation();
-    osg::Vec3 rotation = point->getRotation();
-    scadFile << "optiTrackPointBase([" << translation.x() << "," << translation.y() << "," << translation.z() << "], [" << rotation.x() << "," << rotation.y() << "," << rotation.z() << "]);\n";
-  }
-  scadFile.close();
-  system("openscad -o /tmp/output.stl /tmp/output.scad");
-}
-
-class StoreHandler {
-public:
-  void addTrackingPoint(osg::Vec3 point, osg::Vec3 normal);
-  StoreHandler(osg::ref_ptr<osg::Group> root);
-  std::vector<TrackPoint*> getPoints();
-
-protected:
-  std::vector<TrackPoint*> points;
-
-private:
-  osg::ref_ptr<osg::Group> _root;
-};
-
-void StoreHandler::addTrackingPoint(osg::Vec3 point, osg::Vec3 normal) {
-  TrackPoint* trackPoint = new TrackPoint(point, normal);
-  points.push_back(trackPoint);
-  _root->addChild(trackPoint->getUppermostRoot());
-}
-
-StoreHandler::StoreHandler(osg::ref_ptr<osg::Group> root) {
-  _root = root;
-}
-
-std::vector<TrackPoint*> StoreHandler::getPoints() {
-  return points;
-}
-
-StoreHandler* storeHandler;
-OpenScadRenderer* openScadRenderer;
-osg::ref_ptr<osg::Node> axesNode;
-
-class PickHandler: public osgGA::GUIEventHandler {
-public:
-  osg::Node* getOrCreateSelectionCylinder();
-  virtual bool handle(const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa);
-  void moveTo(osg::Vec3f position);
-  void rotateToNormalVector(osg::Vec3f normal);
-  void setVisibility(bool mode);
-
-protected:
-  osg::ref_ptr<osg::Switch> _selectionSwitch;
-  osg::ref_ptr<osg::MatrixTransform> _selectionTranslateGroup;
-  osg::ref_ptr<osg::MatrixTransform> _selectionRotateGroup;
-  osg::ref_ptr<osg::MatrixTransform> _selectionMoveToEndGroup;
-  bool isSelection = false;
-};
-
-osg::Node* PickHandler::getOrCreateSelectionCylinder() {
-  if (!_selectionTranslateGroup) {
-    osg::ref_ptr<osg::Geode> geode = new osg::Geode;
-    osg::ref_ptr<osg::ShapeDrawable> cylinder = new osg::ShapeDrawable();
-    cylinder->setShape(new osg::Cylinder(osg::Vec3(0.0f, 0.0f, 0.0f), 1.0f, 10.0f));
-    cylinder->setColor(osg::Vec4(1.0f, 0.0f, 0.0f, 0.2f));
-    geode->addDrawable(cylinder.get());
-
-    _selectionRotateGroup = new osg::MatrixTransform;
-    _selectionRotateGroup->addChild(geode.get());
-
-    _selectionMoveToEndGroup = new osg::MatrixTransform;
-    _selectionMoveToEndGroup->addChild(_selectionRotateGroup.get());
-
-    _selectionTranslateGroup = new osg::MatrixTransform;
-    _selectionTranslateGroup->addChild(_selectionMoveToEndGroup.get());
-
-    _selectionSwitch = new osg::Switch;
-    _selectionSwitch->addChild(_selectionTranslateGroup.get());
-  }
-  return _selectionSwitch.get();
-}
-
-bool PickHandler::handle(const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa) {
-  if (ea.getModKeyMask()&osgGA::GUIEventAdapter::MODKEY_CTRL) {
-    isSelection = !isSelection;
-    setVisibility(false);
-  }
-  if (ea.getEventType() == osgGA::GUIEventAdapter::RELEASE && ea.getButton() == osgGA::GUIEventAdapter::LEFT_MOUSE_BUTTON && isSelection) {
-    osgViewer::Viewer* viewer = dynamic_cast<osgViewer::Viewer*>(&aa);
-    if (viewer) {
-      osg::ref_ptr<osgUtil::LineSegmentIntersector> intersector = new osgUtil::LineSegmentIntersector(osgUtil::Intersector::WINDOW, ea.getX(), ea.getY());
-      osgUtil::IntersectionVisitor iv(intersector.get());
-      iv.setTraversalMask(~0x1);
-      viewer->getCamera()->accept(iv);
-      if (intersector->containsIntersections()) {
-        for (const osgUtil::LineSegmentIntersector::Intersection result: intersector->getIntersections()) {
-          if (std::find(result.nodePath.begin(), result.nodePath.end(), axesNode) != result.nodePath.end()) {
-            moveTo(result.localIntersectionPoint);
-            rotateToNormalVector(result.localIntersectionNormal);
-            storeHandler->addTrackingPoint(result.localIntersectionPoint, result.localIntersectionNormal);
-            openScadRenderer->render(storeHandler->getPoints());
-            break;
-          }
-        }
-      }
-    }
-  }
-  if (ea.getEventType() == osgGA::GUIEventAdapter::MOVE && isSelection) {
-    osgViewer::Viewer* viewer = dynamic_cast<osgViewer::Viewer*>(&aa);
-    if (viewer) {
-      osg::ref_ptr<osgUtil::LineSegmentIntersector> intersector = new osgUtil::LineSegmentIntersector(osgUtil::Intersector::WINDOW, ea.getX(), ea.getY());
-      osgUtil::IntersectionVisitor iv(intersector.get());
-      iv.setTraversalMask(~0x1);
-      viewer->getCamera()->accept(iv);
-      if (intersector->containsIntersections()) {
-        for (const osgUtil::LineSegmentIntersector::Intersection result: intersector->getIntersections()) {
-          if (std::find(result.nodePath.begin(), result.nodePath.end(), axesNode) != result.nodePath.end()) {
-            moveTo(result.localIntersectionPoint);
-            rotateToNormalVector(result.localIntersectionNormal);
-            setVisibility(true);
-            break;
-          }
-        }
-      } else {
-        setVisibility(false);
-      }
-    }
-  }
-  return false;
-}
-
-void PickHandler::moveTo(osg::Vec3f position) {
-  _selectionTranslateGroup->setMatrix(osg::Matrix::translate(position));
-}
-
-void PickHandler::rotateToNormalVector(osg::Vec3f normal) {
-  _selectionRotateGroup->setMatrix(osg::Matrix::rotate(osg::Vec3f(0.0f, 0.0f, 1.0f), normal));
-  osg::Vec3f movementVector = normal.operator*(5.0f);
-  _selectionMoveToEndGroup->setMatrix(osg::Matrix::translate(movementVector));
-}
-
-void PickHandler::setVisibility(bool mode) {
-  _selectionSwitch->setValue(0, mode);
-}
-
-int main(int argc, char** argv) {
-    // Root node of the scene
-    osg::ref_ptr<osg::Group> root = new osg::Group;
-
-    // Create the viewer
-    osgViewer::Viewer viewer;
-    viewer.setSceneData(root);
-    viewer.realize();
-
-    // Add axesNode under root
-    axesNode = osgDB::readNodeFile("../../testdata/testbutton.stl");
-    if (!axesNode) {
-        printf("Origin node not loaded, model not found\n");
-        return 1;
-    }
-    root->addChild(axesNode);
-
-    // Attach a manipulator (it's usually done for us when we use viewer.run())
-    osg::ref_ptr<osgGA::TrackballManipulator> tm = new osgGA::TrackballManipulator;
-    viewer.setCameraManipulator(tm);
-
-    storeHandler = new StoreHandler(root);
-    openScadRenderer = new OpenScadRenderer();
-
-    osg::ref_ptr<PickHandler> picker = new PickHandler();
-    root->addChild(picker->getOrCreateSelectionCylinder());
-
-    viewer.addEventHandler(picker.get());
-
-    return viewer.run();
-}