237 lines
7.5 KiB
C++
237 lines
7.5 KiB
C++
/*
|
|
* Copyright (C) 2012 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 <boost/bind.hpp>
|
|
|
|
#include "gazebo/common/MeshManager.hh"
|
|
#include "gazebo/transport/transport.hh"
|
|
|
|
#include "gazebo/rendering/Conversions.hh"
|
|
#include "gazebo/rendering/Scene.hh"
|
|
#include "gazebo/rendering/DynamicLines.hh"
|
|
#include "gazebo/rendering/LaserVisualPrivate.hh"
|
|
#include "gazebo/rendering/LaserVisual.hh"
|
|
|
|
using namespace gazebo;
|
|
using namespace rendering;
|
|
|
|
/////////////////////////////////////////////////
|
|
LaserVisual::LaserVisual(const std::string &_name, VisualPtr _vis,
|
|
const std::string &_topicName)
|
|
: Visual(*new LaserVisualPrivate, _name, _vis)
|
|
{
|
|
LaserVisualPrivate *dPtr =
|
|
reinterpret_cast<LaserVisualPrivate *>(this->dataPtr);
|
|
|
|
dPtr->type = VT_SENSOR;
|
|
|
|
dPtr->receivedMsg = false;
|
|
|
|
dPtr->node = transport::NodePtr(new transport::Node());
|
|
dPtr->node->Init(dPtr->scene->Name());
|
|
|
|
dPtr->laserScanSub = dPtr->node->Subscribe(_topicName,
|
|
&LaserVisual::OnScan, this);
|
|
|
|
dPtr->connection = event::Events::ConnectPreRender(
|
|
boost::bind(&LaserVisual::Update, this));
|
|
}
|
|
|
|
/////////////////////////////////////////////////
|
|
LaserVisual::~LaserVisual()
|
|
{
|
|
LaserVisualPrivate *dPtr =
|
|
reinterpret_cast<LaserVisualPrivate *>(this->dataPtr);
|
|
|
|
for (auto ray : dPtr->rayStrips)
|
|
this->DeleteDynamicLine(ray);
|
|
|
|
for (auto ray : dPtr->noHitRayStrips)
|
|
this->DeleteDynamicLine(ray);
|
|
|
|
for (auto ray : dPtr->deadzoneRayFans)
|
|
this->DeleteDynamicLine(ray);
|
|
|
|
for (auto ray : dPtr->rayLines)
|
|
this->DeleteDynamicLine(ray);
|
|
|
|
dPtr->rayStrips.clear();
|
|
dPtr->noHitRayStrips.clear();
|
|
dPtr->deadzoneRayFans.clear();
|
|
dPtr->rayLines.clear();
|
|
}
|
|
|
|
/////////////////////////////////////////////////
|
|
void LaserVisual::OnScan(ConstLaserScanStampedPtr &_msg)
|
|
{
|
|
LaserVisualPrivate *dPtr =
|
|
reinterpret_cast<LaserVisualPrivate *>(this->dataPtr);
|
|
|
|
boost::mutex::scoped_lock lock(dPtr->mutex);
|
|
dPtr->laserMsg = _msg;
|
|
dPtr->receivedMsg = true;
|
|
}
|
|
|
|
/////////////////////////////////////////////////
|
|
void LaserVisual::Update()
|
|
{
|
|
LaserVisualPrivate *dPtr =
|
|
reinterpret_cast<LaserVisualPrivate *>(this->dataPtr);
|
|
|
|
boost::mutex::scoped_lock lock(dPtr->mutex);
|
|
|
|
// Skip the update if the user is moving the laser.
|
|
if ((this->GetScene()->SelectedVisual() &&
|
|
this->GetRootVisual()->GetName() ==
|
|
this->GetScene()->SelectedVisual()->GetName()))
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (!dPtr->laserMsg || !dPtr->receivedMsg)
|
|
return;
|
|
|
|
dPtr->receivedMsg = false;
|
|
|
|
double verticalAngle = dPtr->laserMsg->scan().vertical_angle_min();
|
|
ignition::math::Pose3d offset =
|
|
msgs::ConvertIgn(dPtr->laserMsg->scan().world_pose()) -
|
|
this->GetWorldPose().Ign();
|
|
|
|
unsigned int vertCount = dPtr->laserMsg->scan().has_vertical_count() ?
|
|
dPtr->laserMsg->scan().vertical_count() : 1u;
|
|
|
|
double minRange = dPtr->laserMsg->scan().range_min();
|
|
|
|
// Process each ray fan
|
|
for (unsigned int j = 0; j < vertCount; ++j)
|
|
{
|
|
// Create a new render objects, if there are not enough already allocated.
|
|
if (j+1 > dPtr->rayStrips.size())
|
|
{
|
|
// Ray strips fill in-between the ray lines in areas that have
|
|
// intersected an object.
|
|
dPtr->rayStrips.push_back(
|
|
this->CreateDynamicLine(rendering::RENDERING_TRIANGLE_STRIP));
|
|
dPtr->rayStrips[j]->setMaterial("Gazebo/BlueLaser");
|
|
|
|
// No hit ray strips fill in-between the ray lines in areas that have
|
|
// not intersected an object.
|
|
dPtr->noHitRayStrips.push_back(
|
|
this->CreateDynamicLine(rendering::RENDERING_TRIANGLE_STRIP));
|
|
dPtr->noHitRayStrips[j]->setMaterial("Gazebo/LightBlueLaser");
|
|
|
|
// Deadzone ray fans display areas that are between the sensor's origin
|
|
// and start of the rays.
|
|
dPtr->deadzoneRayFans.push_back(
|
|
this->CreateDynamicLine(rendering::RENDERING_TRIANGLE_FAN));
|
|
dPtr->deadzoneRayFans[j]->setMaterial("Gazebo/BlackTransparent");
|
|
dPtr->deadzoneRayFans[j]->AddPoint(ignition::math::Vector3d(0, 0, 0));
|
|
|
|
// Individual ray lines
|
|
dPtr->rayLines.push_back(
|
|
this->CreateDynamicLine(rendering::RENDERING_LINE_LIST));
|
|
dPtr->rayLines[j]->setMaterial("Gazebo/BlueLaser");
|
|
|
|
this->SetVisibilityFlags(GZ_VISIBILITY_GUI);
|
|
}
|
|
dPtr->deadzoneRayFans[j]->SetPoint(0, offset.Pos());
|
|
|
|
double angle = dPtr->laserMsg->scan().angle_min();
|
|
unsigned int count = dPtr->laserMsg->scan().count();
|
|
|
|
// Process each ray in the current scan.
|
|
for (unsigned int i = 0; i < count; ++i)
|
|
{
|
|
// Calculate the range of the ray
|
|
double r = dPtr->laserMsg->scan().ranges(j*count + i);
|
|
if (r < minRange)
|
|
{
|
|
// Less than min range, don't display a ray
|
|
r = minRange;
|
|
}
|
|
bool inf = std::isinf(r);
|
|
|
|
ignition::math::Quaterniond ray(
|
|
ignition::math::Vector3d(0.0, -verticalAngle, angle));
|
|
|
|
ignition::math::Vector3d axis = offset.Rot() * ray *
|
|
ignition::math::Vector3d(1.0, 0.0, 0.0);
|
|
|
|
// Check for infinite range, which indicates the ray did not
|
|
// intersect an object.
|
|
double hitRange = inf ? 0 : r;
|
|
|
|
// Compute the start point of the ray
|
|
ignition::math::Vector3d startPt = (axis * minRange) + offset.Pos();
|
|
|
|
// Compute the end point of the ray
|
|
ignition::math::Vector3d pt = (axis * hitRange) + offset.Pos();
|
|
|
|
double noHitRange = inf ? dPtr->laserMsg->scan().range_max() : hitRange;
|
|
|
|
// Compute the end point of the no-hit ray
|
|
ignition::math::Vector3d noHitPt = (axis * noHitRange) + offset.Pos();
|
|
|
|
// Draw the lines and strips that represent each simulated ray
|
|
if (i >= dPtr->rayLines[j]->GetPointCount()/2)
|
|
{
|
|
dPtr->rayLines[j]->AddPoint(startPt);
|
|
dPtr->rayLines[j]->AddPoint(inf ? noHitPt : pt);
|
|
|
|
dPtr->rayStrips[j]->AddPoint(startPt);
|
|
dPtr->rayStrips[j]->AddPoint(inf ? startPt : pt);
|
|
|
|
dPtr->noHitRayStrips[j]->AddPoint(startPt);
|
|
dPtr->noHitRayStrips[j]->AddPoint(inf ? noHitPt : pt);
|
|
}
|
|
else
|
|
{
|
|
dPtr->rayLines[j]->SetPoint(i*2, startPt);
|
|
dPtr->rayLines[j]->SetPoint(i*2+1, inf ? noHitPt : pt);
|
|
|
|
dPtr->rayStrips[j]->SetPoint(i*2, startPt);
|
|
dPtr->rayStrips[j]->SetPoint(i*2+1, inf ? startPt : pt);
|
|
|
|
dPtr->noHitRayStrips[j]->SetPoint(i*2, startPt);
|
|
dPtr->noHitRayStrips[j]->SetPoint(i*2+1, inf ? noHitPt : pt);
|
|
}
|
|
|
|
// Draw the triangle fan that indicates the dead zone.
|
|
if (i+1 >= dPtr->deadzoneRayFans[j]->GetPointCount())
|
|
dPtr->deadzoneRayFans[j]->AddPoint(startPt);
|
|
else
|
|
dPtr->deadzoneRayFans[j]->SetPoint(i+1, startPt);
|
|
|
|
angle += dPtr->laserMsg->scan().angle_step();
|
|
}
|
|
verticalAngle += dPtr->laserMsg->scan().vertical_angle_step();
|
|
}
|
|
}
|
|
|
|
/////////////////////////////////////////////////
|
|
void LaserVisual::SetEmissive(const common::Color &/*_color*/,
|
|
const bool /*_cascade*/)
|
|
{
|
|
}
|