Read a list of parameters from a LuaRef using LuaBridge - c++

[RESOLVED]
I'm building a game engine that uses LuaBridge in order to read components for entities. In my engine, an entity file looks like this, where "Components" is a list of the components that my entity has and the rest of parameters are used to setup the values for each individual component:
-- myEntity.lua
Components = {"MeshRenderer", "Transform", "Rigidbody"}
MeshRenderer = {
Type = "Sphere",
Position = {0,300,0}
}
Transform = {
Position = {0,150,0},
Scale = {1,1,1},
Rotation = {0,0,0}
}
Rigidbody = {
Type = "Sphere",
Mass = 1
}
I'm currently using this function (in C++) in order to read the value from a parameter (given its name) inside a LuaRef.
template<class T>
T readParameter(LuaRef& table, const std::string& parameterName)
{
try {
return table.rawget(parameterName).cast<T>();
}
catch (std::exception e) {
// std::cout ...
return NULL;
}
}
For example, when calling readVariable<std::string>(myRigidbodyTable, "Type"), with myRigidbodyTable being a LuaRef with the values of Rigidbody, this function should return an std::string with the value "Sphere".
My problem is that when I finish reading and storing the values of my Transform component, when I want to read the values for "Ridigbody" and my engine reads the value "Type", an unhandled exception is thrown at Stack::push(lua_State* L, const std::string& str, std::error_code&).
I am pretty sure that this has to do with the fact that my component Transform stores a list of values for parameters like "Position", because I've had no problems while reading components that only had a single value for each parameter. What's the right way to do this, in case I am doing something wrong?
I'd also like to point out that I am new to LuaBridge, so this might be a beginner problem with a solution that I've been unable to find. Any help is appreciated :)

Found the problem, I wasn't reading the table properly. Instead of
LuaRef myTable = getGlobal(state, tableName.c_str());
I was using the following
LuaRef myTable = getGlobal(state, tableName.c_str()).getMetatable();

Related

What is the equivalent of TiXmlAttribute for tinyxml2 and how to use it?

