I can fetch a layer list, and I can fetch the objects from a certain layer. However, I can't find anything that changes their visibility. Is that not implemented?
If it is, is it possible to run a script that I could use for toggling visibility based on a variable within the script? AFAIK the whole script is always run, so if I define switch variables and change them, they're reset every time I run the script again.
Visibility is managed in three places:
Layer Visibility (turn all features on / off)
Definition Query (exclude features)
Renderer (change symbol to none)
Sounds like you are trying to filter out features based on a selection, you could add the list of selected objectIDS to the layer query definition thus "hiding" them. "...AND NOT OBJECTID IN (#,#,#,#)"
See arcpy layer definition query here...use python to create definition query
The example works for the layers, thanks. However I'm trying to use the visibility in conjunction with an occlusion query. Turning layer visibility off or deleting the model doesn't keep the touches() function from triggering. Only when I don't generate a model through its rule (like case visible == true: extrude(5), else: NIL) does the query work as expected. Should I just give all the objects from the layer a visibility attribute (ce.setAttribute) and change that to false with python before generating or is there a proper way?
Hey ZR,
Ohhh, so you want to toggle visibility on the procedural model level.
I think you have few options here.
For one, NIL will not generate geometry so the occlusion functions may not work (not entirely sure on that). What might be as helpful is the parameter approach you suggested toggling the material.opacity attribute. By toggling this attribute between 1-0 and setting the attribute in python, you should be able to cloak your models while still setting off occlusion functions. Thus this way you get the same effect, without turning off the entire layer. Also you can change the shape attributes opacity ANYWHERE in the shape hierarchy allowing more nuanced control.
Hope this helps,
David
Ah no, I want to prevent touches() from triggering when the object is invisible. I'm almost there (?) however I have a little problem. How do I select the appropriate objects? The current code sets the visibility properly but also every object's "generate" to true. I figured there'd be a "select objects by layer name" but I can't find anything. Also how do I set a boolean value as attribute? My true/false isn't a "real" true/false, so I'm not getting a on/off slider.
Here's a screenshot for clarification. Larger cubes: contents of Layer01-04. The cubes have a case for extrusion or NIL, depending on their "generate" attribute. The purple cubes use a rule with the touches() query. The idea is that invisible cubes don't trigger the purple ones.
script:
from scripting import * # List of visible layers LayerName = ["Layer01", "Layer02", "Touches"] ce = CE() @noUIupdate def main(): layers = ce.getObjectsFrom(ce.scene, ce.isLayer) shapes = ce.getObjectsFrom(ce.scene, ce.isShape) for layer in layers: if str(layer) in LayerName: layer.setVisible(True) for shape in shapes: ce.setAttribute(shape, 'generate', 'true') #ce.setAttribute(shape, 'generate', 'false') else: for shape in shapes: ce.setAttribute(shape, 'generate', 'false') layer.setVisible(False) #ce.generateModels(shapes) #ce.waitForUIIdle() if __name__ == '__main__': main()
Oh got it. Sorry I misunderstood. The opacity method works assuming you still want occlusions to trigger. Now that I see your python script I understand. I think part of the problem is you are iterating through shapes without using a "getObjectsFrom" function. It might help with accessing the objects in question (shapes).
for layer in layers: #for loop iterates through all objects in scene print("Checking objects in layer ", layer) objectList=ce.getObjectsFrom(layer) for object in objectList:
Another part is I am not sure you want to set the attribute equal to the string "true" or "false", does the rule attribute in your rule take a boolean on or a string for triggering? Because now you are passing it is string it seems. Your rule might have to recognize it as a string.
# So if it is boolean: case generate:Rule else: NIL # If it is a string: case generate=="true":Rule else:NIL
Hope this helps with your python code. I see the issue has to do with the layers interaction. I think one question I have is have you just tried deleting and then reinserting the layer again if you need it?
I've not read every post in this thread, but if it helps:
Layer visibility will not affect occlusion functions. So if you have models generated on a layer that is not visible, those models will still be included in occlusion tests. I'm 98.6 percent sure of this, unless it was changed in 2015.2, and I see nothing in the change log about it.
Chris
I was not sure on this point Chris, thanks (my uncertainty is why I suggested deleting the layer entirely). From Z R's post it seems that different layers can set off occlusion functions, so I guess my question is would deleting the layer entirely work?
Thanks. I think I got it now. I built two layer lists and used them to set the right attributes for the objects in the layer groups.
The rule accepts true/false as text because I changed it to do so since I couldn't figure out how to set a boolean true/false . However it still would be nice to set the right attribute type. Deleting the layers isn't feasible, they have to stick around for quick comparisons.
Here's the code, maybe someone else will find it useful:
from scripting import * # List of visible Layers VisibleLayersNames = ["Scene Light", "Panorama", "Layer01", "Layer03", "Touches"] VisibleLayers = [] InvisibleLayers = [] AllLayerNames = [] ce = CE() @noUIupdate def main(): # get visible layers for i in range(len(VisibleLayersNames)): VisibleLayer = ce.getObjectsFrom(ce.scene, ce.isLayer, ce.withName(VisibleLayersNames)) VisibleLayers.extend(VisibleLayer) # get all layers AllLayers = ce.getObjectsFrom(ce.scene, ce.isLayer) #get all layer names for j in range(len(AllLayers)): LayerName = ce.getName(AllLayers) AllLayerNames.append(LayerName) # set layer visibility for Layer in AllLayers: if str(Layer) in VisibleLayersNames: Layer.setVisible(True) else: Layer.setVisible(False) # get invisible layer names InvisibleLayersNames = list(set(AllLayerNames).difference(set(VisibleLayersNames))) # get invisible layers for k in range(len(InvisibleLayersNames)): InvisibleLayer = ce.getObjectsFrom(ce.scene, ce.isLayer, ce.withName(InvisibleLayersNames)) InvisibleLayers.extend(InvisibleLayer) # set generate attribute for visible layers for VisibleLayer in VisibleLayers: VisibleObjects=ce.getObjectsFrom(VisibleLayer) for VisibleObject in VisibleObjects: ce.setAttribute(VisibleObject, 'generate', 'true') # set generate attribute for invisible layers for InvisibleLayer in InvisibleLayers: InvisibleObjects=ce.getObjectsFrom(InvisibleLayer) for InvisibleObject in InvisibleObjects: ce.setAttribute(InvisibleObject, 'generate', 'false') if __name__ == '__main__': main()
Hey ZR,
Glad you got it to pass correctly. The interaction between different data types between languages, GIS, and CGA/CityEngine can be tricky.
David