7 #include "scene2D/adaptor/SCurvedHistogram.hpp" 9 #include <fwData/Float.hpp> 10 #include <fwData/Histogram.hpp> 11 #include <fwData/mt/ObjectReadLock.hpp> 12 #include <fwData/Point.hpp> 14 #include <fwRenderQt/bspline.hpp> 15 #include <fwRenderQt/data/InitQtPen.hpp> 16 #include <fwRenderQt/Scene2DGraphicsView.hpp> 18 #include <fwServices/macros.hpp> 20 #include <QGraphicsRectItem> 21 #include <QGraphicsView> 33 static const ::fwServices::IService::KeyType s_POINT_INOUT =
"point";
34 static const ::fwServices::IService::KeyType s_HISTOGRAM_INPUT =
"histogram";
41 SCurvedHistogram::SCurvedHistogram() noexcept :
42 m_painterPath(
nullptr),
51 SCurvedHistogram::~SCurvedHistogram() noexcept
61 const ConfigType config = this->
getConfigTree().get_child(
"config.<xmlattr>");
63 m_innerColor = QPen( Qt::transparent );
64 m_borderColor = QPen( Qt::transparent );
65 m_brush = QBrush( Qt::NoBrush );
67 if (config.count(
"borderColor"))
70 m_borderColor, config.get<std::string>(
"borderColor"),
m_opacity );
73 if (config.count(
"innerColor"))
76 m_innerColor, config.get<std::string>(
"innerColor"),
m_opacity );
79 if (config.count(
"borderWidth"))
81 m_borderWidth = config.get<
float>(
"borderWidth");
90 m_borderColor.setCosmetic(
true );
91 m_borderColor.setWidthF( static_cast<qreal>(m_borderWidth) );
92 m_borderColor.setStyle( Qt::SolidLine );
93 m_borderColor.setJoinStyle( Qt::RoundJoin );
94 m_borderColor.setCapStyle( Qt::RoundCap );
96 m_brush = QBrush( m_innerColor.color() );
103 SCurvedHistogram::Points SCurvedHistogram::getControlPoints(const ::fwData::Histogram::csptr& _histogram)
const 105 ::fwData::Histogram::fwHistogramValues histogramValues = _histogram->getValues();
106 const float binsWidth = _histogram->getBinsWidth();
107 const float histogramMin = _histogram->getMinValue();
110 Points controlPoints;
111 const size_t nbValues = histogramValues.size();
115 for(
size_t i = 0; i < nbValues; ++i)
117 p.first =
static_cast<double>(histogramMin + i * binsWidth);
118 p.second = histogramValues[i];
120 controlPoints.push_back( p );
123 return controlPoints;
128 SCurvedHistogram::Points SCurvedHistogram::getBSplinePoints(
const Points& _points )
const 130 Points bSplinePoints;
135 list.add_point(
new point(static_cast<float>( _points[0].first), static_cast<float>( _points[0].second * 2) ));
138 for(
const auto& pt : _points )
140 list.add_point(
new point(static_cast<float>(pt.first), static_cast<float>(pt.second) ));
144 list.add_point(
new point(static_cast<float>( _points.back().first),
145 static_cast<float>( _points.back().second / 2 ) ));
149 curve.m_precision =
static_cast<int>(_points.size() * 5);
152 for(
int i = 0; i < curve.m_precision; ++i)
154 bSplinePoints.push_back( Point( curve.m_curve_point[i].x, curve.m_curve_point[i].y ) );
157 return bSplinePoints;
162 SCurvedHistogram::Points SCurvedHistogram::getResampledBSplinePoints(
const Points& _bSplinePoints )
const 165 Point
point = _bSplinePoints.front();
168 const double maxLength = 2000;
169 double segmentLength = 0;
171 points.push_back( point );
173 for(Points::const_iterator it = _bSplinePoints.begin() + 1; it != _bSplinePoints.end(); ++it)
175 dx = abs((*it).first - point.first);
176 dy = abs((*it).second - point.second);
178 segmentLength += sqrt( dx * dx + dy * dy );
180 if(segmentLength > maxLength)
182 points.push_back( *it );
189 points.push_back( _bSplinePoints.back() );
191 OSLM_TRACE(
"B-Spline points size moved from " << _bSplinePoints.size() <<
" to " << points.size());
198 void SCurvedHistogram::computePointToPathLengthMapFromBSplinePoints(Points& _bSplinePoints )
200 Points::iterator it = _bSplinePoints.begin();
202 if( it != _bSplinePoints.end())
207 QPointF prevPt = QPointF(p.first, p.second);
208 m_painterPath->lineTo( p.first, p.second );
209 qreal len = m_painterPath->length();
212 for(; it != _bSplinePoints.end(); ++it)
216 m_painterPath->lineTo( p.first, p.second );
221 QPointF pt(p.first, p.second);
222 len += QLineF( prevPt, pt ).length();
223 m_positionsToPathLength[
static_cast<int>( p.first ) ] = len;
236 const ::fwData::Histogram::csptr histogram = this->getInput< ::fwData::Histogram>(s_HISTOGRAM_INPUT);
240 m_layer =
new QGraphicsItemGroup();
242 m_painterPath =
new QPainterPath();
244 if (!histogram->getValues().empty())
246 Points controlPoints = this->getControlPoints( histogram );
247 Points bSplinePoints = this->getBSplinePoints( controlPoints );
249 this->computePointToPathLengthMapFromBSplinePoints( bSplinePoints );
252 Points resampledBSplinePoints = this->getResampledBSplinePoints( bSplinePoints );
253 bSplinePoints = resampledBSplinePoints;
255 this->buildBSplineFromPoints( bSplinePoints );
258 m_layer->setPos(static_cast<qreal>(
m_xAxis->getOrigin() ), static_cast<qreal>(
m_yAxis->getOrigin() ));
259 m_layer->setZValue(static_cast<qreal>(
m_zValue ));
268 void SCurvedHistogram::buildBSplineFromPoints(Points& _bSplinePoints )
270 const ::fwData::Histogram::csptr histogram = this->getInput< ::fwData::Histogram>(s_HISTOGRAM_INPUT);
272 const bool useBorderColor = (m_borderColor.color() != Qt::transparent);
273 const bool useInnerColor = (m_innerColor.color() != Qt::transparent);
275 Point currentPoint = this->
mapAdaptorToScene( Point(histogram->getMinValue(), _bSplinePoints[0].second),
277 Point previousPoint = currentPoint;
280 const QPointF startPoint( currentPoint.first, currentPoint.second / 10 );
282 QPainterPath path( QPointF(startPoint.x(), 0.0) );
283 path.lineTo( startPoint );
285 previousPoint.first = startPoint.x();
286 previousPoint.second = startPoint.y();
289 for(it = _bSplinePoints.begin() + 1; it != _bSplinePoints.end(); ++it)
293 path.lineTo( currentPoint.first, currentPoint.second );
297 m_painterPath->lineTo( static_cast<qreal>( histogram->getMaxValue() ), _bSplinePoints.back().second);
301 path.lineTo( currentPoint.first, 0.0 );
302 this->addBorderItem( path );
307 path.lineTo( previousPoint.first, 0.0 );
308 this->addInnerItem( path );
314 void SCurvedHistogram::addInnerItem(
const QPainterPath& _path )
316 QGraphicsPathItem* item =
new QGraphicsPathItem( _path );
317 item->setPen( Qt::NoPen );
318 item->setBrush( m_brush );
319 item->setPath( _path );
320 item->setCacheMode( QGraphicsItem::DeviceCoordinateCache );
323 m_layer->addToGroup( item );
328 void SCurvedHistogram::addBorderItem(
const QPainterPath& _path )
330 QGraphicsPathItem* item =
new QGraphicsPathItem( _path );
331 item->setPen( m_borderColor );
332 item->setBrush( Qt::NoBrush );
333 item->setPath( _path );
334 item->setCacheMode( QGraphicsItem::DeviceCoordinateCache );
337 m_layer->addToGroup( item );
342 SCurvedHistogram::Points SCurvedHistogram::quadraticInterpolation(
343 const Point _p0,
const Point _p1,
const Point _p2 )
349 2 * ((_p2.second - _p1.second) / (_p2.first - _p1.first) - (_p1.second - _p0.second)
350 / (_p1.first - _p0.first))
351 / (_p2.first - _p0.first);
353 const double d1 = (_p2.second - _p1.second) / (_p2.first - _p1.first) - 0.5 * d2 * (_p2.first - _p1.first);
354 const double d0 = _p1.second;
356 points.push_back( _p0 );
358 for(
double x = _p0.first;
x < _p2.first;
x += 0.5)
361 p.second = 0.5 * d2 * pow(
x - _p1.first, 2) + d1 * (
x - _p1.first) + d0;
363 points.push_back( p );
371 SCurvedHistogram::Points SCurvedHistogram::cosinusInterpolation(
const Point _p0,
const Point _p1)
376 const double deltaX = _p1.first - _p0.first;
378 for(
double mu = 0.0; mu < 1.0; mu += 0.05)
380 mu2 = (1 - std::cos(mu * PI)) / 2;
382 p.first = _p0.first + mu * deltaX;
383 p.second = _p0.second * (1 - mu2) + _p1.second * mu2;
385 points.push_back( p );
393 SCurvedHistogram::Points SCurvedHistogram::cubicInterpolation(
394 const Point _p0,
const Point _p1,
const Point _p2,
const Point _p3 )
398 double a0, a1, a2, a3, mu2;
399 const double deltaX = _p2.first - _p1.first;
400 for(
double mu = 0.0; mu < 1.0; mu += 0.01)
412 a0 = -0.5*_p0.second + 1.5*_p1.second - 1.5*_p2.second + 0.5*_p3.second;
413 a1 = _p0.second - 2.5*_p1.second + 2*_p2.second - 0.5*_p3.second;
414 a2 = -0.5*_p0.second + 0.5*_p2.second;
417 p.first = _p1.first + mu * deltaX;
418 p.second = a0 * mu * mu2 +a1 * mu2 + a2 * mu + a3;
420 points.push_back( p );
428 void SCurvedHistogram::updateCurrentPoint(const ::fwRenderQt::data::Event& _event, const ::fwData::Point::sptr&
point )
430 const ::fwData::Histogram::csptr histogram = this->getInput< ::fwData::Histogram>(s_HISTOGRAM_INPUT);
431 const ::fwData::Histogram::fwHistogramValues values = histogram->getValues();
433 const float histogramMinValue = histogram->getMinValue();
434 const float histogramBinsWidth = histogram->getBinsWidth();
437 const ::fwRenderQt::data::Coord sceneCoord = this->
getScene2DRender()->mapToScene( _event.getCoord() );
439 const int histIndex =
static_cast<int>( sceneCoord.getX() );
440 const int index =
static_cast<const int>(histIndex - histogramMinValue);
441 const int nbValues =
static_cast<int>(values.size() * histogramBinsWidth);
443 if(index >= 0 && index < nbValues && m_positionsToPathLength.find( histIndex ) != m_positionsToPathLength.end())
445 const double key = m_positionsToPathLength[ histIndex ];
446 const double percent = m_painterPath->percentAtLength( key );
447 const QPointF qPoint = m_painterPath->pointAtPercent( percent );
449 point->getCoord()[0] = sceneCoord.getX();
450 point->getCoord()[1] = qPoint.y() *
static_cast<double>(m_scale);
456 SCurvedHistogram::Points SCurvedHistogram::linearInterpolation(
const Point _p1,
const Point _p2 )
461 for(
int i = 0; i < 100; ++i)
465 p.first = _p1.first + ( _p2.first - _p1.first ) * static_cast<double>(t);
466 p.second = _p1.second + ( _p2.second - _p1.second ) * static_cast<double>(t);
467 points.push_back( p );
483 m_positionsToPathLength.clear();
486 delete m_painterPath;
487 m_painterPath =
nullptr;
495 bool updatePointedPos =
false;
498 if( _event.getType() == ::fwRenderQt::data::Event::MouseWheelUp )
501 m_layer->setTransform(QTransform::fromScale(1, static_cast<qreal>(
SCALE) ),
true);
503 updatePointedPos =
true;
505 else if( _event.getType() == ::fwRenderQt::data::Event::MouseWheelDown )
508 m_layer->setTransform(QTransform::fromScale(1, 1 / static_cast<qreal>(
SCALE) ),
true);
510 updatePointedPos =
true;
512 else if( _event.getType() == ::fwRenderQt::data::Event::MouseMove )
514 updatePointedPos =
true;
517 ::fwData::Point::sptr point = this->getInOut< ::fwData::Point>( s_POINT_INOUT );
518 if( point && updatePointedPos )
520 this->updateCurrentPoint( _event, point );
Root class for all scene2d adaptors.
static const float SCALE
Ratio used for vertical scaling (default value: 1.1)
::fwRenderQt::data::Axis::sptr m_xAxis
The x Axis.
This class is a helper to define the connections of a service and its data.
static const float NB_POINTS_BEZIER
The number of points between to points of the final Bezier curve to compute.
FWRENDERQT_API Point2DType mapAdaptorToScene(const Point2DType &_xy, const ::fwRenderQt::data::Axis::sptr &_xAxis, const ::fwRenderQt::data::Axis::sptr &_yAxis) const
SCENE2D_API::fwServices::IService::KeyConnectionsMap getAutoConnections() const override
Returns proposals to connect service slots to associated object signals, this method is used for obj/...
FWRENDERQT_API std::shared_ptr< ::fwRenderQt::SRender > getScene2DRender() const
Get the render that manages the IAdaptor.
A helper to lock object on read mode.
#define OSLM_TRACE(message)
static FWRENDERQT_API void setPenColor(QPen &_pen, std::string _color)
Set a pen a color.
SCENE2D_API void processInteraction(::fwRenderQt::data::Event &_event) override
SCENE2D_API void starting() override
Initialize the service activity.
This bundles contains data and services used to display a 2D Qt scene.
SCENE2D_API void configuring() override
Configure the service before starting. Apply the configuration to service.
SCENE2D_API void updating() override
Perform some computations according to object (this service is attached to) attribute values and its ...
::fwRenderQt::data::Axis::sptr m_yAxis
The y Axis.
IAdaptor implementation for histogram data.
float m_opacity
Opacity of the adaptor. Default value set to 1 (opaque).
FWRENDERQT_API void configureParams()
Parse the xml configuration for Axis, z value and opacity.
static FWDATA_APIconst::fwCom::Signals::SignalKeyType s_MODIFIED_SIG
Key in m_signals map of signal m_sigModified.
SCENE2D_API void stopping() override
Uninitialize the service activity. The stop() method is always invoked before destroying a service...
This class manage events on the scene 2D (mouse event, keyboard event , ...).
static FWSERVICES_APIconst::fwCom::Slots::SlotKeyType s_UPDATE_SLOT
Slot to call start method.
FWSERVICES_API ConfigType getConfigTree() const
Return the configuration, in an boost property tree.