Skip to content

Commit

Permalink
Merge pull request #335 from cburstedde/feature-calc-coordinates
Browse files Browse the repository at this point in the history
Calculate quadrant boundary coordinates
  • Loading branch information
cburstedde authored Feb 7, 2025
2 parents 9db73da + 8392c19 commit 5024034
Show file tree
Hide file tree
Showing 9 changed files with 353 additions and 54 deletions.
146 changes: 130 additions & 16 deletions src/p4est_bits.c
Original file line number Diff line number Diff line change
Expand Up @@ -659,11 +659,13 @@ p4est_quadrant_child_id (const p4est_quadrant_t * q)
int
p4est_coordinates_is_inside_root (const p4est_qcoord_t coord[])
{
P4EST_ASSERT (coord != NULL);

/* *INDENT-OFF* */
return (coord[0] >= 0 && coord[0] < P4EST_ROOT_LEN) &&
(coord[1] >= 0 && coord[1] < P4EST_ROOT_LEN) &&
return (coord[0] >= 0 && coord[0] <= P4EST_ROOT_LEN) &&
(coord[1] >= 0 && coord[1] <= P4EST_ROOT_LEN) &&
#ifdef P4_TO_P8
(coord[2] >= 0 && coord[2] < P4EST_ROOT_LEN) &&
(coord[2] >= 0 && coord[2] <= P4EST_ROOT_LEN) &&
#endif
/* *INDENT-ON* */
1;
Expand All @@ -672,15 +674,16 @@ p4est_coordinates_is_inside_root (const p4est_qcoord_t coord[])
int
p4est_quadrant_is_inside_root (const p4est_quadrant_t * q)
{
p4est_qcoord_t coord[P4EST_DIM];
P4EST_ASSERT (q != NULL);

coord[0] = q->x;
coord[1] = q->y;
/* *INDENT-OFF* */
return (q->x >= 0 && q->x < P4EST_ROOT_LEN) &&
(q->y >= 0 && q->y < P4EST_ROOT_LEN) &&
#ifdef P4_TO_P8
coord[2] = q->z;
(q->z >= 0 && q->z < P4EST_ROOT_LEN) &&
#endif

return p4est_coordinates_is_inside_root (coord);
/* *INDENT-ON* */
1;
}

int
Expand Down Expand Up @@ -752,8 +755,10 @@ p4est_quadrant_is_node (const p4est_quadrant_t * q, int inside)
int
p4est_coordinates_is_valid (const p4est_qcoord_t coord[], int level)
{
P4EST_ASSERT (coord != NULL);

return
(level >= 0 && level <= P4EST_QMAXLEVEL) &&
(level >= 0 && level <= P4EST_MAXLEVEL) &&
((coord[0] & (P4EST_QUADRANT_LEN (level) - 1)) == 0) &&
((coord[1] & (P4EST_QUADRANT_LEN (level) - 1)) == 0) &&
#ifdef P4_TO_P8
Expand All @@ -765,15 +770,16 @@ p4est_coordinates_is_valid (const p4est_qcoord_t coord[], int level)
int
p4est_quadrant_is_valid (const p4est_quadrant_t * q)
{
p4est_qcoord_t coord[P4EST_DIM];
P4EST_ASSERT (q != NULL);

coord[0] = q->x;
coord[1] = q->y;
return
(q->level >= 0 && q->level <= P4EST_QMAXLEVEL) &&
((q->x & (P4EST_QUADRANT_LEN (q->level) - 1)) == 0) &&
((q->y & (P4EST_QUADRANT_LEN (q->level) - 1)) == 0) &&
#ifdef P4_TO_P8
coord[2] = q->z;
((q->z & (P4EST_QUADRANT_LEN (q->level) - 1)) == 0) &&
#endif

return p4est_coordinates_is_valid (coord, q->level);
p4est_quadrant_is_inside_root (q);
}

int
Expand Down Expand Up @@ -1215,6 +1221,21 @@ p4est_quadrant_enlarge_last (const p4est_quadrant_t * a, p4est_quadrant_t * q)
#endif
}

void
p4est_quadrant_root (p4est_quadrant_t *root)
{
P4EST_ASSERT (root != NULL);

root->x = 0;
root->y = 0;
#ifdef P4_TO_P8
root->z = 0;
#endif
root->level = 0;

P4EST_ASSERT (p4est_quadrant_is_valid (root));
}

void
p4est_quadrant_ancestor (const p4est_quadrant_t * q,
int level, p4est_quadrant_t * r)
Expand Down Expand Up @@ -1289,6 +1310,25 @@ p4est_quadrant_child (const p4est_quadrant_t * q, p4est_quadrant_t * r,
P4EST_ASSERT (p4est_quadrant_is_parent (q, r));
}

void
p4est_quadrant_volume_coordinates (const p4est_quadrant_t * q,
p4est_qcoord_t coords[])
{
/* compute half length of qudrant: legal even when at P4EST_QMAXLEVEL */
const p4est_qcoord_t qhh = P4EST_QUADRANT_LEN (q->level + 1);

/* we require a quadrant in the unit tree, not outside of it */
P4EST_ASSERT (p4est_quadrant_is_valid (q));

/* for any coordinate axis shift by half the quadrant length */
coords[0] = q->x + qhh;
coords[1] = q->y + qhh;
#ifdef P4_TO_P8
coords[2] = q->z + qhh;
#endif
P4EST_ASSERT (p4est_coordinates_is_valid (coords, q->level + 1));
}

void
p4est_quadrant_face_neighbor (const p4est_quadrant_t * q,
int face, p4est_quadrant_t * r)
Expand Down Expand Up @@ -1447,6 +1487,31 @@ p4est_quadrant_all_face_neighbors (const p4est_quadrant_t * q,
}
}

