Reposition component to another selected component

Below is a journal submitted by kam; the code will reposition a selected component. Here is the description from the journal header:

Reposition a component.

The journal repositions the selected component to the position of another selected component.

If the selected component is a member of a subassembly,
not only the selected component but the whole subassembly is repositioned.

If the two selected components are the same,
the component is repositioned to the origin of the displayed part.

NX 11. Written in c#.
2018-8-5

Big thanks to kam for sharing the code with us. We look forward to more code submissions soon!

//Reposition a component.
//
//The journal repositions the selected component to the position of another selected component.
//
//If the selected component is a member of a subassembly,
//not only the selected component but the whole subassembly is repositioned.
//
//If the two selected components are the same,
//the component is repositioned to the origin of the displayed part.
//
//NX 11. Written in c#.
//2018-8-5

using System;
using NXOpen;
using NXOpen.UF;
using NXOpen.Assemblies;
using MiniSnap;

public class AlignComponents
{
static Session theSession = Session.GetSession();
static Part workPart = theSession.Parts.Work;

public static void Main(string[] args) // Program entry point
{
Component comp1 = MySelect.SelectAComponent("Select 1st component", Selection.SelectionScope.WorkPartAndOccurrence);
if (comp1 == null) return;

Component comp2 = MySelect.SelectAComponent("Select 2nd component", Selection.SelectionScope.AnyInAssembly);
if (comp2 == null) return;

//In the displayed part's ComponentAssembly, get a Work Component.
Component workComp = theSession.Parts.WorkComponent;

//When Work Component is null, let's assume the displayed part is the work component.
if(theSession.Parts.WorkComponent == null)
workComp = theSession.Parts.Display.ComponentAssembly.RootComponent;

//Get a Work Component's direct child that comp1 belongs to.
Component comp1assy = comp1;
while (comp1assy.Parent != workComp)
{
comp1assy = comp1assy.Parent;
}

if (comp1 == comp2)
//Move it to the origin of the displayed part.
comp1assy.Move(MyTransform.Create(comp1).Invert());
else
//Move it to the position of comp2.
comp1assy.Move(MyTransform.Create(comp1).Invert().TransformBy(MyTransform.Create(comp2)));
}

public static int GetUnloadOption(string dummy)
{
return (int)Session.LibraryUnloadOption.Immediately;
//retutn (int)Session.LibraryUnloadOption.AtTermination;
}

static void Echo(string output)
{
theSession.ListingWindow.Open();
theSession.ListingWindow.WriteLine(output);
}

}
public class MySelect
{
public static Component SelectAComponent(string msg, Selection.SelectionScope scope)
{
TaggedObject selObj = null;
Point3d cursor;

var masks = new[] { new Selection.MaskTriple(UFConstants.UF_component_type, 0, 0) };

Selection.Response resp = UI.GetUI().SelectionManager.SelectTaggedObject
(msg, msg, //prompt, title
scope, //selection scope
Selection.SelectionAction.ClearAndEnableSpecific,
false, false, // includeFeatures, keepHighlighted
masks,
out selObj, out cursor);

return (Component)selObj;
}
}

public class MyTransform
{
private double[] coords = new double[16];
private static UFMtx4 MatLib4 = UFSession.GetUFSession().Mtx4;

//Constructor. This returns an identity transform.
public MyTransform()
{
MatLib4.Identity(coords);
}

//rotation defined by an orientation.
public static MyTransform CreateRotation(Orientation ori)
{
var tr = new MyTransform();
tr.coords[0] = ori.AxisX.X; tr.coords[1] = ori.AxisY.X; tr.coords[2] = ori.AxisZ.X;
tr.coords[4] = ori.AxisX.Y; tr.coords[5] = ori.AxisY.Y; tr.coords[6] = ori.AxisZ.Y;
tr.coords[8] = ori.AxisX.Z; tr.coords[9] = ori.AxisY.Z; tr.coords[10] = ori.AxisZ.Z;
return tr;
}

//from a component
public static MyTransform Create(Component comp)
{
var pt = new Point3d();
var mat3 = new Matrix3x3();
comp.GetPosition(out pt, out mat3);
var tr = MyTransform.CreateRotation(mat3);
tr.Translate(new Vector(pt));
return tr;
}

//Add the specified offset to the translation part of the current Mytransfrom object.
//To allow method chaining, the current object itself is returned.
public MyTransform Translate(Vector vec)
{
coords[3] = coords[3] + vec.X;
coords[7] = coords[7] + vec.Y;
coords[11] = coords[11] + vec.Z;
return this;
}

//Invert
//To allow method chaining, the current object itself is returned.
public MyTransform Invert()
{
MatLib4.Invert(coords, coords);
return this;
}

//TransformBy
//Method that sets this tr to the result of this tr followed by the specified tr.
//To allow method chaining, the current object itself is returned.
public MyTransform TransformBy(MyTransform B)
{
MatLib4.Multiply(this.coords, B.coords, this.coords);
return this;
}

//get Vector
public Vector GetVector()
{
return new Vector(coords[3], coords[7], coords[11]);
}

//get Orientation -- not used in this journal
public Orientation GetOrientation()
{
var ori = new Matrix3x3();
ori.Xx = coords[0]; ori.Yx = coords[1]; ori.Zx = coords[2];
ori.Xy = coords[4]; ori.Yy = coords[5]; ori.Zy = coords[6];
ori.Xz = coords[8]; ori.Yz = coords[9]; ori.Zz = coords[10];
return new Orientation(ori);
}

//get Rotation
public Matrix3x3 GetRotation()
{
var rot = new Matrix3x3();
rot.Xx = coords[0]; rot.Xy = coords[1]; rot.Xz = coords[2];
rot.Yx = coords[4]; rot.Yy = coords[5]; rot.Yz = coords[6];
rot.Zx = coords[8]; rot.Zy = coords[9]; rot.Zz = coords[10];
return rot;
}
}

