plantuml hide mindmap node - plantuml

Using plantuml's mindmap diagram, I want to hide specific nodes. Of course, I could omit them completely, but I want to render them hidden / visible whenever I like to by just changing a style setting.
For an implementation, I tried this here:
#startmindmap
<style>
leafNode {
.leaf_node_style {
LineColor blue
LineThickness 3.0
BackgroundColor gold
MinimumWidth 400
Shadowing 6
}
}
node {
.invisible {
MaximumWidth 0
}
}
</style>
* root node text
** / <<invisible>>
*** some child node
*** another child node
**** / <<invisible>>
***** a leaf node <<leaf_node_style>>
#endmindmap
The generated mindmap displays the leaf_node_style as defined, but still shows the small nodes containing the slash "/" character, although the invisible style setting was used, defined at the top of the text:
Is it possible to hide specific mindmap nodes so that the output does not show them anymore but instead, moves all it's child nodes to it's own position? Like so?:

Related

ARKit - ARRreferenceImage tracking

I'm playing around with ARReferenceImages in ARKit and I'm trying to add an SCNNode when a reference image is recognised and then leave that node in place regardless of whether the same reference image is then recognised elsewhere.
I can add my SCNode correctly, but if I move my marker it picks it up again and moves my placed node to the position of the marker.
My code to add is as follows:
func renderer(_ renderer: SCNSceneRenderer, didAdd node: SCNNode, for anchor: ARAnchor) {
guard let imageAnchor = anchor as? ARImageAnchor else { return }
let referenceImage = imageAnchor.referenceImage
print("MAPNODE IS NIL = \(self.mapNode == nil)")
updateQueue.async {
if self.mapNode == nil {
// Create a plane to visualize the initial position of the detected image.
let plane = SCNPlane(width: 1.2912,
height: 1.2912)
let planeNode = SCNNode(geometry: plane)
planeNode.opacity = 1
/*
`SCNPlane` is vertically oriented in its local coordinate space, but
`ARImageAnchor` assumes the image is horizontal in its local space, so
rotate the plane to match.
*/
planeNode.eulerAngles.x = -.pi / 2
self.mapNode = planeNode
/*
Image anchors are not tracked after initial detection, so create an
animation that limits the duration for which the plane visualization appears.
*/
// Add the plane visualization to the scene.
node.addChildNode(planeNode)
}
}
}
reading the docs here https://developer.apple.com/documentation/arkit/recognizing_images_in_an_ar_experience#2958517 it states that
Apply Best Practices
This example app simply visualizes where ARKit detects each reference
image in the user’s environment, but your app can do much more. Follow
the tips below to design AR experiences that use image detection well.
Use detected images to set a frame of reference for the AR scene.
Instead of requiring the user to choose a place for virtual content,
or arbitrarily placing content in the user’s environment, use detected
images to anchor the virtual scene. You can even use multiple detected
images. For example, an app for a retail store could make a virtual
character appear to emerge from a store’s front door by recognizing
posters placed on either side of the door and then calculating a
position for the character directly between the posters.
Note
Use the ARSession setWorldOrigin(relativeTransform:) method to
redefine the world coordinate system so that you can place all anchors
and other content relative to the reference point you choose.
Design your AR experience to use detected images as a starting point
for virtual content. ARKit doesn’t track changes to the position or
orientation of each detected image. If you try to place virtual
content that stays attached to a detected image, that content may not
appear to stay in place correctly. Instead, use detected images as a
frame of reference for starting a dynamic scene. For example, your app
might recognize theater posters for a sci-fi film and then have
virtual spaceships appear to emerge from the posters and fly around
the environment.
So I tried setting my world transform to be equal to the transform of my image anchor
self.session.setWorldOrigin(relativeTransform: imageAnchor.transform)
However my mapNode follows the imageAnchor where ever it moves. I haven't implemented the renderer update method so I'm not sure why this keeps moving.
I'm assuming that the setWorldOrigin method is constantly updating to the imageAnchor.transform and not just that moment in time, which is weird as that code is only called once. Any ideas?
If you want to add the mapNode at the position of the ARImageAnchor you could set the position of your mapNode at the transform of the ARImageAnchor and add it to the scene but not linked to the reference image if that makes sense.
This could be done like so:
func renderer(_ renderer: SCNSceneRenderer, didAdd node: SCNNode, for anchor: ARAnchor) {
//1. If Out Target Image Has Been Detected Than Get The Corresponding Anchor
guard let currentImageAnchor = anchor as? ARImageAnchor else { return }
//2. An ImageAnchor Is Only Added Once For Each Identified Target
print("Anchor ID = \(currentImageAnchor.identifier)")
//3. Add An SCNNode At The Position Of The Identified ImageTarget
let nodeHolder = SCNNode()
let nodeGeometry = SCNBox(width: 0.02, height: 0.02, length: 0.02, chamferRadius: 0)
nodeGeometry.firstMaterial?.diffuse.contents = UIColor.cyan
nodeHolder.geometry = nodeGeometry
nodeHolder.position = SCNVector3(currentImageAnchor.transform.columns.3.x,
currentImageAnchor.transform.columns.3.y,
currentImageAnchor.transform.columns.3.z)
augmentedRealityView?.scene.rootNode.addChildNode(nodeHolder)
}
In another part of your question you seem to imply that you want to detect multiple occurrences of the same image. I could be wrong but I think the only way to do this is to remove the corresponding ARImageAnchor for the reference image, which can be done like so (by adding it at the end of the last code snippet):
augmentedRealitySession.remove(anchor: currentImageAnchor)
The issue here is that once the ARImageAnchor is removed, any time it is detected again, you would have to handle whether content should be added, which is tricky since the ARImageAnchor.identifier is always the same for the referenceImage regardless of whether it is removed and then re-added thus making it difficult to store in a dictionary etc. As such depending on your needs you would then need to find a way to determine if content existed at that location and whether to re add it etc.
The last part of your question about setWorldOrigin seems a bit odd like you said, but maybe you could add a Bool to prevent it from potentially changing e.g:
var hasSetWorldOrigin = false
Then based on this you could ensure that it is only set once e.g:
func renderer(_ renderer: SCNSceneRenderer, didAdd node: SCNNode, for anchor: ARAnchor) {
//1. If Out Target Image Has Been Detected Than Get The Corresponding Anchor
guard let currentImageAnchor = anchor as? ARImageAnchor else { return }
//2. If We Havent Set The World Origin Set It Based On The ImageAnchorTranform
if !hasSetWorldOrigin{
self.augmentedRealitySession.setWorldOrigin(relativeTransform: currentImageAnchor.transform)
hasSetWorldOrigin = true
//3. Create Two Nodes To Add To The Scene And Distribute Them
let nodeHolderA = SCNNode()
let nodeGeometryA = SCNBox(width: 0.04, height: 0.04, length: 0.04, chamferRadius: 0)
nodeGeometryA.firstMaterial?.diffuse.contents = UIColor.green
nodeHolderA.geometry = nodeGeometryA
let nodeHolderB = SCNNode()
let nodeGeometryB = SCNBox(width: 0.04, height: 0.04, length: 0.04, chamferRadius: 0)
nodeGeometryB.firstMaterial?.diffuse.contents = UIColor.red
nodeHolderB.geometry = nodeGeometryB
if let cameraTransform = augmentedRealitySession.currentFrame?.camera.transform{
nodeHolderA.simdPosition = float3(cameraTransform.columns.3.x,
cameraTransform.columns.3.y,
cameraTransform.columns.3.z)
nodeHolderB.simdPosition = float3(cameraTransform.columns.3.x + 0.2,
cameraTransform.columns.3.y,
cameraTransform.columns.3.z)
}
augmentedRealityView?.scene.rootNode.addChildNode(nodeHolderA)
augmentedRealityView?.scene.rootNode.addChildNode(nodeHolderB)
}
}
Hopefully my answer will provide a useful starting point to you assuming of course I have interpreted your question correctly,