I've encountered a problem that I'm not being able to solve using tinyxml2.
I have a function that receives as a parameter a XMLElement and I need to iterate over its attributes. With tinyxml, this worked:
void xmlreadLight(TiXmlElement* light){
for (TiXmlAttribute* a = light->FirstAttribute(); a ; a = a->Next()) {
//Do stuff
}
}
Using the same with tinyxml2, like in the example below, I get the following error:
a value of type const tinyxml2::XMLAttribute * cannot be used to initialize an entity of type tinyxml2::XMLAttribute *
void xmlreadLight(XMLElement* light){
for (XMLAttribute* a = light->FirstAttribute(); a ; a = a->Next()) {
//Do stuff
}
}
The XML code in question is:
<lights>
<light type="POINT" posX=-1.0 posY=1.0 posZ=-1.0 ambtR=1.0 ambtG=1.0 ambtB=1.0 />
</lights>
where light is the XMLElement passed into the function xmlreadLight. Not sure if my question is properly set up, so if theres some info missing, let me know.
Going by the error message, it looks like you need to do:
for (const XMLAttribute* a = light->FirstAttribute(); a ; a = a->Next()) { ...
^^^^^
Presumbably, the return type of FirstAttribute has been made const in tinyxml2.
If you check the Github repository for the tinyxml2.h file on line 1513 you will see this:
/// Return the first attribute in the list.
const XMLAttribute* FirstAttribute() const {
return _rootAttribute;
}

Assign randomly chosen, but matching parameters for connected OMNeT++ gates?

I'm developing a network model in OMNeT++ in which I have introduced a custom channel type to represent links in my network. For one property of this channel type's instances, I'd like to assign a random parameter. However, the random number should be the same for connected gates.
My node definition has the following gates definition:
simple GridAgent
{
/* ... other paramters/definitions omitted ... */
gates:
inout agentConnections[];
}
In my network configuration, I connect nodes using the simple <--> syntax, e.g.:
someSwitchyard.agentConnections++ <--> AgentConnectionChannel <--> someWindfarm.agentConnections++;
Now, this AgentConnectionChannel has a property called impedance, which I'd like to randomly assign. This impedance property should be the same for both A -> B and B -> A. I have tried to add { impedance = default(unitform(1, 10)) } to the network definition, as well as putting **.agentConnections$o[*].channel.impedance = uniform(1, 10) into omnetpp.ini. In both cases, however, A -> B has a different value assigned than B -> A.
As indicated on the OMNet++ mailing list, this happens because the <--> syntax is actually a shorthand for creating two distinct connections, hence two drawings from the random number distribution happen.
How can I assign a random parameter to a connection's property and have the same value for both directions of two connected gates? Is there a way to do this in the omnetpp.ini file, or do I need to create a script in, e.g., Perl, Ruby, or Python to generate the omnetpp.ini for my runs?
There is no simple solution of your problem, and it could not be resolved manipulating omnetpp.ini file merely.
I propose manual rewriting a parameter value for the second direction. It requires preparing a C++ class for a channel (which you have probably done).
Assuming that your channel definition in NED is following:
channel AgentConnectionChannel extends ned.DatarateChannel {
#class(AgentConnectionChannel);
double impedance;
}
and in omnetpp.ini you has:
**.agentConnections$o[*].channel.impedance = uniform(1, 10)
you should prepare C++ class AgentConnectionChannel:
class AgentConnectionChannel: public cDatarateChannel {
public:
AgentConnectionChannel() : parAlreadyRewritten(false) {}
void setParAlreadyRewritten() {parAlreadyRewritten=true;}
protected:
virtual void initialize();
private:
bool parAlreadyRewritten;
private:
double impedance;
};
Define_Channel(AgentConnectionChannel);
void AgentConnectionChannel::initialize() {
if (parAlreadyRewritten == false) {
parAlreadyRewritten = true;
cGate * srcOut = this->getSourceGate();
cModule *owner = srcOut->getOwnerModule();
int index = srcOut->isVector() ? srcOut->getIndex() : -1;
cGate *srcIn = owner->gateHalf(srcOut->getBaseName(), cGate::INPUT,
index);
cChannel * channel = srcIn->findIncomingTransmissionChannel();
AgentConnectionChannel * reverseChan =
dynamic_cast<AgentConnectionChannel*>(channel);
if (reverseChan) {
reverseChan->setParAlreadyRewritten();
// assigning a value from forward direction channel
reverseChan->par("impedance") = this->par("impedance");
}
}
// and now read a parameter as usual
impedance = par("impedance").doubleValue();
EV << getFullPath() << ", impedance=" << impedance << endl;
}

Extract polygons from shapefile using Geotools

I have a shape file (Sample.shp) along with two other files (Sample.shx and Sample.dbf), which has geometry (polygons) defined for 15 pincodes of Bombay.
I am able to view the .shp file using the Quickstart tutorial.
File file = JFileDataStoreChooser.showOpenFile("shp", null);
if (file == null) {
return;
}
FileDataStore store = FileDataStoreFinder.getDataStore(file);
SimpleFeatureSource featureSource = store.getFeatureSource();
// Create a map content and add our shapefile to it
MapContent map = new MapContent();
map.setTitle("Quickstart");
Style style = SLD.createSimpleStyle(featureSource.getSchema());
Layer layer = new FeatureLayer(featureSource, style);
map.addLayer(layer);
// Now display the map
JMapFrame.showMap(map);
Now I want to convert the geometry of these 15 pincodes to 15 Geometry/Polygon objects so that I can use Geometry.contains() to find if a point falls in a particular Geometry/Polygon.
I tried:
ShapefileReader r = new ShapefileReader(new ShpFiles(file),true,false,geometryFactory);
System.out.println(r.getCount(0)); >> returns 51
System.out.println(r.hasNext()); >> returns false
Any help is really appreciated
In fact you don't need to extract the geometries your self - just create a filter and iterate through the filtered collection. In your case there will probably be only one feature returned.
Filter pointInPolygon = CQL.toFilter("CONTAINS(the_geom, POINT(1 2))");
SimpleFeatureCollection features = source.getFeatures(filter);
SimpleFeatureIterator iterator = features.features();
try {
while (iterator.hasNext()) {
SimpleFeature feature = iterator.next();
Geometry geom = (Geometry) feature.getDefaultGeometry();
/*... do something here */
}
} finally {
iterator.close(); // IMPORTANT
}
For a full discussion of querying datastores see the Query Lab.
I used the above solution and tried a few combinations. Just changed "THE_GEOM" to lower case and POINT is in order (Lon Lat)
Filter filter = CQL.toFilter("CONTAINS(the_geom, POINT(72.82916 18.942883))");
SimpleFeatureCollection collection=featureSource.getFeatures(filter);
SimpleFeatureIterator iterator = collection.features();
try {
while (iterator.hasNext()) {
SimpleFeature feature = iterator.next();
.....
}
} finally {
iterator.close(); // IMPORTANT
}

Qjson handling an returned array of ojbects

I'm using Qjson to parse a json object that is returned from a web service. I'm stuck on handling an array of complex ojects.
At the first level the web service returns a map consisting of "error", "id", and "return". If there are no errors I can get the first level value by using
nestedMap = m_jsonObject["result"].toMap();
group = new Group();
group->Caption = nestedMap["Caption"].toString();
group->CollectionCount = nestedMap["CollectionCount"].toInt();
I can even get a date item value that is at the second level using
group->ModifiedOn = nestedMap["ModifiedOn"].toMap()["Value"].toDateTime();
I have an object called "Elements" that consists of 29 key-value pairs. The web service is returning an array of these "Elements" and I am unable to find the right way to parse it. In the header file the container for the elements is defined as
QList<GroupElement> Elements;
The line
group->Elements = nestedMap["Elements"].toList();
causes the compiler to throw an error 'error: no match for 'operator=' in '((MyClass*)this)->MyClass::group->Group::Elements = QVariant::toMap() const()'
I would like to learn the correct syntax to put this element into the class.
Update: I wrote another function to convert the QVariantMap object to a
first:
The group-> Elements object was changed to a
class ParentClass{
QList<SharedDataPointer<Address> > Elements;
other class memmbers...
};
Second:
A method to convert the QMap object to an Address object was created
QSharedDataPointer<Address>
API_1_6::mapToAddress(QVariantMap o)
{
QSharedDataPointer<Address> address (new Address());
address-> FirstName = o["FirstName"].toString();
address->LastName = o["LastName"].toString();
address->CompanyName = o["CompanyName"].toString();
address->Street = o["Street"].toString();
address->Street2 = o["Street2"].toString();
address->City = o["City"].toString();
address->Zip = o["Zip"].toString();
address-> State = o["State"].toString();
address->Country = o["Country"].toString();
address->Phone = o["Phone"].toString();
address->Phone2 = o["Phone2"].toString();
address-> Fax = o["Fax"].toString();
address-> Url = o["Url"].toString();
address->Email = o["Email"].toString();
address->Other = o["Other"].toString();
return address;
}
third: In the code, foreach is used to walk through the list and create and store the new objects
// get the list of the elements
elementsList = nestedMap["Elements"].toList();
// Add the element, converted to the new type, to the Elements object of the'parent' class
foreach(QVariant qElement, elementsList){
group-> Elements.append(mapToAddress(qElement))
}

Using Conversion Studio by To-Increase to import Notes into Microsoft Dynamics AX 2009

Currently, I'm using Conversion Studio to bring in a CSV file and store the contents in an AX table. This part is working. I have a block defined and the fields are correctly mapped.
The CSV file contains several comments columns, such as Comments-1, Comments-2, etc. There are a fixed number of these. The public comments are labeled as Comments-1...5, and the private comments are labeled as Private-Comment-1...5.
The desired result would be to bring the data into the AX table (as is currently working) and either concatenate the comment fields or store them as separate comments into the DocuRef table as internal or external notes.
Would it not require just setting up a new block in the Conversion Studio project that I already have setup? Can you point me to a resource that maybe shows a similar procedure or how to do this?
Thanks in advance!
After chasing the rabbit down the deepest of rabbit holes, I discovered that the easiest way to do this is like so:
Override the onEntityCommit method of your Document Handler (that extends AppDataDocumentHandler), like so:
AppEntityAction onEntityCommit(AppDocumentBlock documentBlock, AppBlock fromBlock, AppEntity toEntity)
{
AppEntityAction ret;
int64 recId; // Should point to the record currently being imported into CMCTRS
;
ret = super(documentBlock, fromBlock, toEntity);
recId = toEntity.getRecord().recId;
// Do whatever you need to do with the recId now
return ret;
}
Here is my method to insert the notes, in case you need that too:
private static boolean insertNote(RefTableId _tableId, int64 _docuRefId, str _note, str _name, boolean _isPublic)
{
DocuRef docuRef;
boolean insertResult = false;
;
if (_docuRefId)
{
try
{
docuRef.clear();
ttsbegin;
docuRef.RefCompanyId = curext();
docuRef.RefTableId = _tableId;
docuRef.RefRecId = _docuRefId;
docuRef.TypeId = 'Note';
docuRef.Name = _name;
docuRef.Notes = _note;
docuRef.Restriction = (_isPublic) ? DocuRestriction::External : DocuRestriction::Internal;
docuRef.insert();
ttscommit;
insertResult = true;
}
catch
{
ttsabort;
error("Could not insert " + ((_isPublic) ? "public" : "private") + " comment:\n\n\t\"" + _note + "\"");
}
}
return insertResult;
}