#include <utils/geom/GeomHelper.h>
#include <utils/gui/div/GLHelper.h>
#include <utils/gui/globjects/GLIncludes.h>
#include <utils/gui/globjects/GUIGlObjectTypes.h>
#include <utils/gui/div/GUIGlobalViewObjectsHandler.h>
#include "GUIGeometry.h"
#define CIRCLE_RESOLUTION (double)10
PositionVector GUIGeometry::myCircleCoords;
GUIGeometry::GUIGeometry() {
}
GUIGeometry::GUIGeometry(const PositionVector& shape) :
myShape(shape) {
calculateShapeRotationsAndLengths();
}
GUIGeometry::GUIGeometry(const PositionVector& shape, const std::vector<double>& shapeRotations,
const std::vector<double>& shapeLengths) :
myShape(shape),
myShapeRotations(shapeRotations),
myShapeLengths(shapeLengths) {
}
void
GUIGeometry::updateGeometry(const PositionVector& shape) {
clearGeometry();
myShape = shape;
calculateShapeRotationsAndLengths();
}
void
GUIGeometry::updateGeometry(const PositionVector& shape, const double posOverShape,
const double lateralOffset) {
clearGeometry();
const double shapeLength = shape.length();
if (posOverShape < 0) {
myShape.push_back(shape.positionAtOffset(0, lateralOffset));
myShapeRotations.push_back(shape.rotationDegreeAtOffset(0));
} else if (posOverShape > shapeLength) {
myShape.push_back(shape.positionAtOffset(shapeLength, lateralOffset));
myShapeRotations.push_back(shape.rotationDegreeAtOffset(shapeLength));
} else {
myShape.push_back(shape.positionAtOffset(posOverShape, lateralOffset));
myShapeRotations.push_back(shape.rotationDegreeAtOffset(posOverShape));
}
}
void
GUIGeometry::updateGeometry(const PositionVector& shape, double starPosOverShape,
double endPosOverShape, const double lateralOffset) {
clearGeometry();
myShape = shape;
myShape.move2side(lateralOffset);
const double shapeLength = myShape.length2D();
if (starPosOverShape < 0) {
endPosOverShape = 0;
}
if (starPosOverShape < 0) {
endPosOverShape = shapeLength;
}
if (starPosOverShape > (shapeLength - POSITION_EPS)) {
endPosOverShape = (shapeLength - POSITION_EPS);
}
if ((endPosOverShape > shapeLength)) {
endPosOverShape = shapeLength;
}
if (endPosOverShape <= starPosOverShape) {
endPosOverShape = endPosOverShape + POSITION_EPS;
}
myShape = myShape.getSubpart2D(starPosOverShape, endPosOverShape);
calculateShapeRotationsAndLengths();
}
void
GUIGeometry::updateGeometry(const PositionVector& shape, double beginTrimPosition, const Position& extraFirstPosition,
double endTrimPosition, const Position& extraLastPosition) {
clearGeometry();
myShape = shape;
if ((beginTrimPosition != -1) || (endTrimPosition != -1)) {
const double shapeLength = myShape.length2D();
if (beginTrimPosition < 0) {
beginTrimPosition = 0;
}
if (endTrimPosition < 0) {
endTrimPosition = shapeLength;
}
if (beginTrimPosition > (shapeLength - POSITION_EPS)) {
beginTrimPosition = (shapeLength - POSITION_EPS);
}
if ((endTrimPosition > shapeLength)) {
endTrimPosition = shapeLength;
}
if (endTrimPosition <= beginTrimPosition) {
endTrimPosition = endTrimPosition + POSITION_EPS;
}
myShape = myShape.getSubpart2D(beginTrimPosition, endTrimPosition);
if (extraFirstPosition != Position::INVALID) {
myShape.push_front_noDoublePos(extraFirstPosition);
}
if (extraLastPosition != Position::INVALID) {
myShape.push_back_noDoublePos(extraLastPosition);
}
}
calculateShapeRotationsAndLengths();
}
void
GUIGeometry::updateSinglePosGeometry(const Position& position, const double rotation) {
clearGeometry();
myShape.push_back(position);
myShapeRotations.push_back(rotation);
}
void GUIGeometry::clearGeometry() {
myShape.clear();
myShapeRotations.clear();
myShapeLengths.clear();
}
void
GUIGeometry::moveGeometryToSide(const double amount) {
myShape.move2side(amount);
}
void
GUIGeometry::scaleGeometry(const double scale) {
myShape.scaleRelative(scale);
for (auto& shapeLength : myShapeLengths) {
shapeLength *= scale;
}
}
const PositionVector&
GUIGeometry::getShape() const {
return myShape;
}
const std::vector<double>&
GUIGeometry::getShapeRotations() const {
return myShapeRotations;
}
const std::vector<double>&
GUIGeometry::getShapeLengths() const {
return myShapeLengths;
}
double
GUIGeometry::calculateRotation(const Position& first, const Position& second) {
return ((double)atan2((second.x() - first.x()), (first.y() - second.y())) * (double) 180.0 / (double)M_PI);
}
double
GUIGeometry::calculateLength(const Position& first, const Position& second) {
return first.distanceTo2D(second);
}
void
GUIGeometry::adjustStartPosGeometricPath(double& startPos, const PositionVector& startLaneShape,
double& endPos, const PositionVector& endLaneShape) {
if ((startLaneShape.size() > 0) &&
(endLaneShape.size() > 0) &&
(startLaneShape == endLaneShape) &&
(startPos != -1) &&
(endPos != -1)) {
if (startPos >= endPos) {
endPos = (startPos + POSITION_EPS);
}
}
if ((startPos != -1) && (startLaneShape.size() > 0)) {
if (startPos < POSITION_EPS) {
startPos = POSITION_EPS;
}
if (startPos > (startLaneShape.length() - POSITION_EPS)) {
startPos = (startLaneShape.length() - POSITION_EPS);
}
}
if ((endPos != -1) && (endLaneShape.size() > 0)) {
if (endPos < POSITION_EPS) {
endPos = POSITION_EPS;
}
if (endPos > (endLaneShape.length() - POSITION_EPS)) {
endPos = (endLaneShape.length() - POSITION_EPS);
}
}
}
void
GUIGeometry::drawGeometry(const GUIVisualizationSettings::Detail d, const GUIGeometry& geometry,
const double width, double offset) {
if (d <= GUIVisualizationSettings::Detail::GeometryBoxLines) {
GLHelper::drawBoxLines(geometry.getShape(), geometry.getShapeRotations(), geometry.getShapeLengths(), width, 0, offset);
} else if (d < GUIVisualizationSettings::Detail::GeometryBoxSimpleLine) {
glLineWidth(static_cast<float>(width));
GLHelper::drawLine(geometry.getShape());
glLineWidth(1);
} else {
GLHelper::drawLine(geometry.getShape());
}
}
void
GUIGeometry::drawGeometry(const GUIVisualizationSettings::Detail d, const GUIGeometry& geometry,
const std::vector<RGBColor>& colors, const double width, double offset) {
if (d <= GUIVisualizationSettings::Detail::GeometryBoxLines) {
GLHelper::drawBoxLines(geometry.getShape(), geometry.getShapeRotations(), geometry.getShapeLengths(), colors, width, 0, offset);
} else {
GLHelper::setColor(*colors.begin());
if (d < GUIVisualizationSettings::Detail::GeometryBoxSimpleLine) {
glLineWidth(static_cast<float>(width));
GLHelper::drawLine(geometry.getShape());
glLineWidth(1);
} else {
GLHelper::drawLine(geometry.getShape());
}
}
}
void
GUIGeometry::drawContourGeometry(const GUIGeometry& geometry, const double width, const bool drawExtremes) {
PositionVector shapeA = geometry.getShape();
PositionVector shapeB = geometry.getShape();
shapeA.move2side((width - 0.1));
shapeB.move2side((width - 0.1) * -1);
if (drawExtremes) {
shapeB = shapeB.reverse();
shapeA.append(shapeB, 0);
shapeA.closePolygon();
GLHelper::drawBoxLines(shapeA, 0.1);
} else {
GLHelper::drawBoxLines(shapeA, 0.1);
GLHelper::drawBoxLines(shapeB, 0.1);
}
}
void
GUIGeometry::drawGeometryPoints(const GUIVisualizationSettings::Detail d, const PositionVector& shape,
const RGBColor& color, const double radius, const double exaggeration,
const bool editingElevation) {
if (editingElevation || (d <= GUIVisualizationSettings::Detail::GeometryPoint)) {
const double exaggeratedRadio = (radius * exaggeration);
for (const auto& geometryPos : shape) {
GLHelper::pushMatrix();
glTranslated(geometryPos.x(), geometryPos.y(), 0.2);
GLHelper::setColor(color);
GLHelper::drawFilledCircleDetailled(d, exaggeratedRadio);
GLHelper::popMatrix();
if (d <= GUIVisualizationSettings::Detail::Text) {
if (editingElevation) {
GLHelper::pushMatrix();
GLHelper::drawText(toString(geometryPos.z()), geometryPos, 0.3, 0.7, color.invertedColor());
GLHelper::popMatrix();
} else if (geometryPos == shape.front()) {
GLHelper::pushMatrix();
GLHelper::drawText("S", geometryPos, 0.3, 2 * exaggeratedRadio, color.invertedColor());
GLHelper::popMatrix();
} else if (geometryPos == shape.back()) {
GLHelper::pushMatrix();
GLHelper::drawText("E", geometryPos, 0.3, 2 * exaggeratedRadio, color.invertedColor());
GLHelper::popMatrix();
}
}
}
}
}
void
GUIGeometry::drawParentLine(const GUIVisualizationSettings& s, const Position& parent, const Position& child,
const RGBColor& color, const bool drawEntire, const double lineWidth) {
if (!s.drawForRectangleSelection) {
const double rot = RAD2DEG(parent.angleTo2D(child)) + 90;
const double distanceSquared = parent.distanceSquaredTo2D(child);
GLHelper::pushMatrix();
glTranslated(0, 0, -1);
if (drawEntire) {
GLHelper::setColor(color.changedBrightness(-50));
GLHelper::drawBoxLine(parent, rot, sqrt(distanceSquared), lineWidth);
glTranslated(0, 0, 0.1);
GLHelper::setColor(color);
GLHelper::drawBoxLine(parent, rot, sqrt(distanceSquared), .04);
} else if (distanceSquared > 25) {
GLHelper::setColor(color.changedBrightness(-50));
GLHelper::drawBoxLine(parent, rot, 4.9, lineWidth);
glTranslated(0, 0, 0.1);
GLHelper::setColor(color);
GLHelper::drawBoxLine(parent, rot, 4.9, .04);
if (distanceSquared > 100) {
const PositionVector vector = {parent, child};
GLHelper::setColor(color.changedBrightness(-50));
GLHelper::drawTriangleAtEnd(parent,
vector.positionAtOffset2D(5),
s.additionalSettings.arrowWidth,
s.additionalSettings.arrowLength,
s.additionalSettings.arrowOffset);
glTranslated(0, 0, 0.1);
GLHelper::setColor(color);
GLHelper::drawTriangleAtEnd(parent,
vector.positionAtOffset2D(5),
s.additionalSettings.arrowWidth - 0.01,
s.additionalSettings.arrowLength - 0.01,
s.additionalSettings.arrowOffset - 0.01);
}
}
GLHelper::popMatrix();
}
}
void
GUIGeometry::drawChildLine(const GUIVisualizationSettings& s, const Position& child, const Position& parent,
const RGBColor& color, const bool drawEntire, const double lineWidth) {
if (!s.drawForRectangleSelection) {
const double distanceSquared = child.distanceSquaredTo2D(parent);
const double sublineWidth = (lineWidth * 0.8);
const double rot = RAD2DEG(child.angleTo2D(parent)) + 90;
GLHelper::pushMatrix();
glTranslated(0, 0, -1);
GLHelper::setColor(color);
if (drawEntire || (distanceSquared < 25)) {
GLHelper::setColor(color);
GLHelper::setColor(color.changedBrightness(-50));
GLHelper::drawBoxLine(child, rot, sqrt(distanceSquared), lineWidth);
glTranslated(0, 0, 0.1);
GLHelper::setColor(color);
GLHelper::drawBoxLine(child, rot, sqrt(distanceSquared), sublineWidth);
} else {
GLHelper::setColor(color.changedBrightness(-50));
GLHelper::drawBoxLine(child, rot, 4.9, lineWidth);
glTranslated(0, 0, 0.1);
GLHelper::setColor(color);
GLHelper::drawBoxLine(child, rot, 4.9, sublineWidth);
if (distanceSquared > 100) {
const PositionVector vector = {child, parent};
GLHelper::setColor(color.changedBrightness(-50));
GLHelper::drawTriangleAtEnd(child,
vector.positionAtOffset2D(5),
s.additionalSettings.arrowWidth,
s.additionalSettings.arrowLength,
s.additionalSettings.arrowOffset);
glTranslated(0, 0, 0.1);
GLHelper::setColor(color);
GLHelper::drawTriangleAtEnd(child,
vector.positionAtOffset2D(5),
s.additionalSettings.arrowWidth - 0.01,
s.additionalSettings.arrowLength - 0.01,
s.additionalSettings.arrowOffset - 0.01);
}
}
GLHelper::popMatrix();
}
}
PositionVector
GUIGeometry::getVertexCircleAroundPosition(const Position& pos, const double width, const int steps) {
if (myCircleCoords.size() == 0) {
for (int i = 0; i <= (int)(360 * CIRCLE_RESOLUTION); ++i) {
const double x = (double) sin(DEG2RAD(i / CIRCLE_RESOLUTION));
const double y = (double) cos(DEG2RAD(i / CIRCLE_RESOLUTION));
myCircleCoords.push_back(Position(x, y));
}
}
PositionVector vertexCircle;
const double inc = 360 / (double)steps;
for (int i = 0; i <= steps; ++i) {
const Position& vertex = myCircleCoords[GUIGeometry::angleLookup(i * inc)];
vertexCircle.push_back(Position(vertex.x() * width, vertex.y() * width));
}
vertexCircle.add(pos);
return vertexCircle;
}
void
GUIGeometry::rotateOverLane(const double rot) {
glRotated((rot * -1) + 90, 0, 0, 1);
}
int
GUIGeometry::angleLookup(const double angleDeg) {
const int numCoords = (int)myCircleCoords.size() - 1;
int index = ((int)(floor(angleDeg * CIRCLE_RESOLUTION + 0.5))) % numCoords;
if (index < 0) {
index += numCoords;
}
assert(index >= 0);
return (int)index;
}
void
GUIGeometry::calculateShapeRotationsAndLengths() {
myShapeRotations.clear();
myShapeLengths.clear();
int numberOfSegments = (int)myShape.size() - 1;
if (numberOfSegments >= 0) {
myShapeRotations.reserve(numberOfSegments);
myShapeLengths.reserve(numberOfSegments);
for (int i = 0; i < numberOfSegments; i++) {
myShapeRotations.push_back(calculateRotation(myShape[i], myShape[i + 1]));
myShapeLengths.push_back(calculateLength(myShape[i], myShape[i + 1]));
}
}
}