Files
qt5-legatus-legacy/Lts/Viewer/SituationMap/MapImpl/sight_fan_impl.cpp
T
2026-08-13 18:33:10 +02:00

802 lines
24 KiB
C++
Executable File

/*
** -----------------------------------------------------------------------------------------------
**
** @RDE_HEADER@
** Implementation of fan of sight
** $Id$
** $HeadURL : svn ://192.168.133.21/TDS/branches/product/devel/trunk/Lts/Viewer/SituationMap/Rubberbands/rubberband.cpp $
** $Author : ehrlicher $
**
** -----------------------------------------------------------------------------------------------
**
** Hardware - Environment : Intel - PC
** Software - Environment : Windows 7, Qt 5.x.ArcGISRuntimeQt 100.2
**
** Language ........ : C++ 11
**
** -----------------------------------------------------------------------------------------------
**
** Autor ........... : Nikolaus Hanekamp, SEDG, Tel. 2906
** Jörg Turla, SPDG, Tel. 3132
**
** -----------------------------------------------------------------------------------------------
**
** Notices ......... :
**
** 01.02.2005, NH : Urversion
** 15.05.2018, JT : adapting GeISiR source to SituationMap
**
** -----------------------------------------------------------------------------------------------
*/
#include "sight_fan_impl.h"
#include <GraphicalObjects/graphical_object_path.h>
#include <Map/bounding_box.h>
#include <Map/coord_translation_functor.h>
#include <MapImpl/layer_factory_impl.h>
#include <MapImpl/map_impl.h>
#include <ElevationMap/elevation_map_manager.h>
#include <MathUtils/math_const.h>
#include <arcgis/Surface.h>
#include <QtCore/QSharedPointer>
#include <QtCore/QVector>
#include <QTimer>
#include <chrono>
using namespace std::chrono_literals;
namespace SituationMap
{
// class SightFanImpl::Internal;
enum SightMode { VISIBLE = 0, INVISIBLE, UNDEFINED, START };
class SightEntry
{
public:
SightEntry() : _dist(0.0), _mode(START) {;}
SightEntry(double dist, SightMode mode) : _dist(dist), _mode(mode) {;}
~SightEntry() = default;
double & dist() { return _dist; }
SightMode & mode() { return _mode; }
double dist() const { return _dist; }
SightMode mode() const { return _mode; }
private:
double _dist;
SightMode _mode;
}; // SightEntry
class SightBeam : public Referenced
{
public:
explicit SightBeam(int beamId, const QPointF &directionB, const QPointF &directionE)
: _beamId(beamId)
, _directionBeg(directionB)
, _directionEnd(directionE)
, _sightEntryVec()
, _graphicalQuadVec() {;}
SightBeam() = delete;
~SightBeam() = default;
QPointF direction() const
{
auto normalize = [](const QPointF &v) -> QPointF
{
double l = sqrt(v.x()*v.x() + v.y()*v.y());
return v / l;
};
return normalize(QPointF((_directionBeg + _directionEnd)*0.5));
} // QPointF direction()
void add(const SightEntry &sightE)
{
_sightEntryVec.push_back(sightE);
} // void add( const SightEntry &sightE)
void clear() { _sightEntryVec.clear(); }
// void draw(const QPointF &beamCenter, osg::Matrixd mat, QColor colors[]); // todo: Farbtabelle
void updateGraphic( MapImpl *mapImpl, AbstractMapObjectImpl *meMapObj, SightFanImpl::Internal * sightFanInternal );
int _beamId;
protected:
QPointF _directionBeg; // Einheitsvektoren die den Beam begrenzen
QPointF _directionEnd;
using SightEntryVec = QVector<SightEntry>;
SightEntryVec _sightEntryVec;
QVector<QSharedPointer<GraphicalObjectPath>> _graphicalQuadVec;
}; /* SightBeam */
class SightFanImpl::Internal
{
public:
using SightBeamVec = std::vector<RefPointer<SightBeam>> ;
QString m_layerName;
std::shared_ptr<ElevationMapManager> m_eMapManager;
QPointF m_center;
double m_centHat;
double m_objHat;
double m_radius;
double m_innerRadius;
double m_startAngle;
double m_dAngle;
unsigned int m_nrFans;
double m_alpha;
QRectF m_location; // Lage des SightFans in Kartenkoordinaten
SightBeamVec m_sightBeamVec;
QColor m_colors[3]; // 0 : visibleCol, 1 : invisibleCol, 2 : undefinedCol
QColor m_fanColorVec[2][4];
float m_fanMult; // Farbabsenkung jedes 2. Beams < 1.0 !
MapImpl *m_mapImpl;
Esri::ArcGISRuntime::Surface *m_surface;
LOGGER_T m_logger; ///< Interface of the Logging-Facility
Internal()
: m_layerName()
, m_center()
, m_centHat(1.8)
, m_objHat(0.5)
, m_radius(0.0)
, m_innerRadius(0.0)
, m_startAngle(0.0)
, m_dAngle(2.0*MathConst::pi/180)
, m_nrFans(180)
, m_alpha(0.8)
, m_fanMult(0.75)
, m_mapImpl(nullptr)
, m_surface(nullptr)
, m_logger(getLogger("SightFanImpl"))
{;}
void setFanColorMap( double brightness, double bias, double alpha)
{
for (int i = 0; i < 3; i++)
{
double r = (m_colors[i].redF() * brightness) + bias;
double g = (m_colors[i].greenF() * brightness) + bias;
double b = (m_colors[i].blueF() * brightness) + bias;
double a = m_colors[i].alphaF() * alpha;
m_fanColorVec[0][i] = QColor::fromRgbF(r,g,b,a);
m_fanColorVec[1][i] = QColor::fromRgbF(r*m_fanMult,g*m_fanMult,b*m_fanMult,a);
}
m_fanColorVec[0][3] = m_fanColorVec[0][2];
m_fanColorVec[1][3] = m_fanColorVec[1][2];
} // void setFanColorMap()
}; // SightFanImpl::Internal
SightFanImpl::SightFanImpl( const QString &debugInfo )
: SightFan()
, QObject()
, AbstractMapObjectImpl(debugInfo)
, m_internal(new Internal())
, m_moveDelayTimer(new QTimer(this))
{
initColors();
m_internal->setFanColorMap(1, 0, 1);
m_moveDelayTimer->setSingleShot(true);
m_moveDelayTimer->setInterval(250ms);
connect(m_moveDelayTimer, &QTimer::timeout, this, &SightFanImpl::delayedMove);
} // SightFanImpl::SightFanImpl
SightFanImpl::~SightFanImpl()
{
delete m_internal;
} // SightFanImpl::~SightFanImpl()
void SightFanImpl::initColors()
{
m_internal->m_fanMult = 0.75;
m_internal->m_colors[0] = QColor(0, 255, 0, 180);
m_internal->m_colors[1] = QColor(255, 0, 0, 180);
m_internal->m_colors[2] = QColor(0, 0, 255, 180);
} // void SightFanImpl::initColors()
void SightFanImpl::setFanColor( const QColor &visible, const QColor &invisible, const QColor &undefined)
{
m_internal->m_colors[0] = visible;
m_internal->m_colors[1] = invisible;
m_internal->m_colors[2] = undefined;
} // void SightFanImpl::setFanColor( const QColor &visible, const QColor &invisible, const QColor &undefined)
void SightFanImpl::setFanColorMark( float colMult)
{
if( colMult > 1.0)
colMult = 1.0;
if( colMult < 0.0)
colMult = 0.0;
m_internal->m_fanMult = colMult;
} // void SightFanImpl::setFanColorMark( float colMult)
void SightFanImpl::setCenter(const QPointF &center) { m_internal->m_center = center; }
void SightFanImpl::setCenter(const Point3D &center) { m_internal->m_center = center.toPointF();
m_internal->m_centHat = center.z(); }
void SightFanImpl::setCenter(const QPointF &center, double centerHat) { m_internal->m_center = center;
m_internal->m_centHat = centerHat; }
void SightFanImpl::setCenterHat(double centerHat) { m_internal->m_centHat = centerHat; }
void SightFanImpl::setObjectHat(double objHat) { m_internal->m_objHat = objHat; }
void SightFanImpl::setRadius(double radius) { m_internal->m_radius = radius; }
void SightFanImpl::setInnerRadius(double radius) { m_internal->m_innerRadius = radius; }
void SightFanImpl::setStartAngle(double startAngle) { m_internal->m_startAngle = startAngle; }
void SightFanImpl::setdeltaAngle(double dAngle) { m_internal->m_dAngle = dAngle; }
void SightFanImpl::setNoOfFans(double noFans) { m_internal->m_nrFans = noFans; }
void SightFanImpl::setAlpha(double alpha)
{
if (alpha < 0.0) alpha = 0.0;
if (alpha > 1.0) alpha = 1.0;
m_internal->m_alpha = alpha;
} // void SightFanImpl::setAlpha(double alpha)
QPointF SightFanImpl::center() const { return m_internal->m_center; }
double SightFanImpl::centerHat() const { return m_internal->m_centHat; }
double SightFanImpl::objectHat() const { return m_internal->m_objHat; }
double SightFanImpl::innerRadius() const { return m_internal->m_innerRadius; }
double SightFanImpl::radius() const { return m_internal->m_radius; }
double SightFanImpl::startAngle() const { return m_internal->m_startAngle; }
double SightFanImpl::dAngle() const { return m_internal->m_dAngle; }
double SightFanImpl::alpha() const { return m_internal->m_alpha; }
unsigned int SightFanImpl::noOfFans() const { return m_internal->m_nrFans; }
bool SightFanImpl::init(MapImpl *mapImpl, const QString &logicalLayerName)
{
if (mapImpl)
{
m_internal->m_mapImpl = mapImpl;
m_internal->m_layerName = logicalLayerName;
m_internal->m_eMapManager = mapImpl->getElevationMapManager();
if (!m_internal->m_eMapManager)
{
ERROR_LOG(m_internal->m_logger) << LOGFUNCTION << " failure, no ElevationMapManager";
return false;
}
if (!AbstractMapObjectImpl::init(mapImpl, logicalLayerName))
{
ERROR_LOG(m_internal->m_logger) << LOGFUNCTION << " failure, AbstractMapObjectImpl::init failed";
return false;
}
return true;
}
ERROR_LOG(m_internal->m_logger) << LOGFUNCTION << " init SightFanImpl failed";
return false;
} // bool SightFanImpl::init(MapImpl *mapImpl, const QString &logicalLayerName)
void SightFanImpl::boundingBox(BoundingBox &bbox) const
{
bbox.reset();
CoordTranslationFunctor * coordTransFunc = m_internal->m_mapImpl->coordTranslationFunctor();
if (coordTransFunc)
{
const QPointF &centerMap = coordTransFunc->geographicToMap(m_internal->m_center);
double diameter = 2 * m_internal->m_radius;
bbox = BoundingBox( BoundingBox::ExtentType::Sim, Point3D::fromQPointF(centerMap), diameter, diameter );
}
} // void SightFanImpl::boundingBox(BoundingBox &bbox) const
//---------------------------------------------------------------------------------------------------
void SightFanImpl::initFan( const Point3D &center
, double objHat
, double radius
, double innerRadius
, double startAngle
, double dAngle
, unsigned int nrFans
, double alpha )
{
initFan( center.toPointF(), center.z(), objHat, radius, innerRadius, startAngle, dAngle, nrFans, alpha );
} // void SightFanImpl::init(...)
void SightFanImpl::initFan( const QPointF &center
, double centHat
, double objHat
, double radius
, double innerRadius
, double startAngle
, double dAngle
, unsigned int nrFans
, double alpha )
{
if (!m_internal->m_mapImpl)
{
ERROR_LOG(m_internal->m_logger) << LOGFUNCTION << " no mapImpl";
return;
}
if (alpha < 0.0) alpha = 0.0;
if (alpha > 1.0) alpha = 1.0;
m_internal->m_center = center;
m_internal->m_centHat = centHat;
m_internal->m_objHat = objHat;
m_internal->m_radius = radius;
m_internal->m_innerRadius = innerRadius;
m_internal->m_startAngle = startAngle;
m_internal->m_dAngle = (dAngle < 0) ? -dAngle : dAngle;
m_internal->m_nrFans = nrFans;
m_internal->m_alpha = alpha;
QPointF offc(m_internal->m_radius, -m_internal->m_radius);
m_internal->m_location = QRectF(m_internal->m_center - offc, m_internal->m_center + offc);
if ((m_internal->m_nrFans*m_internal->m_dAngle) > (MathConst::pi*2.0))
{
m_internal->m_nrFans = floor((MathConst::pi*2.0) / m_internal->m_dAngle + 0.5); // To avoid error with floor; 30.3.2006 JT
}
calculateSightBeamVec();
} /* SightFan::SightFan */
void SightFanImpl::calculateSightBeamVec()
{
m_internal->m_sightBeamVec.clear();
double dAlfa = (m_internal->m_dAngle / 2.0) + 0.00025; // 0.00025 wegen Überlappung, auf antialiazed Systemen nicht nötig
for (unsigned int i = 0; i < m_internal->m_nrFans; i++)
{
double alfa = m_internal->m_startAngle + m_internal->m_dAngle * i;
double alfaBeg = alfa - dAlfa;
double alfaEnd = alfa + dAlfa;
RefPointer<SightBeam> sBeam = RefPointer<SightBeam>(new SightBeam(i, QPointF(cos(alfaBeg), sin(alfaBeg)), QPointF(cos(alfaEnd), sin(alfaEnd))));
calculateSightBeam(*(sBeam.get()));
m_internal->m_sightBeamVec.push_back(sBeam);
}
} // void SightFanImpl::calculateSightBeamVev()
void SightFanImpl::move(const QPointF &center, double centHat, double objHat)
{
m_internal->m_centHat = centHat;
m_internal->m_objHat = objHat;
move(center);
} // void SightFanImpl::move(ElevationMap &eMap, QPointF &center, double centHat, double objHat)
void SightFanImpl::move(const QPointF & center)
{
m_moveDelayedCenter = center;
m_moveDelayTimer->start();
}
void SightFanImpl::show()
{
move( m_internal->m_center );
} // void SightFanImpl::show
bool SightFanImpl::updateViewImplPre()
{
return true;
} // bool SightFanImpl::updateViewImplPre()
bool SightFanImpl::updateViewImpl()
{
show();
return true;
} // bool SightFanImpl::updateViewImpl()
bool SightFanImpl::updateViewImplPost()
{
return true;
} // bool SightFanImpl::updateViewImplPost()
inline QPointF mittelBreitenRechnung(const QPointF &start, const QPointF &direction, double distance)
{
// ---------------------------------------------------------------
// Vec2d mittelBreitenRechnung( Vec2d start, Vec2d direction, double distance )
// Berechnet näherungsweise die Koordinate der Endposition eines
// Beams gemäß der ersten Aufgabe der Besteckrechnung durch das
// Verfahren der Mittelbreite.
// Siehe http://astrosail.de/de/static/tutorial/best3.php?cat=42
// Start ist die Anfangskoordinate im Bogenmaß, direction der
// normierte Richtungsvektor, distance die Entfernung in Metern.
// ---------------------------------------------------------------
double cosKurs = direction.y();
double sinKurs = direction.x();
double distanceBogen = distance / MathConst::EarthRadius;
double lat = distanceBogen * cosKurs + start.y();
double mittelbreite = (start.y() + lat) * 0.5;
double lon = distanceBogen * sinKurs / cos(mittelbreite) + start.x();
return {lon, lat};
}
inline QPointF endOfBeam( const QPointF &start, const QPointF &direction, double distance )
{
return mittelBreitenRechnung(start,direction,distance);
}
void SightFanImpl::calculateSightBeam(SightBeam &sBeam)
{
const QPointF &direction = sBeam.direction();
const QPointF &end = endOfBeam(m_internal->m_center, direction, m_internal->m_radius);
LOSVector losProfile;
m_internal->m_eMapManager->LOSProfile(m_internal->m_center, end, losProfile);
calculateSightBeam(losProfile, sBeam);
sBeam.updateGraphic(m_internal->m_mapImpl, this, m_internal);
} // void SightFanImpl::calculateSightBeam(ElevationMap &eMap, SightBeam &sBeam)
void SightFanImpl::calculateSightBeam( const LOSVector &losProfile, SightBeam &sBeam )
{
sBeam.clear();
if (losProfile.empty()) // Startpunkt undefiniert oder ausserhalb der Karte
{
sBeam.add( SightEntry(m_internal->m_innerRadius, START) );
sBeam.add( SightEntry(m_internal->m_radius, UNDEFINED) );
return;
}
LOSVector::const_iterator itr = losProfile.begin();
double centerHeight = itr->height() + m_internal->m_centHat;
double d1 = 0.0;
double height1 = itr->height();
// überspringen bis _innerRadius erreicht ist !
while(++itr != losProfile.end())
{
double d2 = itr->dist(); // *EarthRadius;
double height2 = itr->height();
if (d2 >= m_internal->m_innerRadius)
{
height1 = height1 + (m_internal->m_innerRadius - d1) * ( height2 - height1)/(d2 - d1);
d1 = m_internal->m_innerRadius;
--itr;
break;
}
d1 = d2;
height1 = height2;
}
// bool visible = true;
SightMode mode = START;
double curM = (height1 - centerHeight ) / d1; // bestimmende Steigung
sBeam.add(SightEntry( d1, START));
if (itr != losProfile.end())
{
while (++itr != losProfile.end())
{
double d2 = itr->dist(); // *EarthRadius;
double height2 = itr->height();
if (std::isnan(height2)) // Undefined
{
if (mode != START)
{
sBeam.add(SightEntry(d1, mode));
}
mode = UNDEFINED;
break;
}
double hObj = (height2 + m_internal->m_objHat - centerHeight );
double objM = hObj / d2; // Steigung bezogen auf Objekte( Objekte verdecken nicht !)
SightMode newMode = ((objM >= curM)) ? VISIBLE : INVISIBLE;
if(newMode != mode)
{
if ((mode != START) && (d2 != d1))
{
// Korrekturwert für Distanz berechnen, unter Berücksichtigung der Objekthoehe !!
double localM = (height2 - height1) /(d2 -d1);
// localM == curM kann nicht auftreten, da newMode != mode
double dCorr = (hObj - (curM * d2)) / (localM - curM);
if (dCorr < 0.0)
dCorr = 0.0;
dCorr = d2 - dCorr;
if (dCorr < d1)
dCorr = d1;
sBeam.add( SightEntry( dCorr, mode) );
}
mode = newMode;
}
double terrM = (height2 - centerHeight) / d2; // Steigung bezogen auf Gelaende
if (terrM >= curM)
{
curM = terrM; // neue bestimmende Steigung
}
height1 = height2;
d1 = d2;
} /* while */
}
sBeam.add( SightEntry(m_internal->m_radius, mode) );
}
/*!
* \brief SightFanImpl::delayedMove
* \param center
* \details Delays the move call to prevent crash of map beacause of the heavy load while moving
*/
void SightFanImpl::delayedMove()
{
m_internal->m_center = m_moveDelayedCenter;
m_internal->setFanColorMap(1, 0, 1);
QPointF offc(m_internal->m_radius, -m_internal->m_radius);
m_internal->m_location = QRectF(m_internal->m_center - offc, m_internal->m_center + offc);
if (m_internal->m_nrFans == m_internal->m_sightBeamVec.size())
{
for (RefPointer<SightBeam> sBeam : qAsConst(m_internal->m_sightBeamVec))
{
calculateSightBeam(*sBeam.get());
}
}
else
{
calculateSightBeamVec();
}
}
void SightBeam::updateGraphic(MapImpl *mapImpl, AbstractMapObjectImpl *meMapObj, SightFanImpl::Internal *sightFanInternal)
{
if (!mapImpl || !meMapObj || !sightFanInternal)
return;
if (_sightEntryVec.size() <= 1)
return;
Esri::ArcGISRuntime::GraphicsOverlay *graphicLayer = sightFanInternal->m_mapImpl->getGraphicsLayer(sightFanInternal->m_layerName);
if (!graphicLayer)
{
ERROR_LOG(sightFanInternal->m_logger) << LOGFUNCTION << " Creating graphic overlayer \'" << sightFanInternal->m_layerName << "\' failed. Can't render sight fan";
return;
}
// _sightEntryVec[0] is SightMode::START
// resize _graphicalQuadVec according _sightEntryVec
// (_sightEntryVec.size() <= 1 is chexck above)
const int newGraphicalSize = _sightEntryVec.size() - 1;
_graphicalQuadVec.resize(newGraphicalSize);
CoordTranslationFunctor *geoToMap = sightFanInternal->m_mapImpl->coordTranslationFunctor();
int quadNo = 0;
SightEntryVec::iterator itr = _sightEntryVec.begin();
const QPointF &center = sightFanInternal->m_center;
QPointF v0 = endOfBeam(center, _directionBeg, itr->dist());
QPointF v1 = endOfBeam(center, _directionEnd, itr->dist());
if (geoToMap)
{
v0 = geoToMap->geographicToMap(v0);
v1 = geoToMap->geographicToMap(v1);
}
PositionCont locationVec;
// skip first, we know mode==SightMode::START
while (++itr != _sightEntryVec.end())
{
// GraphicalObjectPath already created :
QSharedPointer<GraphicalObjectPath> &spGopRef = _graphicalQuadVec[quadNo];
if (!spGopRef)
{
GraphicalObjectPath * grQuad = new GraphicalObjectPath( GraphicalObjectPathType::Polygon
, mapImpl->getEsriGeoView()
, graphicLayer
, QStringLiteral("FanOfSight-Beam-%1").arg(_beamId)
, meMapObj->uniqueMapId() );
grQuad->setPickable(false);
grQuad->rLineStyle().setLinePattern(LinePattern::Null);
grQuad->rFillStyle().setFillPattern(FillPattern::Solid);
// write to _graphicalQuadVec
spGopRef = QSharedPointer<GraphicalObjectPath>(grQuad);
}
// : GraphicalObjectPath already created
GraphicalObjectPath * grQuad = _graphicalQuadVec[quadNo].data();
Q_ASSERT_X(grQuad, "SightBeam", "GraphicalObjectPath invalid");
SightMode mode = itr->mode();
double dist = itr->dist();
QColor quadColor = sightFanInternal->m_fanColorVec[_beamId % 2][int(mode)];
quadColor.setAlphaF( quadColor.alphaF()*sightFanInternal->m_alpha );
grQuad->rFillStyle().setFillColor(quadColor);
QPointF v2 = endOfBeam(center, _directionBeg, dist);
QPointF v3 = endOfBeam(center, _directionEnd, dist);
if (geoToMap)
{
v2 = geoToMap->geographicToMap(v2);
v3 = geoToMap->geographicToMap(v3);
}
locationVec.clear();
locationVec << Point3D::fromQPointF(v0);
locationVec << Point3D::fromQPointF(v1);
locationVec << Point3D::fromQPointF(v2);
locationVec << Point3D::fromQPointF(v3);
grQuad->setPositions(locationVec);
grQuad->updateView();
v0 = v3;
v1 = v2;
++quadNo;
} /* while */
} // void SightBeam::updateGraphic(MapImpl *mapImpl, AbstractMapObjectImpl *meMapObj, SightFanImpl::Internal *sightFanInternal)
#ifdef NEVER
bool SightFan::draw( const AbstractView * const view, osg::Matrixd mat,
float alpha, float brightness, float bias, MapObject::RenderState rstate ) // todo: Farbtabelle
{
if ((rstate & _renderState) == 0) return false;
if( !( _location.intersects( view->rectBound()) )) return false; // isCulled
ColorVec colors[2][4];
for( int i = 0; i < 3; i++)
{
colors[0][i] = (_colors[i] * brightness) + bias;
colors[1][i] = colors[0][i] * _fanMult;
colors[0][i].alpha = alpha * _colors[i].alpha;
colors[1][i].alpha = alpha * _colors[i].alpha;
}
colors[0][3] = colors[0][2];
colors[1][3] = colors[1][2];
GLint shadeModel;
glGetIntegerv( GL_SHADE_MODEL, &shadeModel );
glShadeModel(GL_FLAT);
glEnable( GL_BLEND);
int n = 0;
for( SightBeamVec::iterator itr = _sightBeamVec.begin(); itr != _sightBeamVec.end(); ++itr)
{
(*itr).get()->draw( _center, mat, colors[(++n)%2]);
}
glDisable( GL_BLEND);
glShadeModel(shadeModel);
return true;
} /* SightFan::draw */
void SightBeam::draw( Vec2d center, osg::Matrixd mat, ColorVec colors[]) // todo: Farbtabelle !?
{
float z = 0;
if( _sightEntryVec.size() <= 1) return;
SightEntryVec::iterator itr = _sightEntryVec.begin();
Vec2d v0 = endOfBeam( center, _directionBeg, (*itr).dist() );
Vec2d v1 = endOfBeam( center, _directionEnd, (*itr).dist() );
osg::Vec3d _v0 = mat.preMult( osg::Vec3d( v0[0], v0[1], 0.0 ));
osg::Vec3d _v1 = mat.preMult( osg::Vec3d( v1[0], v1[1], 0.0 ));
glBegin( GL_QUAD_STRIP);
{
glVertex3f( _v0.x(), _v0.y(), z);
glVertex3f( _v1.x(), _v1.y(), z);
while( ++itr != _sightEntryVec.end() )
{
SightMode mode = (*itr).mode();
glColor4f( colors[mode].red, colors[mode].green, colors[mode].blue, colors[mode].alpha);
v0 = endOfBeam( center, _directionBeg, (*itr).dist() );
v1 = endOfBeam( center, _directionEnd, (*itr).dist() );
_v0 = mat.preMult( osg::Vec3d( v0[0], v0[1], 0.0 ));
_v1 = mat.preMult( osg::Vec3d( v1[0], v1[1], 0.0 ));
glVertex3f( _v0.x(), _v0.y(), z);
glVertex3f( _v1.x(), _v1.y(), z);
} /* while */
}
glEnd();
} /* SightBeam::draw */
#endif
} // SituationMap