static class ExtensionMethodsForComponentType
{
static Session theSession = Session.GetSession();

//move a component.
public static void Move(this Component comp, MyTransform tr)
{
var compNet = theSession.Parts.Display.ComponentAssembly.Positioner.EstablishNetwork();
compNet.SetMovingGroup(new NXObject[] {comp});
compNet.DragByTransform(tr.GetVector(), tr.GetRotation());
compNet.Solve();
}

//reposition a component.
public static void Reposition(this Component comp, MyTransform tr)
{
var tr1 = MyTransform.Create(comp).Invert().TransformBy(tr);
var compNet = theSession.Parts.Display.ComponentAssembly.Positioner.EstablishNetwork();
compNet.SetMovingGroup(new NXObject[] { comp });
compNet.DragByTransform(tr1.GetVector(), tr1.GetRotation());
compNet.Solve();
}
}

Comments

There are some problems.
1. As soon as something is modified with the component, it resets back to it's previous position.
2. When a constrained subassembly is the workpart, an inherited constraint is created in the displayed part.
So I modified the code as below.

//Reposition a Component.
//
//The journal repositions the selected component to the position of another selected component.
//
//If the selected component is a member of a subassembly,
//not only the selected component but the whole subassembly is repositioned.
//
//If the two selected components are the same,
//the component is repositioned to the origin of the displayed part.
//
//NX 11. Written in c#.
//2018-9-10

using System;
using NXOpen;
using NXOpen.UF;
using NXOpen.Assemblies;
using MiniSnap;

public class RepositionComponent
{
static Session theSession = Session.GetSession();

public static void Main(string[] args) // Program entry point
{
Component comp1 = MySelect.SelectAComponent("Select 1st component", Selection.SelectionScope.WorkPartAndOccurrence);
if (comp1 == null) return;

Component comp2 = MySelect.SelectAComponent("Select 2nd component", Selection.SelectionScope.AnyInAssembly);
if (comp2 == null) return;

//In the displayed part's ComponentAssembly, get a Work Component.
Component workComp = theSession.Parts.WorkComponent;

//When Work Component is null, let's assume the displayed part is the work component.
if(theSession.Parts.WorkComponent == null)
workComp = theSession.Parts.Display.ComponentAssembly.RootComponent;

//Get a Work Component's direct child that comp1 belongs to.
Component comp1assy = comp1;
while (comp1assy.Parent != workComp)
{
comp1assy = comp1assy.Parent;
}

if (comp1 == comp2)
//Move it to the origin of the displayed part.
comp1assy.Move(MyTransform.Create(comp1).Inverse());
else
//Move it to the position of comp2.
comp1assy.Move(MyTransform.Create(comp1).Inverse().TransformBy(MyTransform.Create(comp2)));
}
/*
public static int GetUnloadOption(string dummy)
{
return (int)Session.LibraryUnloadOption.Immediately;
//retutn (int)Session.LibraryUnloadOption.AtTermination;
}

static void Echo(string output)
{
theSession.ListingWindow.Open();
theSession.ListingWindow.WriteLine(output);
}
*/
}
public class MySelect
{
public static Component SelectAComponent(string msg, Selection.SelectionScope scope)
{
//Declare variables to get data.
TaggedObject selObj = null;
Point3d cursor;

//Deinfe filters for selection.
var masks = new[] { new Selection.MaskTriple(UFConstants.UF_component_type, 0, 0) };

Selection.Response resp = UI.GetUI().SelectionManager.SelectTaggedObject
(msg, msg, //prompt, title
scope, //selection scope
Selection.SelectionAction.ClearAndEnableSpecific,
false, false, // includeFeatures, keepHighlighted
masks,
out selObj, out cursor);

return (Component)selObj;
}
}