void
p4est_quadrant_face_coordinates (const p4est_quadrant_t * q, int face,
p4est_qcoord_t coords[])
{
/* compute half length of qudrant: legal even when at P4EST_QMAXLEVEL */
const p4est_qcoord_t qh = P4EST_QUADRANT_LEN (q->level);
const p4est_qcoord_t qhh = qh >> 1;

/* store the coordinate axis normal to the face */
const int faceh = face >> 1;

P4EST_ASSERT (0 <= face && face < P4EST_FACES);
P4EST_ASSERT (0 <= faceh && faceh < P4EST_DIM);
P4EST_ASSERT (p4est_quadrant_is_valid (q));

/* for the coordinate axis normal to the face, choose shift of 0 or qh */
/* for a coordinate axis parallel to the face, shift by half */
coords[0] = q->x + ((faceh == 0) ? ((face & 1) ? qh : 0) : qhh);
coords[1] = q->y + ((faceh == 1) ? ((face & 1) ? qh : 0) : qhh);
#ifdef P4_TO_P8
coords[2] = q->z + ((faceh == 2) ? ((face & 1) ? qh : 0) : qhh);
#endif
P4EST_ASSERT (p4est_coordinates_is_valid (coords, q->level + 1));
}

void
p4est_quadrant_corner_neighbor (const p4est_quadrant_t * q,
int corner, p4est_quadrant_t * r)
Expand Down Expand Up @@ -1664,6 +1729,23 @@ p4est_quadrant_corner_node (const p4est_quadrant_t * q,
P4EST_ASSERT (p4est_quadrant_is_node (r, 0));
}

void
p4est_quadrant_corner_coordinates (const p4est_quadrant_t * q, int corner,
p4est_qcoord_t coords[])
{
const p4est_qcoord_t qh = P4EST_QUADRANT_LEN (q->level);

P4EST_ASSERT (0 <= corner && corner < P4EST_CHILDREN);
P4EST_ASSERT (p4est_quadrant_is_valid (q));

coords[0] = q->x + ((corner & 1) ? qh : 0);
coords[1] = q->y + ((corner & 2) ? qh : 0);
#ifdef P4_TO_P8
coords[2] = q->z + ((corner & 4) ? qh : 0);
#endif
P4EST_ASSERT (p4est_coordinates_is_valid (coords, q->level));
}

