How to get data from an upstream node in maya? - maya

I have a maya node myNode, which creates a shadeNode, which inMesh attribute is connected to shapeNode.outMesh and has an attribute distance.
myNode.outMesh -> shapeNode.inMesh
myNode.distance = 10
Then i have a command, which works on the shape node, but requires the distance argument, which it does by iterating over the inMesh connections:
MPlugArray meshConnections;
MPlug inMeshPlug = depNodeFn.findPlug("inMesh");
inMeshPlug.connectedTo(meshConnections, true, false); // in connections
bool node_found = false;
for(uint i = 0; i < numConnections; i++) {
MPlug remotePlug = meshConnections[i];
myNode = remotePlug.node();
if(MFnDependencyNode(myNode ).typeName() == "myNode") {
node_found = true;
break;
}
}
MFnDependencyNode myDepNode(myNode);
MPlug distancePlug = myDepNode.findPlug("distance");
Now i get a problem, when applying another node (of another type) to myShape, because the dependency graph now looks like this:
myNode.outMesh -> myOtherNode.inMesh
myOtherNode.outMesh -> shapeNode.inMesh
myNode.distance = 10
I tried to remove the check for typeName() == "myNode", because i understood the documentation like there should be recursion to the parent node, when the next node return Mstatus::kInvalidParameter for the unknown MPlug, but i cannot reach the distance plug without implementing further graph traversion.
What is the correct way to reliably find an attribute of a parent node, even when some other nodes were added in between?
The command itself should use the distance Plug to either connect to myNode or to some plug which gets the value recursively. If possible i do not want to change myOtherNode to have a distance plug and correspondig connections for forwarding the data.

The usual Maya workflow would be to make the node operate in isolation -- it should not require any knowledge of the graph structure which surrounds it, it just reacts to changes in inputs and emits new data from its outputs. The node needs to work properly if a user manually unhooks the inputs and then manually reconnects them to other objects -- you can't know, for example, that some tool won't insert a deformer upstream of your node changing the graph layout that was there when the node was first created.
You also don't want to pass data around outside the dag graph -- if the data needs to be updated you'll want to pass it as a connection. Otherwise you won't be able to reproduce the scene from the graph alone. You want to make sure that the graph can only ever produce an unambiguous result.
When you do have to do DAG manipulations -- like setting up a network of connectiosn -- put them into an MPXCommand or a mel/python script.

I found the answer in an answer (python code) to the question how to get all nodes in the graph. My code to find the node in the MPxCommand now looks like this:
MPlugArray meshConnections;
MPlug inMeshPlug = depNodeFn.findPlug("inMesh");
MItDependencyGraph depGraphIt(inMeshPlug, MFn::kInvalid, MItDependencyGraph::Direction::kUpstream);
bool offset_mesh_node_found = false;
while(!depGraphIt.isDone()) {
myNode = depGraphIt.currentItem();
if(MFnDependencyNode(myNode).typeName() == "myNode") {
offset_mesh_node_found = true;
break;
}
depGraphIt.next();
}
The MItDependencyGraph can traverse the graph in upstream or downstream direction either starting from an object or a plug. Here i just search for the first instance of myNode, as I assume there will only be one in my use case. It then connects the distance MPlug in the graph, which still works when more mesh transforms are inserted.
The MItDependencyGraph object allows to filter for node ids, but only the numeric node ids not node names. I probably add a filter later, when I have unique maya ids assigned in all plugins.

Related

Best way to mass-insert Edges into ArangoDB?

I'm writing a python converter for Neo4J to ArangoDB and expect +10k Nodes to be imported.
The converter for the Nodes is somewhat trivial but the creator of that database has a rather custom key-setting so I can't export his keys from his Neo4J instance but I know the name of the PK-Field.
That give me multiple approaches to set the Edges. Right now I'm getting the correct _key of the nodes in the ArangoDB-Collection of the from/to and insert a new edge (code below).
Theoretically I could write the AQL-Statements that just insert these edges, but is that more efficient?
Is there a better approach than my current one?
def getLinkN4jNodes(au,relationships,keyname,col,ecol):
for relationship in relationships:
startnode = relationship.start_node
endnode= relationship.end_node
sn_key=dict(startnode)[keyname]
en_key=dict(endnode)[keyname]
a_sn = au.getNodesFromDB(col,keyname,sn_key)# f"FOR doc IN {col} FILTER doc.`{keyname}`== '{sn_key}' RETURN doc"
a_en = au.getNodesFromDB(col,keyname,en_key)
newedge={
"_key":a_sn["_key"]+'_'+a_en["_key"],
"_from":a_sn["_key"],
"_to": a_en["_key"]
}
ecol.insert(newedge)

I am using a collector node on IIB to collect messages. Can someone guide with sample ESQL after collector node to process a message collection?

I'm using the FileOutputNode to write the data into the file. I have tried writing the collection messages in the file but every time the file created is of 0 byte and there is no data.
SET OutputRoot.Properties = InputRoot.Properties;
CREATE FIELD OutputRoot.Collection.IN;
DECLARE refCollection REFERENCE TO InputRoot.Collection.IN[1];
WHILE LASTMOVE(refCollection) DO
SET OutputRoot.Collection.IN= refCollection;
SET i = i + 1;
MOVE refCollection NEXTSIBLING REPEAT TYPE NAME;
END WHILE;
RETURN TRUE;
It is very difficult to provide help without knowing what your input message tree looks like.
You should follow the instructions here: https://www.ibm.com/support/knowledgecenter/en/SSMKHH_10.0.0/com.ibm.etools.mft.doc/bc16130_.htm
If you need further help, you should
add Trace nodes into your message flow before and after the Compute node and set the Pattern property on both nodes to ${Root}. This will allow you to see (and share) the structure of InputRoot and OutputRoot.
Enable user trace using the console commands mqsichangetrace, mqsireadlog, mqsiformatlog. This will show you exactly what the message flow is doing. It will also contain the full text of any errors that are being reported.

