Revit API Forum
Welcome to Autodesk’s Revit API Forums. Share your knowledge, ask questions, and explore popular Revit API topics.
cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

Align conectors in 3D space.

6 REPLIES 6
SOLVED
Reply
Message 1 of 7
halukuzuner
424 Views, 6 Replies

Align conectors in 3D space.

Hi Everybody.

I want to align two families by their connectors. Graphically it is shown in picture below. Families can be placed in any direction in 3D space. Any axis of any element is not to parallel to each other and project coordinates.

halukuzuner_0-1662412020762.png

 

My code is at below. I explained code as much as I could. The code is working when element located parallel to project axes. But it doesn't in other situations.

Am I in the wrong path? Is there a better way to do it?

 

private: static void rotate(UIApplication^ uiapp, elmstoreplace^ elms)
{
	// Select some elements in Revit before invoking this command

	// Get the handle of current document.
	UIDocument^ uidoc = uiapp->ActiveUIDocument;
	Document^ doc = uidoc->Document;

	//	Elelements are stored in other header. We will read from there.
	//	We saved them there by selecting in GUI.
	Element^ elmfrom = doc->GetElement(elmstoreplace::elmFrom);	// Element will be aligned.
	Element^ elmto = doc->GetElement(elmstoreplace::elmTo);	//	Element will be aligned to.
	// 1. Cast Element to FamilyInstance
	FamilyInstance^ faminstfrom = (FamilyInstance^)elmfrom;
	FamilyInstance^ faminstto = (FamilyInstance^)elmto;

	// 2. Get MEPModel Property
	MEPModel^ mepmodelfrom = faminstfrom->MEPModel;
	MEPModel^ mepmodelto = faminstto->MEPModel;

	// 3. Get connector set of MEPModel
	ConnectorSet^ connectorSetfrom = mepmodelfrom->ConnectorManager->Connectors;
	ConnectorSet^ connectorSetto = mepmodelto->ConnectorManager->Connectors;

	// Connector numbers to be aligned to each other are stored in other file.
	//	We saved them there by selecting in GUI.
	Connector^ connFrom =nullptr;	// Connector will be aligned.
	Connector^ connTo = nullptr;	// Connector to be aligned to.

	// Get connector by iterating in connectorset. 
	for each (Connector ^ connector in connectorSetfrom)
	{
		if (connector->Id == elmstoreplace::connNoFrom)
		{
		connFrom = connector;
		}

	}

	// Get connector by iterating in connectorset.
	for each (Connector ^ connector in connectorSetto)
	{
		if (connector->Id == elmstoreplace::connNoTo)
		{
			connTo = connector;
		}
	}

	// Get the element current location
	LocationPoint^ elmfromLoc = (LocationPoint^)elmfrom->Location;

	// Create vector based on element location and connector location.
	XYZ^ diffvec1 = connFrom->Origin->Subtract(elmfromLoc->Point);
	// Subtract element location which will be moved.
	XYZ^ diffvec2 = connTo->Origin->Subtract(elmfromLoc->Point);
	// Bring two connectors to same point
	ElementTransformUtils::MoveElement(doc, elmfrom->Id, diffvec2->Add(diffvec1->Negate()));

	//	Get basisZ of connectors.
	XYZ^ basisZTo = connTo->CoordinateSystem->BasisZ;
	//	Transform vector.
	XYZ^ getOfbasisZTo = getOfVector(basisZTo);
	//	Get basisZ of connectors.
	XYZ^ basisZFrom = connFrom->CoordinateSystem->BasisZ;
	//	Transform vector.
	XYZ^ getOfbasisZFrom = getOfVector(basisZFrom);
	
	//	Calculate angle between connectors.
	double angle  = getOfbasisZTo->AngleTo(getOfbasisZFrom);

	// Calculate crossproduct of two vectors.
	XYZ^ crossprod = getOfbasisZTo->CrossProduct(getOfbasisZFrom);
	//	Calculate crossproduct of two vectors. 
	//	Somehow this always give unit vectors 
	// BasisX(1,0,0), BasisY(0,1,0), BasisX(0,0,1)
	// I think that is my problem.
	XYZ^ getOfcrossprod = getOfVector(crossprod);
	
	// Create rotation axis.
	Line^ rotationaxis = Line::CreateUnbound(connTo->Origin, crossprod->BasisZ);	

	//	Rotate element around axis.
	ElementTransformUtils::RotateElement(doc, elmfrom->Id, rotationaxis, Math::PI - angle);
}