void
p4est_quadrant_children (const p4est_quadrant_t * q,
p4est_quadrant_t * c0, p4est_quadrant_t * c1,
Expand Down Expand Up @@ -2123,6 +2205,38 @@ p4est_quadrant_touches_corner (const p4est_quadrant_t * q,
return incount == P4EST_DIM;
}

void
p4est_coordinates_transform_corner (p4est_qcoord_t coords[], int corner)
{
p4est_qcoord_t shift[2];
#ifdef P4EST_ENABLE_DEBUG
p4est_qcoord_t rcoords[P4EST_DIM];
p4est_quadrant_t root;
#endif

P4EST_ASSERT (coords != NULL);
P4EST_ASSERT (0 <= corner && corner < P4EST_CHILDREN);

shift[0] = 0;
shift[1] = P4EST_ROOT_LEN;

coords[0] = shift[corner & 1];
coords[1] = shift[(corner >> 1) & 1];
#ifdef P4_TO_P8
coords[2] = shift[corner >> 2];
#endif

#ifdef P4EST_ENABLE_DEBUG
p4est_quadrant_root (&root);
p4est_quadrant_corner_coordinates (&root, corner, rcoords);
P4EST_ASSERT (rcoords[0] == coords[0]);
P4EST_ASSERT (rcoords[1] == coords[1]);
#ifdef P4_TO_P8
P4EST_ASSERT (rcoords[2] == coords[2]);
#endif
#endif
}

void
p4est_quadrant_transform_corner (p4est_quadrant_t * q, int corner, int inside)
{
Expand Down
77 changes: 62 additions & 15 deletions src/p4est_bits.h
Original file line number Diff line number Diff line change
Expand Up @@ -188,16 +188,18 @@ int p4est_quadrant_ancestor_id (const p4est_quadrant_t * q,
*/
int p4est_quadrant_child_id (const p4est_quadrant_t * q);

/** Test if Morton indices are inside the unit tree.
* \param [in] coord 2d coordinates.
* \return Returns true if \a (coord[0],coord[1]) is inside the unit tree.
/** Test if Morton indices are inside the unit tree or on its boundary.
* For this function, coordinate values of \ref P4EST_ROOT_LEN are legal.
* It is like \ref p4est_quadrant_is_inside_root with infinite level.
* \param [in] coord 2d coordinates.
* \return true if \a (coord[0],coord[1]) is inside the unit tree.
*/
int p4est_coordinates_is_inside_root (const p4est_qcoord_t
coord[]);

/** Test if a quadrant is inside the unit tree.
* \param [in] q Quadrant to be tested.
* \return Returns true if \a q is inside the unit tree.
* \param [in] q Quadrant (not necessarily valid) to be tested.
* \return true if \a q is inside the unit tree.
*/
int p4est_quadrant_is_inside_root (const p4est_quadrant_t *
q);
Expand Down Expand Up @@ -231,17 +233,17 @@ int p4est_quadrant_is_outside_corner (const p4est_quadrant_t *
int p4est_quadrant_is_node (const p4est_quadrant_t * q,
int inside);

/** Test if Morton indices are valid and are inside the unit tree.
* \param [in] coord 2d coordinates.
* \param [in] level level
* \return Returns true if \a (coord[0],coord[1],level) is valid.
/** Test if Morton indices are valid and inside the unit tree.
* \param [in] coord 2d coordinates may validly lie on any tree boundary.
* \param [in] level A level between 0 and \ref P4EST_MAXLEVEL included.
* \return true if \a (coord[0],coord[1],level) is valid.
*/
int p4est_coordinates_is_valid (const p4est_qcoord_t coord[],
int level);

/** Test if a quadrant has valid Morton indices and is inside the unit tree.
* \param [in] q Quadrant to be tested.
* \return Returns true if \a q is valid.
* \param [in] q Quadrant to be tested.
* \return true if \a q is valid.
*/
int p4est_quadrant_is_valid (const p4est_quadrant_t * q);

Expand Down Expand Up @@ -376,6 +378,14 @@ void p4est_quadrant_enlarge_first (const p4est_quadrant_t * a,
void p4est_quadrant_enlarge_last (const p4est_quadrant_t * a,
p4est_quadrant_t * q);

/** Generate the root quadrant of any tree.
* \param [out] root Quadrant structure's coordinates and level are set.
* As with all other functions that generate or
* modify quadrants, the other bits of the structured
* data type are not touched at all.
*/
void p4est_quadrant_root (p4est_quadrant_t *root);

/** Compute the ancestor of a quadrant at a given level.
* \param [in] q Input quadrant.
* \param [in] level A smaller level than q.
Expand Down Expand Up @@ -417,6 +427,13 @@ void p4est_quadrant_sibling (const p4est_quadrant_t * q,
void p4est_quadrant_child (const p4est_quadrant_t * q,
p4est_quadrant_t * r, int child_id);

/** Compute the coordinates of a quadrant's midpoint.
* \param [in] q Input quadrant, must be valid.
* \param [out] coords 2D coordinates are strictly inside the unit tree.
*/
void p4est_quadrant_volume_coordinates
(const p4est_quadrant_t * q, p4est_qcoord_t coords[]);

/** Compute the face neighbor of a quadrant.
* \param [in] q Input quadrant, must be valid.
* \param [in] face The face across which to generate the neighbor.
Expand Down Expand Up @@ -491,6 +508,15 @@ void p4est_quadrant_all_face_neighbors (const p4est_quadrant_t
* q, int face,
p4est_quadrant_t n[]);

/** Compute the coordinates of a specific quadrant face's midpoint.
* \param [in] q Input quadrant, must be valid.
* \param [in] face The face of which the midpoint coordinates
* are computed.
* \param [out] coords 2D mid-face coordinates are in/on the unit tree.
*/
void p4est_quadrant_face_coordinates
(const p4est_quadrant_t * q, int face, p4est_qcoord_t coords[]);

/** Compute the corner neighbor of a quadrant.
* \param [in] q Input quadrant, must be valid.
* \param [in] corner The corner across which to generate the neighbor.
Expand Down Expand Up @@ -539,7 +565,7 @@ void p4est_quadrant_half_corner_neighbor (const
p4est_quadrant_t *
r);

/** Compute the corner node of a quadrant.
/** Compute a corner node of a quadrant.
* \param [in] q Input quadrant, must be valid.
* \param [in] corner The corner across which to generate the neighbor.
* \param [in,out] r Node that will not be clamped inside.
Expand All @@ -549,6 +575,14 @@ void p4est_quadrant_corner_node (const p4est_quadrant_t * q,
int corner,
p4est_quadrant_t * r);

/** Compute the coordinates of a specific quadrant corner.
* \param [in] q Input quadrant, must be valid.
* \param [in] corner The corner for which the coordinates are computed.
* \param [out] coords 2D corner coordinates are in/on the unit tree.
*/
void p4est_quadrant_corner_coordinates
(const p4est_quadrant_t * q, int corner, p4est_qcoord_t coords[]);

/** Compute the 4 children of a quadrant.
* \param [in] q Input quadrant.
* \param [in,out] c0 First computed child.
Expand Down Expand Up @@ -661,17 +695,30 @@ void p4est_coordinates_transform_face (const p4est_qcoord_t
const int ftransform[]);

/** Checks if a quadrant touches a corner (diagonally inside or outside).
* \param [in] q This quadrant must be valid (if \a inside is true)
* or at least extended (if \a inside is false).
* It may also be a node respecting the \a inside argument.
* \param [in] corner Valid corner index from 0 to 3.
* \param [in] inside Boolean to clarify whether the input \a q is
* inside or outside a unit tree (or root quadrant).
*/
int p4est_quadrant_touches_corner (const p4est_quadrant_t * q,
int corner, int inside);

/** Set a coordinate location to a given tree (root quadrant) corner.
* \param [out] coords Output coordinates filled depending on \a corner.
* \param [in] corner Number of the corner in 0..3.
*/
void p4est_coordinates_transform_corner
(p4est_qcoord_t coords[], int corner);

/** Move a quadrant inside or diagonally outside a corner position.
* \param [in,out] q This quadrant only requires a valid level.
* \param [in] icorner Number of the corner in 0..3.
* \param [int] inside Boolean flag for inside or diagonally outside.
* \param [in] corner Number of the corner in 0..3.
* \param [in] inside Boolean flag for inside or diagonally outside.
*/
void p4est_quadrant_transform_corner (p4est_quadrant_t * q,
int icorner, int inside);
int corner, int inside);

/** Shifts a quadrant until it touches the specified corner from the inside.
* \param [in] q Valid input quadrant.
Expand Down
Loading

0 comments on commit 5024034

Please sign in to comment.