Calculate the Normal of a vertex in maya with Python

I have a script when I make a light it points to my object. I did this with a normalConstrain. But is there any other way to do this without constrains ?
I think I need to calculate the normal of the closest vertex form my Light ?
But I don't know how to do this, if someone can help me would be nice !
See Screenshot
Here is how I did the NormalConstrain :
myNormalConstrain = cmds.normalConstraint('mySphere','myLight', aimVector = (0,0,1), worldUpType = 'scene',name='NormalConstrainToObject')
The easy way is to create a closestPointOnMesh node an connect it to the worldMesh attribute of your mesh. The only wrinkle is that there's a bug in Maya 2016 (not sure about others) where the normal value coming back from the node is not actually normalized if you are using units other than centimeters. Here's a function which does it:
import maya.cmds as cmds
import maya.api.OpenMaya as api
def get_closest_normal(surface, x, y , z):
node = cmds.createNode('closestPointOnMesh')
cmds.connectAttr(surface + '.worldMesh ', node + ".inMesh")
cmds.setAttr( node + ".inPosition", x, y, z, type='double3')
normal = cmds.getAttr(node + ".normal")
# there's a bug in Maya 2016 where the normal
# is not properly normalized. Not sure
# if it's fixed in other years.... this
# is the workaround
result = api.MVector(*normal)
cmds.delete(node)
result.normalize()
return result
print get_closest_normal('pSphereShape1', 10, 1, 1)
Instead of getting the number and deleting the node as done here, you could keep the node around and connect it's normal attribute to something for live updates. This is a fairly expensive node to update, however, so don't use that version for something like an animation rig without testing performance to be sure it's affordable

How to store literals using #entity.values on Slot IBM Conversation Service?

I'm trying use slots on my dialog nodes on Watson conversation but seems that is not properly useful if you want to play with array of literal. I've an entity "#email" that is a pattern so I must use .literal if I want to store the "real value", that is sent by the user, on a context variable. Trouble starts when I try to use #entity.values to store all values that are sent by the user. Actually is not possible to store an array of literals and I'm stuck at this point.
Anyone developed a workaround for this?
The literal is a method, not an attribute. The entities contains a location field, which you can programatically use at the application layer to parse the input text.
If you want to pull them out in conversation, you can use a counter to walk through the entities.
For example:
In your slot node "Then respond with" add the following context bit.
"context": {
"counter": "<? entities.size() ?>",
"literals": ""
},
Next create three child nodes.
Node 1: Create a dummy node, set condition to true. Have it jump to the second node.
Node 2: For the second node, set the condition to $counter > 0 and add the following code to the JSON section.
"context": {
"counter": "<? $counter - 1 ?>",
"literals": "<? entities[$counter].literal + ',' + $literals ?>"
},
Have it jump back to Node 1. The reason for this is Conversation will not allow you to jump to the same node.
Node 3: Have it output the answer. For example: Literal Values: $literals
Here is a sample workspace.
https://pastebin.com/xwgnLq9n
Warning
Watson Conversation has a built in endless loop detection. If a node is hit 50 times in one request, it will throw the following error:
Detected recursion when processing the node with id
[node_20_1513835954092]. This node has been already processed [50] times
in this execution step
At which point the node will fail and you will get no result back. So if you expect more than 50 entities then you need to do this at the application layer.

JPA, flush and Entity Manager sync

I'm using Java EE, Netbeans and a facade session bean to implement the JPA layer (eclipselink).
I've a two table for example: Garden (1) ---> Tree (n).
(Script A) Now, I execute this snippet:
Garden mGarden = new Garden();
.....
gardenFacade.create(garden)
(Script B) Then:
Tree oneTree = new Tree();
oneTree.setGarden(mGarden);
treeFacade.create(oneTree);
In this way, the entity Tree is correctly added into my database and the foreign key is right.
(Script C) When I invoke:
Garden findGarden = gardenFacade.find(gardenId);
int count = findGarden.getTreeCollection().size();
I've count = 0 !!!
If I restart glassfish or reload my app and I execute these snippets I've count = 1.
So, I think that this is a problem of Persistence Context Synchronization because if I change my script B with:
Tree oneTree = new Tree();
oneTree.setGarden(mGarden);
treeFacade.create(oneTree);
mGarden.getTreeCollection().add(oneTree);
gardenFacade.edit(mGarden);
all works correctly!
How can I solve this issue?
EDIT:
create --> getEntityManager().persist(entity);
edit ----> getEntityManager().merge(entity);
find ----> getEntityManager().find(entityClass, id);
It looks like all those calls are using the same hibernate session, and sinc you failed to properly initialize both sides of the collection, of course you don't get anything in the collection:
Garden mGarden = new Garden(); // create a new Garden instance
session.persist(mGarden); // now this Garden instance is persistent.
// Its state will be written to the database at the
// next flush
Tree oneTree = new Tree(); // create a new Tree instance
oneTree.setGarden(mGarden); // set the garden of the tree. This is a basic, simple
// Java method call. Nothing will magically add the tree
// to the garden collection of trees if you don't do
// it explicitely
session.persist(oneTree); // now this Tree instance is persistent.
// Its state will be written to the database at the
// next flush.
Garden findGarden = session.get(Garden.class, gardenId);
// returns the garden that has the specific ID. It's already in the session:
// you created and attached it to the session at the beginning. And you
// never added anything to its collection of trees

Resources