public: static XYZ^ getOfVector(XYZ^ xyz)	
{
	XYZ^ OfVector(xyz);
	return xyz;
}

 

 

 

6 REPLIES 6
Message 2 of 7
jeremy_tammik
in reply to: halukuzuner

Sorry, I do not understand your code, so I will simply try to answer your question:

  

How can I align the connectors?

  

Given two elements E and F containing connectors A and B with locations P and Q. Determine the difference between P and Q, the vector V = Q - P. If you translate the element E containing A by V, A will lie in exactly the same spot as B. If you don't want it in the exact same spot, but only vertically or horizontally aligned in some way, you need to adapt some of the coordinates of V accordingly. The translation can be accomplished using the MoveElement method:

  

https://www.revitapidocs.com/2023/aaddd413-01b0-2878-3f79-a281abb6d364.htm

  

Watch out that other attached elements are not moved as well.

  

 

  

Jeremy Tammik, Developer Advocacy and Support, The Building Coder, Autodesk Developer Network, ADN Open
Message 3 of 7
halukuzuner
in reply to: jeremy_tammik

Hi Jeremy,

O improved picture. As far as understood move element moves families/elements only. So that, I find U vector and subtract W from it and find V vector you mentioned. In the way you mentioned is works if two families placed in the same plane and orientation. In my case none of axes are parallel. My problem starts after moving element. My aim is finding crossproduct of two Z axes which is perpendicular to both axes. And rotate it by angle. I stuck in creating rotation axis along z axis of crossproduct. As shown in the picture, crossproduct BasisX, Y, Z always give unit vectors.

halukuzuner_5-1662493542841.png

 

 

halukuzuner_3-1662492063070.png

 

halukuzuner_4-1662492096637.png

 

 

 

 

 

Message 4 of 7
jeremy_tammik
in reply to: halukuzuner

“When you are a Bear of Very Little Brain, and you Think of Things, you find sometimes that a Thing which seemed very Thingish inside you is quite different when it gets out into the open and has other people looking at it.”

  

Sorry, but this question is beyond my limited capacity for a quick answer. 

  

It seems to me that you require some professional help, sir 🙂

  

Jeremy Tammik, Developer Advocacy and Support, The Building Coder, Autodesk Developer Network, ADN Open
Message 5 of 7
halukuzuner
in reply to: jeremy_tammik

Dear Jeremy,

Thanks for your modest answer. Possibly I couldn't express my problem. I finally made it worked. My problem was understanding "Basis" vectors. My final code is at below. It worked perfectly for me. I additionally draw rotation axis and rotation arc to visualize rotation.