How to color a scnplane with 2 different materials?

I have a SCNPlane that I created in the SceneKit editor and I want 1 side of the plane to have a certain image and the other side of the plane to have another image. How do I do that in the Scenekit editor
So far what I've tried to do is adding 2 materials to the plane. I tried adding 2 materials and unchecking double-sided but that doesn't work.
Any help would be appreciated!
Per the SCNPlane docs:
The surface is one-sided. Its surface normal vectors point in the positive z-axis direction of its local coordinate space, so it is only visible from that direction by default. To render both sides of a plane, ether set the isDoubleSided property of its material to true or create two plane geometries and orient them back to back.
That implies a plane has only one material — isDoubleSided is a property of a material, letting that one material render on both sides of a surface, but there's nothing you can do to one material to turn it into two.
If you want a flat surface with two materials, you can arrange two planes back to back as the doc suggests. Make them both children of a containing node and you can then use that to move them together. Or you could perhaps make an SCNBox that's very thin in one dimension.
Very easy to do in 2022.
It's very easy and common to do this, you just add the rear as a child.
To be clear the node (and the rear you add) should both use the single-sided shader.
Obviously, the rear you add points in the other direction!
Do note that they are indeed in "exactly the same place". Sometimes folks new to 3D mesh think the two meshes would need to be "a little apart", not so.
public var rear = SCNNode()
private var theRearPlane = SCNPlane()
private func addRear() {
addChildNode(rear)
rear.eulerAngles = SCNVector3(0, CGFloat.pi, 0)
theRearPlane. ... set width, height etc
theRearPlane.firstMaterial?.isDoubleSided = false
rear.geometry = theRearPlane
rear.geometry?.firstMaterial!.diffuse.contents = .. your rear image/etc
}
So ...
///Double-sided sprite
class SCNTwoSidedNode: SCNNode {
public var rear = SCNNode()
private var thePlane = SCNPlane()
override init() {
super.init()
thePlane. .. set size, etc
thePlane.firstMaterial?.isDoubleSided = false
thePlane.firstMaterial?.transparencyMode = .aOne
geometry = thePlane
addRear()
}
Consuming code can just refer to .rear , for example,
playerNode. ... the drawing of the Druid
playerNode.rear. ... Druid rules and abilities text
enemyNode. ... the drawing of the Mage
enemyNode.rear. ... Mage rules and abilities text
If you want to do this in the visual editor - very easy
It's trivial. Simply add the rear as a child. Rotate the child 180 degrees on Y.
It's that easy.
Make them both single-sided and put anything you want on the front and rear.
Simply move the main one (the front) normally and everything works.

How to get data from an upstream node in 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.

Kendo TreeView: How to set Intermediate state Programmatically

I am trying to use Kendo TreeView with other controls. Each of the leaf node on tree opens a detail pane. When I select all the elements from detail pane, I set the state of that node as Checked
myTree.dataItem(node).set("checked", true);
and when all the items are un-selected, I set the state of node as unchecked.
myTree.dataItem(node).set("checked", false);
but if some of the items are selected, I want to show the state of node as Intermediate
how can I do that. I cant find anything in the documentation that can help me. The closest thing I found is
myTree.updateIndeterminate()
however, it is not doing the job. Apparently, it sets the state based on the state of child nodes. but in my case, there are no child nodes. I am dealing with leaf nodes here. Can I set the state of a leaf node as Intermediate ? if yes, how?
Couldn't find any help on this.
Ended up using the following approach
I am now finding the checkbox associated with that particular node and setting it's indeterminate value using jQuery.
function SetTreeNodeIndeterminate(nodeId, set) {
var uid = $("#" + nodeId).parents('li').attr('data-uid');
var node = myTree.findByUid(uid);
if (node.length == 0) return;
var checkBox = $("#_" + uid);
if (checkBox.length == 0) return;
checkBox.prop('indeterminate', set);
updateParentNodeState(node);
}
the following line makes sure that all the parents of a node are also marked as indeterminate
function updateParentNodeState(node) {
myTree.updateIndeterminate(node);
let parentNode = myTree.parent(node);
if (parentNode.length > 0)
updateParentNodeState(parentNode);
}

How to capture which treeview node is clicked

I created a tree view controls using WinApi. I want to capture mouse click on checkboxes. The notification message NM_CLICK contains NMHDR, which has no information about the node being clicked. since the clicked node may be different from the selected node, there should be a way to find which node has been checked or unchecked, It could be HTREEITEM, or lParam Inserted when adding items to tree view. I want to capture the checking/unchecking in real time. How can I specify which Node being checked/unchecked? any help or link appreciated.
mr.abzadeh
I want to capture the checking/unchecking in real time. How can I
specify which Node being checked/unchecked?
for this exist notification TVN_ITEMCHANGING and TVN_ITEMCHANGED - look for uStateNew and uStateOld members of NMTVITEMCHANGE - when tree view have checkboxes (TVS_CHECKBOXES style) it used as state image list with 2 images - unchecked and checked.
so state & TVIS_STATEIMAGEMASK will be 0 when no checkbox, INDEXTOSTATEIMAGEMASK(1) for unchecked and INDEXTOSTATEIMAGEMASK(2) for checked. based on this info we can and capture mouse click on checkboxes
by using TVN_ITEMCHANGING you can also prevent the change when you return TRUE for this notification. if you need only notify - use TVN_ITEMCHANGED
case WM_NOTIFY:
{
union {
LPARAM lp;
NMTVITEMCHANGE *pnm;
NMHDR* phdr;
};
lp = lParam;
switch (phdr->code)
{
case TVN_ITEMCHANGING:
{
UINT CheckStateOld = pnm->uStateOld & TVIS_STATEIMAGEMASK;
UINT CheckStateNew = pnm->uStateNew & TVIS_STATEIMAGEMASK;
if (CheckStateNew != CheckStateOld)
{
PCSTR szstate = "??";
switch (CheckStateNew)
{
case INDEXTOSTATEIMAGEMASK(1):
szstate = "uncheck";
break;
case INDEXTOSTATEIMAGEMASK(2):
szstate = "check";
break;
}
DbgPrint("%p>%s\n", pnm->lParam, szstate);
}
}
return FALSE;
}
}
also read How to Work With State Image Indexes
// Image 1 in the tree-view check box image list is the unchecked box.
// Image 2 is the checked box.
tvItem.state = INDEXTOSTATEIMAGEMASK((fCheck ? 2 : 1));
notification TVN_ITEMCHANGING and TVN_ITEMCHANGED is available begin from Windows Vista. if you need XP support too - on xp only option use #IInspectable solution
You can send a TVM_HITTEST message (or use the TreeView_HitTest macro) to find the tree view item, given a client-relative coordinate.
To get the cursor position at the time the NM_CLICK message was generated, use the GetMessagePos API.
This allows you do monitor any mouse click in the client area of the control. If you are interested in the state changes as the result of the standard tree view control implementation, you can handle the TVN_ITEMCHANGING or TVN_ITEMCHANGED notifications instead. Both supply an NMTVITEMCHANGE structure, where the hItem identifies the item being changed, and lParam carries application specific data.

Resources