pxmlw6n2f/Gazebo_Distributed_TCP/gazebo/gui/building/WallSegmentItem.cc

295 lines
9.5 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.
*
*/
#include <ignition/math/Angle.hh>
#include <ignition/math/Vector2.hh>
#include "gazebo/common/Color.hh"
#include "gazebo/gui/Conversions.hh"
#include "gazebo/gui/building/EditorView.hh"
#include "gazebo/gui/building/MeasureItem.hh"
#include "gazebo/gui/building/RectItem.hh"
#include "gazebo/gui/building/WallInspectorDialog.hh"
#include "gazebo/gui/building/WallSegmentItem.hh"
#include "gazebo/gui/building/WallSegmentItemPrivate.hh"
using namespace gazebo;
using namespace gui;
/////////////////////////////////////////////////
WallSegmentItem::WallSegmentItem(const ignition::math::Vector2d &_start,
const ignition::math::Vector2d &_end, const double _height)
: SegmentItem(), dataPtr(new WallSegmentItemPrivate())
{
this->editorType = "WallSegment";
this->dataPtr->measure = new MeasureItem(this->StartPoint(),
this->EndPoint());
this->dataPtr->measure->setParentItem(this);
this->SegmentUpdated();
this->level = 0;
this->dataPtr->wallThickness = 15;
this->dataPtr->wallHeight = _height;
this->SetThickness(this->dataPtr->wallThickness);
this->SetLine(_start, _end);
this->SetColor(common::Color(247, 142, 30));
this->zValueIdle = 0;
this->zValueSelected = 5;
this->setFlag(QGraphicsItem::ItemSendsGeometryChanges);
this->setAcceptHoverEvents(true);
this->dataPtr->inspector = new WallInspectorDialog();
this->dataPtr->inspector->setModal(false);
connect(this->dataPtr->inspector, SIGNAL(Applied()), this, SLOT(OnApply()));
this->dataPtr->openInspectorAct =
new QAction(tr("&Open Wall Inspector"), this);
this->dataPtr->openInspectorAct->setStatusTip(tr("Open Wall Inspector"));
connect(this->dataPtr->openInspectorAct, SIGNAL(triggered()),
this, SLOT(OnOpenInspector()));
this->dataPtr->deleteItemAct = new QAction(tr("&Delete"), this);
this->dataPtr->deleteItemAct->setStatusTip(tr("Delete"));
connect(this->dataPtr->deleteItemAct, SIGNAL(triggered()),
this, SLOT(OnDeleteItem()));
}
/////////////////////////////////////////////////
WallSegmentItem::~WallSegmentItem()
{
delete this->dataPtr->inspector;
}
/////////////////////////////////////////////////
double WallSegmentItem::Height() const
{
return this->dataPtr->wallHeight;
}
/////////////////////////////////////////////////
void WallSegmentItem::SetHeight(const double _height)
{
this->dataPtr->wallHeight = _height;
}
/////////////////////////////////////////////////
WallSegmentItem *WallSegmentItem::Clone() const
{
WallSegmentItem *wallSegmentItem = new WallSegmentItem(this->StartPoint(),
this->EndPoint(), this->dataPtr->wallHeight);
wallSegmentItem->SetLevel(this->level);
wallSegmentItem->SetThickness(this->dataPtr->wallThickness);
return wallSegmentItem;
}
/////////////////////////////////////////////////
void WallSegmentItem::Update()
{
this->WallSegmentChanged();
this->SegmentChanged();
}
/////////////////////////////////////////////////
void WallSegmentItem::WallSegmentChanged()
{
emit DepthChanged(this->dataPtr->wallThickness);
emit HeightChanged(this->dataPtr->wallHeight);
emit PosZChanged(this->levelBaseHeight);
this->SegmentUpdated();
}
/////////////////////////////////////////////////
void WallSegmentItem::UpdateInspector()
{
double segmentLength = this->line().length() + this->dataPtr->wallThickness;
QPointF segmentStartPoint = this->mapToScene(this->line().p1());
QPointF segmentEndPoint = this->mapToScene(this->line().p2());
this->dataPtr->inspector->SetName(this->Name());
this->dataPtr->inspector->SetThickness(
this->dataPtr->wallThickness * this->itemScale);
this->dataPtr->inspector->SetHeight(
this->dataPtr->wallHeight * this->itemScale);
this->dataPtr->inspector->SetLength(segmentLength * this->itemScale);
QPointF startPos = segmentStartPoint * this->itemScale;
startPos.setY(-startPos.y());
this->dataPtr->inspector->SetStartPosition(Conversions::Convert(startPos));
QPointF endPos = segmentEndPoint * this->itemScale;
endPos.setY(-endPos.y());
this->dataPtr->inspector->SetEndPosition(Conversions::Convert(endPos));
this->dataPtr->inspector->SetColor(this->visual3dColor);
this->dataPtr->inspector->SetTexture(this->visual3dTexture);
}
/////////////////////////////////////////////////
void WallSegmentItem::SegmentUpdated()
{
// distance in px between wall and measure line
double d = 20;
double t = this->Thickness()/2;
auto p1 = this->StartPoint();
auto p2 = this->EndPoint();
double angle = IGN_DTOR(this->line().angle());
this->dataPtr->measure->SetStartPoint(ignition::math::Vector2d(
p1.X()+(d+t)*qCos(angle+M_PI/2.0)+t*qCos(angle+M_PI),
p1.Y()-(d+t)*qSin(angle+M_PI/2.0)-t*qSin(angle+M_PI)));
this->dataPtr->measure->SetEndPoint(ignition::math::Vector2d(
p2.X()+(d+t)*qCos(angle+M_PI/2.0)-t*qCos(angle+M_PI),
p2.Y()-(d+t)*qSin(angle+M_PI/2.0)+t*qSin(angle+M_PI)));
this->dataPtr->measure->SetValue(
(this->line().length()+2*t)*this->itemScale);
// Doors, windows...
QList<QGraphicsItem *> children = this->childItems();
for (int j = 0; j < children.size(); ++j)
{
// TODO find a more generic way than casting child as rect item,
// and need to keep wall-children pos ratio fixed
RectItem *rectItem = dynamic_cast<RectItem *>(children[j]);
if (rectItem)
{
rectItem->SetRotation(-this->line().angle() + rectItem->AngleOnWall());
QPointF segLine = this->line().p2() - this->line().p1();
rectItem->setPos(this->line().p1() + rectItem->PositionOnWall()*
segLine);
}
}
}
/////////////////////////////////////////////////
void WallSegmentItem::contextMenuEvent(QGraphicsSceneContextMenuEvent *_event)
{
this->scene()->clearSelection();
this->setSelected(true);
QMenu menu;
menu.addAction(this->dataPtr->openInspectorAct);
menu.addAction(this->dataPtr->deleteItemAct);
menu.exec(dynamic_cast<QGraphicsSceneContextMenuEvent *>(
_event)->screenPos());
}
/////////////////////////////////////////////////
void WallSegmentItem::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *
_event)
{
if (this->isSelected())
{
this->scene()->clearSelection();
this->setSelected(true);
this->OnOpenInspector();
_event->setAccepted(true);
}
}
/////////////////////////////////////////////////
QVariant WallSegmentItem::itemChange(GraphicsItemChange _change,
const QVariant &_value)
{
if (_change == QGraphicsItem::ItemSelectedChange && this->scene())
{
this->SetHighlighted(_value.toBool());
}
return QGraphicsItem::itemChange(_change, _value);
}
/////////////////////////////////////////////////
void WallSegmentItem::SetHighlighted(bool _highlighted)
{
if (_highlighted)
{
this->ShowHandles(true);
this->dataPtr->measure->setVisible(true);
this->setZValue(this->zValueSelected);
this->SetColor(Conversions::Convert(QColor(247, 142, 30)));
this->Set3dTransparency(0.0);
}
else
{
this->ShowHandles(false);
this->dataPtr->measure->setVisible(false);
this->setZValue(this->zValueIdle);
this->SetColor(common::Color::Black);
this->Set3dTransparency(0.4);
}
}
/////////////////////////////////////////////////
void WallSegmentItem::OnApply()
{
WallInspectorDialog *dialog =
qobject_cast<WallInspectorDialog *>(QObject::sender());
double segmentLength = this->line().length() + this->dataPtr->wallThickness;
this->dataPtr->wallThickness = dialog->Thickness() / this->itemScale;
this->SetThickness(this->dataPtr->wallThickness);
this->dataPtr->wallHeight = dialog->Height() / this->itemScale;
this->SetTexture3d(dialog->Texture());
this->SetColor3d(dialog->Color());
this->WallSegmentChanged();
double newLength = dialog->Length() / this->itemScale;
// The if statement below limits the change to either the length of
// the wall segment or its start/end pos.
// Comparison between doubles up to 1 decimal place
if (fabs(newLength - segmentLength) > 0.1)
{
newLength = std::max(newLength - this->dataPtr->wallThickness, 1.0);
QLineF newLine = this->line();
newLine.setLength(newLength);
this->SetEndPoint(Conversions::Convert(this->mapToScene(newLine.p2())));
}
else
{
auto newStartPoint = dialog->StartPosition() / this->itemScale;
newStartPoint.Y(-newStartPoint.Y());
auto newEndPoint = dialog->EndPosition() / this->itemScale;
newEndPoint.Y(-newEndPoint.Y());
this->SetStartPoint(newStartPoint);
this->SetEndPoint(newEndPoint);
}
this->UpdateLinkedGrabbers(this->grabbers[0], this->StartPoint());
this->UpdateLinkedGrabbers(this->grabbers[1], this->EndPoint());
this->update();
this->UpdateInspector();
}
/////////////////////////////////////////////////
void WallSegmentItem::OnOpenInspector()
{
this->UpdateInspector();
this->dataPtr->inspector->move(QCursor::pos());
this->dataPtr->inspector->show();
}
/////////////////////////////////////////////////
void WallSegmentItem::OnDeleteItem()
{
dynamic_cast<EditorView *>(this->scene()->views()[0])->DeleteItem(this);
}