371 lines
10 KiB
C++
371 lines
10 KiB
C++
/*
|
|
* Copyright (C) 2014 Open Source Robotics Foundation
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*
|
|
*/
|
|
|
|
#ifdef _WIN32
|
|
// Ensure that Winsock2.h is included before Windows.h, which can get
|
|
// pulled in by anybody (e.g., Boost).
|
|
#include <Winsock2.h>
|
|
#endif
|
|
|
|
#include "gazebo/transport/transport.hh"
|
|
|
|
#include "gazebo/rendering/RenderTypes.hh"
|
|
#include "gazebo/rendering/RenderEvents.hh"
|
|
#include "gazebo/rendering/RenderingIface.hh"
|
|
#include "gazebo/rendering/Visual.hh"
|
|
#include "gazebo/rendering/Scene.hh"
|
|
#include "gazebo/rendering/UserCamera.hh"
|
|
#include "gazebo/rendering/RayQuery.hh"
|
|
|
|
#include "gazebo/gui/qt.h"
|
|
#include "gazebo/gui/MouseEventHandler.hh"
|
|
#include "gazebo/gui/GuiIface.hh"
|
|
#include "gazebo/gui/GuiEvents.hh"
|
|
|
|
#include "gazebo/gui/ModelAlignPrivate.hh"
|
|
#include "gazebo/gui/ModelAlign.hh"
|
|
|
|
using namespace gazebo;
|
|
using namespace gui;
|
|
|
|
/////////////////////////////////////////////////
|
|
ModelAlign::ModelAlign()
|
|
: dataPtr(new ModelAlignPrivate)
|
|
{
|
|
this->dataPtr->initialized = false;
|
|
}
|
|
|
|
/////////////////////////////////////////////////
|
|
ModelAlign::~ModelAlign()
|
|
{
|
|
this->Clear();
|
|
delete this->dataPtr;
|
|
this->dataPtr = NULL;
|
|
}
|
|
|
|
/////////////////////////////////////////////////
|
|
void ModelAlign::Clear()
|
|
{
|
|
this->dataPtr->targetVis.reset();
|
|
this->dataPtr->scene.reset();
|
|
this->dataPtr->node.reset();
|
|
this->dataPtr->userCmdPub.reset();
|
|
this->dataPtr->selectedVisuals.clear();
|
|
this->dataPtr->connections.clear();
|
|
this->dataPtr->originalVisualPose.clear();
|
|
this->dataPtr->initialized = false;
|
|
}
|
|
|
|
/////////////////////////////////////////////////
|
|
void ModelAlign::Init()
|
|
{
|
|
if (this->dataPtr->initialized)
|
|
return;
|
|
|
|
rendering::UserCameraPtr cam = gui::get_active_camera();
|
|
if (!cam)
|
|
{
|
|
this->dataPtr->scene = rendering::get_scene();
|
|
}
|
|
else
|
|
{
|
|
this->dataPtr->scene = cam->GetScene();
|
|
}
|
|
|
|
if (!this->dataPtr->scene)
|
|
{
|
|
gzerr << "Unable to initialize Model Align tool, scene is NULL"
|
|
<< std::endl;
|
|
}
|
|
|
|
this->dataPtr->node = transport::NodePtr(new transport::Node());
|
|
this->dataPtr->node->TryInit(common::Time::Maximum());
|
|
this->dataPtr->userCmdPub =
|
|
this->dataPtr->node->Advertise<msgs::UserCmd>("~/user_cmd");
|
|
|
|
this->dataPtr->initialized = true;
|
|
}
|
|
|
|
/////////////////////////////////////////////////
|
|
void ModelAlign::Transform(math::Box _bbox, math::Pose _worldPose,
|
|
std::vector<math::Vector3> &_vertices)
|
|
{
|
|
math::Vector3 center = _bbox.GetCenter();
|
|
|
|
// Get the 8 corners of the bounding box.
|
|
math::Vector3 v0 = center +
|
|
math::Vector3(-_bbox.GetXLength()/2.0, _bbox.GetYLength()/2.0,
|
|
_bbox.GetZLength()/2.0);
|
|
math::Vector3 v1 = center +
|
|
math::Vector3(_bbox.GetXLength()/2.0, _bbox.GetYLength()/2.0,
|
|
_bbox.GetZLength()/2.0);
|
|
math::Vector3 v2 = center +
|
|
math::Vector3(-_bbox.GetXLength()/2.0, -_bbox.GetYLength()/2.0,
|
|
_bbox.GetZLength()/2.0);
|
|
math::Vector3 v3 = center +
|
|
math::Vector3(_bbox.GetXLength()/2.0, -_bbox.GetYLength()/2.0,
|
|
_bbox.GetZLength()/2.0);
|
|
|
|
math::Vector3 v4 = center +
|
|
math::Vector3(-_bbox.GetXLength()/2.0, _bbox.GetYLength()/2.0,
|
|
-_bbox.GetZLength()/2.0);
|
|
math::Vector3 v5 = center +
|
|
math::Vector3(_bbox.GetXLength()/2.0, _bbox.GetYLength()/2.0,
|
|
-_bbox.GetZLength()/2.0);
|
|
math::Vector3 v6 = center +
|
|
math::Vector3(-_bbox.GetXLength()/2.0, -_bbox.GetYLength()/2.0,
|
|
-_bbox.GetZLength()/2.0);
|
|
math::Vector3 v7 = center +
|
|
math::Vector3(_bbox.GetXLength()/2.0, -_bbox.GetYLength()/2.0,
|
|
-_bbox.GetZLength()/2.0);
|
|
|
|
// Transform corners into world spacce.
|
|
v0 = _worldPose.rot * v0 + _worldPose.pos;
|
|
v1 = _worldPose.rot * v1 + _worldPose.pos;
|
|
v2 = _worldPose.rot * v2 + _worldPose.pos;
|
|
v3 = _worldPose.rot * v3 + _worldPose.pos;
|
|
v4 = _worldPose.rot * v4 + _worldPose.pos;
|
|
v5 = _worldPose.rot * v5 + _worldPose.pos;
|
|
v6 = _worldPose.rot * v6 + _worldPose.pos;
|
|
v7 = _worldPose.rot * v7 + _worldPose.pos;
|
|
|
|
_vertices.clear();
|
|
_vertices.push_back(v0);
|
|
_vertices.push_back(v1);
|
|
_vertices.push_back(v2);
|
|
_vertices.push_back(v3);
|
|
_vertices.push_back(v4);
|
|
_vertices.push_back(v5);
|
|
_vertices.push_back(v6);
|
|
_vertices.push_back(v7);
|
|
}
|
|
|
|
/////////////////////////////////////////////////
|
|
void ModelAlign::GetMinMax(std::vector<math::Vector3> _vertices,
|
|
math::Vector3 &_min, math::Vector3 &_max)
|
|
{
|
|
if (_vertices.empty())
|
|
return;
|
|
|
|
_min = _vertices[0];
|
|
_max = _vertices[0];
|
|
|
|
// find min / max in world space;
|
|
for (unsigned int i = 1; i < _vertices.size(); ++i)
|
|
{
|
|
math::Vector3 v = _vertices[i];
|
|
if (_min.x > v.x)
|
|
_min.x = v.x;
|
|
if (_max.x < v.x)
|
|
_max.x = v.x;
|
|
if (_min.y > v.y)
|
|
_min.y = v.y;
|
|
if (_max.y < v.y)
|
|
_max.y = v.y;
|
|
if (_min.z > v.z)
|
|
_min.z = v.z;
|
|
if (_max.z < v.z)
|
|
_max.z = v.z;
|
|
}
|
|
}
|
|
|
|
/////////////////////////////////////////////////
|
|
void ModelAlign::AlignVisuals(std::vector<rendering::VisualPtr> _visuals,
|
|
const std::string &_axis, const std::string &_config,
|
|
const std::string &_target, const bool _publish, const bool _inverted)
|
|
{
|
|
if (_config == "reset" || _publish)
|
|
{
|
|
std::map<rendering::VisualPtr, math::Pose>::iterator it =
|
|
this->dataPtr->originalVisualPose.begin();
|
|
for (it; it != this->dataPtr->originalVisualPose.end(); ++it)
|
|
{
|
|
if (it->first)
|
|
{
|
|
it->first->SetWorldPose(it->second);
|
|
this->SetHighlighted(it->first, false);
|
|
}
|
|
}
|
|
this->dataPtr->originalVisualPose.clear();
|
|
if (this->dataPtr->scene)
|
|
this->dataPtr->scene->SelectVisual("", "normal");
|
|
if (!_publish)
|
|
return;
|
|
}
|
|
|
|
this->dataPtr->selectedVisuals = _visuals;
|
|
|
|
if (this->dataPtr->selectedVisuals.size() <= 1)
|
|
return;
|
|
|
|
unsigned int start = 0;
|
|
unsigned int end = 0;
|
|
if (_target == "first")
|
|
{
|
|
start = 1;
|
|
end = this->dataPtr->selectedVisuals.size();
|
|
this->dataPtr->targetVis = this->dataPtr->selectedVisuals.front();
|
|
}
|
|
else if (_target == "last")
|
|
{
|
|
start = 0;
|
|
end = this->dataPtr->selectedVisuals.size()-1;
|
|
this->dataPtr->targetVis = this->dataPtr->selectedVisuals.back();
|
|
}
|
|
|
|
math::Pose targetWorldPose = this->dataPtr->targetVis->GetWorldPose();
|
|
math::Box targetBbox = this->dataPtr->targetVis->GetBoundingBox();
|
|
targetBbox.min *= this->dataPtr->targetVis->GetScale();
|
|
targetBbox.max *= this->dataPtr->targetVis->GetScale();
|
|
|
|
std::vector<math::Vector3> targetVertices;
|
|
this->Transform(targetBbox, targetWorldPose, targetVertices);
|
|
|
|
math::Vector3 targetMin;
|
|
math::Vector3 targetMax;
|
|
this->GetMinMax(targetVertices, targetMin, targetMax);
|
|
|
|
std::vector<rendering::VisualPtr> visualsToPublish;
|
|
for (unsigned i = start; i < end; ++i)
|
|
{
|
|
rendering::VisualPtr vis = this->dataPtr->selectedVisuals[i];
|
|
|
|
math::Pose worldPose = vis->GetWorldPose();
|
|
math::Box bbox = vis->GetBoundingBox();
|
|
bbox.min *= vis->GetScale();
|
|
bbox.max *= vis->GetScale();
|
|
|
|
std::vector<math::Vector3> vertices;
|
|
this->Transform(bbox, worldPose, vertices);
|
|
|
|
math::Vector3 min;
|
|
math::Vector3 max;
|
|
this->GetMinMax(vertices, min, max);
|
|
|
|
math::Vector3 trans;
|
|
if (_config == "center")
|
|
{
|
|
trans = (targetMin + (targetMax-targetMin)/2) - (min + (max-min)/2);
|
|
}
|
|
else
|
|
{
|
|
if (!_inverted)
|
|
{
|
|
if (_config == "min")
|
|
trans = targetMin - min;
|
|
else if (_config == "max")
|
|
trans = targetMax - max;
|
|
}
|
|
else
|
|
{
|
|
if (_config == "min")
|
|
trans = targetMin - max;
|
|
else if (_config == "max")
|
|
trans = targetMax - min;
|
|
}
|
|
}
|
|
|
|
if (!_publish)
|
|
{
|
|
if (this->dataPtr->originalVisualPose.find(vis) ==
|
|
this->dataPtr->originalVisualPose.end())
|
|
{
|
|
this->dataPtr->originalVisualPose[vis] = vis->GetWorldPose();
|
|
this->SetHighlighted(vis, true);
|
|
}
|
|
// prevent the visual pose from being updated by the server
|
|
if (this->dataPtr->scene)
|
|
this->dataPtr->scene->SelectVisual(vis->GetName(), "move");
|
|
}
|
|
|
|
if (_axis == "x")
|
|
{
|
|
trans.y = trans.z = 0;
|
|
vis->SetWorldPosition(vis->GetWorldPose().pos + trans);
|
|
}
|
|
else if (_axis == "y")
|
|
{
|
|
trans.x = trans.z = 0;
|
|
vis->SetWorldPosition(vis->GetWorldPose().pos + trans);
|
|
}
|
|
else if (_axis == "z")
|
|
{
|
|
trans.x = trans.y = 0;
|
|
vis->SetWorldPosition(vis->GetWorldPose().pos + trans);
|
|
}
|
|
|
|
if (_publish)
|
|
visualsToPublish.push_back(vis);
|
|
}
|
|
// Register user command on server
|
|
if (_publish)
|
|
{
|
|
msgs::UserCmd userCmdMsg;
|
|
userCmdMsg.set_description(
|
|
"Align to [" + this->dataPtr->targetVis->GetName() + "]");
|
|
userCmdMsg.set_type(msgs::UserCmd::MOVING);
|
|
|
|
for (const auto &vis : visualsToPublish)
|
|
{
|
|
// Only publish for models
|
|
if (vis->GetType() == gazebo::rendering::Visual::VT_MODEL)
|
|
{
|
|
msgs::Model msg;
|
|
|
|
auto id = gui::get_entity_id(vis->GetName());
|
|
if (id)
|
|
msg.set_id(id);
|
|
|
|
msg.set_name(vis->GetName());
|
|
msgs::Set(msg.mutable_pose(), vis->GetWorldPose().Ign());
|
|
|
|
auto modelMsg = userCmdMsg.add_model();
|
|
modelMsg->CopyFrom(msg);
|
|
}
|
|
}
|
|
|
|
this->dataPtr->userCmdPub->Publish(userCmdMsg);
|
|
}
|
|
}
|
|
|
|
/////////////////////////////////////////////////
|
|
void ModelAlign::SetHighlighted(rendering::VisualPtr _vis, bool _highlight)
|
|
{
|
|
if (_vis->GetChildCount() != 0)
|
|
{
|
|
for (unsigned int j = 0; j < _vis->GetChildCount(); ++j)
|
|
{
|
|
this->SetHighlighted(_vis->GetChild(j), _highlight);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Highlighting increases transparency for opaque visuals (0 < t < 0.3) and
|
|
// decreases transparency for semi-transparent visuals (0.3 < t < 1).
|
|
// A visual will never become fully transparent (t = 1) when highlighted.
|
|
if (_highlight)
|
|
{
|
|
_vis->SetTransparency((1.0 - _vis->GetTransparency()) * 0.5);
|
|
}
|
|
// The inverse operation restores the original transparency value.
|
|
else
|
|
{
|
|
_vis->SetTransparency(std::abs(_vis->GetTransparency()*2.0-1.0));
|
|
}
|
|
}
|
|
}
|