public class MyTransform
{
private double[] coords = new double[16];
private static UFMtx4 MatLib4 = UFSession.GetUFSession().Mtx4;

//Constructor. This returns an identity transform.
public MyTransform()
{
MatLib4.Identity(coords);
}

//rotaion about an axis through a point by an angle(in degrees). -- Not used in this Journal.
public static MyTransform CreateRotation(Position pos, Vector axis, double angle)//angle in degrees
{
var tr = new MyTransform();
MatLib4.Rotation(pos.Array, axis.Array, angle, tr.coords);
return tr;
}

//rotation defined by an orientation.
public static MyTransform CreateRotation(Orientation ori)
{
var tr = new MyTransform();
tr.coords[0] = ori.AxisX.X; tr.coords[1] = ori.AxisY.X; tr.coords[2] = ori.AxisZ.X;
tr.coords[4] = ori.AxisX.Y; tr.coords[5] = ori.AxisY.Y; tr.coords[6] = ori.AxisZ.Y;
tr.coords[8] = ori.AxisX.Z; tr.coords[9] = ori.AxisY.Z; tr.coords[10] = ori.AxisZ.Z;
return tr;
}

//from a component
public static MyTransform Create(Component comp)
{
var pt = new Point3d();
var mat3 = new Matrix3x3();
comp.GetPosition(out pt, out mat3);
var tr = MyTransform.CreateRotation(mat3);
tr.Translate(new Vector(pt));
return tr;
}

//Add the specified offset to the translation part of the current Mytransfrom object.
//To allow method chaining, the current object itself is returned.
public MyTransform Translate(Vector vec)
{
coords[3] = coords[3] + vec.X;
coords[7] = coords[7] + vec.Y;
coords[11] = coords[11] + vec.Z;
return this;
}

//Inverse
//Returns the inverse of this MyTransform object.
public MyTransform Inverse()
{
var tr = new MyTransform();
MatLib4.Invert(this.coords, tr.coords);
return tr;
}

//TransformBy
//Method that sets this tr to the result of this tr followed by the specified tr.
//To allow method chaining, the current object itself is returned.
public MyTransform TransformBy(MyTransform B)
{
MatLib4.Multiply(this.coords, B.coords, this.coords);
return this;
}

//Vector
public Vector GetVector()
{
return new Vector(coords[3], coords[7], coords[11]);
}

//Orientation --- Not used in this Journal.
public Orientation GetOrientation()
{
var ori = new Matrix3x3();
ori.Xx = coords[0]; ori.Yx = coords[1]; ori.Zx = coords[2];
ori.Xy = coords[4]; ori.Yy = coords[5]; ori.Zy = coords[6];
ori.Xz = coords[8]; ori.Yz = coords[9]; ori.Zz = coords[10];
return new Orientation(ori);
}

//Rotation
public Matrix3x3 GetRotation()
{
var rot = new Matrix3x3();
rot.Xx = coords[0]; rot.Xy = coords[1]; rot.Xz = coords[2];
rot.Yx = coords[4]; rot.Yy = coords[5]; rot.Yz = coords[6];
rot.Zx = coords[8]; rot.Zy = coords[9]; rot.Zz = coords[10];
return rot;
}
}

static class ExtensionMethodsForComponentType
{
static Session theSession = Session.GetSession();

//move a component.
public static void Move(this Component comp, MyTransform tr)
{
//Map comp onto a corresponding component in the comp's DirectOwner's assembly.
var compA = (comp.DirectOwner).MapComponentFromParent(comp);

//Map MyTransform from a comp's space to the comp's DirectOwner's space.
var trP = MyTransform.Create(comp.Parent);
var trA = new MyTransform().TransformBy(trP).TransformBy(tr).TransformBy(trP.Inverse());

//Get the positioner for this assembly and establishes a NXOpen.Positioning.Network in the positioner.
var compNet = comp.DirectOwner.Positioner.EstablishNetwork();

//Set the elements of the moving group.
compNet.SetMovingGroup(new NXObject[] {compA});

//Move objects which have been added to the network. Constraints are honored.
compNet.BeginDrag();
compNet.DragByTransform(trA.GetVector(), trA.GetRotation());
compNet.EndDrag();

//Solve the constraint network. Does apply the results to the model but does not do an update.(from API reference)
compNet.Solve();

//Return the display objects to their model positions.
compNet.ResetDisplay();

//Apply the current network state to the model. Does not do a solve or an update.
compNet.ApplyToModel(); //Necessary.
}

//reposition a component. -- Not used in this Journal.
public static void Reposition(this Component comp, MyTransform tr)
{
comp.Move(MyTransform.Create(comp).Inverse().TransformBy(tr));
}
}

as per our standards the model's datum layer has to be 9
whereas the assembly's datum layers has to be 109.

Will the code finds/differentiate which type of work part we are in. and assign the layer number accordingly

Please suggest.

An assembly will have one or more components. You could check to see if there are any components and move the datums/label layers accordingly.