[SOLVED] Custom NonSattelite PositionSource
-
Hi folks.
Some of you aware that QML's PositionSource has got some issues currently with positioning indoors (http://bugreports.qt.nokia.com/browse/QTMOBILITY-1550 FYI). This will be possibly fixed by making methods writable from QML (http://bugreports.qt.nokia.com/browse/QTMOBILITY-1631) approx since Qt Mobility 1.3
But since I have no time to wait for QtM 1.3 I would like to make it clear for myself is it possible to do a Qt C++ based snippet and expose it to QML which will be purely non-sattelite position method?
I mean something like add to main.cpp a snippet of code with QGeoPositionInfoSource being set to nonsat method (via QGeoPositionInfoSource::setPreferredPositioningMethods) and make it "callable" from within QML? just like if it would be the PositionSource element that only works with non-sattelite method. (I hope I explained it clear enough:)
Fact is - for me and many other developers GPS based methods are less important than non-GPS - as in many cases people use the apps indoors OR the precision of their location is not required to be a few meters (ok to have 1000m radius even)
Please advise?
-
I'm not exactly sure I understand what you're trying to do. But it's easy to create you own QGeoPositionInfoSource and use that from C++. Then you can expose the calculated position to QML.
However that would mean you have to write you own positioning logic. Not sure that's what you want :)
-
Thanks Conny, I think you answered that...so in theory I am able to create my own nonsattelite source in C++ and expose the position to QML...
My goal is to make geolocation available based on non-satellite method only since it is faster and precision is ok for the task...
-
Yes you can. But as I said, you then have to implement the source yourself. Where are you getting the non-satellite data from?
-
Hi Conny, not sure I quite understand what you mean by implement source?
Current plan is:
- take source code snippet from this example http://developer.qt.nokia.com/wiki/Retrieve_Location_Using_Qt_Mobility
- find the way how to expose to QML the location data (latitude, longitude)
SO eventually I should have longitude and latitude data available with updates in QML from non-sat source, isn't it?:)
-
Hmm, I had implemented the Qt C++ code from the examples, I learned a bit on how to expose Qt C++ data to QML, but seems I am not quite there to do it properly...
The code in C++ actually "loads" data into m_pLabel (below)
@QGeoCoordinate geoCoordinate = geoPositionInfo.coordinate();
qreal latitude = geoCoordinate.latitude();
qreal longitude = geoCoordinate.longitude();m_pLabel->setText( QString("Latitude: %1 \n Longitude: %2").arg(latitude).arg(longitude) );@
But how can I refer to this text in C++ to get it passed as ContextProperty to QML??
@QmlApplicationViewer viewer;
viewer.setOrientation(QmlApplicationViewer::ScreenOrientationLockPortrait);
viewer.rootContext()->setContextProperty("currentDateTime",m_pLabel.text );@What should be there in the code instead of m_pLabel.text?
I know I am naive trying to apply QML approach;) Please help!
-
A QObject subclass instance exposing the text via a property with a proper notify signal :P
-
Hmm what do you mean?
Sorry I only started C++ "induction" :(I got the idea - I need to set a NOTIFY property and signal for an object.
But what would be the best solution here - to create a new QObject, somehow pass to it the location data from the m_pLabel and then expose to QML??[EDIT: fixed smiley that made "induction" a link :-), Volker]
-
You don't need the label at all.
Write your own QObject subclass, expose a QString(if you want the data to be exposed as text) property with READ and NOTIFY. And make sure to emit your NOTIFY signal whenever the value changes.
Just create an instance of your class and expose to QML as a context property.
"Exchanging data between QML and C++":http://developer.qt.nokia.com/doc/qt-4.7/qtbinding.html#id-1b3a8b62-0fb5-44c3-b68b-ee1cbf29d0c3
-
Thanks a lot;) !
I will try to post my code hereto for the others and put SOLVED afterwards
-
Kkrzewniak, many thanks for your help, could you please validate the code a bit (I guess I am still missing the part with emiting signal and also seems like I haven't yet added important chunk of the code to the CPP file...
Header:
@class NonSatCoordsSource : public QObject
{
Q_OBJECT
Q_PROPERTY (QString text READ text WRITE setText NOTIFY textChanged)
public:
void positionUpdated(QGeoPositionInfo geoPositionInfo);
private:
void startLocationAPI();
QGeoPositionInfoSource* m_pLocationInfo;
QString* m_pString;
signals:
void textChanged();
};@I declared the class and made one property there which could be read/written and notified.
I also declared the functions (at least I hope I did it correctly)Now in CPP part I need to expose the class and describe these functions as I get it:
@NonSatCoordsSource::NonSatCoordsSource(QObject *parent) : m_pLocationInfo(NULL), m_pString(NULL)
NonSatCoordsSource::~NonSatCoordsSource()
{}
void NonSatCoordsSource::startLocationAPI()
{
if (!m_pLocationInfo)
{
m_pLocationInfo =
QGeoPositionInfoSource::createDefaultSource(this);
m_pLocationInfo->setPreferredPositioningMethods(QGeoPositionInfoSource::NonSatellitePositioningMethods);
connect(m_pLocationInfo, SIGNAL(positionUpdated(QGeoPositionInfo)),
this, SLOT(positionUpdated(QGeoPositionInfo)));
m_pLocationInfo->startUpdates();
}
}void NonSatCoordsSource::positionUpdated(QGeoPositionInfo geoPositionInfo)
{
if (geoPositionInfo.isValid())
{
QGeoCoordinate geoCoordinate = geoPositionInfo.coordinate();
qreal latitude = geoCoordinate.latitude();
qreal longitude = geoCoordinate.longitude();
m_pString->setText( QString("Lat: %1 Long: %2").arg(latitude).arg(longitude) );
}
}@This is where I stuck basically for now just reading C++ for dummies further...But feels like I am close enough?:)
-
Here is the solution and final "code" (sorry if it is not high class code though as I only started to learn Qt). So basically I am able to turn it on off using nonsatdata.enable(), I can "read" the coordinates from within QML via nonsatdata.lat and nonsatdata.lon...
The problem I have below is that the signals are not working/firing off (onLatChanged and onLonChanged ) ;(
I kind of feel what the problem is but can't fix it...so any help is very appreciated!- Qml:
@import NonSatLocation 1.0
...
NonSatLocation { // defined in nonsat.cpp & h, exposed to qml as a type
id: nonsatdata
onLatChanged: { console.log("signal nonsatdata.lat")}
onLonChanged: { console.log("signal nonsatdata.lon")}
}
@- main.cpp:
@...
qmlRegisterType<NonSatLocation> ("NonSatLocation", 1,0, "NonSatLocation");
...@- nonsat.h:
@class NonSatLocation : public QObject
{
Q_OBJECT
Q_PROPERTY (double lat READ lat WRITE setLat NOTIFY latChanged)
Q_PROPERTY (double lon READ lon WRITE setLon NOTIFY lonChanged)
public:
NonSatLocation (QObject *parent = 0);
double lat () const {return m_lat;}
double lon () const {return m_lon;}
void setLat (double &lat)
{
m_lat = lat;
emit latChanged();
}
void setLon (double &lon)
{
m_lon = lon;
emit lonChanged();
}Q_INVOKABLE void enable(); Q_INVOKABLE void disable();
signals:
void latChanged();
void lonChanged();private slots:
void positionUpdated(const QGeoPositionInfo &info);private:
double m_lat;
double m_lon;
QGeoPositionInfoSource *source;
};@- nonsat.cpp:
@NonSatLocation::NonSatLocation (QObject *parent)
: QObject (parent)
{
source = QGeoPositionInfoSource::createDefaultSource(this);
if (source) {
source->setUpdateInterval(3000); // time in milliseconds
source->setPreferredPositioningMethods(QGeoPositionInfoSource::NonSatellitePositioningMethods);
}
}void NonSatLocation::enable()
{
if (source) {
connect(source, SIGNAL(positionUpdated(QGeoPositionInfo)),
this, SLOT(positionUpdated(QGeoPositionInfo)));
source->startUpdates();
}
}
void NonSatLocation::disable()
{
if (source) {
source->stopUpdates();
disconnect(source, SIGNAL(positionUpdated(QGeoPositionInfo)),
this, SLOT(positionUpdated(QGeoPositionInfo)));
}
}
void NonSatLocation::positionUpdated(const QGeoPositionInfo &info)
{
if (info.isValid()) {qDebug() << info.coordinate(); QGeoCoordinate geoCoordinate = info.coordinate(); double latitude = geoCoordinate.latitude(); double longitude = geoCoordinate.longitude(); m_lat = latitude; m_lon = longitude; }
}@
-
Yes you are missing one more think:
instead of:
@m_lat = latitude;
m_lon = longitude;@
you should use your methods that call signals i.e :
@setLat(latitude);
setLon(longitude);@
And that's it, it works !!!
By the way thanks for sharing your code :)