Access revit element data - python revit api - python

I'm a little confused about how you get access to Revit's element data, such as an element's parameters, location, Id, etc.. If I have this code:
collector = FilteredElementCollector(doc)
collector.OfCategory(BuiltInCategory.OST_Walls)
walls = collector.OfClass(FamilySymbol)
return walls
It will print: Autodesk.Revit.DB.FilteredElementCollector object at 0x0000000000000038 [Auto...]. Where do I go from here? For instance, How do I get a return of the walls' location?
There might be a lot in here, and multiple steps for each item. I am mainly looking for a general concept of getting and/or setting new element data.
Any thoughts?

I can't help with the Python, but I'm pretty familiar with Revit's API + C#.
You are using the collector to list all the walls on the project. What you want (to get the locations) is the FamilyInstance objects of these walls.
In C# would be something like this:
new FilteredElementCollector(uidoc.Document).OfClass(FamilyInstance).ToElements();
Next, you should loop the result to get each individual Element and convert it to a Wall:
foreach (Wall i in instances)
{
var location = i.Location as LocationCurve;
// The Curve element is a Line - 2 points defining it's position
var p0 = location.Curve.GetEndPoint(0);
var p1 = location.Curve.GetEndPoint(1);
}
Most of the information you want is on this FamilyInstance Object -> http://wikihelp.autodesk.com/Revit/enu/2014/Help/3665-Developers/0074-Revit_Ge74/0083-Family_I83/0086-FamilyIn86

The Revit API documentation points out that a FilteredElementCollector is an IEnumerable<Element>. So you actually have a list of wall objects. I like to add these to a python list to make working with them easier:
walls = list(collector)
Behind the scenes, list(collector) will do something like:
walls = []
for w in collector:
walls.append(w)
(note, that this is not really how it works, but sort of explains it).
You can use the .NET inner workings to enumerate the walls in the collector by doing this:
enumerator = collector.GetEnumerator()
walls = []
while not enumerator.IsDone():
walls.append(enumerator.Current)
enumerator.MoveNext()
You will want to check if the collector.OfClass(FamilySymbol) line is correct - in my example document, that yielded an empty list - but maybe you do have walls that are FamilySymbols...
Next, you want to work with a wall object. So, take the first wall:
wall = walls[0]
interior_type_parameter = wall.Parameter['Interior Type']
And then work with the parameter... If you install the Revit SDK, you will find a tool for snooping objects and finding their parameters and values. Use this! Explore! Have fun!

Related

Listing the title of created items in a choice field of another item in plone

I have a problem with my Plone item I cannot solve. 'Car' is supposed to create a list of all instances of 'Colour'.
All 'Colour' instances are in a given container. I cannot make it static because I want to add more 'Colour' instances in the future.
I tried selecting each item in my container and add it to my vocabularylist. I only need the id/title of my object, but I always end up with a giant stacktrace of failures.
In the end I want to choose a colour out of the given instances on creating a new 'Car' instance similar to a dropdown.
I have read the docs but cannot find a solution and this is my best idea.
I am also not a python programmer and this is my first plone project. I can add the complete failure list later if you need it.
I appreciate every bit of help. Thank you.
```colour= schema.Choice(
title=u"Colour",
description=u"Paintjob",
vocabulary=givecolour(),
required=False
)
#provider(IContextSourceBinder)
def givecolour():
colourlist = self.context.portal_catalog(path={"query" : "/madb-entw/it/colourcontainer", "depth" : 1})
list = []
i = 0
for colour in colourlist:
list.append(
SimpleVocabulary.createTerm(
colourlist.[i].getObject().id
)
)
i += 1
return SimpleVocabulary(list)```
Please always add your traces, so that we can help you better.
There is also the official community.plone.org forum, where are more people can help you.
I recommend you to use the plone.api to find your objects, this is a bit easier and well doumented.
something like this:
from plone import api
color_brains = api.content.find(context=api.content.get(path='/madb-entw/it/colourcontainer'), depth=1, portal_type='Color')
# no need to do getOject() here, get the id/title directly from the catalog brain
colors = [(color.id, color.Title) for color in color_brains]
One note to your query:
colourlist = self.context.portal_catalog(path={"query" :
"/madb-entw/it/colourcontainer", "depth" : 1})
Path has to be absolute, which means it includes the Plone site id and this can be different in another Plone site.
So an absolute path is not a good idea here, better get the portal object and traverse your path relative from there.
If madb-entw is your Plone site id:
portal.restrictedTraverse('it/colourcontainer')
or better as above, use plone.api.content.get(path='/it/colourcontainer')
Which is cleaner and easier.