Besides I was very surprised there is no similar code samples on internet. There is many codes but they are working on parallel planes. Revit itself already does the action which I was after. Bu API developers didn't need it.

 

	private: static void RotateOnConnector(UIApplication^ uiapp, elmstoreplace^ elms)
	{
		try
		{
			// Select some elements in Revit before invoking this command

			// Get the handle of current document.
			UIDocument^ uidoc = uiapp->ActiveUIDocument;
			Document^ doc = uidoc->Document;
			
			//	Elelements are stored in other header. They will be read from there.
			//	They are saved there by selecting in GUI.
			Element^ elmfrom = doc->GetElement(elmstoreplace::elmFrom);
			Element^ elmto = doc->GetElement(elmstoreplace::elmTo);
			// 1. Cast Element to FamilyInstance
			FamilyInstance^ faminstfrom = (FamilyInstance^)elmfrom;
			FamilyInstance^ faminstto = (FamilyInstance^)elmto;

			// 2. Get MEPModel Property
			MEPModel^ mepmodelfrom = faminstfrom->MEPModel;
			MEPModel^ mepmodelto = faminstto->MEPModel;

			// 3. Get connector set of MEPModel
			ConnectorSet^ connectorSetfrom = mepmodelfrom->ConnectorManager->Connectors;
			ConnectorSet^ connectorSetto = mepmodelto->ConnectorManager->Connectors;

			// Connector numbers to be aligned to each other are stored in other file.
			//	They saved there by selecting in GUI.
			Connector^ connFrom =nullptr;	// Connector will be aligned.
			Connector^ connTo = nullptr;	// Connector to be aligned to.

			// Get connector by iterating in connectorset. 
			for each (Connector ^ connector in connectorSetfrom)
			{
				if (connector->Id == elmstoreplace::connNoFrom)
				{

				connFrom = connector;
					String^ message = "Connector is owned by: " + connector->Owner->Name;
				}

			}
			// Get connector by iterating in connectorset.
			for each (Connector ^ connector in connectorSetto)
			{
				if (connector->Id == elmstoreplace::connNoTo)
				{
					connTo = connector;
				}
			}

			// Get the element current location
			LocationPoint^ elmfromLoc = (LocationPoint^)elmfrom->Location;

			// Create vector based on element location and connector location.
			XYZ^ diffvec1 = connFrom->Origin->Subtract(elmfromLoc->Point);
			// Subtract element location which will be moved.
			XYZ^ diffvec2 = connTo->Origin->Subtract(elmfromLoc->Point);
			// Bring two connectors to same point
			ElementTransformUtils::MoveElement(doc, elmfrom->Id, diffvec2->Add(diffvec1->Negate()));

			//	Get BasisZ of connectors.
			XYZ^ basisZTo = connTo->CoordinateSystem->BasisZ;
			XYZ^ basisZFrom = connFrom->CoordinateSystem->BasisZ;
			
			//	Calculate angle between connectors.
			double angle  = basisZTo->AngleTo(basisZFrom);
			
			// Calculate crossproduct of two vectors.
			XYZ^ crossprod = basisZTo->CrossProduct(basisZFrom);

			// Create rotation axis.
			Line^ rotationaxis = Line::CreateBound(connTo->Origin, gcnew XYZ(connTo->Origin->X+crossprod->X, connTo->Origin->Y+crossprod->Y, connTo->Origin->Z+crossprod->Z));

			//	Rotate element around axis.
			ElementTransformUtils::RotateElement(doc, elmfrom->Id, rotationaxis, Math::PI-angle);

			// get handle to application from document
			Autodesk::Revit::ApplicationServices::Application^ application = doc->Application;

			// Create a geometry line in Revit application
			XYZ^ startPoint = connTo->Origin;
			XYZ^ endPoint = gcnew XYZ(connTo->Origin->X + crossprod->X, 
									connTo->Origin->Y + crossprod->Y, 
									connTo->Origin->Z + crossprod->Z);
			Line^ geomLine = Line::CreateBound(startPoint, endPoint);

			// Create a geometry plane in Revit application
			Plane^ linePlane = Plane::CreateByThreePoints(
				connTo->Origin,
				gcnew XYZ(connTo->Origin->X,
					connTo->Origin->Y,
					connTo->Origin->Z + connTo->CoordinateSystem->BasisZ->Z),
				gcnew XYZ(connTo->Origin->X + crossprod->X,
					connTo->Origin->Y + crossprod->Y,
					connTo->Origin->Z + crossprod->Z));
			Plane^ arcPlane = Plane::CreateByNormalAndOrigin(crossprod->Normalize(), connTo->Origin);
			Arc^ geomArc = Arc::Create(arcPlane, 0.5, 0, angle);

			// Create a sketch plane in current document
			SketchPlane^ linesketch = SketchPlane::Create(doc, linePlane);
			SketchPlane^ arcsketch = SketchPlane::Create(doc, arcPlane);

			// Create a ModelLine element using the created geometry line and sketch plane
			ModelLine^ line = (ModelLine^)doc->Create->NewModelCurve(geomLine, linesketch);

			// Create a ModelArc element using the created geometry arc and sketch plane
			ModelArc^ arc = (ModelArc^)doc->Create->NewModelCurve(geomArc, arcsketch);
		}
		catch (Exception^ ex)
		{
			TaskDialog::Show("!!! ", ex->Message->ToString());
		}
	}

 

Message 6 of 7
jeremy_tammik
in reply to: halukuzuner

Thank you very much for raising this and sharing your nice solution. So, now a sample is available online. I edited and shared it on the blog for posterity:

  

https://thebuildingcoder.typepad.com/blog/2022/09/aligning-connectors.html#2

  

Jeremy Tammik, Developer Advocacy and Support, The Building Coder, Autodesk Developer Network, ADN Open
Message 7 of 7
ivo.lafeber
in reply to: halukuzuner

Thanks, this works great. 

Can't find what you're looking for? Ask the community or share your knowledge.

Post to forums  

Autodesk Customer Advisory Groups


Rail Community