Related
We are looking for an efficient algorithm to solve the following problem:
Given two increasingly sorted arrays.
Find the closest corresponding elements in each array that difference is
below a user given threshold. But only the closest of possible candidates
(in the range of array1[i] +/- threshold) should be returned.
The second closest could be matched to another element but
matches to more than one element are not allowed. If two elements in
array1 have the same distance to array2[j] the first (leftmost) match
should be reported.
The arrays can contain duplicated values. There the first (leftmost) match
should be reported (and all the others ignored/not matched).
Examples:
x: 1, 3, 5, 6, 8
y: 3, 4, 5, 7
threshold: 1
output: NA, 1, 3, 4, NA
(index of y that matches best to x)
x: 1, 1.5, 2, 2.1, 5, 6.1, 7.2
y: 4.6, 4.7, 4.8, 4.9, 5, 6, 7, 8
threshold: 3
output: NA, NA, NA, 1, 5, 6, 7
(index of y that matches best to x)
x: 1, 1, 1, 2, 2, 2
y: 1, 2
threshold: 0
output: 1, NA, NA, 2, NA, NA
(index of y that matches best to x, for duplicates choose to first one)
x: 1, 2
y: 1, 1, 1, 2, 2, 2
threshold: 0
output: 1, 4
(index of y that matches best to x, for duplicates choose to first one)
We use this to find the closest matching values between two m/z-values
(mass-to-charge ratios) while comparing mass spectra.
Currently we iterate through both arrays and lookahead the differences for the
next two elements and correct the previous element if a closer one was found.
But this fails for more than two duplicate elements in a row (second example):
Our current implementation (C code as part of an R package):
https://github.com/rformassspectrometry/MsCoreUtils/blob/master/src/closest.c#L73-L129
A commented version below:
SEXP C_closest_dup_closest(SEXP x, SEXP table, SEXP tolerance, SEXP nomatch) {
/* x is the first array of doubles */
double *px = REAL(x);
const unsigned int nx = LENGTH(x);
/* table is the second array of doubles where x should be matched against */
double *ptable = REAL(table);
const unsigned int ntable = LENGTH(table);
/* user given tolerance threshold */
double *ptolerance = REAL(tolerance);
/* integer array to store the results */
SEXP out = PROTECT(allocVector(INTSXP, nx));
int* pout = INTEGER(out);
/* integer that should returned if no valid match or a closer one was found */
const unsigned int inomatch = asInteger(nomatch);
/* indices */
unsigned int ix = 0, ixlastused = 1;
unsigned int itbl = 0, itbllastused = 1;
/* differences: current, difference to next element of x and table, respectively */
double diff = R_PosInf, diffnxtx = R_PosInf, diffnxttbl = R_PosInf;
while (ix < nx) {
if (itbl < ntable) {
/* difference for current pair */
diff = fabs(px[ix] - ptable[itbl]);
/* difference for next pairs */
diffnxtx =
ix + 1 < nx ? fabs(px[ix + 1] - ptable[itbl]) : R_PosInf;
diffnxttbl =
itbl + 1 < ntable ? fabs(px[ix] - ptable[itbl + 1]) : R_PosInf;
if (diff <= ptolerance[ix]) {
/* valid match, add + 1 to convert between R/C index */
pout[ix] = itbl + 1;
if (itbl == itbllastused &&
(diffnxtx < diffnxttbl || diff < diffnxttbl))
pout[ixlastused] = inomatch;
ixlastused = ix;
itbllastused = itbl;
} else
pout[ix] = inomatch;
if (diffnxtx < diff || diffnxttbl < diff) {
/* increment the index with the smaller distance */
if (diffnxtx < diffnxttbl)
++ix;
else
++itbl;
} else {
/* neither next x nor next table item offer a better match */
++ix;
++itbl;
}
} else
pout[ix++] = inomatch;
}
/* R provided MACRO to free allocated memory */
UNPROTECT(1);
return out;
}
Could anybody give us a hint for a better algorithm?
I don't understand the guru interface of FFTW. Let me explain how I thought it worked based on the manual and this question How to use fftw Guru interface and maybe someone can clear up my misunderstanding.
fftw_plan fftw_plan_guru64_dft(
int rank, const fftw_iodim64 *dims,
int howmany_rank, const fftw_iodim64 *howmany_dims,
fftw_complex *in, fftw_complex *out,
int sign, unsigned flags);
Suppose we want to calculate the DFT of interleaved multidimensional arrays, such as the six 2x2 arrays (each with a different colour) in this picture.
interleaved dfts
Because the dfts have stride 3 in the vertical direction, and stride 2 in the horizontal direction, I thought we would need rank = 2 and dims = {(2, 3, 3), (2, 2, 2)}. The starting points are a 3 x 2 subarray, so I thought howmany_rank = 2, howmany_dims = {(3, 1, 1), (2, 1, 1)}.
However, this is not actually what FFTW does. I made a smaller example that is easy to calculate by hand, consisting of 4 DFTs of size 2x1 (indicated by colours). Each dft is of the form (+-1, 0) which has as output (+-1, +-1), but that is not what FFTW calculates.
small example
Here is the code I used to calculate the DFT.
#include <stdio.h>
#include <stdlib.h>
#include <complex.h>
#include <math.h>
#include <fftw3.h>
int main()
{
fftw_complex* X = fftw_malloc(8 * sizeof(fftw_complex));
fftw_iodim* sizes = malloc(2 * sizeof(fftw_iodim));
fftw_iodim* startingPoints = malloc(2 * sizeof(fftw_iodim));
sizes[0].n = 2; sizes[0].is = 2; sizes[0].os = 2;
sizes[1].n = 1; sizes[1].is = 2; sizes[1].os = 2;
startingPoints[0].n = 2; startingPoints[0].is = 1; startingPoints[0].os = 1;
startingPoints[1].n = 2; startingPoints[1].is = 1; startingPoints[1].os = 1;
fftw_plan plan = fftw_plan_guru_dft(2, sizes, 2, startingPoints, X, X, FFTW_FORWARD, FFTW_ESTIMATE);
X[0] = 1.0; X[1] = -1.0;
X[2] = 1.0; X[3] = -1.0;
X[4] = 0.0; X[5] = 0.0;
X[6] = 0.0; X[7] = 0.0;
fftw_execute(plan);
printf("\nOutput in row-major order:\n");
for (int i = 0; i < 8; i++) {
printf("%lf + %lfi, ", creal(X[i]), cimag(X[i]));
}
return 0;
}
Strides even for major axes are in "units", i.e. doubles or fftw_complexes, not number of rows: https://www.fftw.org/fftw3_doc/Guru-vector-and-transform-sizes.html#Guru-vector-and-transform-sizes
My guess is that in major axis strides have to be multiplied by the distance between consecutive rows, also in units. So for the arrays their iodims.is and iodims.os strides should be 4*3 == 12.
It's code from vec3.c in gl-matrix.
vec3_t vec3_create(vec3_t vec) {
vec3_t dest = calloc(sizeof(double_t), 3);
if (vec) {
dest[0] = vec[0];
dest[1] = vec[1];
dest[2] = vec[2];
} else {
dest[0] = dest[1] = dest[2] = 0;
}
return dest;
}
How can I crate new vector using that function?
How to create vector with different values?
I was trying to set double values to array like this:
vec3_t vec;
vec3_t vec3_create(vec);
vec[0] = 1.0;
vec[1] = 0.0;
vec[2] = 0.0;
But I get EXC_BAD_ACCESS. Have the same problem with matrices.
Code in mat4.c in gl-matrix.
mat4_t mat4_create(mat4_t mat) {
mat4_t dest = calloc(sizeof(double), 16);
if (mat) {
dest[0] = mat[0];
dest[1] = mat[1];
dest[2] = mat[2];
dest[3] = mat[3];
dest[4] = mat[4];
dest[5] = mat[5];
dest[6] = mat[6];
dest[7] = mat[7];
dest[8] = mat[8];
dest[9] = mat[9];
dest[10] = mat[10];
dest[11] = mat[11];
dest[12] = mat[12];
dest[13] = mat[13];
dest[14] = mat[14];
dest[15] = mat[15];
}
return dest;
}
EXC_BAD_ACCESS.
mat4_t transform_mat;
mat4_create(transform_mat);
vec3_t is a pointer to a double as defined in the header
typedef double *vec3_t;
From the header you find also some documentation, which will tell you how to use it:
/*
* vec3_t - 3 Dimensional Vector
*/
/*
* vec3_create
* Creates a new instance of a vec3_t
*
* Params:
* vec - Optional, vec3_t containing values to initialize with. If NULL, the
* vector will be initialized with zeroes.
*
* Returns:
* New vec3
*/
vec3_t vec3_create(vec3_t vec);
So you would might want to do something like this:
vec3_t vec = vec3_create(NULL); // initially a vector with 0s
vec[0] = 1.0; // set the first element to 1.0
In regard to the matrix:
mat4_t transform_mat = mat4_create(NULL);
This will allocate memory and transform_mat will point to its address. You need to initialize the values yourself, as they are not initialized to 0s by default (as it is done with vec3_t).
I have imported an FBX model that composes of multiple meshes. Unfortunately, I am not able to display each mesh in their correct positions. For each mesh I multiply a geometric transformation of the mesh with a local transformation of the mesh and then pass it to shader. How can I fix this problem?
OpenGL Shader
gl_Position = modelViewProjectionMatrix *TransformationMatrix*vertexPositionsOfMesh;
Creating Transformation Matrix
GLKMatrix4 LcLTransformation = createTransformationMatrix(
Mesh->LclRotation,
Mesh->LclScaling,
Mesh->LclTranslation);
GLKMatrix4 GeoTransformation = createTransformationMatrix(
Mesh->GeometricRotation,
Mesh->GeometricScaling,
Mesh->GeometricTranslation);
TransformationMatrix=GLKMatrix4Transpose(GLKMatrix4Multiply(LcLTransformation,
GeoTransformation));
createTransformationMatrix
GLKMatrix4 createTransformationMatrix(float* _rotation, float* _scaling, float* _translation)
{
GLKMatrix4 Rx = GLKMatrix4Make(1, 0, 0, 0,
0, cos(_rotation[0]), -sin(_rotation[0]), 0,
0, sin(_rotation[0]), cos(_rotation[0]), 0,
0, 0, 0, 1
);
GLKMatrix4 Ry = GLKMatrix4Make(cos(_rotation[1]), 0, sin(_rotation[1]), 0,
0, 1, 0, 0,
-sin(_rotation[1]), 0, cos(_rotation[1]), 0,
0, 0, 0, 1
);
GLKMatrix4 Rz = GLKMatrix4Make(cos(_rotation[2]), -sin(_rotation[2]), 0, 0,
sin(_rotation[2]), cos(_rotation[2]), 0, 0,
0, 0, 1, 0,
0, 0, 0, 1
);
GLKMatrix4 Translation = GLKMatrix4Make(1, 0, 0, _translation[0],
0, 1, 0, _translation[1],
0, 0, 1, _translation[2],
0, 0, 0, 1
);
GLKMatrix4 Scaling = GLKMatrix4Identity;
Scaling.m00 = _scaling[0];
Scaling.m11 = _scaling[1];
Scaling.m22 = _scaling[2];
GLKMatrix4 Rotation = GLKMatrix4Multiply(GLKMatrix4Multiply(Rx, Ry), Rz);
Transformation = GLKMatrix4Multiply(Scaling, GLKMatrix4Multiply(Rotation, Translation));
return Transformation;
}
I correctly imported fbx from MAX in my engine.
You have to:
WorldMatrix= [ParentWorldMatrix * ModelMatrix] * GeometricMatrix
You have to ONLY multiply geometric matrices AFTER getting the worlds of the hierarchy. The "ParentMatrix" does NOT contain GEOMs.
So a model should be:
World = GrandGrandParentModel * [...] * GrandParentModel * ParentModel
* Model * CurrentModelGeometric.
Remember that the rotations are ZYX.
Code:
void GRPNODE::UpdateWorldMatrix(bool * mustUpdate)
{
if (!parent)
return;
parent->UpdateWorldMatrix(mustUpdate);
if (worldmatrix_is_pending)
*mustUpdate = true;
if (*mustUpdate)
this->worldmatrix.GetMulplicationMatrix(parent->GetWorldMatrixPointer(), &modelmatrix);
}
And after that I get the world matrix of the node, when I transform vertices I do:
void GRPELEMENT::ComputeMatrices(GRPMATRIX* viewmatrix, GRPMATRIX* viewprojection, GRPMATRIX* projection)
{
modelmatrix=node->GetWorldMatrix();
if (node->UsesGeometric)
modelmatrix.GetMulplicationMatrix(modelmatrix, (*node->GetGeometricMatrix()));
modelviewmatrix.GetMulplicationMatrix((*viewmatrix), modelmatrix);
modelviewprojectionmatrix.GetMulplicationMatrix(projection, &modelviewmatrix);
}
void GRPNODE::MaxUpdate()
{
// 1.0 Create Scale matrix
scalematrix.BuildScaleMatrix(scale.vector[0], scale.vector[1], scale.vector[2]);
// 1.1 Create current Rotation Translation Matrix
Rx.BuildRotationMatrixX (this->rotation.vector[0]);
Ry.BuildRotationMatrixY (this->rotation.vector[1]);
Rz.BuildRotationMatrixZ (this->rotation.vector[2]);
if (UsesPreRotation)
{
Rpre.GetMulplicationMatrix(&prerotationmatrix, &Rz);
Rt.GetMulplicationMatrix(&Rpre, &Ry);
rotationmatrix.GetMulplicationMatrix(&Rt, &Rx);
}
else
{
Rt.GetMulplicationMatrix(&Rz, &Ry);
rotationmatrix.GetMulplicationMatrix(&Rt, &Rx);
}
if (UsesPostRotation)
{
Rpost.GetMulplicationMatrix(&rotationmatrix, &postrotationmatrix);
rotationmatrix = Rpost;
}
translationmatrix.BuildTranslationMatrix(position);
//1.2. Create current model matrix (from stored matrix with rotation/translation)
m.GetMulplicationMatrix(translationmatrix, rotationmatrix);
modelmatrix.GetMulplicationMatrix(m, scalematrix);
}
Locked. There are disputes about this answer’s content being resolved at this time. It is not currently accepting new interactions.
According to the Transformations example code in Autodesk's official SDK, a node's global position in the world space is recursively calculated by the CalculateGlobalTransform(FbxNode* pNode) function as in the sample code below. Very important things to notice are this function takes into account not just pre and post rotations, but also pivot location and offsets. Also depending on the node's transformation inheritance type, the transformation formula changes.
In case you import the model from 3ds Max, after calculating a node's global transformation information, you still have to multiply it with geometric transformations in order to find the position of node attribute in global coordinates.
/*
Copyright (C) 2013 Autodesk, Inc.
Terminology:
Suffix "M" means this is a matrix, suffix "V" means it is a vector.
T is translation.
R is rotation.
S is scaling.
SH is shear.
GlobalRM(x) means the Global Rotation Matrix of node "x".
GlobalRM(P(x)) means the Global Rotation Matrix of the parent node of node "x".
All other transforms are described in the similar way.
The algorithm description:
To calculate global transform of a node x according to different InheritType,
we need to calculate GlobalTM(x) and [GlobalRM(x) * (GlobalSHM(x) * GlobalSM(x))] separately.
GlobalM(x) = GlobalTM(x) * [GlobalRM(x) * (GlobalSHM(x) * GlobalSM(x))];
InhereitType = RrSs:
GlobalRM(x) * (GlobalSHM(x) * GlobalSM(x)) = GlobalRM(P(x)) * LocalRM(x) * [GlobalSHM(P(x)) * GlobalSM(P(x))] * LocalSM(x);
InhereitType = RSrs:
GlobalRM(x) * (GlobalSHM(x) * GlobalSM(x)) = GlobalRM(P(x)) * [GlobalSHM(P(x)) * GlobalSM(P(x))] * LocalRM(x) * LocalSM(x);
InhereitType = Rrs:
GlobalRM(x) * (GlobalSHM(x) * GlobalSM(x)) = GlobalRM(P(x)) * LocalRM(x) * LocalSM(x);
LocalM(x)= TM(x) * RoffsetM(x) * RpivotM(x) * RpreM(x) * RM(x) * RpostM(x) * RpivotM(x)^-1 * SoffsetM(x) *SpivotM(x) * SM(x) * SpivotM(x)^-1
LocalTWithAllPivotAndOffsetInformationV(x) = Local(x).GetT();
GlobalTV(x) = GlobalM(P(x)) * LocalTWithAllPivotAndOffsetInformationV(x);
Notice: FBX SDK does not support shear yet, so all local transform won't have shear.
However, global transform might bring in shear by combine the global transform of node in higher hierarchy.
For example, if you scale the parent by a non-uniform scale and then rotate the child node, then a shear will
be generated on the child node's global transform.
In this case, we always compensates shear and store it in the scale matrix too according to following formula:
Shear*Scaling = RotationMatrix.Inverse * TranslationMatrix.Inverse * WholeTranformMatrix
*/
FbxAMatrix CalculateGlobalTransform(FbxNode* pNode)
{
FbxAMatrix lTranlationM, lScalingM, lScalingPivotM, lScalingOffsetM, lRotationOffsetM, lRotationPivotM, \
lPreRotationM, lRotationM, lPostRotationM, lTransform;
FbxAMatrix lParentGX, lGlobalT, lGlobalRS;
if(!pNode)
{
lTransform.SetIdentity();
return lTransform;
}
// Construct translation matrix
FbxVector4 lTranslation = pNode->LclTranslation.Get();
lTranlationM.SetT(lTranslation);
// Construct rotation matrices
FbxVector4 lRotation = pNode->LclRotation.Get();
FbxVector4 lPreRotation = pNode->PreRotation.Get();
FbxVector4 lPostRotation = pNode->PostRotation.Get();
lRotationM.SetR(lRotation);
lPreRotationM.SetR(lPreRotation);
lPostRotationM.SetR(lPostRotation);
// Construct scaling matrix
FbxVector4 lScaling = pNode->LclScaling.Get();
lScalingM.SetS(lScaling);
// Construct offset and pivot matrices
FbxVector4 lScalingOffset = pNode->ScalingOffset.Get();
FbxVector4 lScalingPivot = pNode->ScalingPivot.Get();
FbxVector4 lRotationOffset = pNode->RotationOffset.Get();
FbxVector4 lRotationPivot = pNode->RotationPivot.Get();
lScalingOffsetM.SetT(lScalingOffset);
lScalingPivotM.SetT(lScalingPivot);
lRotationOffsetM.SetT(lRotationOffset);
lRotationPivotM.SetT(lRotationPivot);
// Calculate the global transform matrix of the parent node
FbxNode* lParentNode = pNode->GetParent();
if(lParentNode)
{
lParentGX = CalculateGlobalTransform(lParentNode);
}
else
{
lParentGX.SetIdentity();
}
//Construct Global Rotation
FbxAMatrix lLRM, lParentGRM;
FbxVector4 lParentGR = lParentGX.GetR();
lParentGRM.SetR(lParentGR);
lLRM = lPreRotationM * lRotationM * lPostRotationM;
//Construct Global Shear*Scaling
//FBX SDK does not support shear, to patch this, we use:
//Shear*Scaling = RotationMatrix.Inverse * TranslationMatrix.Inverse * WholeTranformMatrix
FbxAMatrix lLSM, lParentGSM, lParentGRSM, lParentTM;
FbxVector4 lParentGT = lParentGX.GetT();
lParentTM.SetT(lParentGT);
lParentGRSM = lParentTM.Inverse() * lParentGX;
lParentGSM = lParentGRM.Inverse() * lParentGRSM;
lLSM = lScalingM;
//Do not consider translation now
FbxTransform::EInheritType lInheritType = pNode->InheritType.Get();
if(lInheritType == FbxTransform::eInheritRrSs)
{
lGlobalRS = lParentGRM * lLRM * lParentGSM * lLSM;
}
else if(lInheritType == FbxTransform::eInheritRSrs)
{
lGlobalRS = lParentGRM * lParentGSM * lLRM * lLSM;
}
else if(lInheritType == FbxTransform::eInheritRrs)
{
FbxAMatrix lParentLSM;
FbxVector4 lParentLS = lParentNode->LclScaling.Get();
lParentLSM.SetS(lParentLS);
FbxAMatrix lParentGSM_noLocal = lParentGSM * lParentLSM.Inverse();
lGlobalRS = lParentGRM * lLRM * lParentGSM_noLocal * lLSM;
}
else
{
FBXSDK_printf("error, unknown inherit type! \n");
}
// Construct translation matrix
// Calculate the local transform matrix
lTransform = lTranlationM * lRotationOffsetM * lRotationPivotM * lPreRotationM * lRotationM * lPostRotationM * lRotationPivotM.Inverse()\
* lScalingOffsetM * lScalingPivotM * lScalingM * lScalingPivotM.Inverse();
FbxVector4 lLocalTWithAllPivotAndOffsetInfo = lTransform.GetT();
// Calculate global translation vector according to:
// GlobalTranslation = ParentGlobalTransform * LocalTranslationWithPivotAndOffsetInfo
FbxVector4 lGlobalTranslation = lParentGX.MultT(lLocalTWithAllPivotAndOffsetInfo);
lGlobalT.SetT(lGlobalTranslation);
//Construct the whole global transform
lTransform = lGlobalT * lGlobalRS;
return lTransform;
}
Is there any way to do this in a condensed form?
GLfloat coordinates[8];
...
coordinates[0] = 1.0f;
coordinates[1] = 0.0f;
coordinates[2] = 1.0f;
coordinates[3] = 1.0f;
coordinates[4] = 0.0f;
coordinates[5] = 1.0f;
coordinates[6] = 0.0f;
coordinates[7] = 0.0f;
return coordinates;
Something like coordinates = {1.0f, ...};?
If you really to assign values (as opposed to initialize), you can do it like this:
GLfloat coordinates[8];
static const GLfloat coordinates_defaults[8] = {1.0f, 0.0f, 1.0f ....};
...
memcpy(coordinates, coordinates_defaults, sizeof(coordinates_defaults));
return coordinates;
Although in your case, just plain initialization will do, there's a trick to wrap the array into a struct (which can be initialized after declaration).
For example:
struct foo {
GLfloat arr[10];
};
...
struct foo foo;
foo = (struct foo) { .arr = {1.0, ... } };
The old-school way:
GLfloat coordinates[8];
...
GLfloat *p = coordinates;
*p++ = 1.0f; *p++ = 0.0f; *p++ = 1.0f; *p++ = 1.0f;
*p++ = 0.0f; *p++ = 1.0f; *p++ = 0.0f; *p++ = 0.0f;
return coordinates;
You can use:
GLfloat coordinates[8] = {1.0f, ..., 0.0f};
but this is a compile-time initialisation - you can't use that method in the current standard to re-initialise (although I think there are ways to do it in the upcoming standard, which may not immediately help you).
The other two ways that spring to mind are to blat the contents if they're fixed:
GLfloat base_coordinates[8] = {1.0f, ..., 0.0f};
GLfloat coordinates[8];
:
memcpy (coordinates, base_coordinates, sizeof (coordinates));
or provide a function that looks like your initialisation code anyway:
void setCoords (float *p0, float p1, ..., float p8) {
p0[0] = p1; p0[1] = p2; p0[2] = p3; p0[3] = p4;
p0[4] = p5; p0[5] = p6; p0[6] = p7; p0[7] = p8;
}
:
setCoords (coordinates, 1.0f, ..., 0.0f);
keeping in mind those ellipses (...) are placeholders, not things to literally insert in the code.
I went with an array initialization method:
#include <stdarg.h>
void int_array_init(int *a, const int ct, ...) {
va_list args;
va_start(args, ct);
for(int i = 0; i < ct; ++i) {
a[i] = va_arg(args, int);
}
va_end(args);
}
called like,
const int node_ct = 8;
int expected[node_ct];
int_array_init(expected, node_ct, 1, 3, 4, 2, 5, 6, 7, 8);
The C99 array initialization, like this:
const int node_ct = 8;
const int expected[node_ct] = { 1, 3, 4, 2, 5, 6, 7, 8 };
And in the configure.ac:
AC_PROG_CC_C99
had the compiler on my dev box perfectly happy. The compiler on the server complained with:
error: variable-sized object may not be initialized
const int expected[node_ct] = { 1, 3, 4, 2, 5, 6, 7, 8 };
and
warning: excess elements in array initializer
const int expected[node_ct] = { 1, 3, 4, 2, 5, 6, 7, 8 };
for each element
It doesn't complain at all about, for example:
int expected[] = { 1, 2, 3, 4, 5 };
I like the check on size, and that the varargs support is acting more robustly than the support for the array initializer.
Find PR with sample code at https://github.com/wbreeze/davenport/pull/15/files
Regarding https://stackoverflow.com/a/3535455/608359 from #paxdiablo, I liked it; but, felt insecure about having the number of times the initializaion pointer advances synchronized with the number of elements allocated to the array. Worst case, the initializing pointer moves beyond the allocated length. As such, the diff in the PR contains,
int expected[node_ct];
- int *p = expected;
- *p++ = 1; *p++ = 2; *p++ = 3; *p++ = 4;
+ int_array_init(expected, node_ct, 1, 2, 3, 4);
The int_array_init method will safely assign junk if the number of
arguments is fewer than the node_ct. The junk assignment ought to be easier
to catch and debug.
Exactly, you nearly got it:
GLfloat coordinates[8] = {1.0f, ..., 0.0f};
If you are doing these same assignments a lot in your program and want a shortcut, the most straightforward solution might be to just add a function
static inline void set_coordinates(
GLfloat coordinates[static 8],
GLfloat c0, GLfloat c1, GLfloat c2, GLfloat c3,
GLfloat c4, GLfloat c5, GLfloat c6, GLfloat c7)
{
coordinates[0] = c0;
coordinates[1] = c1;
coordinates[2] = c2;
coordinates[3] = c3;
coordinates[4] = c4;
coordinates[5] = c5;
coordinates[6] = c6;
coordinates[7] = c7;
}
and then simply call
GLfloat coordinates[8];
// ...
set_coordinates(coordinates, 1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f);
typedef struct{
char array[4];
}my_array;
my_array array = { .array = {1,1,1,1} }; // initialisation
void assign(my_array a)
{
array.array[0] = a.array[0];
array.array[1] = a.array[1];
array.array[2] = a.array[2];
array.array[3] = a.array[3];
}
char num = 5;
char ber = 6;
int main(void)
{
printf("%d\n", array.array[0]);
// ...
// this works even after initialisation
assign((my_array){ .array = {num,ber,num,ber} });
printf("%d\n", array.array[0]);
// ....
return 0;
}