py2neo cypher create several relations to central node in for loop

just starting out with neo4j, py2neo and Cypher.
I have encountered the following problem and google and my knowledge of what to ask have not yet given me an answer or a helpful hint in the right direction. Anyway:
Problem:
I don't know how to, in python/py2neo, create relations between a unique starting node and a number of following nodes that I create dynamically in a for loop.
Background:
I have a json object which defines a person object, who will have an id, and several properties, such as favourite colour, favourite food etc.
So at the start of my py2neo script I define my person. After this I loop through my json for every property this person has.
This works fine, and with no relations I end up with a neo4j chart with several nodes with the right parameters.
If I'm understanding the docs right I have to make a match to find my newly created person, for each new property I want to link. This seems absurd to me as I just created this person and still have the reference to the person object in memory. But for me it is unclear on how to actually write the code for creating the relation. Also, as a relative newbie in both python and Cypher, best practices are still an unknown to me.
What I understand is I can use py2neo
graph = Graph(http://...)
tx = graph.begin()
p = Node("Person", id)
tx.create(p)
and then I can reference p later on. But for my properties, of which there can be many, I create a string in python like so (pseudocode here, I have a nice oneliner for this that fits my actual case with lambda, join, map, format and so on)
for param in params:
par = "MERGE (par:" + param + ... )
tx.append(par)
tx.process()
tx.commit()
How do I create a relation "likes" back to the person for each and every par in the for loop?
Or do I need to rethink my whole solution?
Help?! :-)
//Jonas
Considering you've created a node Alice and you want to create the other as dynamic, I'll suggest while dynamically parsing through the nodes, store it everytime (in the loop) in a variable, make a node out of it and then implement in Relationship Syntax. The syntax is
Relationship(Node_1, Relation, Node_2)
Now key thing to know here is type(Node_1) and type(Node_2) both will be Node.
I've stored all the nodes (only their names) from json in a list named nodes.
Since you mentioned you only have reference to Alice
a = ("Person", name:"Alice")
for node in nodes: (excluding Alice)
= Node(, name:"")
= Relationship(a, ,
Make sure to iterate variable name, else it'll keep overwriting.

How to detect if an object is overlapping with specific tag?

Using Tkinter in Python 3.6.0, is there a 'good' way to detect if a specific object, in this case my player sprite, is overlapping any other object with a specific tag?
I would want to do something like:
if canvas.find_overlapping( *canvas.coords(player) ) == (player, "item_tag"):
return True
where item_tag is the tag applied to 100+ objects on the canvas.
I can use canvas.find_withtag("item_tag") to return the object ID of all the objects I wish the player to interact with, but I can't get this to work within find_overlapping, e.g. take each object ID and let find_overlapping detect if it is overlapping.
Thanks!
Considering both are lists, all you have to do is take each element of one and check if it is in the other:
tagged_objects = canvas.find_withtag("item_tag")
overlapping_objects = canvas.find_overlapping(*canvas.coords(player))
for item in overlapping_objects:
if (item in tagged_objects):
return True
You could do this in reverse and look to see if each element of tagged_objects is in overlapping_objects, but considering you said there are 100+ tagged objects, that would probably be slower.

Loop doesn't work, 3-lines python code

this question is about blender, python scripting
I'm completely new in this, so please excuse me for any stupid/newbie question/comment.
I made it simple (3 lines code) to make it easy addressing the problem.
what I need is a code that adds a new uv map for each object within loop function.
But this code instead is adding multiple new UV maps to only one object.
import bpy
for x in bpy.context.selected_objects:
bpy.ops.mesh.uv_texture_add()
what's wrong I'm doing here??
Thanks
Similar to what Sambler said, I always use:
for active in bpy.context.selected_objects:
bpy.context.scene.objects.active = active
...
These two lines I use more than any other when programming for Blender (except import bpy of course).
I think I first learned this here if you'd like a good intro on how this works:
https://cgcookiemarkets.com/2014/12/11/writing-first-blender-script/
In the article he uses:
# Create a list of all the selected objects
selected = bpy.context.selected_objects
# Iterate through all selected objects
for obj in selected:
bpy.context.scene.objects.active = obj
...
His comments explain it pretty well, but I will take it a step further. As you know, Blender lacks built-in multi-object editing, so you have selected objects and one active object. The active object is what you can and will edit if you try to set its values from python or Blender's gui itself. So although we are writing it slightly differently each time, the effect is the same. We loop over all selected objects with the for active in bpy.context.selected_objects, then we set the active object to be the next one in the loop that iterates over all the objects that are selected with bpy.context.scene.objects.active = active. As a result, whatever we do in the loop gets done once for every object in the selection and any operation we do on the object in question gets done on all of the objects. What would happen if we only used the first line and put our code in the for loop?
for active in bpy.context.selected_objects:
...
Whatever we do in the loop gets done once for every object in the selection but any operation we do on the object in question gets done on only the active object, but as many times as there are selected objects. This is why we need to set the active object from within the loop.
The uv_texture_add operator is one that only works on the current active object. You can change the active object by setting scene.objects.active
import bpy
for x in bpy.context.selected_objects:
bpy.context.scene.objects.active = x
bpy.ops.mesh.uv_texture_add()
note: I am not really familiar with blender
It seems that bpy.ops operations depend on the state of bpy.context. The context can also be overridden per-operation.
I assume that uv_texture_add() only works on a single object at a time?
Try something like this:
import bpy
for x in bpy.context.selected_objects:
override = { "selected_objects": x }
bpy.ops.mesh.uv_texture_add(override)
That should run the operations as if only one object was selected at a time.
Source:
https://www.blender.org/api/blender_python_api_2_63_17/bpy.ops.html#overriding-context

short name for a string/dict/list index

In python I seem to need to frequently make dicts/lists within dicts/lists within dicts/lists and then access these structures in complex if/elif/else trees. Is there someway that I could make a shorthand way of accessing a certain level of this data structure to make the code more concise.
This is an example line of code now:
schema[exp][node]['properties']['date'] = i.partition('(')[2].rpartition(')')[0].strip()
which is followed by a whole heap of other lines starting with "schema[exp][node]['properties']['foo']"
What I would like is something like:
reference_maker(schema[exp][node]['properties']['date'], schema_props)
schema_props['date'] = i.partition('(')[2].rpartition(')')[0].strip()
but I can't even really think where to begin.
If you're not worried about it changing:
schema_props = schema[exp][node]['properties']
schema_props['date'] = ...
But if you want the reference to hang around and auto-update:
schema_props = lambda: schema[exp][node]['properties']
schema_props()['date'] = ...
node = node + 1
# this now uses the next node
schema_props()['date'] = ...
Or without the lambda:
def schema_props():
return schema[exp][node]['properties']
schema_props()['date'] = ...
node = node + 1
# this now uses the next node
schema_props()['date'] = .
Not sure I understand but what’s the problem with the following?
schema_props = schema[exp][node]['properties']
schema_props['date'] = i.partition('(')[2].rpartition(')')[0].strip()
Of course, you have to be careful that schema_props always points to a still valid entry in your dict. Ie. once you manually reset schema[exp][node]['properties'] your schema_props reference will not update the original dict anymore.
For more elaborate indirection handling, you could build your own collection types which may then always keep a reference to the base dict. (See also: http://docs.python.org/2/library/collections.html#collections-abstract-base-classes)

Categories

Resources