Translating Geometry and Mapping Speckle Objects in Python

Hi all.
I’ve got some related question.

I have a speckle commit with some walls. I need these walls to be slightly ofsetted by the x axis and then transferred to Revit. Is it enough to modify baseline/start/x & baseline/end/x, pack it into the new commit and send to Revit to see the walls displaced? I don’t care for the displayValue in speckle.

2 Likes

Modifying any of the “instruction set” that is what Speckle->Revit uses to regenerate Elements on Receive will work, even without touching the display value. So in principle, yes, amending the Baseline will change the wall.

A few watch points:

  • as you note, only changing the baseline won’t amend display of that Wall outside of Revit (until it is republished)
  • X and Y may be easy Cartesian coordinates to understand, but what the specifics of the source Revit model understands them to be will vary (object rotation to axes etc)
  • be careful with units
  • the data will need to be reseralized to handle the detached properties and generate a new id for your amended wall

What environment are you hoping to amend these baselines? Purely code, notebook, Excel, or within an application you build???

1 Like

@jonathon thank you for an answer!

The goal is to translate Archicad model into the Revit native elements using the mapping. I’ve tried this with Rhino/Revit, works absolutely cool. With Archicad it’s a bit harder, as I need to assign manually additional attributes to enable mapping while importing this scheme to Revit, i.e:

obj['@Wall'][i]['category'] = 'Walls'
obj['@Wall'][i]['family'] = 'Basic Wall'
obj['@Wall'][i]['type'] = 'Wall - Custom'

This works fine, I could map all these elements into the existing Revit families. However, there a lot of nuances in element positions, some geometry etc while trying to convert into the native elements. For example, the logic of baseline (reference line) is a bit different in Archicad and Revit so I need to apply some manipulations (I’m updating the speckle commit schema with python) to fix this, that’s why I was asking is this a right way.

And the last question about serialization, am I doing it right:

# receiving here ...

bos = BaseObjectSerializer()
obj = bos.traverse_base(result) # result received from speckle

# ...
# some scheme manipulation ...
obj['@Wall'][i]['category'] = "Walls"
# ...

base = bos.recompose_base(obj[1]) # repacking the schema
obj_upd = operations.send(base, [transport])

# committing here ...

1 Like

So in short; rather than use the ArchiCAD and Revit Connectors to translate elements, you want to effectively work on your own conversion such that you affine translate geometry as well?

::Applause::, … but I can only urge caution

Partly. Connector process is absolutely fine, if speaking about the geometry in general. Our objective is a bit harder, as we need to translate to the existing Revit families used in the project. I see it’s possible, but not so easy. (And in general I see a huge potential here, that’s why I’m interested).

Well, I’m using both connectors, but I’m adjusting the scheme before the usage of Revit connector while receiving from speckle platform.

And one more question about serialization: do I need to deserialize the entire speckle schema? Or exactly the walls I’m fixing?

Yeah, as you’ve told, I need to de/serialize a single wall object in order to fix the baselines. It works. Here’s a small part of the code which fixes only one case for the wall X offsets:

# Establish connections
arc = Archicad(arg.port)
spk = Cloud()

# Get contents
obj = spk.retrieve(arg.stream, arg.commit)
selection = arc.com.GetSelectedElements()

for s in selection:
	# get main info
	guId = str(s.elementId.guid)
	catIds = arc.com.GetTypesOfElements([s])
	catName = catIds[0].typeOfElement.elementType

	if catName == 'Wall':
		for i in range(0, len(obj['@Wall'])):
			if guId.lower() == obj['@Wall'][i]['applicationId'].lower():
				print(guId)
			    # update schema
                bos = BaseObjectSerializer()
				wall = bos.traverse_base(obj['@Wall'][i])[1]
				# print(wall)

				wall['category'] = 'Walls'
				wall['family'] = 'Basic Wall'
				wall['type'] = 'User Custom'

				wall['parameters'] = {}
				wall['parameters']['speckle_type'] = 'Base'
				wall['parameters']['applicationId'] = None

				wall['parameters']['WALL_KEY_REF_PARAM'] = {}
				wall['parameters']['WALL_KEY_REF_PARAM'] = {
					'speckle_type': 'Objects.BuiltElements.Revit.Parameter',
					'applicationId': None,
					'applicationInternalName': 'WALL_KEY_REF_PARAM',
					'applicationUnit': None,
					'applicationUnitType': None,
					'isReadOnly': False,
					'isShared': False,
					'isTypeParameter': False,
					'name': 'Location Line',
					'units': None,
					'value': 0
				}

				t  = wall['thickness']
				sx = wall['baseLine']['start']['x']
				sy = wall['baseLine']['start']['y']
				sz = wall['baseLine']['start']['z']
				ex = wall['baseLine']['end']['x']
				ey = wall['baseLine']['end']['y']
				ez = wall['baseLine']['end']['z']
				mod = 0

				if obj['@Wall'][i]['referenceLineStartIndex'] == -1:
					mod = t/2
				elif obj['@Wall'][i]['referenceLineStartIndex'] == -3:
					mod = -t/2

				wall['baseLine']['start']['x'] = sx + mod
				wall['baseLine']['end']['x'] = ex + mod

				obj['@Wall'][i] = bos.recompose_base(wall)

# comitting
spk.update(obj, 'walls 001d')