Hi Guys：

I'm sorry. Ferdinand told me that I should check the python matrix manual. After checking it, I thought that the python matrix was very easy to understand, but could not be applied to the c++ matrix, which made me very confused. I've been worrying about this problem for four days. I hope that I can set the matrix through two points and set my axis. Next, I use pictures to explain my problem. If I can provide the c++ code, Thank you very much (there may be some problems with the software translation I use. Please forgive me).

thx!

# SOLVED How to change polygon axis

Hello @neekoe,

Thank you for reaching out to us.

There is no need to be sorry. I also just realized something, when you say "changing the polygon axis", and with your image you show, you probably want to transform the vertices of a point object and not set the matrix, i.e., transform, of the object itself. So, you want the geometry to be reoriented, but the "axis" of the object should remain the same, right? I have provided a code example and brief screencast for

- constructing a frame from a vector in C++,
- setting this frame to be the frame, i.e., orientation, of a
`BaseObject`

itself, - and transforming all vertices of the object if it is a
`PointObject`

at the end of this posting.

Cheers,

Ferdinand

The result:

The code:

```
#include "c4d_baseobject.h"
#include "c4d_basedocument.h"
#include "maxon/apibase.h"
#include "maxon/lib_math.h"
/// Gets the first two objects in the scene and constructs a frame for them to either reorient the
/// first object itself or its vertices.
static maxon::Result<void> PC14100(BaseDocument* doc)
{
// Get the first and second object in the document.
BaseObject* const objectA = doc->GetFirstObject();
if (objectA == nullptr)
return maxon::UnexpectedError(MAXON_SOURCE_LOCATION, "Could not find input objects."_s);
BaseObject* const objectB = objectA->GetNext();
if (objectB == nullptr)
return maxon::UnexpectedError(MAXON_SOURCE_LOCATION, "Could not find input objects."_s);
// Get their global matrices and compute a normalized delta vector for their offsets from A to B.
Matrix mgA = objectA->GetMg();
const Matrix mgB = objectB->GetMg();
const Vector delta = mgB.off - mgA.off;
// #delta is at this point a vector pointing from the origin of A towards the origin of B. We are
// now going to construct a frame for this vector and an up-vector, where the delta vector will
// become the z/k/v3 axis.
// The unit vector of #delta will be the z-axis of our frame.
const maxon::Vector z = delta.GetNormalized(); // This the frame component z/k/v3
// Choose an up-vector that is not (anti-)parallel to that z-component.
const maxon::Float64 epsilon = 1E-5;
const Bool isParallel = 1. - maxon::Abs(Dot(Vector(0., 1., 0.), z)) > epsilon;
const Vector up = isParallel ? Vector(0, 1, epsilon).GetNormalized() : Vector(0, 1, 0);
// Compute the remaining components with the cross product.
const Vector x = Cross(up, z).GetNormalized(); // This the frame component x/i/v1
const Vector y = Cross(z, x).GetNormalized(); // This the frame component y/j/v2
// We could optionally scale here these unit vectors, but we are not going to do this, as we
// want to maintain a uniform scale of 1 for the object.
// Construct the new transform for the object A with the frame components we did compute. We
// could give the object also a different offset (i.e., 'position'), but in this case we just
// want to reorient the object A but maintain its position.
Matrix newMg(mgA.off, x, y, z);
// If #objectA is a BaseObject only, i.e., an object that cannot be edited on a vertex level,
// then just set the transform as the global transform of the object. The z-axis of #objectA
// will point towards #objectB after this.
if (!objectA->IsInstanceOf(Opoint))
{
objectA->SetMg(newMg);
}
// ... otherwise we carry out the transform on a vertex level, i.e., we transform each vertex as
// if the object containing these vertices would have been set to #newMg. The result will be
// a geometry that is oriented as in the previous condition, but the global transform, i.e.,
// the "axis" of the object will stay in place.
else
{
// Cast the BaseObject to a point object so that we can manipulate its vertices and get its
// the writable point array that stores the vertex positions.
PointObject* pointObject = static_cast<PointObject*>(objectA);
Vector* points = pointObject->GetPointW();
// We could just multiply each vertex position by #newMg and this would work if #objectA has
// the identity matrix as its frame, i.e., "has the orientation of the world axis of (0, 0, 0)",
// but not in other cases. For these cases we first have to compute the delta between the old
// transform of objectA and the new value. We are also going to zero out the translations of
// both transforms, as we do not want to translate the points, but only rotate them.
mgA.off = Vector();
newMg.off = Vector();
// Multiply the new transform by the inverse of the old transform to get the "difference"
// between both transforms.
const Matrix deltaMg = ~mgA * newMg;
for (int i = 0; i < pointObject->GetPointCount(); i++)
{
points[i] = deltaMg * points[i];
}
}
// Push an update event to Cinema 4D so that its GUI will update after this function has been
// exited when this code runs on the main thread (the only place where we are allowed to do this).
if (GeIsMainThreadAndNoDrawThread())
EventAdd();
return maxon::OK;
}
```

Hello @neekoe,

Thank you for reaching out to us.

There is no need to be sorry. I also just realized something, when you say "changing the polygon axis", and with your image you show, you probably want to transform the vertices of a point object and not set the matrix, i.e., transform, of the object itself. So, you want the geometry to be reoriented, but the "axis" of the object should remain the same, right? I have provided a code example and brief screencast for

- constructing a frame from a vector in C++,
- setting this frame to be the frame, i.e., orientation, of a
`BaseObject`

itself, - and transforming all vertices of the object if it is a
`PointObject`

at the end of this posting.

Cheers,

Ferdinand

The result:

The code:

```
#include "c4d_baseobject.h"
#include "c4d_basedocument.h"
#include "maxon/apibase.h"
#include "maxon/lib_math.h"
/// Gets the first two objects in the scene and constructs a frame for them to either reorient the
/// first object itself or its vertices.
static maxon::Result<void> PC14100(BaseDocument* doc)
{
// Get the first and second object in the document.
BaseObject* const objectA = doc->GetFirstObject();
if (objectA == nullptr)
return maxon::UnexpectedError(MAXON_SOURCE_LOCATION, "Could not find input objects."_s);
BaseObject* const objectB = objectA->GetNext();
if (objectB == nullptr)
return maxon::UnexpectedError(MAXON_SOURCE_LOCATION, "Could not find input objects."_s);
// Get their global matrices and compute a normalized delta vector for their offsets from A to B.
Matrix mgA = objectA->GetMg();
const Matrix mgB = objectB->GetMg();
const Vector delta = mgB.off - mgA.off;
// #delta is at this point a vector pointing from the origin of A towards the origin of B. We are
// now going to construct a frame for this vector and an up-vector, where the delta vector will
// become the z/k/v3 axis.
// The unit vector of #delta will be the z-axis of our frame.
const maxon::Vector z = delta.GetNormalized(); // This the frame component z/k/v3
// Choose an up-vector that is not (anti-)parallel to that z-component.
const maxon::Float64 epsilon = 1E-5;
const Bool isParallel = 1. - maxon::Abs(Dot(Vector(0., 1., 0.), z)) > epsilon;
const Vector up = isParallel ? Vector(0, 1, epsilon).GetNormalized() : Vector(0, 1, 0);
// Compute the remaining components with the cross product.
const Vector x = Cross(up, z).GetNormalized(); // This the frame component x/i/v1
const Vector y = Cross(z, x).GetNormalized(); // This the frame component y/j/v2
// We could optionally scale here these unit vectors, but we are not going to do this, as we
// want to maintain a uniform scale of 1 for the object.
// Construct the new transform for the object A with the frame components we did compute. We
// could give the object also a different offset (i.e., 'position'), but in this case we just
// want to reorient the object A but maintain its position.
Matrix newMg(mgA.off, x, y, z);
// If #objectA is a BaseObject only, i.e., an object that cannot be edited on a vertex level,
// then just set the transform as the global transform of the object. The z-axis of #objectA
// will point towards #objectB after this.
if (!objectA->IsInstanceOf(Opoint))
{
objectA->SetMg(newMg);
}
// ... otherwise we carry out the transform on a vertex level, i.e., we transform each vertex as
// if the object containing these vertices would have been set to #newMg. The result will be
// a geometry that is oriented as in the previous condition, but the global transform, i.e.,
// the "axis" of the object will stay in place.
else
{
// Cast the BaseObject to a point object so that we can manipulate its vertices and get its
// the writable point array that stores the vertex positions.
PointObject* pointObject = static_cast<PointObject*>(objectA);
Vector* points = pointObject->GetPointW();
// We could just multiply each vertex position by #newMg and this would work if #objectA has
// the identity matrix as its frame, i.e., "has the orientation of the world axis of (0, 0, 0)",
// but not in other cases. For these cases we first have to compute the delta between the old
// transform of objectA and the new value. We are also going to zero out the translations of
// both transforms, as we do not want to translate the points, but only rotate them.
mgA.off = Vector();
newMg.off = Vector();
// Multiply the new transform by the inverse of the old transform to get the "difference"
// between both transforms.
const Matrix deltaMg = ~mgA * newMg;
for (int i = 0; i < pointObject->GetPointCount(); i++)
{
points[i] = deltaMg * points[i];
}
}
// Push an update event to Cinema 4D so that its GUI will update after this function has been
// exited when this code runs on the main thread (the only place where we are allowed to do this).
if (GeIsMainThreadAndNoDrawThread())
EventAdd();
return maxon::OK;
}
```

@ferdinand Hello ferdinand

thank you very much for the python matrix manual you provided me yesterday. I have solved this problem so far. However, there is a new problem. I hope that my axis can become vertical like the model, similar to the world coordinates. How to set my axis? Thank you

```
const Vector xNor = xPos.GetNormalized();
const Vector yNor = yPos.GetNormalized();
const Vector zNor = zPos.GetNormalized();
const Matrix m = Matrix(Vector(1,0,0),xNor, yNor, zNor);
const Matrix inverseMat = ~m;
op3->SetMg(inverseMat);
const Matrix cuttomM = Matrix(Vector(1, 0, 0), Vector(0, 1, 0), Vector(0, 0, 1), Vector(0, 0, 0));
//No response at this step
op3->SetModelingAxis(cuttomM);
ApplicationOutput(" m is @", inverseMat);
```

Hey @neekoe,

I would recommend having a look at the code example I have posted here, it will show you how your *"axis can become vertical like the model"*. You must for that transform the vertices of the object, not that object itself (or both). `SetModelingAxis`

does not work like you think it does and "axis" are more or less a virtual concept, if you want to the origin/coordinate system to change in relation to the geometry it governs, you must transform the points that make up that geometry and then the object by the invers of that. E.g., when you move all vertices of an object by +100 units on the x-axis in the coordinate system of the object, and then move the object in its own coordinate system by -100 units on the x axis, it will appear as if the "axis" of the object has been moved, while the points have been kept in place.

Cheers,

Ferdinand

@ferdinand Thank you very much for your continuous help in the past two days. I just searched axis related content in cafe, and it is confirmed that my idea is wrong. You are a patient and good teacher. Thank you again, Ferdinand.