Skip to content

AFNI/NIfTI Server

Sections
Personal tools
You are here: Home » AFNI » Documentation

Doxygen Source Code Documentation


Main Page   Alphabetical List   Data Structures   File List   Data Fields   Globals   Search  

SUMA_GeomComp.c File Reference

#include "SUMA_suma.h"

Go to the source code of this file.


Data Structures

struct  SUMA_AreaDiffDataStruct
struct  SUMA_VolDiffDataStruct

Defines

#define DBG   1
 A function to calculate the geodesic distance of nodes connected to node n See labbook NIH-3 pp 138 and on for notes on algorithm.

#define DoCheck   1
#define SUMA_BEGINNING_OF_LAYER(list, LayInd, Elm)
#define SUMA_FIND_ELMENT_FOR_NODE(list, n_jne, Elm)
#define SUMA_MAX_BRANCHES   300
 SBv = SUMA_AssignTriBranch (SO, SPI, Nx, BranchCount, DoCopy).

#define NO_LOG
#define LARGE_NUM   9e300
 Path = SUMA_Dijkstra (SO, Nx, Ny, isNodeInMesh, N_isNodeInMesh, Method_Number, Path_length, N_Path); Finds the shortest distance between nodes Nx and Ny on SO with a restriction on the number of nodes available for travel. In other terms, the search space is limited to a subset of the nodes forming SO. The subset of nodes is stored in isNodeInMesh. This subset is typically specified in SUMA_Surf_Plane_Intersect.


Functions

int SUMA_Subdivide_Mesh (float **NodeListp, int *N_Nodep, int **FaceSetListp, int *N_FaceSetp, float maxarea)
 function to subdivide triangles to meet a maxarea criterion Divisions are done by adding a node at the centroid of the triangle to be subdivided. Bad idea, for very large triangles, such as produced by convex hull, you could end up with nodes that have hundreds of neighbors...

SUMA_VTISUMA_CreateVTI (int N_TriIndex, int *TriIndex)
 Function to allocate and initialize a SUMA_VTI * structure.

SUMA_VTISUMA_FreeVTI (SUMA_VTI *vti)
SUMA_VTISUMA_GetVoxelsIntersectingTriangle (SUMA_SurfaceObject *SO, SUMA_VOLPAR *VolPar, float *NodeIJKlist, SUMA_VTI *vti)
 Function to return a set of voxels that are intersected by a triangle.

int SUMA_isSelfIntersect (SUMA_SurfaceObject *SO, int StopAt)
 Function to detect surface self intersection returns -1 in case of error, 0 in case of no intersection 1 in case of intersection.

int SUMA_VoxelNeighbors (int ijk, int ni, int nj, int nk, SUMA_VOX_NEIGHB_TYPES ntype, int *nl)
 find the neighbors to a voxel.

byteSUMA_FillToVoxelMask (byte *ijkmask, int ijkseed, int ni, int nj, int nk, int *N_in, byte *usethisisin)
 Function to fill the volume enclose in a mask.

SUMA_Boolean SUMA_VoxelsInBox (int *voxelsijk, int *N_in, float *c1, float *c2)
 find voxels whose centers are inside the box with corners c1 and c2 c1, c2 are in voxel index coordinates. c1 is the minimum coordinates point. c2 is the maximum coordinates point.

SUMA_Boolean SUMA_ApplyAffine (float *NodeList, int N_Node, float M[][4], float *center)
 Applies an affine transform the coordinates in NodeList.

SUMA_Boolean SUMA_getoffsets (int n, SUMA_SurfaceObject *SO, float *Off, float lim)
SUMA_GET_OFFSET_STRUCTSUMA_Initialize_getoffsets (int N_Node)
 Allocate and initialize SUMA_GET_OFFSET_STRUCT* struct OffS = SUMA_Initialize_getoffsets (N_Node);.

SUMA_Boolean SUMA_AddNodeToLayer (int n, int LayInd, SUMA_GET_OFFSET_STRUCT *OffS)
 Add node n to neighboring layer LayInd in OffS ans = SUMA_AddNodeToLayer (n, LayInd, OffS);.

SUMA_GET_OFFSET_STRUCTSUMA_Free_getoffsets (SUMA_GET_OFFSET_STRUCT *OffS)
 free memory associated with SUMA_GET_OFFSET_STRUCT * struct

SUMA_Boolean SUMA_Recycle_getoffsets (SUMA_GET_OFFSET_STRUCT *OffS)
 reset the SUMA_GET_OFFSET_STRUCT after it has been used by a node

float ** SUMA_CalcNeighbDist (SUMA_SurfaceObject *SO)
 calculates the length of the segments defined by a node and its first-order neighbors. The resulting matrix very closely resembles SO->FN->FirstNeighb DistFirstNeighb = SUMA_CalcNeighbDist (SO);

SUMA_Boolean SUMA_getoffsets2 (int n, SUMA_SurfaceObject *SO, float lim, SUMA_GET_OFFSET_STRUCT *OffS, int *CoverThisNode, int N_CoverThisNode)
 A function to calculate the geodesic distance of nodes connected to node n SUMA_getoffsets was the first incarnation but it was too slow. ans = SUMA_getoffsets2 (n, SO, lim, OffS, CoverThisNode, N_CoverThisNode).

void SUMA_Free_Offset_ll_Datum (void *data)
SUMA_OFFSET_LL_DATUMSUMA_New_Offset_ll_Datum (int n, int layer)
DListSUMA_getoffsets_ll (int n, SUMA_SurfaceObject *SO, float lim, int *CoverThisNode, int N_CoverThisNode)
double SUMA_NewAreaAtRadius (SUMA_SurfaceObject *SO, double r, double Rref, float *tmpList)
 Changes the coordinates of SO's nodes so that the new average radius of the surface is equal to r.

double SUMA_NewVolumeAtRadius (SUMA_SurfaceObject *SO, double r, double Rref, float *tmpList)
 Changes the coordinates of SO's nodes so that the new average radius of the surface is equal to r.

double SUMA_AreaDiff (double r, void *fvdata)
double SUMA_VolDiff (double r, void *fvdata)
double SUMA_BinaryZeroSearch (double a, double b, double(*f)(double x, void *data), void *fdata, int Nitermax, double tol)
 Binary Zero Search, a function to find the zero of a function.

SUMA_Boolean SUMA_GetAreaDiffRange (SUMA_AreaDiffDataStruct *fdata, double *ap, double *bp)
 a function to find two values a and b such that DA(a) is < 0 and DA(b) is > 0 These two starting points are used for the optimization function SUMA_BinaryZeroSearch

SUMA_Boolean SUMA_GetVolDiffRange (SUMA_VolDiffDataStruct *fdata, double *ap, double *bp)
 a function to find two values a and b such that DV(a) is < 0 and DV(b) is > 0 These two starting points are used for the optimization function SUMA_BinaryZeroSearch

SUMA_Boolean SUMA_EquateSurfaceAreas (SUMA_SurfaceObject *SO, SUMA_SurfaceObject *SOref, float tol, SUMA_COMM_STRUCT *cs)
 inflates or deflates a surface to make the area of one surface (SO) equal to the area of another (SOref)

SUMA_Boolean SUMA_EquateSurfaceVolumes (SUMA_SurfaceObject *SO, SUMA_SurfaceObject *SOref, float tol, SUMA_COMM_STRUCT *cs)
 inflates or deflates a surface to make the volume of one surface (SO) equal to the volume of another (SOref)

SUMA_Boolean SUMA_ProjectSurfaceToSphere (SUMA_SurfaceObject *SO, SUMA_SurfaceObject *SOref,float radius, SUMA_COMM_STRUCT *cs)
 stretch each node along the center--node direction such that the new distance is = radius

SUMA_Boolean SUMA_EquateSurfaceSize (SUMA_SurfaceObject *SO, SUMA_SurfaceObject *SOref, float max_off, SUMA_COMM_STRUCT *cs)
 make the size of 2 surfaces match see help -match_size option in SurfSmooth

float ** SUMA_Chung_Smooth_Weights (SUMA_SurfaceObject *SO)
 calculate the interpolation weights required to smooth data on the surface using M.K. Chung et al. Neuroimage 03

SUMA_Boolean SUMA_Taubin_Smooth_TransferFunc (float l, float m, int N, FILE *Out)
 Show the transfer function (f(k)) for the Taubin smoothing algorithm for a combination of scaling factors and number of iterations.

SUMA_Boolean SUMA_Taubin_Smooth_Coef (float k, float *l, float *m)
 Calculates Mu(m) and Lambda(l) smoothing coefficients based on Taubin's smoothing algorithm in Geometric Signal Processing on Polygonal Meshes (Eurographics 2000).

float * SUMA_Taubin_Smooth (SUMA_SurfaceObject *SO, float **wgt, float lambda, float mu, float *fin_orig, int N_iter, int vpn, SUMA_INDEXING_ORDER d_order, float *fout_final_user, SUMA_COMM_STRUCT *cs, byte *nmask)
 performs smoothing based on Taubin's smoothing algorithm in Geometric Signal Processing on Polygonal Meshes (Eurographics 2000)

SUMA_Boolean SUMA_GetOffset2Offset (SUMA_GET_OFFSET_STRUCT *GOS, SUMA_OFFSET_STRUCT *OS)
 a function to turn the often cumbersome SUMA_GET_OFFSET_STRUCT to a more friendly SUMA_OFFSET_STRUCT

char * SUMA_ShowOffset_Info (SUMA_GET_OFFSET_STRUCT *OffS, int detail)
char * SUMA_ShowOffset_ll_Info (DList *list, int detail)
SUMA_OFFSET_STRUCTSUMA_FormNeighbOffset (SUMA_SurfaceObject *SO, float OffsetLim)
 creates a vector of node neighbors structures such that: OffS = SUMA_FormNeighbOffset ( SUMA_SurfaceObject *SO, float OffsetLim);

SUMA_OFFSET_STRUCTSUMA_free_NeighbOffset (SUMA_SurfaceObject *SO, SUMA_OFFSET_STRUCT *OffS_out)
 frees what is created by SUMA_FormNeighbOffset

float * SUMA_Offset_GeomSmooth (SUMA_SurfaceObject *SO, int N_iter, float OffsetLim, float *fin_orig, int vpn, SUMA_INDEXING_ORDER d_order, float *fout_final_user, SUMA_COMM_STRUCT *cs)
 A filtering function that is based on brute force estimates of node neighbor distance matrix. It is not finished because it makes no use of the neighbor distances to properly weigh the interpolation. It ends up being too slow because of the high memory load for computing OffS_out.

float * SUMA_NN_GeomSmooth (SUMA_SurfaceObject *SO, int N_iter, float *fin_orig, int vpn, SUMA_INDEXING_ORDER d_order, float *fout_final_user, SUMA_COMM_STRUCT *cs)
float * SUMA_Chung_Smooth (SUMA_SurfaceObject *SO, float **wgt, int N_iter, float FWHM, float *fin_orig, int vpn, SUMA_INDEXING_ORDER d_order, float *fout_final_user, SUMA_COMM_STRUCT *cs)
 Filter data defined on the surface using M.K. Chung et al.'s method (Neuroimage 03) dm_smooth = SUMA_Chung_Smooth (SO, wgt, N_iter, FWHM, fin, vpn, d_order, fout_user, SUMA_COMM_STRUCT *cs);.

int SUMA_OrientTriangles (float *NodeList, int N_Node, int *FaceSetList, int N_FaceSet, int orient, int Force)
 determine overall orientation of triangle normals and change triangle orientation if required

SUMA_SurfaceObjectSUMA_Patch2Surf (float *NodeList, int N_NodeList, int *PatchFaces, int N_PatchFaces, int PatchDim)
SUMA_BooleanSUMA_MaskOfNodesInPatch (SUMA_SurfaceObject *SO, int *N_NodesUsedInPatch)
 a function to return a mask indicating if a node is part of a patch or not isNodeInPatch = SUMA_MaskOfNodesInPatch( SUMA_SurfaceObject *SO, int * N_NodesUsedInPatch);

SUMA_PATCHSUMA_getPatch (int *NodesSelected, int N_Nodes, int *Full_FaceSetList, int N_Full_FaceSetList, SUMA_MEMBER_FACE_SETS *Memb, int MinHits)
SUMA_Boolean SUMA_freePatch (SUMA_PATCH *Patch)
SUMA_Boolean SUMA_ShowPatch (SUMA_PATCH *Patch, FILE *Out)
SUMA_CONTOUR_EDGESSUMA_GetContour (SUMA_SurfaceObject *SO, int *Nodes, int N_Node, int *N_ContEdges, int ContourMode, SUMA_PATCH *UseThisPatch)
 Returns the contour of a patch if you have the patch already created, then pass it in the last argument mode (int) 0: nice contour, not necessarily outermost boundary 1: outermost edge, might look a tad jagged.

double SUMA_Pattie_Volume (SUMA_SurfaceObject *SO1, SUMA_SurfaceObject *SO2, int *Nodes, int N_Node, SUMA_SurfaceObject *UseThisSO, int minPatchHits)
 Stitch together two isotopic patches to calculate the volume between them.

double SUMA_Mesh_Volume (SUMA_SurfaceObject *SO, int *FSI, int N_FaceSet)
 Calculate the volume of a mesh per the method in Hughes, S.W. et al. Phys. Med. Biol. 1996.

double SUMA_Mesh_Area (SUMA_SurfaceObject *SO, int *FaceSets, int N_FaceSet)
 computes the total area of a surface. NOTE: This function will replace whatever values you have in SO->PolyArea. If SO->PolyArea is NULL, it will remain that way.

float * SUMA_Plane_Equation (float *P1, float *P2, float *P3, float *usethisEq)
 finds the plane passing through 3 points

SUMA_SURF_PLANE_INTERSECTSUMA_Surf_Plane_Intersect (SUMA_SurfaceObject *SO, float *PlaneEq)
 Determines the intersection of a plane and a surface.

SUMA_ROI_DATUMSUMA_Surf_Plane_Intersect_ROI (SUMA_SurfaceObject *SO, int Nfrom, int Nto, float *P)
 a wrapper function for SUMA_Surf_Plane_Intersect that returns the intersection in the form of an ROI datum

SUMA_TRI_BRANCHSUMA_AssignTriBranch (SUMA_SurfaceObject *SO, SUMA_SURF_PLANE_INTERSECT *SPI, int Nx, int *BranchCount, SUMA_Boolean DoCopy)
SUMA_Boolean SUMA_show_STB (SUMA_TRI_BRANCH *B, FILE *Out)
void SUMA_free_STB (SUMA_TRI_BRANCH *Bv, int N_Bv)
SUMA_SURF_PLANE_INTERSECTSUMA_Allocate_SPI (SUMA_SurfaceObject *SO)
 Allocates a structure for computing the intersection of a surface with a plane The allocation is done conservatively, expecting the worse case scenario.

void SUMA_free_SPI (SUMA_SURF_PLANE_INTERSECT *SPI)
SUMA_Boolean SUMA_Show_SPI (SUMA_SURF_PLANE_INTERSECT *SPI, FILE *Out, SUMA_SurfaceObject *SO)
SUMA_Boolean SUMA_Mark_Tri (SUMA_EDGE_LIST *EL, int E1, int iBranch, int *TriBranch, int *IsInter, int *N_IsInter, int *VisitationOrder, int *ivisit)
int SUMA_Find_Edge_Nhost (SUMA_EDGE_LIST *EL, int *IsInter, int N_IsInter, int *i, int Nhost)
 Finds an edge that has Nhost hosting triangles. Only the edges indexed in IsInter are examined.

int * SUMA_Dijkstra (SUMA_SurfaceObject *SO, int Nx, int Ny, SUMA_Boolean *isNodeInMesh, int *N_isNodeInMesh, int Method_Number, float *Lfinal, int *N_Path)
int * SUMA_NodePath_to_EdgePath (SUMA_EDGE_LIST *EL, int *Path, int N_Path, int *N_Edge)
 Converts a path formed by a series of connected nodes to a series of edges ePath = SUMA_NodePath_to_EdgePath (EL, Path, N_Path, N_Edge);.

SUMA_Boolean SUMA_isSameEdge (SUMA_EDGE_LIST *EL, int E1, int E2)
 determines whether to edges are identical or not. Recall that an edge can be represented multiple times in SO->EL, once for each triangle that uses it. Two edges are the same if and only if EL->EL[E1][0] == EL->EL[E2][0] && EL->EL[E1][1] == EL->EL[E2][1]

int * SUMA_IntersectionStrip (SUMA_SurfaceObject *SO, SUMA_SURF_PLANE_INTERSECT *SPI, int *nPath, int N_nPath, float *dinters, float dmax, int *N_tPath)
 This function determines the strip of triangles necessary to go from one node to another along intersected edges. tPath = SUMA_IntersectionStrip (SO, SPI, int *nPath, int N_nPath, float *dinters, float dmax, int *N_tPath).

SUMA_Boolean SUMA_FromIntEdgeToIntEdge (int Tri, int E1, int E2, SUMA_EDGE_LIST *EL, SUMA_SURF_PLANE_INTERSECT *SPI, int Ny, SUMA_Boolean *Visited, float *d, float dmax, int *tPath, int *N_tPath)
 This function moves from one intersected edge to the next until a certain node is encountered or a a certain distance is exceeded. By intersected edge, I mean an edge of the surface's mesh that was intersected by a plane.

int * SUMA_NodePath_to_TriPath_Inters (SUMA_SurfaceObject *SO, SUMA_SURF_PLANE_INTERSECT *SPI, int *nPath, int N_nPath, int *N_tPath)
 Converts a series of connected nodes into a series of connected triangles that were intersected by the plane. There is no guarantee that two nodes that belong to triangles intersected by the plane and part of the shortest path (as returned by SUMA_Dijkstra) for an edge that belongs to a triangle intersected by the plane. See labbook NIH-2 page 158 for sketches illustrating this point. So the strip of triangles that you will get back may have holes in it since it only allows intersected triangles to be members of the path.

int * SUMA_NodePath_to_TriPath_Inters_OLD (SUMA_SurfaceObject *SO, SUMA_TRI_BRANCH *Bv, int *Path, int N_Path, int *N_Tri)
 Converts a series of connected nodes into a series of connected triangles that belong to a branch. The function fails at times, picking the long instead of the short path but it is left here in case I need it in the future.


Variables

SUMA_CommonFieldsSUMAg_CF
SUMA_DOSUMAg_DOv
SUMA_SurfaceViewerSUMAg_SVv
int SUMAg_N_SVv
int SUMAg_N_DOv

Define Documentation

#define DBG   1
 

A function to calculate the geodesic distance of nodes connected to node n See labbook NIH-3 pp 138 and on for notes on algorithm.

Parameters:
n  (int) index of center node
SO  (SUMA_SurfaceObject *) structure containing surface object
off  (float *) a vector such that off[i] = the geodesic distance of node i to node n. The vector should be initialized to -1.0
lim  (float) maximum geodesic distance to travel

  • This function is too slow. See SUMA_getoffsets2
See also:
SUMA_getoffsets2

Definition at line 43 of file SUMA_GeomComp.c.

#define DoCheck   1
 

Definition at line 44 of file SUMA_GeomComp.c.

#define LARGE_NUM   9e300
 

Path = SUMA_Dijkstra (SO, Nx, Ny, isNodeInMesh, N_isNodeInMesh, Method_Number, Path_length, N_Path); Finds the shortest distance between nodes Nx and Ny on SO with a restriction on the number of nodes available for travel. In other terms, the search space is limited to a subset of the nodes forming SO. The subset of nodes is stored in isNodeInMesh. This subset is typically specified in SUMA_Surf_Plane_Intersect.

Path = SUMA_Dijkstra (SO, Nx, Ny, isNodeInMesh, N_isNodeInMesh, Method_Number, Path_length, N_Path)

Parameters:
SO  (SUMA_SurfaceObject *) The surface Object structure. NodeList, EL and FN are needed.
Nx  (int) The node index (referring to SO's nodes) where the search begins.
Ny  (int) The node index (referring to SO's nodes) where the search ends.
isNodeInMesh  (SUMA_Boolean *) Pointer to SO->N_Node long vector such that if (isNodeInMesh[i]) then node i is part of the mesh that is used in the search path. This mesh is a subset of SO->FaceSetList and is typically obtained when one runs SUMA_Surf_Plane_Intersect. Running SUMA_Dijkstra on a complete surface is only for very patient people. NOTE: This vector is modified as a node is visited. Make sure you do not use it after this function has been called.
N_isNodeInMesh  (int *) Pointer to the total number of nodes that make up the mesh (subset of SO) This parameter is passed as a pointer because as nodes in the mesh are visited, that number is reduced and represents when the function returns, the number of nodes that were never visited in the search.
Method_Number  (int) selector for which algorithm to use. Choose from: 0 - Straight forward implementation, slow 1 - Variation to eliminate long searches for minimum of L, much much much faster than 0, 5 time more memory.
Path_length  (float *) The distance between Nx and Ny. This value is negative if no path between Nx and Ny was found.
N_Path  (int *) Number of nodes forming the Path vector
Returns:
Path (float) A vector of N_Path node indices forming the shortest path, from Nx (Path[0]) to Ny (Path[*N_Path - 1]). NULL is returned in case of error.
See also:
Graph Theory by Ronald Gould and labbook NIH-2 page 154 for path construction

Definition at line 6835 of file SUMA_GeomComp.c.

Referenced by SUMA_Dijkstra().

#define NO_LOG
 

Definition at line 6675 of file SUMA_GeomComp.c.

#define SUMA_BEGINNING_OF_LAYER list,
LayInd,
Elm   
 

Value:

{   \
   SUMA_OFFSET_LL_DATUM * m_dat = NULL; \
   DListElmt *m_Elm = NULL;   \
   do {  \
     if (m_Elm) m_Elm = m_Elm->next;   \
     else m_Elm =  dlist_head(list); \
     m_dat = (SUMA_OFFSET_LL_DATUM *)m_Elm->data; \
   } while(m_dat->layer != LayInd && m_Elm != dlist_tail(list));   \
   if (m_dat->layer != LayInd) Elm = NULL;  \
   else Elm = m_Elm; \
}

Definition at line 1170 of file SUMA_GeomComp.c.

Referenced by SUMA_getoffsets_ll().

#define SUMA_FIND_ELMENT_FOR_NODE list,
n_jne,
Elm   
 

Value:

{  \
   SUMA_OFFSET_LL_DATUM * m_dat = NULL; \
   DListElmt *m_Elm = NULL;   \
   do {  \
     if (m_Elm) m_Elm = m_Elm->next;   \
     else m_Elm =  dlist_head(list); \
     m_dat = (SUMA_OFFSET_LL_DATUM *)m_Elm->data; \
   } while(m_dat->ni != n_jne && m_Elm != dlist_tail(list));   \
   if (m_dat->ni != n_jne) Elm = NULL;  \
   else Elm = m_Elm; \
}

Definition at line 1181 of file SUMA_GeomComp.c.

Referenced by SUMA_getoffsets_ll().

#define SUMA_MAX_BRANCHES   300
 

SBv = SUMA_AssignTriBranch (SO, SPI, Nx, BranchCount, DoCopy).

Parameters:
SO  (SUMA_SurfaceObject *) Pointer to Surface Object structure
SPI  (SUMA_SURF_PLANE_INTERSECT *) Pointer to Surface Plane Intersection structure
Nx  (int) Node index to start the first branch at. This parameter is optional. pass -1 if you do not want it set.
BranchCount  (int *) Pointer to the total number of branches found.
DoCopy  (SUMA_Boolean) flag indicating whether to preserve (YUP) the values in SPI->IntersEdges and SPI->N_IntersEdges or not (NOPE). If you choose YUP, a copy of SPI->IntersEdges is made and manipulated.
Returns:
Bv (SUMA_TRI_BRANCH*) Pointer to a vector of *BranchCount branches formed by the intersections. A branch is formed by a series of connected triangles. A Branch can be a loop but that is not determined in this function. NULL if trouble is encountered. On some surfaces with cuts you may have a branch split in two which requires welding. No such thing is done here but a warning is printed out.
NOTE: The vector SPI->IntersEdges is modified by this function.
See also:
SUMA_free_STB for freeing Bv

Definition at line 6331 of file SUMA_GeomComp.c.

Referenced by SUMA_AssignTriBranch().


Function Documentation

SUMA_Boolean SUMA_AddNodeToLayer int    n,
int    LayInd,
SUMA_GET_OFFSET_STRUCT   OffS
 

Add node n to neighboring layer LayInd in OffS ans = SUMA_AddNodeToLayer (n, LayInd, OffS);.

Parameters:
n  (int)
LayInd  (int)
OffS  (SUMA_GET_OFFSET_STRUCT *)
Returns:
YUP/NOPE (good/bad)

  • allocation is automatically taken care of
See also:
SUMA_Free_getoffsets , SUMA_Initialize_getoffsets

Definition at line 818 of file SUMA_GeomComp.c.

References SUMA_GET_OFFSET_STRUCT::layers, LocalHead, SUMA_NODE_NEIGHB_LAYER::N_AllocNodesInLayer, SUMA_GET_OFFSET_STRUCT::N_layers, SUMA_NODE_NEIGHB_LAYER::N_NodesInLayer, SUMA_NODE_NEIGHB_LAYER::NodesInLayer, SUMA_Boolean, SUMA_LH, SUMA_malloc, SUMA_realloc, SUMA_RETURN, and SUMA_SL_Err.

Referenced by SUMA_getoffsets2().

00819 {
00820    static char FuncName[]={"SUMA_AddNodeToLayer"};
00821    static SUMA_Boolean LocalHead = NOPE;
00822    
00823    /* is this a new layer */
00824    if (LayInd > OffS->N_layers) { /* error */
00825       SUMA_SL_Err("LayInd > OffS->N_layers. This should not be!");
00826       SUMA_RETURN(NOPE);
00827    } else if (LayInd == OffS->N_layers) { /* need a new one */
00828       SUMA_LH("Adding layer");
00829       OffS->N_layers += 1;
00830       OffS->layers = (SUMA_NODE_NEIGHB_LAYER *) SUMA_realloc(OffS->layers, OffS->N_layers*sizeof(SUMA_NODE_NEIGHB_LAYER));
00831       OffS->layers[LayInd].N_AllocNodesInLayer = 200;
00832       OffS->layers[LayInd].NodesInLayer = (int *) SUMA_malloc(OffS->layers[LayInd].N_AllocNodesInLayer * sizeof(int));
00833       OffS->layers[LayInd].N_NodesInLayer = 0;
00834    }
00835    
00836    OffS->layers[LayInd].N_NodesInLayer += 1;
00837    /* do we need to reallocate for NodesInLayer ? */
00838    if (OffS->layers[LayInd].N_NodesInLayer ==  OffS->layers[LayInd].N_AllocNodesInLayer) { /* need more space */
00839       SUMA_LH("reallocating neighbors");
00840       OffS->layers[LayInd].N_AllocNodesInLayer += 200;
00841       OffS->layers[LayInd].NodesInLayer = (int *) SUMA_realloc (OffS->layers[LayInd].NodesInLayer, OffS->layers[LayInd].N_AllocNodesInLayer * sizeof(int));
00842    }
00843    
00844    OffS->layers[LayInd].NodesInLayer[OffS->layers[LayInd].N_NodesInLayer - 1] = n;
00845    
00846    SUMA_RETURN(YUP); 
00847 }

SUMA_SURF_PLANE_INTERSECT* SUMA_Allocate_SPI SUMA_SurfaceObject   SO
 

Allocates a structure for computing the intersection of a surface with a plane The allocation is done conservatively, expecting the worse case scenario.

Parameters:
SO  (SUMA_SurfaceObject *) Surface Object structure used to get number of nodes, edges, etc ...
Returns:
SPI (SUMA_SURF_PLANE_INTERSECT *) Pointer to surface plane intersection structure. see structure definition for more info.

Definition at line 6584 of file SUMA_GeomComp.c.

References SUMA_SurfaceObject::EL, i, SUMA_SURF_PLANE_INTERSECT::IntersEdges, SUMA_SURF_PLANE_INTERSECT::IntersNodes, SUMA_SURF_PLANE_INTERSECT::IntersTri, SUMA_SURF_PLANE_INTERSECT::isEdgeInters, SUMA_SURF_PLANE_INTERSECT::isNodeInMesh, SUMA_SURF_PLANE_INTERSECT::isTriHit, SUMA_EDGE_LIST::N_EL, SUMA_SurfaceObject::N_FaceSet, SUMA_SURF_PLANE_INTERSECT::N_IntersEdges, SUMA_SURF_PLANE_INTERSECT::N_IntersTri, SUMA_SurfaceObject::N_Node, SUMA_SURF_PLANE_INTERSECT::N_NodesInMesh, SUMA_Boolean, SUMA_calloc, SUMA_ENTRY, SUMA_malloc, and SUMA_RETURN.

Referenced by SUMA_Surf_Plane_Intersect().

06585 {
06586    static char FuncName[]={"SUMA_Allocate_SPI"};
06587    int i;
06588    SUMA_SURF_PLANE_INTERSECT *SPI = NULL;
06589    
06590    SUMA_ENTRY;
06591    
06592    SPI = (SUMA_SURF_PLANE_INTERSECT *) SUMA_malloc(sizeof(SUMA_SURF_PLANE_INTERSECT));
06593    if (!SPI) {
06594       fprintf (SUMA_STDERR, "Error %s: Could not allocate for SPI\n", FuncName);
06595       SUMA_RETURN (SPI);
06596    }
06597    
06598    SPI->IntersEdges = (int *) SUMA_calloc (SO->EL->N_EL, sizeof(int)); /* allocate for the max imaginable*/
06599    SPI->IntersNodes = (float *) SUMA_calloc (3 * SO->EL->N_EL, sizeof(float));
06600    SPI->isEdgeInters = (SUMA_Boolean *) SUMA_calloc (SO->EL->N_EL, sizeof(SUMA_Boolean));
06601    SPI->IntersTri = (int *) SUMA_calloc (SO->N_FaceSet, sizeof(int));
06602    SPI->isNodeInMesh = (SUMA_Boolean *) SUMA_calloc (SO->N_Node, sizeof(SUMA_Boolean));
06603    SPI->isTriHit = (SUMA_Boolean *) SUMA_calloc (SO->N_FaceSet, sizeof(SUMA_Boolean));
06604 
06605    if (!SPI->IntersEdges || !SPI->IntersTri || !SPI->IntersNodes || !SPI->isTriHit || !SPI->isEdgeInters)
06606       {
06607          fprintf (SUMA_STDERR, "Error %s: Could not allocate \n", FuncName);
06608          SUMA_RETURN (SPI);
06609       }
06610    
06611    SPI->N_IntersEdges = 0;
06612    SPI->N_IntersTri = 0;
06613    SPI->N_NodesInMesh = 0;  
06614    SUMA_RETURN (SPI);
06615 }

SUMA_Boolean SUMA_ApplyAffine float *    NodeList,
int    N_Node,
float    M[][4],
float *    center
 

Applies an affine transform the coordinates in NodeList.

Parameters:
NodeList  (float *) a vector of node XYZ triplets. (N_Node x 3 long)
N_Node  (int) number of nodes in NodeList
M  (float **) the affine transform matrix. Minimum size is 3 rows x 4 columns. The top left 3x3 is mat The right most column is the shift vector vec (3 elements)
center  (float *) If center is not null then XYZnew = mat * (vec - center) + vec + center else XYZnew = mat * (vec ) + vec
Returns:
ans (SUMA_Boolean ) 1 OK, 0 not OK

  • COORDINATES IN NodeList are REPLACED with transformed ones.

Definition at line 623 of file SUMA_GeomComp.c.

References i, LocalHead, SUMA_allocate2D(), SUMA_Boolean, SUMA_ENTRY, SUMA_free2D(), SUMA_LH, SUMA_MULT_MAT, SUMA_RETURN, and SUMA_SL_Err.

00624 {
00625    static char FuncName[] = {"SUMA_ApplyAffine"};
00626    float **XYZo, **Mr, **XYZn, D[3];
00627    int i, i3, idbg = 0;
00628    SUMA_Boolean LocalHead = NOPE;
00629    
00630    SUMA_ENTRY;
00631    
00632    if (!NodeList || N_Node <=0) { 
00633       SUMA_SL_Err("Bad Entries.\n");
00634       SUMA_RETURN(NOPE);
00635    }
00636    
00637    Mr = (float **)SUMA_allocate2D(3, 3, sizeof(float));
00638    XYZn = (float **)SUMA_allocate2D(3, 1, sizeof(float));
00639    XYZo = (float **)SUMA_allocate2D(3, 1, sizeof(float));
00640    
00641    SUMA_LH("Forming Mr");
00642    Mr[0][0] = M[0][0]; Mr[0][1] = M[0][1]; Mr[0][2] = M[0][2]; 
00643    Mr[1][0] = M[1][0]; Mr[1][1] = M[1][1]; Mr[1][2] = M[1][2]; 
00644    Mr[2][0] = M[2][0]; Mr[2][1] = M[2][1]; Mr[2][2] = M[2][2];
00645    D[0] = M[0][3]; D[1] = M[1][3]; D[2] = M[2][3];
00646    
00647    SUMA_LH("Transforming");
00648    if (LocalHead ) {
00649       i3 = 3*idbg;
00650       fprintf (SUMA_STDERR,"In: %f %f %f\n", NodeList[i3], NodeList[i3+1], NodeList[i3+2]);
00651    }
00652    for (i=0; i< N_Node; ++i) {
00653       i3 = 3 * i;
00654       if (!center) {
00655          XYZo[0][0] = NodeList[i3]; XYZo[1][0] = NodeList[i3+1]; XYZo[2][0] = NodeList[i3+2];
00656       } else {
00657          XYZo[0][0] = NodeList[i3] - center[0]; XYZo[1][0] = NodeList[i3+1] - center[1]; XYZo[2][0] = NodeList[i3+2] - center[2];
00658       }   
00659 
00660       SUMA_MULT_MAT(Mr, XYZo, XYZn, 3, 3, 1, float,float,float);
00661       
00662       if (!center) { 
00663          NodeList[i3] = XYZn[0][0]+D[0]; NodeList[i3+1] = XYZn[1][0]+D[1]; NodeList[i3+2] = XYZn[2][0]+D[2]; 
00664       } else {
00665          NodeList[i3] = XYZn[0][0]+D[0] + center[0]; NodeList[i3+1] = XYZn[1][0]+D[1]+ center[1]; NodeList[i3+2] = XYZn[2][0]+D[2]+ center[2]; 
00666       }
00667       
00668    }
00669    if (LocalHead ) {
00670       i3 = 3*idbg;
00671       fprintf (SUMA_STDERR,"Out: %f %f %f\n", NodeList[i3], NodeList[i3+1], NodeList[i3+2]);
00672    }
00673    SUMA_LH("Done");
00674    
00675    SUMA_free2D((char**)Mr, 3);
00676    SUMA_free2D((char**)XYZn, 3);
00677    SUMA_free2D((char**)XYZo, 3);
00678    
00679    SUMA_RETURN(YUP);
00680 }

double SUMA_AreaDiff double    r,
void *    fvdata
 

Definition at line 1433 of file SUMA_GeomComp.c.

References SUMA_AreaDiffDataStruct::Aref, SUMA_AreaDiffDataStruct::cs, i, LocalHead, SUMA_SurfaceObject::NodeList, r, SUMA_AreaDiffDataStruct::Rref, SUMA_COMM_STRUCT::Send, SUMA_AreaDiffDataStruct::SO, SUMA_AreaDiffDataStruct::SOref, SUMA_Boolean, SUMA_ENTRY, SUMA_LH, SUMA_NewAreaAtRadius(), SUMA_NODE_XYZ, SUMA_RETURN, SUMA_SendToSuma(), SUMA_SL_Warn, and SUMA_AreaDiffDataStruct::tmpList.

Referenced by SUMA_EquateSurfaceAreas().

01434 {
01435    static char FuncName[]={"SUMA_AreaDiff"};
01436    double da, *fp, Dr, A;
01437    static int ncall=0;
01438    int i;
01439    static double Rref = 0.0, Aref = 0.0;
01440    SUMA_SurfaceObject *SO, *SOref;
01441    SUMA_COMM_STRUCT *cs=NULL;
01442    SUMA_AreaDiffDataStruct *fdata = (SUMA_AreaDiffDataStruct*)fvdata ;
01443    SUMA_Boolean LocalHead = NOPE;
01444 
01445    SUMA_ENTRY;
01446    
01447    if (!fdata) {
01448       SUMA_LH("Reset");
01449       Rref = 0.0; Aref = 0.0;
01450       ncall = 0;
01451       SUMA_RETURN(0.0);
01452    }
01453    
01454    SO = fdata->SO;
01455    SOref = fdata->SOref;
01456    cs = fdata->cs;
01457    
01458    if (!ncall) {
01459       SUMA_LH("Initializing, calculating Aref and Rref");
01460       Aref = fdata->Aref;
01461       Rref = fdata->Rref;
01462       if (LocalHead) { fprintf(SUMA_STDERR,"%s: Reference volume = %f, radius = %f \n", FuncName, Aref, Rref); }
01463       if (cs->Send) { /* send the first monster (it's SOref "in SUMA" that's being modified on the fly) */
01464          if (!SUMA_SendToSuma (SOref, cs, (void *)SO->NodeList, SUMA_NODE_XYZ, 1)) {
01465          SUMA_SL_Warn("Failed in SUMA_SendToSuma\nCommunication halted.");
01466          }
01467       }
01468    }
01469    
01470    A = SUMA_NewAreaAtRadius(SO, r, Rref, fdata->tmpList);
01471    da = Aref - A; /* the area difference */
01472    if (LocalHead) {
01473       fprintf(SUMA_STDERR,"%s: Call %d, A = %f, Aref = %f, da = %f\n", FuncName,ncall, A, Aref, da);
01474    }
01475       
01476    /* need an update ? */
01477    if (cs->Send) { /* send the update (it's SOref "in SUMA" that's being modified on the fly) */
01478       if (!SUMA_SendToSuma (SOref, cs, (void *)fdata->tmpList, SUMA_NODE_XYZ, 1)) {
01479       SUMA_SL_Warn("Failed in SUMA_SendToSuma\nCommunication halted.");
01480       }
01481    }
01482 
01483    ++ncall;
01484    
01485    SUMA_RETURN(da);
01486 }

SUMA_TRI_BRANCH* SUMA_AssignTriBranch SUMA_SurfaceObject   SO,
SUMA_SURF_PLANE_INTERSECT   SPI,
int    Nx,
int *    BranchCount,
SUMA_Boolean    DoCopy
 

Definition at line 6334 of file SUMA_GeomComp.c.

References SUMA_SurfaceObject::EL, SUMA_EDGE_LIST::EL, SUMA_EDGE_LIST::ELps, i, SUMA_TRI_BRANCH::iBranch, SUMA_SURF_PLANE_INTERSECT::IntersEdges, SUMA_TRI_BRANCH::list, LocalHead, SUMA_EDGE_LIST::N_EL, SUMA_SurfaceObject::N_FaceSet, SUMA_SURF_PLANE_INTERSECT::N_IntersEdges, SUMA_SURF_PLANE_INTERSECT::N_IntersTri, SUMA_TRI_BRANCH::N_list, Nx, SUMA_Boolean, SUMA_calloc, SUMA_disp_dvect(), SUMA_ENTRY, SUMA_Find_Edge_Nhost(), SUMA_free, SUMA_malloc, SUMA_Mark_Tri(), SUMA_MAX_BRANCHES, and SUMA_RETURN.

06336 {
06337    static char FuncName[]={"SUMA_AssignTriBranch"};
06338    int *IntersEdgesCopy = NULL, N_IntersEdgesCopy, i_Branch, E1, kedge, i, 
06339          N_iBranch[SUMA_MAX_BRANCHES], NBlist[SUMA_MAX_BRANCHES], iBranch = 0, 
06340          N_Branch, Bcnt, ilist, j, ivisit, *VisitationOrder, TriCheck;
06341    SUMA_Boolean Local_IntersEdgesCopy = NOPE;
06342    int *TriBranch = NULL; /*!< Vector of SO->EL->N_EL / 3 elements but with only N_IntersTri meaningful values. If TriBranch[j] = b
06343                      then triangle j in SO->FaceSet is a member of Branch b. Branch numbering starts at 1 and may not be consecutive. 
06344                      A branch is a collection of connected triangles and may form a closed loop */
06345    SUMA_TRI_BRANCH *Bv = NULL;
06346    SUMA_Boolean LocalHead = NOPE;
06347    
06348    SUMA_ENTRY;
06349 
06350 
06351    i_Branch = 0;
06352    
06353    /* make a copy of SPI->N_IntersEdges since this vector will be modified and might be needed later, 
06354       might make that optional later and just copy pointers if IntersEdgesCopy is not needed elsewhere.
06355       IntersEdgesCopy flag is used to decide on freeing IntersEdgesCopy or not.*/
06356 
06357    VisitationOrder = (int *)SUMA_calloc (SO->N_FaceSet, sizeof (int)); /* keeps track of the order in which triangles are visited. This is used for creating branches with the proper sequence */
06358    TriBranch = (int *)SUMA_calloc (SO->EL->N_EL / 3,  sizeof(int));
06359    
06360    if (!VisitationOrder || !TriBranch) {
06361       fprintf (SUMA_STDERR, "Error %s: Failed to allocate.\n", FuncName);
06362       if (TriBranch) SUMA_free(TriBranch);
06363       if (VisitationOrder) SUMA_free(VisitationOrder);
06364       SUMA_RETURN (NULL);   
06365    }
06366    
06367    N_IntersEdgesCopy = SPI->N_IntersEdges;
06368    if (DoCopy) {
06369       IntersEdgesCopy = (int *) SUMA_calloc (N_IntersEdgesCopy, sizeof (int));
06370       Local_IntersEdgesCopy = YUP;
06371       for (i=0; i < N_IntersEdgesCopy; ++i) {
06372          IntersEdgesCopy[i] = SPI->IntersEdges[i];
06373       }
06374    }else {
06375       Local_IntersEdgesCopy = NOPE;
06376       IntersEdgesCopy = SPI->IntersEdges;
06377    }
06378 
06379    if (!IntersEdgesCopy) {
06380      fprintf (SUMA_STDERR, "Error %s: Failed to allocate for or receive IntersEdgesCopy.\n", FuncName);
06381      if (TriBranch) SUMA_free(TriBranch);
06382      if (VisitationOrder) SUMA_free(VisitationOrder);
06383      SUMA_RETURN (NULL);
06384    }
06385 
06386    ivisit = 0;
06387    while (N_IntersEdgesCopy) {
06388    
06389       if (!i_Branch && Nx >= 0) {
06390          /* start from edge containing Nx, this is only done at the starting point (i_Branch = 0) */
06391          E1 = -1;
06392          i=0;
06393          while (i < N_IntersEdgesCopy && E1 < 0) {
06394             if ( (SO->EL->EL[IntersEdgesCopy[i]][0] == Nx) || (SO->EL->EL[IntersEdgesCopy[i]][1] == Nx) ) {
06395                E1 = IntersEdgesCopy[i];
06396                kedge = i;
06397             }  
06398             ++i;
06399          }
06400       }else {
06401          /* no starting orders, start from any decent edge */
06402          /* find an edge with one hosting triangle */
06403          E1 = SUMA_Find_Edge_Nhost (SO->EL, IntersEdgesCopy, N_IntersEdgesCopy, &kedge, 1);
06404       }      
06405 
06406       if (E1 < 0) { /* no such edge found, take first edge in InInter */
06407             kedge = 0;
06408             E1 = IntersEdgesCopy[kedge];
06409             if (LocalHead) fprintf (SUMA_STDERR, "%s: No 1 host edge edge found.\n", FuncName);
06410       }else {
06411             if (LocalHead) fprintf (SUMA_STDERR, "%s: Found edge.\n", FuncName);
06412       }
06413       
06414       /* remove this edge from the list */
06415       --(N_IntersEdgesCopy);
06416       if (LocalHead) fprintf (SUMA_STDERR, "%s: kedge = %d, N_IntersEdgesCopy = %d.\n", FuncName, kedge, N_IntersEdgesCopy);
06417       IntersEdgesCopy[kedge] = IntersEdgesCopy[N_IntersEdgesCopy];
06418 
06419       /* start a new i_Branch - All i_Branch indices must be > 0*/
06420       ++i_Branch;   
06421       if (i_Branch > SUMA_MAX_BRANCHES-1) {
06422          fprintf (SUMA_STDERR, "Error %s: No more than %d branches allowed.\n", FuncName, SUMA_MAX_BRANCHES);
06423          SUMA_RETURN (NULL); 
06424       } 
06425       
06426       /* mark the triangle containing E1 */
06427       if (LocalHead) fprintf (SUMA_STDERR, "%s: Marking triangle %d with branch %d.\n", FuncName, SO->EL->ELps[E1][1], i_Branch);
06428       TriBranch[SO->EL->ELps[E1][1]] = i_Branch;
06429       VisitationOrder[ivisit] = SO->EL->ELps[E1][1]; ++ivisit;
06430       
06431       if (LocalHead) fprintf (SUMA_STDERR, "%s: Called recursive SUMA_Mark_Tri.\n", FuncName);
06432       if (!SUMA_Mark_Tri (SO->EL, E1, i_Branch, TriBranch, IntersEdgesCopy, &(N_IntersEdgesCopy), VisitationOrder, &ivisit)) {
06433          fprintf (SUMA_STDERR, "Error %s: Failed in SUMA_Mark_Tri.\n", FuncName);
06434       }
06435       if (LocalHead) fprintf (SUMA_STDERR, "%s: Returned from recursive SUMA_Mark_Tri.\n", FuncName);
06436 
06437       /* repeat till all edges are used up */
06438    }
06439 
06440    if (Local_IntersEdgesCopy) {
06441       if (LocalHead) fprintf (SUMA_STDERR, "%s: freeing IntersEdgesCopy.\n", FuncName);
06442       SUMA_free(IntersEdgesCopy); 
06443    }else {
06444       /* also change N_IntersEdges */
06445       SPI->N_IntersEdges = N_IntersEdgesCopy;
06446    }
06447 
06448    /* SUMA_disp_dvect (TriBranch, SO->N_FaceSet);  */
06449 
06450    N_Branch = i_Branch;
06451 
06452    /* determine the number of branch elements to allocate for - IDIOT PROOF, doing it in the recursive function SUMA_Mark_Tri was annoying*/
06453    for (i=0; i <= N_Branch; ++i) N_iBranch[i] = 0; /* remember, Branch numbering starts at 1 */
06454    if (LocalHead) fprintf (SUMA_STDERR, "%s: Searching all %d intersected triangles.\n", FuncName, SPI->N_IntersTri);
06455    Bcnt = 0;
06456    for (i=0; i < SO->N_FaceSet; ++i) {
06457       if (TriBranch[i]) {
06458          /* fprintf (SUMA_STDERR, "%d:%d\t", TriBranch[i], N_iBranch[TriBranch[i]]); */
06459          ++Bcnt;
06460          N_iBranch[TriBranch[i]] = N_iBranch[TriBranch[i]] + 1;
06461       }
06462    }
06463    
06464    #if 0
06465       fprintf (SUMA_STDERR, "Values in N_iBranch, idiot proof:\n");
06466       SUMA_disp_dvect (N_iBranch, N_Branch+1);
06467       fprintf (SUMA_STDERR, "\n");
06468    #endif
06469    
06470    if (LocalHead) fprintf (SUMA_STDERR, "%s: Found %d triangles belonging to a branch out of %d intersected triangles.\n", FuncName, Bcnt, SPI->N_IntersTri);
06471      
06472    /* Now you want to create a vector of N_Branches to represent the intersection */
06473    Bv = (SUMA_TRI_BRANCH *) SUMA_malloc (sizeof(SUMA_TRI_BRANCH)*(N_Branch+1)); /* you should only need N_Branch, but that 1 won't hurt ...*/
06474    if (!Bv) {
06475       fprintf (SUMA_STDERR, "Error %s: Could not allocate for Bv.\n", FuncName);
06476       SUMA_RETURN (NULL);
06477    }
06478    
06479    /* initialize allocated Bv elements */
06480    for (i=0; i<= N_Branch; ++i) { /* You have allocated for N_Branch+1*/
06481       Bv[i].list = NULL;
06482       Bv[i].N_list = 0;
06483    } 
06484    
06485    Bcnt = 0;
06486    for (i=0; i<= N_Branch; ++i) { /* Branch numbering starts at 1 */
06487       if (N_iBranch[i]) {
06488          /* something in that branch, allocate and initialize*/
06489          if (LocalHead) fprintf (SUMA_STDERR, "%s: Allocating for %d elements, Old Branch %d, New Branch %d.\n", FuncName, N_iBranch[i], i, Bcnt); 
06490          Bv[Bcnt].list = (int *) SUMA_calloc (N_iBranch[i]+1, sizeof(int));
06491          Bv[Bcnt].N_list = N_iBranch[i];
06492          Bv[Bcnt].iBranch = Bcnt;
06493          NBlist[i] = Bcnt; /* store new indexing for Branches */
06494          ++Bcnt;
06495       }
06496       
06497    }
06498    
06499    /* store the total number of used branches */
06500    *BranchCount = Bcnt;
06501    
06502    /* now fill up the branches*/
06503    if (LocalHead) fprintf (SUMA_STDERR, "%s: Filling up branches...\n", FuncName);
06504    for (i=0; i <= N_Branch; ++i) N_iBranch[i] = 0; /* now use this vector as a counter for the filling at each new branch index */
06505    for (i=0; i < SPI->N_IntersTri; ++i) { /* only go over visited triangles */
06506       TriCheck = TriBranch[VisitationOrder[i]]; /* returns the branch number of triangle VisitationOrder[i] */
06507       if (TriCheck) {
06508          Bcnt = NBlist[TriCheck]; /* get the new branch number from the original (old) branch number */
06509          #if 0
06510          fprintf (SUMA_STDERR,"%s: Tricheck = %d\n", FuncName, TriCheck); */
06511          if (Bcnt >= *BranchCount) {
06512             fprintf (SUMA_STDERR, "\aError %s: BranchCount = %d <= Bcnt = %d.\n", FuncName, *BranchCount, Bcnt);
06513          }
06514          if (N_iBranch[Bcnt] >= Bv[Bcnt].N_list) {
06515             fprintf (SUMA_STDERR, "\aError %s: Bcnt = %d. N_iBranch[Bcnt] = %d >= Bv[Bcnt].N_list = %d\n", FuncName, Bcnt, N_iBranch[Bcnt], Bv[Bcnt].N_list);
06516          }
06517          #endif
06518          Bv[Bcnt].list[N_iBranch[Bcnt]] = VisitationOrder[i]; /* store the index of the visited triangle in that branch */
06519          N_iBranch[Bcnt] += 1; /* store the number of elements in that branch */
06520       }
06521    }
06522    
06523    if (LocalHead) fprintf (SUMA_STDERR, "%s: freeing ...\n", FuncName);
06524    if (VisitationOrder) SUMA_free(VisitationOrder);
06525    if (TriBranch) SUMA_free(TriBranch);
06526    SUMA_RETURN (Bv);    
06527 }

double SUMA_BinaryZeroSearch double    a,
double    b,
double(*    f)(double x, void *data),
void *    fdata,
int    Nitermax,
double    tol
 

Binary Zero Search, a function to find the zero of a function.

Parameters:
a  (double) 1st point, f(a) < 0
b  (double) 2nd point, f(b) > 0 (actually all you need is that f(a)*f(b) is < 0
f  (double )(double x, void *data) function to find the zero point (at the right x)
fdata  (void *)a pointer to the data that accompanies x as input to f
Nitermax  (int) the maximum number of iterations
tol  (double) the tolerance for convergence. Stop when ( |f(x)| < tol )

Definition at line 1548 of file SUMA_GeomComp.c.

References a, LocalHead, SUMA_Boolean, SUMA_ENTRY, SUMA_RETURN, and SUMA_SL_Warn.

Referenced by SUMA_EquateSurfaceAreas(), and SUMA_EquateSurfaceVolumes().

01548                                                                                                                           {
01549    static char FuncName[]={"SUMA_BinaryZeroSearch"};
01550    int Niter;
01551    double x, fx;
01552    SUMA_Boolean done;
01553    SUMA_Boolean LocalHead = NOPE;
01554 
01555    SUMA_ENTRY;
01556    
01557    if (Nitermax < 0) Nitermax = 1000;
01558 
01559    x = 0.0;
01560    Niter = 0;
01561    done = NOPE;
01562    while(!done && Niter < Nitermax) {
01563       x = (a+b)/2.0;
01564       fx = (*f)(x, fdata);
01565       if (LocalHead) fprintf(SUMA_STDERR,"%s: %d\ta=%.4f\tb=%.4f\tx=%.4f\tfx=%.4f\n", 
01566                                           FuncName, Niter, a, b, x, fx);
01567       if (fx < 0) a = x;
01568       else b = x;
01569       if (fabs(fx) < tol) done = YUP;
01570       ++Niter;
01571    }
01572    
01573    if (!done) {
01574       SUMA_SL_Warn(  "Reached iteration limit\n"
01575                      "without converging.\n");
01576    }
01577    
01578    SUMA_RETURN(x);
01579 }

float** SUMA_CalcNeighbDist SUMA_SurfaceObject   SO
 

calculates the length of the segments defined by a node and its first-order neighbors. The resulting matrix very closely resembles SO->FN->FirstNeighb DistFirstNeighb = SUMA_CalcNeighbDist (SO);

Parameters:
SO  (SUMA_SurfaceObject *) with FN field required
Returns:
DistFirstNeighb (float **) DistFirstNeighb[i][j] contains the length of the segment formed by nodes SO->FN->NodeId[i] and SO->FN->FirstNeighb[i][j]
This function was created to try and speed up SUMA_getoffsets2 but it proved useless. Sample code showing two ways of getting segment length: if 1 calculate segment distances(a necessary horror) this made no difference in speed DistFirstNeighb = SUMA_CalcNeighbDist (SO); if (!DistFirstNeighb) { SUMA_SL_Crit("Failed to allocate for DistFirstNeighb
"); exit(1); } { int n1, n2, iseg; n1 = 5; n2 = SO->FN->FirstNeighb[n1][2]; iseg = SUMA_FindEdge(SO->EL, n1, n2); fprintf(SUMA_STDERR, "s: Distance between nodes d and d:
" "from DistFirstNeighb = f
" "from SO->EL->Le = f
", FuncName, n1, n2, DistFirstNeighb[n1][2], SO->EL->Le[iseg]); exit(1); } endif

Definition at line 945 of file SUMA_GeomComp.c.

References a, SUMA_NODE_FIRST_NEIGHB::FirstNeighb, SUMA_SurfaceObject::FN, i, LocalHead, SUMA_NODE_FIRST_NEIGHB::N_Neighb, SUMA_NODE_FIRST_NEIGHB::N_Neighb_max, SUMA_NODE_FIRST_NEIGHB::N_Node, SUMA_NODE_FIRST_NEIGHB::NodeId, SUMA_SurfaceObject::NodeList, SUMA_allocate2D(), SUMA_Boolean, SUMA_ENTRY, SUMA_RETURN, SUMA_SEG_LENGTH, and SUMA_SL_Crit.

00946 {
00947    static char FuncName[]={"SUMA_CalcNeighbDist"};
00948    float **DistFirstNeighb=NULL, *a, *b;
00949    int i, j;
00950    static SUMA_Boolean LocalHead = NOPE;
00951    
00952    SUMA_ENTRY;
00953    
00954    if (!SO) { SUMA_RETURN(NULL); }
00955    if (!SO->FN) { SUMA_RETURN(NULL); }
00956    
00957    DistFirstNeighb = (float **)SUMA_allocate2D(SO->FN->N_Node, SO->FN->N_Neighb_max, sizeof(float));
00958    if (!DistFirstNeighb) {
00959       SUMA_SL_Crit("Failed to allocate for DistFirstNeighb");
00960       SUMA_RETURN(NULL);
00961    }
00962    for (i=0; i < SO->FN->N_Node; ++i) {
00963       a = &(SO->NodeList[3*SO->FN->NodeId[i]]);
00964       for (j=0; j < SO->FN->N_Neighb[i]; ++j) {
00965          b = &(SO->NodeList[3*SO->FN->FirstNeighb[i][j]]);
00966          SUMA_SEG_LENGTH(a, b, DistFirstNeighb[i][j]);
00967          if (SO->FN->NodeId[i] == 5 && SO->FN->FirstNeighb[i][j] == 133092) {
00968             fprintf (SUMA_STDERR, "%f %f %f\n%f %f %f\n%f\n", 
00969                SO->NodeList[3*SO->FN->NodeId[i]], SO->NodeList[3*SO->FN->NodeId[i]+1], SO->NodeList[3*SO->FN->NodeId[i]+2],
00970                SO->NodeList[3*SO->FN->FirstNeighb[i][j]], SO->NodeList[3*SO->FN->FirstNeighb[i][j]+1], 
00971                SO->NodeList[3*SO->FN->FirstNeighb[i][j]+2], DistFirstNeighb[i][j]);
00972          }
00973       }
00974    }
00975    
00976    SUMA_RETURN (DistFirstNeighb);
00977 }

float* SUMA_Chung_Smooth SUMA_SurfaceObject   SO,
float **    wgt,
int    N_iter,
float    FWHM,
float *    fin_orig,
int    vpn,
SUMA_INDEXING_ORDER    d_order,
float *    fout_final_user,
SUMA_COMM_STRUCT   cs
 

Filter data defined on the surface using M.K. Chung et al.'s method (Neuroimage 03) dm_smooth = SUMA_Chung_Smooth (SO, wgt, N_iter, FWHM, fin, vpn, d_order, fout_user, SUMA_COMM_STRUCT *cs);.

Parameters:
SO  (SUMA_SurfaceObject *) Surface object with valid SO->NodeList, SO->FaceSetList and SO->FN
wgt  (float **) interpolation weights for each node. These weights are obtained from SUMA_Chung_Smooth_Weights
N_iter  (int) number of smoothing iterations (must be even, > 1)
FWHM  (float) Full Width at Half Maximum of equivalent Gaussian filter
fin  (float *) vector containing node data. The length of this vector is vpn x SO->N_Node , where vpn is the number of values per node.
vpn  (int) the numberof values per node in fin
d_order  (SUMA_INDEXING_ORDER) Indicates how multiple values per node are stored in fin SUMA_ROW_MAJOR: The data in fin is stored in *** Row Major *** order. The ith value (start at 0) for node n is at index fin[vpn*n+i] SUMA_COLUMN_MAJOR: The data in fin is stored in *** Column Major *** order. The ith (start at 0) value for node n is at index fin[n+SO->N_Node*i]; etc...
fout_user  (float *) a pointer to the vector where the smoothed version of fin will reside You can pass NULL and the function will do the allocation for you and return the pointer to the smoothed data in dm_smooth. If you already have space allocated for the result, then pass the pointer in fout_user and save on allocation time and space. In that case, dm_smooth is equal to fout_user. Either way, you are responsible for freeing memory pointed to by dm_smooth DO NOT PASS fout_user = fin
cs  (SUMA_COMM_STRUCT *) A pointer to the structure containing info for taking to SUMA
Returns:
dm_smooth (float *) A pointer to the smoothed data (vpn * SO->N_Node values). You will have to free the memory allocated for dm_smooth yourself.
See also:
SUMA_Chung_Smooth_Weights

Definition at line 3068 of file SUMA_GeomComp.c.

References SUMA_NODE_FIRST_NEIGHB::FirstNeighb, SUMA_SurfaceObject::FN, fout, LocalHead, SUMA_NODE_FIRST_NEIGHB::N_Neighb, SUMA_SurfaceObject::N_Node, SUMA_COMM_STRUCT::Send, SUMA_Boolean, SUMA_calloc, SUMA_COLUMN_MAJOR, SUMA_ENTRY, SUMA_free, SUMA_INDEXING_ORDER, SUMA_NODE_RGBAb, SUMA_RETURN, SUMA_ROW_MAJOR, SUMA_SendToSuma(), SUMA_SL_Crit, SUMA_SL_Err, SUMA_SL_Warn, and vpn.

Referenced by SUMA_Reposition_Touchup().

03072 {
03073    static char FuncName[]={"SUMA_Chung_Smooth"};
03074    float *fout_final = NULL, *fbuf=NULL, *fin=NULL, *fout=NULL, *fin_next = NULL;
03075    float delta_time, fp, dfp, fpj, minfn=0.0, maxfn=0.0;
03076    int n , k, j, niter, vnk, os;
03077    SUMA_Boolean LocalHead = NOPE;
03078    
03079    SUMA_ENTRY;
03080 
03081    if (N_iter % 2) {
03082       SUMA_SL_Err("N_iter must be an even number\n");
03083       SUMA_RETURN(NULL);
03084    }
03085    
03086    if (!SO || !wgt || !fin_orig) {
03087       SUMA_SL_Err("NULL SO or wgt or fin_orig\n");
03088       SUMA_RETURN(NULL);
03089    }
03090    if (!SO->FN) {
03091       SUMA_SL_Err("NULL SO->FN\n");
03092       SUMA_RETURN(NULL);
03093    }
03094    
03095    if (vpn < 1) {
03096       SUMA_SL_Err("vpn < 1\n");
03097       SUMA_RETURN(NULL);
03098    }  
03099    
03100    if (fout_final_user == fin_orig) {
03101       SUMA_SL_Err("fout_final_user == fin_orig");
03102       SUMA_RETURN(NULL);
03103    }
03104    
03105    if (!fout_final_user) { /* allocate for output */
03106       fout_final = (float *)SUMA_calloc(SO->N_Node * vpn, sizeof(float));
03107       if (!fout_final) {
03108          SUMA_SL_Crit("Failed to allocate for fout_final\n");
03109          SUMA_RETURN(NULL);
03110       }
03111    }else {
03112       fout_final = fout_final_user; /* pre-allocated */
03113    }
03114    
03115    /* allocate for buffer */
03116    fbuf = (float *)SUMA_calloc(SO->N_Node * vpn, sizeof(float));
03117    if (!fbuf) {
03118       SUMA_SL_Crit("Failed to allocate for fbuf\n");
03119       SUMA_RETURN(NULL);
03120    }
03121    
03122    
03123    if (cs->Send) { /* send the first monster */
03124       if (!SUMA_SendToSuma (SO, cs, (void *)fin_orig, SUMA_NODE_RGBAb, 1)) {
03125          SUMA_SL_Warn("Failed in SUMA_SendToSuma\nCommunication halted.");
03126       }
03127    }
03128    
03129    fin_next = fin_orig;
03130    delta_time= (FWHM * FWHM)/(16*N_iter*log(2));
03131    switch (d_order) {
03132       case SUMA_COLUMN_MAJOR:
03133          for (niter=0; niter < N_iter; ++niter) {
03134             if ( niter % 2 ) { /* odd */
03135                fin = fin_next; /* input from previous output buffer */
03136                fout = fout_final; /* results go into final vector */
03137                fin_next = fout_final; /* in the next iteration, the input is from fout_final */
03138             } else { /* even */
03139                /* input data is in fin_new */
03140                fin = fin_next;
03141                fout = fbuf; /* results go into buffer */
03142                fin_next = fbuf; /* in the next iteration, the input is from the buffer */
03143             }
03144             for (k=0; k < vpn; ++k) {
03145                os = SO->N_Node*k;   /* node value indexing offset */
03146                for (n=0; n < SO->N_Node; ++n) {
03147                   vnk = n+os; /* index of kth value at node n */
03148                   fp = fin[vnk]; /* kth value at node n */
03149                   dfp = 0.0;
03150                   if (SO->FN->N_Neighb[n]) minfn = maxfn = fin[SO->FN->FirstNeighb[n][0]+os];
03151                   for (j=0; j < SO->FN->N_Neighb[n]; ++j) {
03152                      fpj = fin[SO->FN->FirstNeighb[n][j]+os]; /* value at jth neighbor of n */
03153                      if (fpj < minfn) minfn = fpj;
03154                      if (fpj > maxfn) maxfn = fpj;
03155                      dfp += wgt[n][j] * (fpj - fp); 
03156                   }/* for j*/
03157                   fout[vnk] = fin[vnk] + delta_time * dfp;
03158                   if (fout[vnk] < minfn) fout[vnk] = minfn;
03159                   if (fout[vnk] > maxfn) fout[vnk] = maxfn;
03160                }/* for n */ 
03161                  
03162                if (cs->Send) {
03163                   if (!SUMA_SendToSuma (SO, cs, (void *)fout, SUMA_NODE_RGBAb, 1)) {
03164                      SUMA_SL_Warn("Failed in SUMA_SendToSuma\nCommunication halted.");
03165                   }
03166                }
03167             } /* for k */
03168          }/* for niter */
03169          break;
03170       case SUMA_ROW_MAJOR:
03171          SUMA_SL_Err("Row Major not implemented");
03172          SUMA_RETURN(NULL);
03173          break;
03174       default:
03175          SUMA_SL_Err("Bad Major, very bad.\n");
03176          SUMA_RETURN(NULL);
03177          break;
03178    }
03179    
03180    if (fbuf) SUMA_free(fbuf); fbuf = NULL;
03181                
03182    SUMA_RETURN(fout);
03183 }

float** SUMA_Chung_Smooth_Weights SUMA_SurfaceObject   SO
 

calculate the interpolation weights required to smooth data on the surface using M.K. Chung et al. Neuroimage 03

Parameters:
SO  (SUMA_SurfaceObject *) Surface object with valid SO->NodeList, SO->FaceSetList and SO->FN
Returns:
wgt (float **) 2D matrix of the same size as SO->FirstNeighb that contains the weights to be applied to a node's neighbors in interpolation Free the result with SUMA_free2D ((char **)wgt, SO->N_Node); The weights are computed using the Finite Element method.
See also:
SUMA_Chung_Smooth

Definition at line 2095 of file SUMA_GeomComp.c.

References SUMA_NODE_FIRST_NEIGHB::FirstNeighb, SUMA_SurfaceObject::FN, i, LocalHead, SUMA_NODE_FIRST_NEIGHB::N_Neighb, SUMA_NODE_FIRST_NEIGHB::N_Neighb_max, SUMA_SurfaceObject::N_Node, SUMA_SurfaceObject::NodeList, p, q, SUMA_allocate2D(), SUMA_Boolean, SUMA_disp_vect(), SUMA_ENTRY, SUMA_free, SUMA_malloc, SUMA_MT_CROSS, SUMA_MT_DOT, SUMA_NORM, SUMA_RETURN, SUMA_SL_Crit, and SUMA_SL_Err.

Referenced by SUMA_Reposition_Touchup().

02096 {
02097    static char FuncName[]={"SUMA_Chung_Smooth_Weights"};
02098    float **wgt=NULL, *coord_nbr=NULL, *cotan=NULL, *tfp=NULL;
02099    float dv[3], p[3], q[3];
02100    float area, area_p, area_q, dot_p, dot_q;
02101    int i, j, k, n, j3p1, j3m1, n3, j3=0, nj, nj3, i_dbg;
02102    SUMA_Boolean LocalHead = NOPE;
02103    
02104    SUMA_ENTRY;
02105 
02106    if (!SO) {
02107       SUMA_SL_Err("Null SO");
02108       SUMA_RETURN(NULL);
02109    }
02110    if (!SO->FN) {
02111       SUMA_SL_Err("Null SO->FN");
02112       SUMA_RETURN(NULL);
02113    }
02114    
02115    i_dbg = -1; /* index of debugging node, set to -1 for no debugging */
02116    /* in the demo mesh that Moo Chung gave me, 
02117    Node 17 has the following neighbors in ccw order:
02118    231 230 250 261 239 236 - 231 230 250 261 239 236 
02119    Set i_dbg = 17 and turn on LocalHead to get a confirmation of this
02120    by this function*/
02121    /* implement the non-parametric weight estimation method */
02122    wgt = (float **)SUMA_allocate2D(SO->N_Node, SO->FN->N_Neighb_max, sizeof(float));  /* vector of node weights */
02123    coord_nbr = (float *)SUMA_malloc((SO->FN->N_Neighb_max + 2) * sizeof(float) * 3); /* vector of neighboring node coordinates */ 
02124    cotan = (float *)SUMA_malloc(SO->FN->N_Neighb_max * sizeof(float)); 
02125    if (!wgt || !coord_nbr || !cotan) {
02126       SUMA_SL_Crit("Failed to allocate for wgt &/|coord_nbr &/|cotan");
02127       SUMA_RETURN(NULL);
02128    }
02129    
02130    for (n=0; n < SO->N_Node; ++n) {
02131       n3 = 3 * n;
02132       /* translate the coordinates of the neighboring nodes to make n be the origin */
02133       for (j=0; j<SO->FN->N_Neighb[n]; ++j) {
02134          j3 = 3 * (j+1);
02135          nj = SO->FN->FirstNeighb[n][j]; nj3 = 3 * nj;
02136          coord_nbr[j3] = SO->NodeList[nj3] - SO->NodeList[n3];
02137          coord_nbr[j3+1] = SO->NodeList[nj3+1] - SO->NodeList[n3+1];
02138          coord_nbr[j3+2] = SO->NodeList[nj3+2] - SO->NodeList[n3+2];
02139       }  /* for j */
02140       /* padd with last neighbor at the very beginning and 1st neighbor at the end 
02141          in matlab: coord_nbr = [coord_nbr(:,last_neighb) coord_nbr coord_nbr(:,first_neighb)];
02142       */   
02143       for (k=0; k < 3; ++k) coord_nbr[k] = coord_nbr[j3+k];  
02144       j3 = 3 * ( SO->FN->N_Neighb[n] + 1);
02145       for (k=0; k < 3; ++k) coord_nbr[j3+k] = coord_nbr[3+k];
02146       if (LocalHead && n == i_dbg) { SUMA_disp_vect (coord_nbr, 3 * (SO->FN->N_Neighb[n] + 2)) ;  }
02147       
02148       
02149       area = 0.0;
02150       for (j=1; j<=SO->FN->N_Neighb[n]; ++j) { 
02151          j3 = 3 * j; j3p1 = 3 * (j+1); j3m1 = 3 * (j-1);
02152          for (k=0; k < 3; ++k) dv[k] = coord_nbr[j3p1+k] - coord_nbr[j3+k]; 
02153          tfp = &(coord_nbr[j3p1]);
02154          dot_p = SUMA_MT_DOT (tfp, dv);
02155          SUMA_MT_CROSS(p, tfp, dv);
02156          for (k=0; k < 3; ++k) dv[k] = coord_nbr[j3m1+k] - coord_nbr[j3+k]; 
02157          tfp = &(coord_nbr[j3m1]);
02158          dot_q = SUMA_MT_DOT (tfp, dv);
02159          SUMA_MT_CROSS(q, tfp, dv);
02160          
02161          SUMA_NORM(area_p, p); 
02162          SUMA_NORM(area_q, q); 
02163          
02164          cotan[j-1] = dot_p/area_p + dot_q/area_q;
02165          area += area_p/2.0;
02166          if (LocalHead && n == i_dbg) {
02167             fprintf (SUMA_STDERR,"[%d->%d] area_p, area_q = %f, %f\n",
02168                                   n, SO->FN->FirstNeighb[n][j-1],
02169                                   area_p / 2.0,  area_q / 2.0);
02170          }
02171       }
02172       
02173       for (j=0; j<SO->FN->N_Neighb[n]; ++j) {
02174          wgt[n][j] = cotan[j]/area;
02175       }
02176       if (LocalHead && n == i_dbg) {
02177          fprintf (SUMA_STDERR,"%s: Weight Results for neighbors of %d (matlab node %d):\n",
02178                               FuncName, n, n+1);
02179          SUMA_disp_vect (wgt[n], SO->FN->N_Neighb[n]);
02180       }
02181    }  /* for n */
02182 
02183    /* free local variables */
02184    if (coord_nbr) SUMA_free(coord_nbr); coord_nbr = NULL;
02185    if (cotan) SUMA_free(cotan); cotan = NULL;
02186 
02187    SUMA_RETURN(wgt);
02188 }

SUMA_VTI* SUMA_CreateVTI int    N_TriIndex,
int *    TriIndex
 

Function to allocate and initialize a SUMA_VTI * structure.

Parameters:
N_TriIndex  (int): Number of triangles whose intersections will be sought
TriIndex  (int **): Pointer to vector containing indices of triangles whose intersections will be sought. This vector will essentially be stored in vti if you supply it and its pointer is set to NULL so that you can't free it afterwards. If this parameter is NULL, then an empty vti->TriIndex is created.
Returns:
vti (SUMA_VTI *): Initialized structure containing allocated TriIndex, N_IntersectedVoxels, IntersectedVoxels vectors.
  • Free with SUMA_FreeVTI

Definition at line 132 of file SUMA_GeomComp.c.

References SUMA_VTI::IntersectedVoxels, SUMA_VTI::N_IntersectedVoxels, SUMA_VTI::N_TriIndex, SUMA_calloc, SUMA_ENTRY, SUMA_malloc, SUMA_RETURN, SUMA_SL_Crit, SUMA_SL_Err, and SUMA_VTI::TriIndex.

00133 {
00134    static char FuncName[]={"SUMA_CreateVTI"};
00135    SUMA_VTI *vti = NULL;
00136    
00137    SUMA_ENTRY;
00138    if (!N_TriIndex) {
00139       SUMA_SL_Err("Nothing to do !");
00140       SUMA_RETURN(vti);
00141    }
00142    
00143    vti = (SUMA_VTI *)SUMA_malloc(sizeof(SUMA_VTI));
00144    vti->N_TriIndex = N_TriIndex;
00145    if (TriIndex ) {
00146       vti->TriIndex = TriIndex;
00147    }else {
00148       /* create empty copy */
00149       vti->TriIndex = (int *)SUMA_calloc(N_TriIndex, sizeof(int));
00150       if (!vti->TriIndex) {
00151          SUMA_SL_Crit("Failed to allocate for vti->TriIndex");
00152          SUMA_RETURN(NULL);
00153       }
00154    }
00155    vti->N_IntersectedVoxels = (int *)SUMA_calloc(N_TriIndex, sizeof(int));
00156    vti->IntersectedVoxels = (int **)SUMA_calloc(N_TriIndex, sizeof(int*));
00157    if (!vti->N_IntersectedVoxels || !vti->IntersectedVoxels) {
00158          SUMA_SL_Crit("Failed to allocate for vti's innerds");
00159          SUMA_RETURN(NULL);
00160    }
00161 
00162    SUMA_RETURN(vti);
00163 }

int* SUMA_Dijkstra SUMA_SurfaceObject   SO,
int    Nx,
int    Ny,
SUMA_Boolean   isNodeInMesh,
int *    N_isNodeInMesh,
int    Method_Number,
float *    Lfinal,
int *    N_Path
 

Definition at line 6837 of file SUMA_GeomComp.c.

References SUMA_NODE_FIRST_NEIGHB::FirstNeighb, SUMA_SurfaceObject::FN, i, L, LARGE_NUM, LocalHead, SUMA_NODE_FIRST_NEIGHB::N_Neighb, SUMA_SurfaceObject::N_Node, SUMA_SurfaceObject::NodeList, Nx, SUMA_Boolean, SUMA_calloc, SUMA_ENTRY, SUMA_etime(), SUMA_free, SUMA_malloc, SUMA_MIN_LOC_VEC, SUMA_RETURN, and v.

Referenced by SUMA_ReportDrawnROIDatumLength(), and SUMA_Surf_Plane_Intersect_ROI().

06838 {
06839    static char FuncName[] = {"SUMA_Dijkstra"};
06840    SUMA_Boolean LocalHead = NOPE;
06841    float *L = NULL, Lmin = -1.0, le = 0.0, DT_DIJKSTRA;
06842    int i, iw, iv, v, w, N_Neighb, *Path = NULL;
06843    struct  timeval  start_time;
06844    SUMA_DIJKSTRA_PATH_CHAIN *DC = NULL, *DCi, *DCp;
06845    SUMA_Boolean Found = NOPE;
06846    /* variables for method 2 */
06847    int N_Lmins, *vLmins, *vLocInLmins, iLmins, ReplacingNode, ReplacedNodeLocation;
06848    float *Lmins; 
06849    
06850    
06851    SUMA_ENTRY;
06852    
06853    *Lfinal = -1.0;
06854    *N_Path = 0;
06855    
06856    /* make sure Both Nx and Ny exist in isNodeInMesh */
06857    if (!isNodeInMesh[Nx]) {
06858       fprintf (SUMA_STDERR,"\aError %s: Node %d (Nx) is not in mesh.\n", FuncName, Nx);
06859       SUMA_RETURN (NULL);
06860    }  
06861    if (!isNodeInMesh[Ny]) {
06862       fprintf (SUMA_STDERR,"\aError %s: Node %d (Ny) is not in mesh.\n", FuncName, Ny);
06863       SUMA_RETURN (NULL);
06864    }
06865 
06866    if (!SO->FN) {
06867       fprintf (SUMA_STDERR, "Error %s: SO does not have FN structure.\n", FuncName);
06868       SUMA_RETURN (NULL);
06869    }
06870 
06871    if (LocalHead) {
06872       /* Start timer for next function */
06873       SUMA_etime(&start_time,0);      
06874    }
06875    
06876    /* allocate for chain */
06877    DC = (SUMA_DIJKSTRA_PATH_CHAIN *) SUMA_malloc (sizeof(SUMA_DIJKSTRA_PATH_CHAIN) * SO->N_Node);
06878    if (!DC) {
06879       fprintf (SUMA_STDERR, "Error %s: Could not allocate. \n", FuncName);
06880       SUMA_RETURN (NULL);
06881    }
06882    
06883    switch (Method_Number) {
06884    
06885       case 0:  /* Method 0, Brute force */
06886          /* allocate for vertices labels */
06887          L = (float *) SUMA_calloc (SO->N_Node, sizeof (float));
06888          if (!L) {
06889             fprintf (SUMA_STDERR, "Error %s: Failed to allocate.\n", FuncName);
06890             SUMA_free(DC);
06891             SUMA_RETURN (NULL);
06892          }
06893 
06894          /* label all vertices with very large numbers, initialize path previous pointers to null */
06895          for (i=0; i < SO->N_Node; ++i) {
06896             L[i] = LARGE_NUM;   
06897             DC[i].Previous = NULL;
06898          }
06899          /* label starting vertex with 0 */
06900          L[Nx] = 0.0;
06901          Lmin = 0.0;
06902          v = Nx;
06903          *Lfinal = -1.0;
06904          /* initialize path at Nx */
06905          DC[Nx].Previous = NULL;
06906          DC[Nx].node = Nx;
06907          DC[Nx].le = 0.0;
06908          DC[Nx].order = 0;
06909          *N_Path = 0;
06910          /* Brute force method */
06911          do {
06912             /* find v in Mesh / L(v) is minimal */
06913             /* this sucks up a lot of time because it is searching the entire set of SO->N_Node instead of the one that was intersected only.
06914             This can be sped up, considerably */
06915             SUMA_MIN_LOC_VEC(L, SO->N_Node, Lmin, v);   /* locates and finds the minimum of L, nodes not in mesh will keep their large values and will not be picked*/
06916             if (!isNodeInMesh[v]) {
06917                fprintf (SUMA_STDERR, "\aERROR %s: Dijkstra derailed. v = %d, Lmin = %f\n. Try another point.", FuncName, v, Lmin);
06918                SUMA_free (L);
06919                SUMA_free(DC);
06920                SUMA_RETURN (NULL); 
06921             }
06922             if (v == Ny) {
06923                if (LocalHead) fprintf (SUMA_STDERR, "%s: Done.\n", FuncName);
06924                *Lfinal = L[v];
06925                Found = YUP;
06926             } else {
06927                N_Neighb = SO->FN->N_Neighb[v];
06928                for (i=0; i < N_Neighb; ++i) {
06929                   w = SO->FN->FirstNeighb[v][i];
06930                   if (isNodeInMesh[w]) {
06931                      iw = 3*w;
06932                      iv = 3*v;
06933                      le = sqrt ( (SO->NodeList[iw] - SO->NodeList[iv]) * (SO->NodeList[iw] - SO->NodeList[iv]) +
06934                                  (SO->NodeList[iw+1] - SO->NodeList[iv+1]) * (SO->NodeList[iw+1] - SO->NodeList[iv+1]) +
06935                                  (SO->NodeList[iw+2] - SO->NodeList[iv+2]) * (SO->NodeList[iw+2] - SO->NodeList[iv+2]) );
06936                      if (L[w] > L[v] + le ) {
06937                         L[w] = L[v] + le;  
06938                         /* update the path */
06939                         DCp = &(DC[v]); /* previous path */
06940                         DC[w].Previous = (void *) DCp;
06941                         DC[w].le = le;
06942                         DC[w].node = w;
06943                         DC[w].order = DCp->order + 1;
06944                      } 
06945                   }
06946                }
06947 
06948                /* remove node v from isNodeInMesh and reset their distance value to a very large one, 
06949                   this way you do not have to reinitialize this variable. */
06950                isNodeInMesh[v] = NOPE;
06951                *N_isNodeInMesh -= 1;
06952                L[v] = LARGE_NUM; 
06953                Found = NOPE;
06954             }
06955          } while (*N_isNodeInMesh > 0 && !Found);
06956 
06957          if (!Found) {
06958             fprintf (SUMA_STDERR, "Error %s: No more nodes in mesh, failed to reach target.\n", FuncName);
06959             SUMA_free (L);
06960             SUMA_free(DC);
06961             SUMA_RETURN (NULL);
06962          }else {
06963             if (LocalHead) fprintf (SUMA_STDERR, "%s: Path between Nodes %d and %d is %f.\n", FuncName, Nx, Ny, *Lfinal);
06964          }
06965 
06966 
06967          if (LocalHead) {
06968             /* stop timer */
06969             DT_DIJKSTRA = SUMA_etime(&start_time,1);
06970             fprintf (SUMA_STDERR, "%s: Method 1- Elapsed time in function %f seconds.\n", FuncName, DT_DIJKSTRA);
06971          }
06972 
06973          SUMA_free(L);
06974          break;
06975 
06976       case 1:  /********* Method 1- faster minimum searching *******************/
06977          if (LocalHead) {
06978             /* Start timer for next function */
06979             SUMA_etime(&start_time,0);      
06980          }
06981 
06982          /* allocate for vertices labels and minimums vectors*/
06983          L = (float *) SUMA_calloc (SO->N_Node, sizeof (float));        /* L[i] = distance to a node i*/
06984          Lmins = (float *) SUMA_calloc (SO->N_Node, sizeof (float));    /* Lmins = vector containing minimum calculated distances to node */
06985          vLmins = (int *) SUMA_calloc (SO->N_Node, sizeof (int));       /* vLmins[i] = index (into L) of the node having a distance Lmins[i] */
06986          vLocInLmins = (int *) SUMA_calloc (SO->N_Node, sizeof (int));  /* vLocInLmin[j] = index (into Lmins) of a node having index j (into L) */
06987 
06988          if (!L || !Lmins || !vLmins || !vLocInLmins) {
06989             fprintf (SUMA_STDERR, "Error %s: Failed to allocate.\n", FuncName);
06990             SUMA_RETURN (NULL);
06991          }
06992 
06993          /* label all vertices with very large numbers and initialize vLocInLmins to -1*/
06994          for (i=0; i < SO->N_Node; ++i) {
06995             L[i] = LARGE_NUM;
06996             Lmins[i] = LARGE_NUM;   
06997             vLocInLmins[i] = -1;            
06998             DC[i].Previous = NULL;
06999          }
07000 
07001          /* label starting vertex with 0 */
07002          L[Nx] = 0.0;
07003          *Lfinal = -1.0;
07004 
07005          /* initialize values of vectors used to keep track of minimum values of L and their corresponding nodes */
07006          Lmins[0] = 0.0;
07007          vLmins[0] = Nx;
07008          vLocInLmins[Nx] = 0;
07009          N_Lmins = 1;
07010 
07011          /* initialize path at Nx */
07012          DC[Nx].Previous = NULL;
07013          DC[Nx].node = Nx;
07014          DC[Nx].le = 0.0;
07015          DC[Nx].order = 0;
07016          *N_Path = 0;
07017          
07018          /* method with efficient tracking of minimum */
07019          if (LocalHead) fprintf (SUMA_STDERR, "%s: about to MIN_LOC ....N_isNodeInMesh = %d\n", FuncName, *N_isNodeInMesh);
07020          do {
07021             /* find v in Mesh / L(v) is minimal */
07022             SUMA_MIN_LOC_VEC(Lmins, N_Lmins, Lmin, iLmins);   /* locates the minimum value in Lmins vector */
07023             v = vLmins[iLmins];   /* get the node for this Lmin value */
07024             if (!isNodeInMesh[v]) {
07025                fprintf (SUMA_STDERR, "\aERROR %s: Dijkstra derailed. v = %d, Lmin = %f\n. Try another point.", FuncName, v, Lmin);
07026                SUMA_free (L);
07027                SUMA_free (Lmins);
07028                SUMA_free(vLmins);
07029                SUMA_free(vLocInLmins);
07030                SUMA_free(DC);
07031                SUMA_RETURN (NULL);
07032             }
07033             #ifdef LOCALDEBUG
07034                fprintf (SUMA_STDERR, "%s: Node v = %d.\n", FuncName, v);
07035             #endif
07036             if (v == Ny) {
07037                if (LocalHead) fprintf (SUMA_STDERR, "%s: Done.\n", FuncName);
07038                *Lfinal = L[v];
07039                Found = YUP;
07040             } else {
07041                N_Neighb = SO->FN->N_Neighb[v];
07042                for (i=0; i < N_Neighb; ++i) {
07043                   w = SO->FN->FirstNeighb[v][i];
07044                   if (isNodeInMesh[w]) {
07045                      iw = 3*w;
07046                      iv = 3*v;
07047                      le = sqrt ( (SO->NodeList[iw] - SO->NodeList[iv]) * (SO->NodeList[iw] - SO->NodeList[iv]) +
07048                                  (SO->NodeList[iw+1] - SO->NodeList[iv+1]) * (SO->NodeList[iw+1] - SO->NodeList[iv+1]) +
07049                                  (SO->NodeList[iw+2] - SO->NodeList[iv+2]) * (SO->NodeList[iw+2] - SO->NodeList[iv+2]) );
07050                      if (L[w] > L[v] + le ) {
07051                         #ifdef LOCALDEBUG
07052                            fprintf (SUMA_STDERR, "%s: L[%d]=%f > L[%d] = %f + le = %f.\n", FuncName, w, L[w], v, L[v], le);
07053                         #endif
07054                         L[w] = L[v] + le; 
07055                         /* update the path */
07056                         DCp = &(DC[v]); /* previous path */
07057                         DC[w].Previous = (void *) DCp;
07058                         DC[w].le = le;
07059                         DC[w].node = w;
07060                         DC[w].order = DCp->order + 1;
07061                         
07062                         if (vLocInLmins[w] < 0) { 
07063                            #ifdef LOCALDEBUG
07064                               fprintf (SUMA_STDERR, "%s: adding entry for w = %d - First Hit. \n", FuncName, w);
07065                            #endif
07066                            Lmins[N_Lmins] = L[w]; /* add this value to Lmins vector */
07067                            vLmins[N_Lmins] = w; /* store the node for this Lmins value */
07068                            vLocInLmins[w] = N_Lmins; /* store where that node is represented in Lmins */
07069                            ++N_Lmins;  /* increment N_Lmins */  
07070                         } else {
07071                            #ifdef LOCALDEBUG
07072                               fprintf (SUMA_STDERR, "%s: modifying entry for w = %d  Second Hit.\n", FuncName, w); */
07073                            #endif
07074                            Lmins[vLocInLmins[w]] = L[w]; /* update value for Lmins */
07075                         }                        
07076                      }else {
07077                         #ifdef LOCALDEBUG
07078                            fprintf (SUMA_STDERR, "%s: L[%d]=%f < L[%d] = %f + le = %f.\n", FuncName, w, L[w], v, L[v], le); */
07079                         #endif
07080                      } 
07081                   }
07082                }
07083 
07084                /* remove node v from isNodeInMesh and reset their distance value to a very large one, 
07085                   this way you do not have to reinitialize this variable. */
07086                isNodeInMesh[v] = NOPE;
07087                *N_isNodeInMesh -= 1;
07088                L[v] = LARGE_NUM; 
07089                Found = NOPE;
07090 
07091                /* also remove the values (by swapping it with last element) for this node from Lmins */
07092                #ifdef LOCALDEBUG
07093                   {
07094                      int kkk;
07095                      fprintf (SUMA_STDERR,"Lmins\tvLmins\tvLocInLmins\n");
07096                      for (kkk=0; kkk < N_Lmins; ++kkk) fprintf (SUMA_STDERR,"%f\t%d\t%d\n", Lmins[kkk], vLmins[kkk], vLocInLmins[vLmins[kkk]] );
07097                
07098                   }
07099                #endif
07100                
07101                if (vLocInLmins[v] >= 0) { /* remove its entry if there is one */
07102                   #ifdef LOCALDEBUG
07103                      fprintf (SUMA_STDERR, "%s: removing node v = %d. N_Lmins = %d\n", FuncName,  v, N_Lmins);
07104                   #endif
07105                   --N_Lmins;
07106                   ReplacingNode = vLmins[N_Lmins];
07107                   ReplacedNodeLocation = vLocInLmins[v];
07108                   Lmins[vLocInLmins[v]] = Lmins[N_Lmins];
07109                   vLmins[vLocInLmins[v]] = vLmins[N_Lmins];
07110                   vLocInLmins[ReplacingNode] = ReplacedNodeLocation;
07111                   vLocInLmins[v] = -1;
07112                   Lmins[N_Lmins] = LARGE_NUM; 
07113                }
07114             }
07115          } while (*N_isNodeInMesh > 0 && !Found);
07116 
07117          if (!Found) {
07118             fprintf (SUMA_STDERR, "Error %s: No more nodes in mesh, failed to reach target %d. NLmins = %d\n", FuncName, Ny, N_Lmins);
07119             SUMA_free (L);
07120             SUMA_free (Lmins);
07121             SUMA_free(vLmins);
07122             SUMA_free(vLocInLmins);
07123             SUMA_free(DC);
07124             SUMA_RETURN (NULL);
07125          }else {
07126             if (LocalHead) fprintf (SUMA_STDERR, "%s: Path between Nodes %d and %d is %f.\n", FuncName, Nx, Ny, *Lfinal);
07127          }
07128 
07129 
07130          if (LocalHead) {
07131             /* stop timer */
07132             DT_DIJKSTRA = SUMA_etime(&start_time,1);
07133             fprintf (SUMA_STDERR, "%s: Method 2- Elapsed time in function %f seconds.\n", FuncName, DT_DIJKSTRA);
07134          }
07135 
07136          SUMA_free(L);
07137          SUMA_free(Lmins);
07138          SUMA_free(vLmins);
07139          SUMA_free(vLocInLmins);
07140          break;   /********** Method 1- faster minimum searching **************/
07141       default: 
07142          fprintf (SUMA_STDERR, "Error %s: No such method (%d).\n", FuncName, Method_Number);
07143          if (DC) SUMA_free(DC);
07144          SUMA_RETURN (NULL);
07145          break;
07146    }
07147    
07148    /* now reconstruct the path */
07149    *N_Path = DC[Ny].order+1;
07150    Path = (int *) SUMA_calloc (*N_Path, sizeof(int));
07151    if (!Path) {
07152       fprintf (SUMA_STDERR, "Error %s: Failed to allocate.\n", FuncName);
07153       if (DC) SUMA_free(DC);
07154       SUMA_RETURN (NULL);
07155    }
07156    
07157    DCi = &(DC[Ny]);
07158    iv = *N_Path - 1;
07159    Path[iv] = Ny;
07160    if (iv > 0) {
07161       do {
07162          --iv;
07163          DCp = (SUMA_DIJKSTRA_PATH_CHAIN *) DCi->Previous;
07164          Path[iv] = DCp->node;
07165          DCi = DCp;
07166       } while (DCi->Previous);
07167    }
07168    
07169    if (iv != 0) {
07170       fprintf (SUMA_STDERR, "Error %s: iv = %d. This should not be.\n", FuncName, iv);
07171    }  
07172    
07173    SUMA_free(DC);
07174    SUMA_RETURN (Path);
07175 }

SUMA_Boolean SUMA_EquateSurfaceAreas SUMA_SurfaceObject   SO,
SUMA_SurfaceObject   SOref,
float    tol,
SUMA_COMM_STRUCT   cs
 

inflates or deflates a surface to make the area of one surface (SO) equal to the area of another (SOref)

Parameters:
SO:  The surface to modify. SO's NodeList pointer is reallocated in the function!
SOref:  The reference surface
tol  (float): The acceptable difference between the two areas
cs  (SUMA_COMM_STRUCT *): The suma communication structure

  • This function does not update the normals and other coordinate related properties for SO.
See also:
SUMA_RECOMPUTE_NORMALS

Definition at line 1700 of file SUMA_GeomComp.c.

References a, SUMA_SurfaceObject::Center, SUMA_AreaDiffDataStruct::cs, i, LocalHead, SUMA_SurfaceObject::N_FaceSet, SUMA_SurfaceObject::N_Node, SUMA_SurfaceObject::NodeDim, SUMA_SurfaceObject::NodeList, SUMA_AreaDiffDataStruct::SO, SUMA_AreaDiffDataStruct::SOref, SUMA_AreaDiff(), SUMA_BinaryZeroSearch(), SUMA_Boolean, SUMA_ENTRY, SUMA_free, SUMA_GetAreaDiffRange(), SUMA_malloc, SUMA_RETURN, SUMA_SL_Err, and SUMA_AreaDiffDataStruct::tmpList.

01701 {
01702    static char FuncName[]={"SUMA_EquateSurfaceAreas"};
01703    int iter, i, iter_max, ndiv;
01704    double a, b, d;
01705    SUMA_AreaDiffDataStruct fdata;
01706    SUMA_Boolean LocalHead = NOPE;
01707    
01708    SUMA_ENTRY;
01709 
01710    if (!SO || !SOref) { SUMA_SL_Err("NULL surfaces"); SUMA_RETURN(NOPE); }
01711    if (SO->N_Node != SOref->N_Node || SO->N_FaceSet != SOref->N_FaceSet) { SUMA_SL_Err("Surfaces not isotopic"); SUMA_RETURN(NOPE); }
01712    
01713    if (LocalHead) {
01714       fprintf(SUMA_STDERR, "%s:\n"
01715                            " SO    Center: %f, %f, %f\n"
01716                            " SOref Center: %f, %f, %f\n"
01717                            , FuncName, 
01718                            SO->Center[0], SO->Center[1], SO->Center[2],
01719                            SOref->Center[0], SOref->Center[1], SOref->Center[2]);  
01720    }
01721      
01722    /* fill up fdata */
01723    fdata.SO = SO; fdata.SOref = SOref; fdata.cs = cs;
01724    fdata.tmpList = (float *)SUMA_malloc(SOref->NodeDim * SOref->N_Node * sizeof(float));
01725    if (!fdata.tmpList) {
01726       SUMA_SL_Err("Failed to allocate");
01727       SUMA_RETURN(0);
01728    }
01729 
01730    if (!SUMA_GetAreaDiffRange(&fdata, &a, &b)) {
01731       SUMA_SL_Err("Failed to get range");
01732       SUMA_RETURN(NOPE);
01733    }
01734    
01735    if (LocalHead) {
01736       fprintf(SUMA_STDERR,"%s:\na = %f\tb=%f\n", FuncName, a, b);
01737    }      
01738    SUMA_BinaryZeroSearch(a, b, SUMA_AreaDiff, &fdata, 500, tol);  
01739    
01740    /* now make the new node list be SO's thingy*/
01741    SUMA_free(SO->NodeList); SO->NodeList = fdata.tmpList; fdata.tmpList = NULL;
01742        
01743    SUMA_RETURN(YUP);
01744 }

SUMA_Boolean SUMA_EquateSurfaceSize SUMA_SurfaceObject   SO,
SUMA_SurfaceObject   SOref,
float    max_off,
SUMA_COMM_STRUCT   cs
 

make the size of 2 surfaces match see help -match_size option in SurfSmooth

Parameters:
SO  The surface to be modified. Adjust node coordinates of SO so that it matches the original size. Node i on SO is repositioned such that |c i| = 1/N sum(|cr j|) where c and cr are the centers of SO and SOref, respectively. N is the number of nodes that are within max_off along the surface (geodesic) from node i. j is one of the nodes neighboring i.
SOref  The surface to be matched
max_off  geodesic neighborhood to search around i
cs  the famed communication structure

Definition at line 1942 of file SUMA_GeomComp.c.

References a, SUMA_SurfaceObject::Center, free, i, SUMA_GET_OFFSET_STRUCT::LayerVect, LocalHead, SUMA_SurfaceObject::N_FaceSet, SUMA_SurfaceObject::N_Node, SUMA_GET_OFFSET_STRUCT::N_Nodes, SUMA_SurfaceObject::NodeList, SUMA_GET_OFFSET_STRUCT::OffVect, SUMA_COMM_STRUCT::Send, SUMA_append_replace_string(), SUMA_Boolean, SUMA_ENTRY, SUMA_etime(), SUMA_Extension(), SUMA_Free_getoffsets(), SUMA_getoffsets2(), SUMA_Initialize_getoffsets(), SUMA_NODE_XYZ, SUMA_POINT_AT_DISTANCE_NORM, SUMA_Recycle_getoffsets(), SUMA_RETURN, SUMA_SEG_LENGTH, SUMA_SendToSuma(), SUMA_SL_Err, SUMA_SL_Warn, and SUMA_UNIT_VEC.

01943 {
01944    static char FuncName[]={"SUMA_EquateSurfaceSize"};
01945    int i=0, j=0, cnt = 0, istrt, istp;
01946    struct timeval start_time, start_time_all;
01947    float etime_GetOffset, etime_GetOffset_all, ave_dist= 0.0, dj = 0.0, ave_dist_ref= 0.0, *a=NULL;
01948    float P2[2][3], U[3], Un;
01949    SUMA_GET_OFFSET_STRUCT *OffS = NULL;
01950    SUMA_Boolean LocalHead = NOPE;
01951    
01952    SUMA_ENTRY;
01953 
01954    if (!SO || !SOref) { SUMA_SL_Err("NULL surfaces"); SUMA_RETURN(NOPE); }
01955    if (SO->N_Node != SOref->N_Node || SO->N_FaceSet != SOref->N_FaceSet) { SUMA_SL_Err("Surfaces not isotopic"); SUMA_RETURN(NOPE); }
01956    
01957    if (LocalHead) {
01958       fprintf(SUMA_STDERR, "%s:\n"
01959                            " SO    Center: %f, %f, %f\n"
01960                            " SOref Center: %f, %f, %f\n"
01961                            " max_off = %f\n", FuncName, 
01962                            SO->Center[0], SO->Center[1], SO->Center[2],
01963                            SOref->Center[0], SOref->Center[1], SOref->Center[2],
01964                            max_off);  
01965    }
01966       
01967    OffS = SUMA_Initialize_getoffsets (SOref->N_Node);
01968    #ifdef FROM_THIS_NODE
01969    istrt = FROM_THIS_NODE;
01970    istp = TO_THIS_NODE+1;
01971    #else
01972    istrt = 0;
01973    istp = SOref->N_Node;
01974    #endif
01975    for (i =istrt ; i<istp; ++i) {
01976       if (i == 0) {
01977          SUMA_etime(&start_time,0);
01978       }
01979       SUMA_getoffsets2 (i, SOref, max_off, OffS, NULL, 0);
01980       /* find average distance between nodes within offset and center of surface */
01981       a = &(SOref->NodeList[3*i]); SUMA_SEG_LENGTH(a, SOref->Center, ave_dist_ref); 
01982       cnt = 1;
01983       #ifdef FROM_THIS_NODE
01984             fprintf(SUMA_STDERR, "%s: Considering the following %d neighbors to:\n"
01985                                  "i=%d; [%f, %f, %f]; d[%d] = %f\n", FuncName, OffS->N_Nodes,
01986                                     i, SOref->NodeList[3*i], SOref->NodeList[3*i+1], SOref->NodeList[3*i+2], 
01987                                     cnt, ave_dist_ref);
01988       #endif
01989       for (j=0; j<OffS->N_Nodes; ++j)
01990       {
01991          
01992          if (i!=j && OffS->LayerVect[j] >= 0 && OffS->OffVect[j] <= max_off)
01993          {
01994             
01995             a = &(SOref->NodeList[3*j]); SUMA_SEG_LENGTH(a, SOref->Center, dj);
01996             ave_dist_ref += dj;
01997             ++cnt;
01998             #ifdef FROM_THIS_NODE
01999                fprintf(SUMA_STDERR, ""
02000                                  "j=%d; [%f, %f, %f]; d[%d] = %f\n",
02001                                     j, SOref->NodeList[3*j], SOref->NodeList[3*j+1], SOref->NodeList[3*j+2], 
02002                                     cnt, dj);
02003             #endif
02004          }
02005       }
02006       ave_dist_ref /=  (float)cnt;
02007       /* move node i to the reference average location
02008       Do not travel along normals, you should travel along
02009       radial direction Center-->node*/
02010       a = &(SO->NodeList[3*i]); SUMA_UNIT_VEC(SO->Center, a, U, Un);
02011       if (Un) {
02012          SUMA_POINT_AT_DISTANCE_NORM(U, SO->Center, ave_dist_ref, P2);
02013          SO->NodeList[3*i] = P2[0][0]; SO->NodeList[3*i+1] = P2[0][1]; SO->NodeList[3*i+2] = P2[0][2];
02014       } else {
02015             SUMA_SL_Err("Identical points!\n"
02016                         "No coordinates modified");
02017       }
02018       
02019       if (LocalHead) {
02020          if (! (i%999)) {
02021             a = &(SO->NodeList[3*i]);
02022             SUMA_SEG_LENGTH(a, SOref->Center, dj);
02023             fprintf(SUMA_STDERR, "%s:\n"
02024                            "node i=%d, avg_dist_ref = %f\ncnt = %d\n"
02025                            "Check on P2: New dist =%f ?=? %f\n", 
02026                            FuncName, i, ave_dist_ref, cnt, dj, ave_dist_ref);
02027             etime_GetOffset = SUMA_etime(&start_time,1);
02028             fprintf(SUMA_STDERR, "%s: Search to %f mm took %f seconds for %d nodes.\n"
02029                   "Projected completion time: %f minutes\n",
02030                   FuncName, max_off, etime_GetOffset, i+1,
02031                   etime_GetOffset * SO->N_Node / 60.0 / (i+1));
02032          }
02033       }
02034       if (! (i%99) && cs) {
02035          if (cs->Send) { /* send the first monster (it's SOref  "in SUMA" that's being modified on the fly*/
02036             if (!SUMA_SendToSuma (SOref, cs, (void *)SO->NodeList, SUMA_NODE_XYZ, 1)) {
02037             SUMA_SL_Warn("Failed in SUMA_SendToSuma\nCommunication halted.");
02038             }
02039          }
02040       }
02041       
02042       #ifdef FROM_THIS_NODE
02043       {
02044          FILE *fid=NULL;
02045          char *outname=NULL, tmp[20];
02046          int ii;
02047          if (cs->Send) { /* send the first monster (it's SOref that's being modified on the fly*/
02048             if (!SUMA_SendToSuma (SOref, cs, (void *)SO->NodeList, SUMA_NODE_XYZ, 1)) {
02049             SUMA_SL_Warn("Failed in SUMA_SendToSuma\nCommunication halted.");
02050             }
02051          }
02052          sprintf(tmp,"offset_n%d", FROM_THIS_NODE);
02053          outname = SUMA_Extension("", ".1D", YUP);
02054          outname = SUMA_append_replace_string(outname, "offset.1D", "", 1);
02055          fid = fopen(outname, "w"); free(outname); outname = NULL;
02056          if (!fid) {
02057             SUMA_SL_Err("Could not open file for writing.\nCheck file permissions, disk space.\n");
02058          } else {
02059             fprintf (fid,"#Column 1 = Node index\n"
02060                          "#column 2 = Neighborhood layer\n"
02061                          "#Column 3 = Distance from node %d\n", 99);
02062             for (ii=0; ii<SO->N_Node; ++ii) {
02063                if (OffS->LayerVect[ii] >= 0) {
02064                   fprintf(fid,"%d\t%d\t%f\n", ii, OffS->LayerVect[ii], OffS->OffVect[ii]);
02065                }
02066             }
02067             fclose(fid);
02068          }
02069          { int jnk; fprintf(SUMA_STDOUT,"Pausing, next node is %d...", i+1); jnk = getchar(); fprintf(SUMA_STDOUT,"\n"); }
02070       }
02071       #endif
02072              
02073       /* recycle offsets structure */
02074       SUMA_Recycle_getoffsets (OffS);
02075       
02076    }   
02077    
02078    /* offsets are to be freed */
02079    SUMA_Free_getoffsets(OffS); OffS = NULL;
02080    
02081    SUMA_RETURN(YUP);
02082 }

SUMA_Boolean SUMA_EquateSurfaceVolumes SUMA_SurfaceObject   SO,
SUMA_SurfaceObject   SOref,
float    tol,
SUMA_COMM_STRUCT   cs
 

inflates or deflates a surface to make the volume of one surface (SO) equal to the volume of another (SOref)

Parameters:
SO:  The surface to modify
SOref:  The reference surface
tol  (float): The acceptable difference between the two volumes
cs  (SUMA_COMM_STRUCT *): The suma communication structure

  • This function does not update the normals and other coordinate related properties for SO.
See also:
SUMA_RECOMPUTE_NORMALS

Definition at line 1756 of file SUMA_GeomComp.c.

References a, SUMA_SurfaceObject::Center, SUMA_VolDiffDataStruct::cs, i, LocalHead, SUMA_SurfaceObject::N_FaceSet, SUMA_SurfaceObject::N_Node, SUMA_SurfaceObject::NodeDim, SUMA_SurfaceObject::NodeList, SUMA_VolDiffDataStruct::SO, SUMA_VolDiffDataStruct::SOref, SUMA_BinaryZeroSearch(), SUMA_Boolean, SUMA_ENTRY, SUMA_free, SUMA_GetVolDiffRange(), SUMA_malloc, SUMA_RETURN, SUMA_SL_Err, SUMA_VolDiff(), and SUMA_VolDiffDataStruct::tmpList.

01757 {
01758    static char FuncName[]={"SUMA_EquateSurfaceVolumes"};
01759    int iter, i, iter_max, ndiv;
01760    double a, b, d;
01761    SUMA_VolDiffDataStruct fdata;
01762    SUMA_Boolean LocalHead = NOPE;
01763    
01764    SUMA_ENTRY;
01765 
01766    if (!SO || !SOref) { SUMA_SL_Err("NULL surfaces"); SUMA_RETURN(NOPE); }
01767    if (SO->N_Node != SOref->N_Node || SO->N_FaceSet != SOref->N_FaceSet) { SUMA_SL_Err("Surfaces not isotopic"); SUMA_RETURN(NOPE); }
01768    
01769    if (LocalHead) {
01770       fprintf(SUMA_STDERR, "%s:\n"
01771                            " SO    Center: %f, %f, %f\n"
01772                            " SOref Center: %f, %f, %f\n"
01773                            , FuncName, 
01774                            SO->Center[0], SO->Center[1], SO->Center[2],
01775                            SOref->Center[0], SOref->Center[1], SOref->Center[2]);  
01776    }
01777      
01778    /* fill up fdata */
01779    fdata.SO = SO; fdata.SOref = SOref; fdata.cs = cs;
01780    fdata.tmpList = (float *)SUMA_malloc(SOref->NodeDim * SOref->N_Node * sizeof(float));
01781    if (!fdata.tmpList) {
01782       SUMA_SL_Err("Failed to allocate");
01783       SUMA_RETURN(0);
01784    }
01785 
01786    if (!SUMA_GetVolDiffRange(&fdata, &a, &b)) {
01787       SUMA_SL_Err("Failed to get range");
01788       SUMA_RETURN(NOPE);
01789    }
01790    
01791    if (LocalHead) {
01792       fprintf(SUMA_STDERR,"%s:\na = %f\tb=%f\n", FuncName, a, b);
01793    }      
01794    SUMA_BinaryZeroSearch(a, b, SUMA_VolDiff, &fdata, 500, tol);  
01795    
01796    /* now make the new node list be SO's thingy*/
01797    SUMA_free(SO->NodeList); SO->NodeList = fdata.tmpList; fdata.tmpList = NULL;
01798        
01799    SUMA_RETURN(YUP);
01800 }

byte* SUMA_FillToVoxelMask byte   ijkmask,
int    ijkseed,
int    ni,
int    nj,
int    nk,
int *    N_in,
byte   usethisisin
 

Function to fill the volume enclose in a mask.

Parameters:
ijkmask  (byte *) mask (nvox x 1), typically the result of the intersection of a closed surface with a volume
ijkseed  (int) 1D index of seed voxel. Must be inside the mask and not a part of it.
ni  (int) number of voxels in the i direction
nj  (int) number of voxels in the j direction
nk  (int) number of voxels in the k direction
N_in  (int *) to contain the number of voxels inside the mask
m usethisisin (byte *)store results in this mask vector rather than allocate for a new one.
Parameters:
fillhole  (int) fills small holes, intended to correct for volume masks created from surfaces with minor intersections
Returns:
isin (byte *) a nvox x 1 vector containing: 0: for voxels outside mask 1: for voxels inside mask

Definition at line 481 of file SUMA_GeomComp.c.

References DListElmt_::data, dlist_destroy(), dlist_head, dlist_init(), dlist_ins_next(), dlist_remove(), dlist_size, dlist_tail, i, itmp, LocalHead, SUMA_1D_2_3D_index, SUMA_Boolean, SUMA_calloc, SUMA_ENTRY, SUMA_free, SUMA_malloc, SUMA_RETURN, SUMA_SL_Crit, SUMA_SL_Err, SUMA_VOX_NEIGHB_FACE, and SUMA_VoxelNeighbors().

Referenced by SUMA_SurfGridIntersect().

00482 {
00483    static char FuncName[]={"SUMA_FillToVoxelMask"};
00484    byte *isin = NULL, *visited=NULL;
00485    DList*candlist=NULL;
00486    DListElmt *dothiselm=NULL;
00487    int dothisvoxel, itmp;
00488    int nl[50], N_n, in ,neighb, nijk, i, j, k, nij;
00489    SUMA_Boolean LocalHead = NOPE;
00490    
00491    SUMA_ENTRY;
00492    
00493    *N_in = 0;
00494    
00495    if (!ijkmask) {
00496       SUMA_SL_Err("Nothing to do");
00497       SUMA_RETURN(NULL);
00498    }
00499    if (ijkmask[ijkseed]) {
00500       SUMA_SL_Err("Seed is on mask. Bad business.");
00501       SUMA_RETURN(NULL);
00502    }
00503    
00504    nij = ni * nj;
00505    nijk = ni * nj * nk;
00506    
00507    if (LocalHead) {
00508       SUMA_1D_2_3D_index (ijkseed, i, j, k, ni, nij);
00509       fprintf(SUMA_STDERR,"%s:\nSeed is %d %d %d\n", FuncName, i, j, k); 
00510    }
00511    candlist = (DList*)SUMA_malloc(sizeof(DList));
00512    visited = (byte *)SUMA_calloc(nijk, sizeof(byte));
00513    if (!visited || !candlist) {
00514       SUMA_SL_Crit("Failed to allocate for visited or candlist");  
00515       SUMA_RETURN(NULL);  
00516    }
00517    
00518    if (usethisisin) isin = usethisisin;
00519    else {
00520       isin = (byte *)SUMA_calloc(nijk, sizeof(byte));
00521       if (!isin) {
00522          SUMA_SL_Crit("Failed to allocate");
00523          SUMA_RETURN(NULL);
00524       }
00525    }
00526    
00527    dothisvoxel = ijkseed;
00528    dlist_init(candlist, NULL);
00529    
00530    
00531    isin[dothisvoxel] = 1; ++(*N_in); /* Add voxel to cluster */
00532    visited[dothisvoxel] = 1;  
00533    dlist_ins_next(candlist, dlist_tail(candlist), (void *)dothisvoxel); /* Add voxel as next candidate*/
00534    
00535    while (dlist_size(candlist)) {
00536       /* find neighbors in its vicinity */
00537       dothiselm = dlist_head(candlist); dothisvoxel = (int) dothiselm->data;
00538       N_n = SUMA_VoxelNeighbors (dothisvoxel, ni, nj, nk, SUMA_VOX_NEIGHB_FACE, nl);
00539       /* remove node from candidate list */
00540       dlist_remove(candlist, dothiselm, (void*)&itmp);
00541       /* search to see if any are to be assigned */
00542       for (in=0; in<N_n; ++in) { 
00543          neighb = nl[in];
00544          if (!ijkmask[neighb]) {
00545             isin[neighb] = 1; ++(*N_in); /* Add voxel to cluster */
00546             /* mark it as a candidate if it has not been visited as a candidate before */
00547             if (!visited[neighb]) {
00548                dlist_ins_next(candlist, dlist_tail(candlist), (void *)neighb);
00549                visited[neighb] = 1;   
00550             }
00551          }
00552       }
00553    }
00554    
00555    if (visited) SUMA_free(visited); visited = NULL;
00556    if (candlist) { dlist_destroy(candlist); SUMA_free(candlist); candlist  = NULL; }
00557 
00558    
00559    SUMA_RETURN(isin);
00560 }

int SUMA_Find_Edge_Nhost SUMA_EDGE_LIST   EL,
int *    IsInter,
int    N_IsInter,
int *    i,
int    Nhost
 

Finds an edge that has Nhost hosting triangles. Only the edges indexed in IsInter are examined.

E = SUMA_Find_Edge_N_Host (EL, IsInter, N_IsInter, Nhost);

Parameters:
EL  (SUMA_EDGE_LIST *) Complete Edge list structure for surface
IsInter  (int *) vector containing indices into EL->EL matrix which contains the EdgeList
N_IsInter  (int) number of elements in IsInter
kedge  (int *) pointer to index into IsInter where E was found
Nhost  number of hosting triangles (should be 2 for a closed surface, 1 for edge edges and more than 2 for errors in tessellation
Returns:
E (int) index into EL->EL of the first edge (of those listed in IsInter) encountered that has N hosting triangles. -1 is returned if no edges are found
This function is meant to be used with SUMA_Surf_Plane_Intersect

Definition at line 6787 of file SUMA_GeomComp.c.

References SUMA_EDGE_LIST::ELps, i, SUMA_ENTRY, and SUMA_RETURN.

Referenced by SUMA_AssignTriBranch().

06788 {
06789    static char FuncName[]={"SUMA_Find_Edge_Nhost"};
06790    
06791    SUMA_ENTRY;
06792 
06793    for (*i=0; *i < N_IsInter; ++(*i)) {
06794       if (EL->ELps[IsInter[*i]][2] == Nhost) SUMA_RETURN (IsInter[*i]);
06795    }
06796    
06797    SUMA_RETURN (-1);
06798 
06799 }

SUMA_OFFSET_STRUCT* SUMA_FormNeighbOffset SUMA_SurfaceObject   SO,
float    OffsetLim
 

creates a vector of node neighbors structures such that: OffS = SUMA_FormNeighbOffset ( SUMA_SurfaceObject *SO, float OffsetLim);

Parameters:
OffS  (SUMA_OFFSET_STRUCT *) SO->Node x 1 vector of structures OffS[i] is a structure containing node neighbors of node i OffS[i].N_Neighb (int) number of neighbors of node i OffS[i].Neighb_ind (int *) OffS[i].N_Neighb x 1 vector containing nodes neighboring node i OffS[i].Neighb_dist (float *) OffS[i].N_Neighb x 1 vector containing node distances from node i. These are the shortes distances ON THE GRAPH. The distances might be larger than OffsetLim because the child function SUMA_getoffsets2 does so.
OffsetLim  (float) maximal inclusive neighbor distance. In reality, some nodes may be farther apart. But all nodes closer than OffsetLim to each node will be included
  • NOTE: This function will chew up a lot of memory, real quick. An approximate equation for the size needed for OffS: (mean_N_Neighb_per_Node * 8 + 12) * SO->N_Node Bytes With OffsetLim = 10 and a FreeSurfer surface of 150'000 nodes, the average number of neighbors per node is ~800. Which means 962MB for the returned structure. When memory usage is this high, you should consider using SUMA_getoffsets2 repeatedly for each node, as is done in this function.

Definition at line 2699 of file SUMA_GeomComp.c.

References SUMA_SurfaceObject::FN, free, i, SUMA_GET_OFFSET_STRUCT::layers, SUMA_GET_OFFSET_STRUCT::LayerVect, LocalHead, SUMA_GET_OFFSET_STRUCT::N_layers, SUMA_SurfaceObject::N_Node, SUMA_NODE_NEIGHB_LAYER::N_NodesInLayer, SUMA_NODE_NEIGHB_LAYER::NodesInLayer, SUMA_GET_OFFSET_STRUCT::OffVect, SUMA_append_replace_string(), SUMA_Boolean, SUMA_ENTRY, SUMA_etime(), SUMA_Extension(), SUMA_Free_getoffsets(), SUMA_getoffsets2(), SUMA_Initialize_getoffsets(), SUMA_malloc, SUMA_Recycle_getoffsets(), SUMA_RETURN, and SUMA_SL_Err.

Referenced by SUMA_Offset_GeomSmooth().

02700 {
02701    static char FuncName[]={"SUMA_FormNeighbOffset"};
02702    int i, ii, il, jl, noffs, ShowNode = 4;
02703    SUMA_GET_OFFSET_STRUCT *OffS = NULL;
02704    struct  timeval start_time;
02705    float etime_GetOffset, mean_N_Neighb, dist, dist_norm;   
02706    SUMA_OFFSET_STRUCT *OffS_out=NULL;
02707    SUMA_Boolean LocalHead = NOPE;
02708    
02709    SUMA_ENTRY;
02710    if (!SO) { SUMA_SL_Err("NULL SO"); SUMA_RETURN(NULL); }
02711    if (!SO->FN) {
02712       SUMA_SL_Err("NULL SO->FN");
02713       SUMA_RETURN(NULL);
02714    }
02715    OffS_out = (SUMA_OFFSET_STRUCT *)SUMA_malloc(SO->N_Node * sizeof(SUMA_OFFSET_STRUCT));
02716    
02717    SUMA_etime(&start_time,0);
02718    
02719    OffS = SUMA_Initialize_getoffsets (SO->N_Node);
02720    mean_N_Neighb = 0;
02721    dist_norm = 1.1 * OffsetLim;
02722    for (i=0; i < SO->N_Node; ++i) {
02723       SUMA_getoffsets2 (i, SO, OffsetLim, OffS, NULL, 0);
02724       /* Now store all the relevant info in OffS in OffS_out[i] */
02725       OffS_out[i].N_Neighb = 0; 
02726       for (il=1; il<OffS->N_layers; ++il) {
02727          OffS_out[i].N_Neighb += OffS->layers[il].N_NodesInLayer;
02728       }
02729       OffS_out[i].Neighb_ind = (int *)SUMA_malloc(OffS_out[i].N_Neighb * sizeof(int));
02730       OffS_out[i].Neighb_dist = (float *)SUMA_malloc(OffS_out[i].N_Neighb * sizeof(float));
02731       mean_N_Neighb += OffS_out[i].N_Neighb;
02732       noffs = 0;
02733       for (il=1; il<OffS->N_layers; ++il) {
02734          for (jl=0; jl<OffS->layers[il].N_NodesInLayer; ++jl) {
02735             OffS_out[i].Neighb_ind[noffs] = OffS->layers[il].NodesInLayer[jl]; 
02736             #if 1
02737             /* don't play fancy with the weights here */
02738             OffS_out[i].Neighb_dist[noffs] = OffS->OffVect[OffS_out[i].Neighb_ind[noffs]];
02739             #else
02740             dist = OffS->OffVect[OffS_out[i].Neighb_ind[noffs]];
02741             if (dist > OffsetLim) OffS_out[i].Neighb_dist[noffs] = 0;
02742             else OffS_out[i].Neighb_dist[noffs] = (dist ); 
02743             #endif
02744             ++noffs;
02745          }
02746       }
02747       
02748       /* Show me the offsets for one node*/
02749       if (0) {
02750          if (i == ShowNode) {
02751             FILE *fid=NULL;
02752             char *outname=NULL;
02753             outname = SUMA_Extension("SomethingOffset", ".1D", YUP);
02754             outname = SUMA_append_replace_string(outname, "offset.1D", "", 1);
02755             fid = fopen(outname, "w"); free(outname); outname = NULL;
02756             if (!fid) {
02757                SUMA_SL_Err("Could not open file for writing.\nCheck file permissions, disk space.\n");
02758             } else {
02759                fprintf (fid,"#Column 1 = Node index\n"
02760                             "#column 2 = Neighborhood layer\n"
02761                             "#Column 3 = Distance from node %d\n", ShowNode);
02762                for (ii=0; ii<SO->N_Node; ++ii) {
02763                   if (OffS->LayerVect[ii] >= 0) {
02764                      fprintf(fid,"%d\t%d\t%f\n", ii, OffS->LayerVect[ii], OffS->OffVect[ii]);
02765                   }
02766                }
02767                fclose(fid);
02768             }
02769          }
02770       }
02771                
02772       if (i == 99) {
02773          etime_GetOffset = SUMA_etime(&start_time,1);
02774          fprintf(SUMA_STDERR, "%s: Search to %f mm took %f seconds for %d nodes.\n"
02775                               "Projected completion time: %f minutes\n"
02776                               "Projected memory need for structure %f MB", 
02777                               FuncName, OffsetLim, etime_GetOffset, i+1, 
02778                               etime_GetOffset * SO->N_Node / 60.0 / (i+1),
02779                               (mean_N_Neighb / (i+1) * 8 + 12)* SO->N_Node/1000000.0);
02780       }
02781       SUMA_Recycle_getoffsets (OffS);
02782    }
02783    SUMA_Free_getoffsets(OffS); OffS = NULL;
02784    
02785    etime_GetOffset = SUMA_etime(&start_time,1);
02786    fprintf(SUMA_STDERR, "%s: Search to %f mm took %f seconds for %d nodes.\n"
02787                         "Mean number of neighbors per node: %f\n",
02788                         FuncName, OffsetLim, etime_GetOffset, SO->N_Node, mean_N_Neighb / SO->N_Node);
02789    
02790    SUMA_RETURN(OffS_out);           
02791 } 

SUMA_GET_OFFSET_STRUCT* SUMA_Free_getoffsets SUMA_GET_OFFSET_STRUCT   OffS
 

free memory associated with SUMA_GET_OFFSET_STRUCT * struct

Parameters:
OffS  (SUMA_GET_OFFSET_STRUCT *) Offset strcture
Returns:
NULL
See also:
SUMA_Recycle_getoffsets , SUMA_Initialize_getoffsets

Definition at line 858 of file SUMA_GeomComp.c.

References i, SUMA_GET_OFFSET_STRUCT::layers, SUMA_GET_OFFSET_STRUCT::LayerVect, LocalHead, SUMA_GET_OFFSET_STRUCT::N_layers, SUMA_GET_OFFSET_STRUCT::OffVect, SUMA_Boolean, SUMA_ENTRY, SUMA_free, and SUMA_RETURN.

Referenced by calcWithOffsets(), SUMA_Build_Cluster_From_Node(), SUMA_Build_Cluster_From_Node_NoRec(), SUMA_ClusterCenterofMass(), SUMA_EquateSurfaceSize(), SUMA_FormNeighbOffset(), and SUMA_getoffsets2().

00859 {
00860    static char FuncName[]={"SUMA_Free_getoffsets"};
00861    int i = 0;
00862    static SUMA_Boolean LocalHead = NOPE;
00863    
00864    SUMA_ENTRY;
00865    
00866    if (!OffS) SUMA_RETURN(NULL);
00867    
00868    if (OffS->layers) {
00869       for (i=0; i< OffS->N_layers; ++i) if (OffS->layers[i].NodesInLayer) SUMA_free(OffS->layers[i].NodesInLayer);
00870       SUMA_free(OffS->layers);
00871    }
00872    
00873    if (OffS->OffVect) SUMA_free(OffS->OffVect);
00874    if (OffS->LayerVect) SUMA_free(OffS->LayerVect);
00875    SUMA_free(OffS); OffS = NULL;
00876    
00877    SUMA_RETURN(NULL);
00878 }

SUMA_OFFSET_STRUCT* SUMA_free_NeighbOffset SUMA_SurfaceObject   SO,
SUMA_OFFSET_STRUCT   OffS_out
 

frees what is created by SUMA_FormNeighbOffset

See also:
SUMA_FormNeighbOffset

Definition at line 2798 of file SUMA_GeomComp.c.

References i, SUMA_SurfaceObject::N_Node, SUMA_ENTRY, SUMA_free, SUMA_RETURN, and SUMA_S_Err.

Referenced by SUMA_Offset_GeomSmooth().

02799 {
02800    static char FuncName[]={"SUMA_free_NeighbOffset"};
02801    int i;
02802    SUMA_ENTRY;
02803 
02804    if (!SO) {
02805       SUMA_S_Err("NULL SO!");
02806       SUMA_RETURN(NULL);
02807    }
02808    if (!OffS_out) SUMA_RETURN(NULL);
02809    for (i=0; i < SO->N_Node; ++i) {
02810       OffS_out[i].N_Neighb = 0;
02811       if (OffS_out[i].Neighb_dist) SUMA_free(OffS_out[i].Neighb_dist); OffS_out[i].Neighb_dist = NULL;
02812       if (OffS_out[i].Neighb_ind) SUMA_free(OffS_out[i].Neighb_ind); OffS_out[i].Neighb_ind = NULL;
02813    }
02814    SUMA_free(OffS_out); 
02815    SUMA_RETURN(NULL);
02816 }

void SUMA_Free_Offset_ll_Datum void *    data
 

*** SegPres added Jul 08 04, ZSS bug before ...

Definition at line 1141 of file SUMA_GeomComp.c.

References dt, SUMA_ENTRY, SUMA_free, and SUMA_RETURNe.

Referenced by SUMA_getoffsets_ll().

01142 {
01143    static char FuncName[]={"SUMA_Free_Offset_ll_Datum"};
01144    SUMA_OFFSET_LL_DATUM *dt;
01145    
01146    SUMA_ENTRY;
01147    
01148    if (data) {
01149       dt = (SUMA_OFFSET_LL_DATUM *)data; 
01150       SUMA_free(dt);
01151    }
01152    
01153    SUMA_RETURNe;
01154 }   

void SUMA_free_SPI SUMA_SURF_PLANE_INTERSECT   SPI
 

free the SPI structure

Definition at line 6620 of file SUMA_GeomComp.c.

References SUMA_SURF_PLANE_INTERSECT::IntersEdges, SUMA_SURF_PLANE_INTERSECT::IntersNodes, SUMA_SURF_PLANE_INTERSECT::IntersTri, SUMA_SURF_PLANE_INTERSECT::isEdgeInters, SUMA_SURF_PLANE_INTERSECT::isNodeInMesh, SUMA_SURF_PLANE_INTERSECT::isTriHit, SUMA_ENTRY, SUMA_free, and SUMA_RETURNe.

Referenced by SUMA_Surf_Plane_Intersect(), and SUMA_Surf_Plane_Intersect_ROI().

06621 {
06622    static char FuncName[]={"SUMA_free_SPI"};
06623    
06624    SUMA_ENTRY;
06625    
06626    if (!SPI) SUMA_RETURNe;
06627    if (SPI->IntersTri) SUMA_free(SPI->IntersTri);
06628    if (SPI->IntersNodes) SUMA_free(SPI->IntersNodes);
06629    if (SPI->IntersEdges) SUMA_free(SPI->IntersEdges);
06630    if (SPI->isNodeInMesh) SUMA_free(SPI->isNodeInMesh); 
06631    if (SPI->isTriHit) SUMA_free (SPI->isTriHit);
06632    if (SPI->isEdgeInters) SUMA_free (SPI->isEdgeInters);
06633      
06634    if (SPI) SUMA_free(SPI);
06635    
06636    SUMA_RETURNe;
06637 }

void SUMA_free_STB SUMA_TRI_BRANCH   Bv,
int    N_Bv
 

Function to free a vector of SUMA_TRI_BRANCH structures.

Definition at line 6558 of file SUMA_GeomComp.c.

References i, SUMA_ENTRY, SUMA_free, and SUMA_RETURNe.

06559 {
06560 
06561    static char FuncName[]={"SUMA_free_STB"};
06562    int i;
06563    
06564    SUMA_ENTRY;
06565    
06566    for (i=0; i < N_Bv; ++i) {
06567       if (Bv[i].list) SUMA_free(Bv[i].list);
06568    }
06569    if (Bv) SUMA_free(Bv);
06570    
06571    SUMA_RETURNe;
06572     
06573 }

SUMA_Boolean SUMA_freePatch SUMA_PATCH   Patch
 

ans = SUMA_freePatch (SUMA_PATCH *Patch) ; frees Patch pointer

Parameters:
Patch  (SUMA_PATCH *) Surface patch pointer \ret ans (SUMA_Boolean)
See also:
SUMA_getPatch

Definition at line 5298 of file SUMA_GeomComp.c.

References SUMA_PATCH::FaceSetIndex, SUMA_PATCH::FaceSetList, SUMA_PATCH::nHits, SUMA_Boolean, SUMA_ENTRY, SUMA_free, and SUMA_RETURN.

Referenced by main(), SUMA_GetContour(), and SUMA_Pattie_Volume().

05299 {
05300    static char FuncName[]={"SUMA_freePatch"};
05301    
05302    SUMA_ENTRY;
05303    
05304    
05305    if (Patch->FaceSetIndex) SUMA_free(Patch->FaceSetIndex);
05306    if (Patch->FaceSetList) SUMA_free(Patch->FaceSetList);
05307    if (Patch->nHits) SUMA_free(Patch->nHits);
05308    if (Patch) SUMA_free(Patch);
05309    SUMA_RETURN(YUP);
05310    
05311 }

SUMA_VTI* SUMA_FreeVTI SUMA_VTI   vti
 

Definition at line 165 of file SUMA_GeomComp.c.

References free, i, SUMA_VTI::IntersectedVoxels, SUMA_VTI::N_IntersectedVoxels, SUMA_VTI::N_TriIndex, SUMA_ENTRY, SUMA_free, SUMA_RETURN, and SUMA_VTI::TriIndex.

00166 {
00167    static char FuncName[]={"SUMA_FreeVTI"};
00168    int i;
00169    
00170    SUMA_ENTRY;
00171    
00172    if (!vti) SUMA_RETURN(NULL);
00173    if (vti->TriIndex) SUMA_free(vti->TriIndex);
00174    if (vti->IntersectedVoxels) {
00175       for (i=0; i<vti->N_TriIndex; ++i) {
00176          if (vti->IntersectedVoxels[i]) free(vti->IntersectedVoxels[i]);
00177       }
00178       SUMA_free(vti->IntersectedVoxels);
00179    }
00180    if (vti->N_IntersectedVoxels) SUMA_free(vti->N_IntersectedVoxels);    
00181    SUMA_free(vti);
00182      
00183    SUMA_RETURN(NULL);
00184 }     

SUMA_Boolean SUMA_FromIntEdgeToIntEdge int    Tri,
int    E1,
int    E2,
SUMA_EDGE_LIST   EL,
SUMA_SURF_PLANE_INTERSECT   SPI,
int    Ny,
SUMA_Boolean   Visited,
float *    d,
float    dmax,
int *    tPath,
int *    N_tPath
 

This function moves from one intersected edge to the next until a certain node is encountered or a a certain distance is exceeded. By intersected edge, I mean an edge of the surface's mesh that was intersected by a plane.

ans = SUMA_FromIntEdgeToIntEdge (int Tri, int E1, int E2, SUMA_EDGE_LIST *EL, SPI, int Ny, Visited, float *d, float dmax, int *tPath, int *N_tPath);

Parameters:
Tri  (int) index of triangle to start with (index into SO->FaceSetList)
E1  (int) index of edge in Tri to start from
E2  (int) index of edge in Tri to move in the direction of (Both E1 and E2 must be intersected edges)
EL  (SUMA_EDGE_LIST *) pointer to the edge list structure, typically SO->EL
SPI  (SUMA_SURF_PLANE_INTERSECT *) pointer to structure containing intersection of plane with surface
Ny  (int) node index to stop at (index into SO->NodeList)
Visited  (SUMA_Boolean *) pointer to vector (SO->N_FaceSet elements) that keeps track of triangles visited. This vector should be all NOPE when you first call this function.
d  (float *) pointer to total distance from first intersected edge E1 to the last edge that contains E2
dmax  (float) maximum distance to go for before reversing and going in the other direction. Typically this measure should be a bit larger than the distance of a Dijkstra path although you should never get a distance that is larger than the Dijkstra path.
tPath  (int *) vector of indices of triangles visited from first edge to last edge (make sure you allocate a bundle for tPath)
N_tPath  (int *) number of elements in tPath
Returns:
ans (SUMA_Boolean) YUP/NOPE, for success/failure.
NOTE: This function is recursive.

See also:
SUMA_Surf_Plane_Intersect , SUMA_IntersectionStrip

Definition at line 7483 of file SUMA_GeomComp.c.

References SUMA_EDGE_LIST::EL, SUMA_SURF_PLANE_INTERSECT::IntersNodes, SUMA_SURF_PLANE_INTERSECT::isEdgeInters, SUMA_SURF_PLANE_INTERSECT::isTriHit, LocalHead, SUMA_Boolean, SUMA_ENTRY, SUMA_Get_Incident(), SUMA_isSameEdge(), SUMA_RETURN, and SUMA_EDGE_LIST::Tri_limb.

Referenced by SUMA_IntersectionStrip().

07485 {  static char FuncName[]={"SUMA_FromIntEdgeToIntEdge"};
07486    int Tri2 = 0, cnt, Incident[5], N_Incident;
07487    float dx, dy, dz;
07488    SUMA_Boolean Found, LocalHead = NOPE;
07489    
07490    SUMA_ENTRY;
07491 
07492    if (Tri < 0 || E1 < 0 || E2 < 0) {
07493       fprintf (SUMA_STDERR, "Error %s: Tri (%d) or E1 (%d) or E2 (%d) is negative!\n", FuncName, Tri, E1, E2);
07494       SUMA_RETURN (NOPE);
07495    }
07496    
07497    
07498    dx = (SPI->IntersNodes[3*E2] - SPI->IntersNodes[3*E1]);
07499    dy = (SPI->IntersNodes[3*E2+1] - SPI->IntersNodes[3*E1+1]);
07500    dz = (SPI->IntersNodes[3*E2+2] - SPI->IntersNodes[3*E1+2]);
07501    if (LocalHead) {
07502       fprintf (SUMA_STDERR, "%s: Entered - Tri %d, E1 %d [%d %d], E2 %d [%d %d]\n\tdx = %f dy = %f dz = %f\n", 
07503          FuncName, Tri, E1, EL->EL[E1][0], EL->EL[E1][1], E2, EL->EL[E2][0], EL->EL[E2][1], dx, dy, dz);
07504    }
07505    *d += sqrt( dx * dx + dy * dy + dz * dz);
07506    
07507    if (*d > dmax) {
07508       /* path already longer than Dijkstra path, no need to search further in this direction, get out with this d value */
07509       fprintf (SUMA_STDERR, "%s: Path longer than dmax. Returning.\n", FuncName);
07510       SUMA_RETURN (YUP);
07511    }
07512    
07513    if (EL->EL[E2][0] == Ny || EL->EL[E2][1] == Ny) {
07514       fprintf (SUMA_STDERR, "%s: Found Ny, d = %f\n", FuncName, *d);
07515       if (!Visited[Tri]) {
07516          /* add triangle to path */
07517          tPath[*N_tPath] = Tri;
07518          ++*N_tPath;
07519       }
07520       SUMA_RETURN (YUP);
07521    } else if (Visited[Tri]) {
07522       fprintf (SUMA_STDERR, "Error %s: Triangle %d already visited.\n",FuncName, Tri); 
07523       SUMA_RETURN (NOPE);
07524    }
07525      
07526    /* mark triangle as visited */
07527    if (LocalHead) fprintf (SUMA_STDERR, "%s: Marking triangle %d and adding %dth element to tPath.\n", FuncName, Tri, *N_tPath);
07528    Visited[Tri] = YUP;
07529    
07530    /* add triangle to path */
07531    tPath[*N_tPath] = Tri;
07532    ++*N_tPath;
07533    
07534    /* now get the second intersected triangle, incident to E2 */
07535    if (LocalHead) fprintf (SUMA_STDERR, "%s: Searching for triangles incident to E2 %d.\n", FuncName, E2);
07536    if (!SUMA_Get_Incident(EL->EL[E2][0], EL->EL[E2][1], EL, Incident, &N_Incident, 1)) {
07537       fprintf (SUMA_STDERR,"Error %s: Failed to get Incident triangles.\n", FuncName);
07538       SUMA_RETURN (NOPE);
07539    }
07540    
07541    /* find Tri2 such that Tri2 != Tri and Tri2 is an intersected triangle */
07542    cnt = 0;
07543    Found = NOPE;
07544    while (cnt < N_Incident && !Found) {
07545       if (SPI->isTriHit[Incident[cnt]] && Incident[cnt] != Tri && !Visited[Incident[cnt]]) {
07546          Found = YUP;
07547          Tri2 = Incident[cnt];
07548       }
07549       ++cnt;
07550    }
07551    
07552    if (!Found) {
07553       fprintf (SUMA_STDERR,"Error %s: Could not find next triangle.\n", FuncName);
07554       SUMA_RETURN (NOPE);
07555    }
07556    
07557    Tri = Tri2;
07558    E1 = E2;
07559    
07560    /* now find the new E2 */
07561    if (LocalHead) fprintf (SUMA_STDERR, "%s: Finding new E2.\n", FuncName);
07562    
07563    if (!SUMA_isSameEdge (EL, EL->Tri_limb[Tri][0], E1) && SPI->isEdgeInters[EL->Tri_limb[Tri][0]]) {
07564       E2 = EL->Tri_limb[Tri][0];
07565    }else if (!SUMA_isSameEdge (EL, EL->Tri_limb[Tri][1], E1) && SPI->isEdgeInters[EL->Tri_limb[Tri][1]]) {
07566       E2 = EL->Tri_limb[Tri][1];
07567    }else if (!SUMA_isSameEdge (EL, EL->Tri_limb[Tri][2], E1) && SPI->isEdgeInters[EL->Tri_limb[Tri][2]]) {
07568       E2 = EL->Tri_limb[Tri][2];
07569    }else {
07570       fprintf (SUMA_STDERR,"Error %s: No E2 found.\n", FuncName);
07571       SUMA_RETURN (NOPE);
07572    }
07573    
07574    /* call the same function again */
07575    if (!SUMA_FromIntEdgeToIntEdge (Tri, E1, E2, EL, SPI, Ny, Visited, d, dmax, tPath, N_tPath)) {
07576       fprintf (SUMA_STDERR,"Error %s: Failed in SUMA_FromIntEdgeToIntEdge.\n", FuncName);
07577       SUMA_RETURN (NOPE);
07578    }
07579    
07580    SUMA_RETURN (YUP);
07581 }

SUMA_Boolean SUMA_GetAreaDiffRange SUMA_AreaDiffDataStruct   fdata,
double *    ap,
double *    bp
 

a function to find two values a and b such that DA(a) is < 0 and DA(b) is > 0 These two starting points are used for the optimization function SUMA_BinaryZeroSearch

Definition at line 1592 of file SUMA_GeomComp.c.

References SUMA_AreaDiffDataStruct::A, a, SUMA_AreaDiffDataStruct::Aref, LocalHead, SUMA_AreaDiffDataStruct::R, SUMA_AreaDiffDataStruct::Rref, SUMA_AreaDiffDataStruct::SO, SUMA_AreaDiffDataStruct::SOref, SUMA_Boolean, SUMA_ENTRY, SUMA_LH, SUMA_Mesh_Area(), SUMA_NewAreaAtRadius(), SUMA_RETURN, SUMA_SL_Err, SUMA_SO_RADIUS, and SUMA_AreaDiffDataStruct::tmpList.

Referenced by SUMA_EquateSurfaceAreas().

01593 {
01594    static char FuncName[]={"SUMA_GetAreaDiffRange"};
01595    double a = 0.0, b = 0.0, nat=0, nbt=0, An, Bn;
01596    SUMA_Boolean LocalHead = NOPE;
01597 
01598    SUMA_ENTRY;
01599 
01600    /* decide on segment range */
01601    fdata->Aref = fabs((double)SUMA_Mesh_Area(fdata->SOref, NULL, -1));
01602    SUMA_SO_RADIUS(fdata->SOref, fdata->Rref);
01603    fdata->A = fabs((double)SUMA_Mesh_Area(fdata->SO, NULL, -1));
01604    SUMA_SO_RADIUS(fdata->SO, fdata->R);
01605 
01606    /* a very simple range setting. might very well fail at times */
01607    if (fdata->Aref - fdata->A < 0) { 
01608       a = fdata->R; /* choose 'a' such that Aref - A is < 0, Choose b later*/
01609       An = fdata->A;
01610       b = fdata->Rref;
01611       do {
01612          SUMA_LH("Looking for b");
01613          b *= 1.3;  /* choose A that Aref - A is > 0 */
01614          Bn = SUMA_NewAreaAtRadius(fdata->SO, b, fdata->Rref, fdata->tmpList);
01615          ++nbt;
01616       } while ( fdata->Aref - Bn < 0 && nbt < 200);
01617    }else{
01618       b = fdata->R; /* choose 'b' such that Aref - A is > 0, Choose a later*/
01619       Bn = fdata->A;
01620       a = fdata->Rref;
01621       do {
01622          SUMA_LH("Looking for a");
01623          a *= 0.7;
01624          An = SUMA_NewAreaAtRadius(fdata->SO, a, fdata->Rref, fdata->tmpList);
01625          ++nat;
01626       } while ( fdata->Aref -  An> 0 && nat < 200);
01627    }
01628 
01629    *ap = a; *bp = b;
01630 
01631    if (nat >= 200 || nbt >= 200) {
01632       SUMA_SL_Err("Failed to find segment.");
01633       SUMA_RETURN(NOPE);
01634    }
01635 
01636    if (LocalHead) {
01637       fprintf (SUMA_STDERR,"%s:\nChosen range is [%f %f] with Areas [%f %f], reference Area is %f\n", 
01638             FuncName, a, b, An, Bn, fdata->Aref);
01639    }
01640    
01641    SUMA_RETURN(YUP); 
01642 }

SUMA_CONTOUR_EDGES* SUMA_GetContour SUMA_SurfaceObject   SO,
int *    Nodes,
int    N_Node,
int *    N_ContEdges,
int    ContourMode,
SUMA_PATCH   UseThisPatch
 

Returns the contour of a patch if you have the patch already created, then pass it in the last argument mode (int) 0: nice contour, not necessarily outermost boundary 1: outermost edge, might look a tad jagged.

Definition at line 5340 of file SUMA_GeomComp.c.

References SUMA_EDGE_LIST::EL, SUMA_EDGE_LIST::ELps, SUMA_SurfaceObject::FaceSetList, SUMA_PATCH::FaceSetList, i, LocalHead, SUMA_SurfaceObject::MF, SUMA_CONTOUR_EDGES::n1, SUMA_CONTOUR_EDGES::n2, SUMA_EDGE_LIST::N_EL, SUMA_SurfaceObject::N_FaceSet, SUMA_PATCH::N_FaceSet, SUMA_SurfaceObject::N_Node, SUMA_PATCH::nHits, SUMA_SurfaceObject::NodeList, SUMA_Boolean, SUMA_calloc, SUMA_ENTRY, SUMA_free, SUMA_free_Edge_List(), SUMA_freePatch(), SUMA_getPatch(), SUMA_LH, SUMA_Make_Edge_List_eng(), SUMA_malloc, SUMA_realloc, SUMA_RETURN, SUMA_Show_Edge_List(), SUMA_ShowPatch(), SUMA_SL_Err, SUMA_SLP_Crit, and SUMA_SLP_Err.

Referenced by SUMA_1DROI_to_DrawnROI(), SUMA_FinishedROI(), and SUMA_Pattie_Volume().

05341 {
05342    static char FuncName[]={"SUMA_GetContour"};
05343    SUMA_EDGE_LIST * SEL=NULL;
05344    SUMA_PATCH *Patch = NULL;
05345    int i, Tri, Tri1, Tri2, sHits;
05346    SUMA_CONTOUR_EDGES *CE = NULL;
05347    SUMA_Boolean *isNode=NULL;
05348    SUMA_Boolean LocalHead = NOPE;
05349    
05350    SUMA_ENTRY;
05351 
05352    *N_ContEdges = -1;
05353    
05354    /* get the Node member structure if needed*/
05355    if (!SO->MF) {
05356       SUMA_SLP_Err("Member FaceSet not created.\n");
05357       SUMA_RETURN(CE);
05358    }  
05359 
05360    /* create a flag vector of which node are in Nodes */
05361    isNode = (SUMA_Boolean *) SUMA_calloc(SO->N_Node, sizeof(SUMA_Boolean));
05362    if (!isNode) {
05363       SUMA_SLP_Crit("Failed to allocate for isNode");
05364       SUMA_RETURN(CE);
05365    }
05366    
05367    for (i=0; i < N_Node; ++i) isNode[Nodes[i]] = YUP;
05368   
05369    if (UseThisPatch) {
05370       SUMA_LH("Using passed patch");
05371       Patch = UseThisPatch;
05372    } else { 
05373       SUMA_LH("Creating patch");
05374       switch (ContourMode) {
05375          case 0:
05376             Patch = SUMA_getPatch (Nodes, N_Node, SO->FaceSetList, SO->N_FaceSet, SO->MF, 2);
05377             break;
05378          case 1:
05379             Patch = SUMA_getPatch (Nodes, N_Node, SO->FaceSetList, SO->N_FaceSet, SO->MF, 1);
05380             break;
05381          default:
05382             SUMA_SL_Err("Bad contour mode"); SUMA_RETURN(NULL);
05383             break;
05384       }
05385    }
05386    if (LocalHead) SUMA_ShowPatch (Patch,NULL);
05387    
05388    if (Patch->N_FaceSet) {
05389       SEL = SUMA_Make_Edge_List_eng (Patch->FaceSetList, Patch->N_FaceSet, SO->N_Node, SO->NodeList, 0, NULL);
05390    
05391       if (0 && LocalHead) SUMA_Show_Edge_List (SEL, NULL);
05392       /* allocate for maximum */
05393       CE = (SUMA_CONTOUR_EDGES *) SUMA_malloc(SEL->N_EL * sizeof(SUMA_CONTOUR_EDGES));
05394       if (!CE) {
05395          SUMA_SLP_Crit("Failed to allocate for CE");
05396          SUMA_RETURN(CE);
05397       }
05398    
05399       switch (ContourMode) {
05400          case 0: /* a pretty contour, edges used here may not be the outermost of the patch */
05401             /* edges that are part of unfilled triangles are good */
05402             i = 0;
05403             *N_ContEdges = 0;
05404             while (i < SEL->N_EL) {
05405                if (SEL->ELps[i][2] == 2) {
05406                   Tri1 = SEL->ELps[i][1];
05407                   Tri2 = SEL->ELps[i+1][1];
05408                   sHits = Patch->nHits[Tri1] + Patch->nHits[Tri2];
05409                   if (sHits == 5 || sHits == 4) { /* one tri with 3 hits and one with 2 hits or 2 Tris with 2 hits each */
05410                      /* Pick edges that are part of only one triangle with three hits */
05411                                                  /* or two triangles with two hits */
05412                      /* There's one more condition, both nodes have to be a part of the original list */
05413                      if (isNode[SEL->EL[i][0]] && isNode[SEL->EL[i][1]]) {
05414                         CE[*N_ContEdges].n1 = SEL->EL[i][0];
05415                         CE[*N_ContEdges].n2 = SEL->EL[i][1];
05416                         ++ *N_ContEdges;
05417 
05418                         if (LocalHead) {
05419                            fprintf (SUMA_STDERR,"%s: Found edge made up of nodes [%d %d]\n",
05420                               FuncName, SEL->EL[i][0], SEL->EL[i][1]);
05421                         }
05422                      }
05423                   }
05424                }
05425 
05426                if (SEL->ELps[i][2] > 0) {
05427                   i += SEL->ELps[i][2];
05428                } else {
05429                   i ++;
05430                }
05431             }
05432             break;
05433          case 1: /* outermost contour, not pretty, but good for getting the outermost edge */
05434             i = 0;
05435             *N_ContEdges = 0;
05436             while (i < SEL->N_EL) {
05437                if (SEL->ELps[i][2] == 1) {
05438                   CE[*N_ContEdges].n1 = SEL->EL[i][0];
05439                   CE[*N_ContEdges].n2 = SEL->EL[i][1];
05440                   ++ *N_ContEdges;
05441                   if (LocalHead) {
05442                            fprintf (SUMA_STDERR,"%s: Found edge made up of nodes [%d %d]\n",
05443                               FuncName, SEL->EL[i][0], SEL->EL[i][1]);
05444                   }
05445                }
05446                if (SEL->ELps[i][2] > 0) {
05447                   i += SEL->ELps[i][2];
05448                } else {
05449                   i ++;
05450                }
05451             }
05452             break;
05453          default:
05454             SUMA_SL_Err("Bad ContourMode");
05455             SUMA_RETURN(NULL);
05456             break;            
05457       }
05458       
05459       /* Now reallocate */
05460       if (! *N_ContEdges) {
05461          SUMA_free(CE); CE = NULL;
05462          SUMA_RETURN(CE);
05463       }else {
05464          CE = (SUMA_CONTOUR_EDGES *) SUMA_realloc (CE, *N_ContEdges * sizeof(SUMA_CONTOUR_EDGES));
05465          if (!CE) {
05466             SUMA_SLP_Crit("Failed to reallocate for CE");
05467             SUMA_RETURN(CE);
05468          }
05469       }
05470          
05471       SUMA_free_Edge_List (SEL); 
05472    }
05473    
05474    if (!UseThisPatch) {
05475       SUMA_freePatch (Patch); 
05476    }
05477    Patch = NULL;
05478    
05479    SUMA_free(isNode);
05480    
05481    SUMA_RETURN(CE);
05482 }

SUMA_Boolean SUMA_GetOffset2Offset SUMA_GET_OFFSET_STRUCT   GOS,
SUMA_OFFSET_STRUCT   OS
 

a function to turn the often cumbersome SUMA_GET_OFFSET_STRUCT to a more friendly SUMA_OFFSET_STRUCT

Definition at line 2563 of file SUMA_GeomComp.c.

References SUMA_GET_OFFSET_STRUCT::layers, LocalHead, SUMA_GET_OFFSET_STRUCT::N_layers, SUMA_OFFSET_STRUCT::N_Neighb, SUMA_NODE_NEIGHB_LAYER::N_NodesInLayer, SUMA_OFFSET_STRUCT::Neighb_dist, SUMA_OFFSET_STRUCT::Neighb_ind, SUMA_NODE_NEIGHB_LAYER::NodesInLayer, SUMA_GET_OFFSET_STRUCT::OffVect, SUMA_Boolean, SUMA_ENTRY, SUMA_malloc, SUMA_RETURN, SUMA_SL_Crit, and SUMA_SL_Err.

Referenced by SUMA_ClusterCenterofMass().

02564 {
02565    static char FuncName[]={"SUMA_GetOffset2Offset"};
02566    int il, jl, noffs;
02567    SUMA_Boolean LocalHead = NOPE;
02568    
02569    SUMA_ENTRY;
02570    
02571    if (!GOS || !OS) {
02572       SUMA_SL_Err("NULL input"); SUMA_RETURN(NOPE);
02573    }
02574    
02575    OS->N_Neighb = 0; 
02576    for (il=1; il<GOS->N_layers; ++il) {
02577       OS->N_Neighb += GOS->layers[il].N_NodesInLayer;
02578    }
02579    OS->Neighb_ind = (int *)SUMA_malloc(OS->N_Neighb * sizeof(int));
02580    OS->Neighb_dist = (float *)SUMA_malloc(OS->N_Neighb * sizeof(float));
02581    if (!OS->Neighb_ind || !OS->Neighb_dist) {
02582       SUMA_SL_Crit("Failed to allocate.");
02583       SUMA_RETURN(NOPE);
02584    }
02585    
02586    noffs = 0;
02587    for (il=1; il<GOS->N_layers; ++il) {
02588       for (jl=0; jl<GOS->layers[il].N_NodesInLayer; ++jl) {
02589          OS->Neighb_ind[noffs] = GOS->layers[il].NodesInLayer[jl]; 
02590          OS->Neighb_dist[noffs] = GOS->OffVect[OS->Neighb_ind[noffs]];
02591          ++noffs;
02592       }
02593    }
02594    
02595    SUMA_RETURN(YUP);
02596 }

SUMA_Boolean SUMA_getoffsets int    n,
SUMA_SurfaceObject   SO,
float *    Off,
float    lim
 

Definition at line 682 of file SUMA_GeomComp.c.

References SUMA_SurfaceObject::EL, SUMA_NODE_FIRST_NEIGHB::FirstNeighb, SUMA_SurfaceObject::FN, i, SUMA_EDGE_LIST::Le, LocalHead, SUMA_NODE_FIRST_NEIGHB::N_Neighb, SUMA_Boolean, SUMA_ENTRY, SUMA_FindEdge(), SUMA_RETURN, and SUMA_SL_Err.

00683 {
00684    static char FuncName[]={"SUMA_getoffsets"};
00685    int i, ni, iseg;
00686    float Off_tmp;
00687    SUMA_Boolean Visit = NOPE;
00688    static SUMA_Boolean LocalHead = NOPE;
00689    
00690    SUMA_ENTRY;
00691    
00692    #if DoCheck
00693    if (!SO->FN || !SO->EL) {
00694       SUMA_SL_Err("SO->FN &/| SO->EL are NULL.\n");
00695       SUMA_RETURN(NOPE);
00696    }
00697    #endif
00698    
00699    #if DBG
00700    if (LocalHead) fprintf(SUMA_STDERR,"%s: Working node %d, %d neighbs. lim = %f\n", 
00701                                     FuncName, n, SO->FN->N_Neighb[n], lim);
00702    #endif
00703    
00704    for (i=0; i < SO->FN->N_Neighb[n]; ++i) {
00705       ni = SO->FN->FirstNeighb[n][i]; /* for notational sanity */
00706       iseg = SUMA_FindEdge (SO->EL, n, SO->FN->FirstNeighb[n][i]);
00707       #if DoCheck
00708       if (iseg < 0) {
00709          SUMA_SL_Err("Failed to find segment");
00710          SUMA_RETURN(NOPE);
00711       }
00712       #endif
00713       
00714       Off_tmp = Off[n] + SO->EL->Le[iseg];   /* that is the distance from n (original n) to ni along
00715                                                 that particular path */
00716                                              
00717       Visit = NOPE;
00718       if (Off[ni] < 0 || Off_tmp < Off[ni]) { /* Distance improvement, visit/revist that node */
00719          if (Off_tmp < lim) { /* only record if less than lim */
00720             Visit = YUP;
00721             Off[ni] = Off_tmp;
00722          } 
00723       } 
00724       
00725       #if DBG
00726       if (LocalHead) fprintf(SUMA_STDERR,"%s: %d --> %d. Visit %d, Current %f, Old %f\n", 
00727          FuncName, n, ni, Visit, Off_tmp, Off[ni]);
00728       #endif
00729       
00730       #if 0
00731          { int jnk; fprintf(SUMA_STDOUT,"Pausing ..."); jnk = getchar(); fprintf(SUMA_STDOUT,"\n"); }
00732       #endif
00733 
00734       if (Visit) { /* a new node has been reached with an offset less than limit, go down that road */
00735          if (!SUMA_getoffsets (ni, SO, Off, lim))  {
00736             SUMA_SL_Err("Failed in SUMA_getoffsets");
00737             SUMA_RETURN (NOPE);
00738          }
00739       }
00740    }
00741 
00742    SUMA_RETURN(YUP);
00743 }

SUMA_Boolean SUMA_getoffsets2 int    n,
SUMA_SurfaceObject   SO,
float    lim,
SUMA_GET_OFFSET_STRUCT   OffS,
int *    CoverThisNode,
int    N_CoverThisNode
 

A function to calculate the geodesic distance of nodes connected to node n SUMA_getoffsets was the first incarnation but it was too slow. ans = SUMA_getoffsets2 (n, SO, lim, OffS, CoverThisNode, N_CoverThisNode).

Parameters:
n  (int) index of center node
SO  (SUMA_SurfaceObject *) structure containing surface object
lim  (float) maximum geodesic distance to travel (ignored when CoverThisNode is used)
OffS  (SUMA_GET_OFFSET_STRUCT *) initialized structure to contain the nodes that neighbor n within lim mm or until all the nodes in CoverThisNode are used up
CoverThisNode  (int *) SO->N_Node mask vector such that if CoverThisNode[i] then node i has to be reached (supersedes lim) NULL if you don't want to use it.
N_CoverThisNode  (int) number of nodes to cover (where CoverThisNode = 1).
Returns:
ans (SUMA_Boolean) YUP = GOOD, NOPE = BAD
See also:
SUMA_AddNodeToLayer , SUMA_Free_getoffsets , SUMA_Initialize_getoffsets , SUMA_getoffsets_ll
The following code was used to test different methods for calculating the segment length, none (except for Seg = constant) proved to be faster, probably because of memory access time. One of the options required the use of DistFirstNeighb which is calculated by function SUMA_CalcNeighbDist. It mirrors SO->EL->FirstNeighb

static int SEG_METHOD; switch (SEG_METHOD) { case CALC_SEG: this is the slow part, too many redundant computations. cuts computation time by a factor > 3 if Seg was set to a constant However, attempts at accessing pre-calculated segment lengths proved to be slower. SUMA_SEG_LENGTH (a, b, Seg); break; case FIND_EDGE_MACRO: this one's even slower, calculations have been made once but function calls are costly (7.53 min) iseg = -1; if (n_k < n_jne) {SUMA_FIND_EDGE (SO->EL, n_k, n_jne, iseg);} else {SUMA_FIND_EDGE (SO->EL, n_jne, n_k, iseg);} if (iseg < 0) { SUMA_SL_Err("Segment not found.\nSetting Seg = 10000.0"); Seg = 10000.0; } else Seg = SO->EL->Le[iseg]; break; case FIND_EDGE: this one's even slower, calculations have been made once but function calls are costly iseg = SUMA_FindEdge (SO->EL, n_k, n_jne); Seg = SO->EL->Le[iseg]; break;

case DIST_FIRST_NEIGHB: consumes memory but might be faster than previous 2 (5.22 min) Seg = DistFirstNeighb[n_jne][k]; break; case CONST: 1.7 min Seg = 1.0; break; default: SUMA_SL_Err("Bad option"); break; }

Definition at line 1050 of file SUMA_GeomComp.c.

References a, SUMA_NODE_FIRST_NEIGHB::FirstNeighb, SUMA_SurfaceObject::FN, SUMA_GET_OFFSET_STRUCT::layers, SUMA_GET_OFFSET_STRUCT::LayerVect, LocalHead, SUMA_NODE_FIRST_NEIGHB::N_Neighb, SUMA_NODE_NEIGHB_LAYER::N_NodesInLayer, SUMA_SurfaceObject::NodeList, SUMA_NODE_NEIGHB_LAYER::NodesInLayer, SUMA_GET_OFFSET_STRUCT::OffVect, SUMA_AddNodeToLayer(), SUMA_Boolean, SUMA_ENTRY, SUMA_Free_getoffsets(), SUMA_RETURN, SUMA_SEG_LENGTH_SQ, SUMA_SL_Crit, and SUMA_SL_Err.

Referenced by calcWithOffsets(), SUMA_Build_Cluster_From_Node(), SUMA_Build_Cluster_From_Node_NoRec(), SUMA_ClusterCenterofMass(), SUMA_EquateSurfaceSize(), and SUMA_FormNeighbOffset().

01051 {
01052    static char FuncName[]={"SUMA_getoffsets2"};
01053    int LayInd, il, n_il, n_jne, k, n_prec = -1, n_k, jne, iseg=0;
01054    float Off_tmp, Seg, *a, *b, minSeg, SegPres; /*! *** SegPres added Jul 08 04, ZSS bug before ... */
01055    SUMA_Boolean Visit = NOPE;
01056    SUMA_Boolean AllDone = NOPE;
01057    static SUMA_Boolean LocalHead = NOPE;
01058    
01059    SUMA_ENTRY;
01060    
01061    if (!OffS) {
01062       SUMA_SL_Err("NULL OffS");
01063       SUMA_RETURN(NOPE);
01064    }
01065    
01066    /* setup 0th layer */
01067    OffS->OffVect[n] = 0.0;   /* n is at a distance 0.0 from itself */
01068    OffS->LayerVect[n] = 0;   /* n is on the zeroth layer */
01069    OffS->layers[0].N_NodesInLayer = 1;
01070    OffS->layers[0].NodesInLayer[0] = n;
01071    if (CoverThisNode) { 
01072       if (CoverThisNode[n]) {
01073          CoverThisNode[n] = 0; --N_CoverThisNode;
01074       }
01075    }
01076    LayInd = 1;  /* index of next layer to build */
01077    AllDone = NOPE;
01078    while (!AllDone) {
01079       
01080       AllDone = YUP; /* assume that this would be the last layer */
01081       for (il=0; il < OffS->layers[LayInd - 1].N_NodesInLayer; ++il) { /* go over all nodes in previous layer */
01082          n_il =  OffS->layers[LayInd - 1].NodesInLayer[il]; /* node from previous layer */
01083          for (jne=0; jne < SO->FN->N_Neighb[n_il]; ++jne) { /* go over all the neighbours of node n_il */
01084             n_jne = SO->FN->FirstNeighb[n_il][jne];        /* node that is an immediate neighbor to n_il */
01085             if (OffS->LayerVect[n_jne] < 0) { /* node is not assigned to a layer yet */
01086                OffS->LayerVect[n_jne] =  LayInd;    /* assign new layer index to node */
01087                OffS->OffVect[n_jne] = 0.0;          /* reset its distance from node n */
01088                SUMA_AddNodeToLayer (n_jne, LayInd, OffS);   /* add the node to the nodes in the layer */
01089                minSeg = 100000.0;
01090                n_prec = -1; 
01091                Seg = 0.0;
01092                SegPres = 0.0;
01093                for (k=0; k < SO->FN->N_Neighb[n_jne]; ++k) { /* calculate shortest distance of node to any precursor */  
01094                   n_k = SO->FN->FirstNeighb[n_jne][k];
01095                   if (OffS->LayerVect[n_k] == LayInd - 1) { /* this neighbor is a part of the previous layer, good */
01096                      if (n_prec < 0) n_prec = SO->FN->FirstNeighb[n_jne][0];
01097                      a = &(SO->NodeList[3*n_k]); b = &(SO->NodeList[3*n_jne]);
01098                      /* this is the slow part, too many redundant computations. 
01099                         Computation time is cut by a factor > 2 if Seg was set to a constant
01100                         However, attempts at accessing pre-calculated segment lengths
01101                         proved to be slower. See Comments in function help*/
01102                      SUMA_SEG_LENGTH_SQ (a, b, Seg);                    
01103                      if (OffS->OffVect[n_prec] + Seg < minSeg) {
01104                         minSeg = Seg + OffS->OffVect[n_prec];
01105                         SegPres = Seg;
01106                         n_prec = n_k;
01107                      }
01108                   }
01109                }/* for k */
01110                
01111                if (n_prec < 0) { /* bad news */
01112                   SUMA_SL_Crit("No precursor found for node.");
01113                   OffS = SUMA_Free_getoffsets (OffS);
01114                   SUMA_RETURN(NOPE);
01115                } else {
01116                   OffS->OffVect[n_jne] = OffS->OffVect[n_prec] + sqrt(SegPres); SegPres = 0.0;
01117                   if (!CoverThisNode) {
01118                      if (OffS->OffVect[n_jne] < lim) { /* must go at least one more layer */
01119                         AllDone = NOPE;
01120                      }
01121                   } else {
01122                      if (CoverThisNode[n_jne]) {
01123                         CoverThisNode[n_jne] = 0; --N_CoverThisNode;
01124                      }
01125                      if (N_CoverThisNode > 0) {
01126                         AllDone = NOPE;
01127                      }
01128                   }
01129                }
01130             } /* node not already in layer */
01131             
01132          } /* for jne */
01133       
01134       } /* for il */    
01135       ++LayInd;
01136    } /* while AllDone */
01137    
01138    SUMA_RETURN(YUP);
01139 }

DList* SUMA_getoffsets_ll int    n,
SUMA_SurfaceObject   SO,
float    lim,
int *    CoverThisNode,
int    N_CoverThisNode
 

Definition at line 1192 of file SUMA_GeomComp.c.

References a, DListElmt_::data, dlist_init(), dlist_ins_next(), dlist_tail, SUMA_NODE_FIRST_NEIGHB::FirstNeighb, SUMA_SurfaceObject::FN, SUMA_OFFSET_LL_DATUM::layer, LocalHead, SUMA_NODE_FIRST_NEIGHB::N_Neighb, DListElmt_::next, SUMA_OFFSET_LL_DATUM::ni, SUMA_SurfaceObject::NodeList, SUMA_OFFSET_LL_DATUM::off, SUMA_BEGINNING_OF_LAYER, SUMA_Boolean, SUMA_ENTRY, SUMA_FIND_ELMENT_FOR_NODE, SUMA_Free_Offset_ll_Datum(), SUMA_LH, SUMA_malloc, SUMA_New_Offset_ll_Datum(), SUMA_RETURN, SUMA_SEG_LENGTH_SQ, SUMA_SL_Crit, and SUMA_SL_Err.

Referenced by SUMA_Build_Cluster_From_Node().

01193 {
01194    static char FuncName[]={"SUMA_getoffsets_ll"};
01195    int LayInd, il, n_il, n_jne, k, n_prec = -1, n_k, jne, iseg=0;
01196    float Off_tmp, Seg, *a, *b, minSeg, SegPres; /*! *** SegPres added Jul 08 04, ZSS bug before ... */
01197    SUMA_Boolean Visit = NOPE;
01198    SUMA_Boolean AllDone = NOPE;
01199    SUMA_OFFSET_LL_DATUM * n_dat = NULL, *dat = NULL, *dat_nk = NULL, *dat_prec = NULL, *dat_ne=NULL;
01200    DList *list = NULL;
01201    DListElmt *elm = NULL, *elm_prec = NULL, *elm_ne=NULL, *elm_nk=NULL;
01202    static SUMA_Boolean LocalHead = NOPE;
01203    
01204    SUMA_ENTRY;
01205    
01206    
01207    /* create the list */
01208    SUMA_LH("Initializing list ...");
01209    list = (DList *)SUMA_malloc(sizeof(DList));
01210    dlist_init(list, SUMA_Free_Offset_ll_Datum);
01211    
01212    /* setup 0th layer */
01213    SUMA_LH("New OffsetDatum");
01214    n_dat = SUMA_New_Offset_ll_Datum(n, 0);
01215    n_dat->off = 0.0;   /* n is at a distance 0.0 from itself */
01216    dlist_ins_next(list, dlist_tail(list), (void*)n_dat);
01217    
01218    if (CoverThisNode) { 
01219       if (CoverThisNode[n]) {
01220          CoverThisNode[n] = 0; --N_CoverThisNode;
01221       }
01222    }
01223    LayInd = 1;  /* index of next layer to build */
01224    AllDone = NOPE;
01225    while (!AllDone) {
01226       AllDone = YUP; /* assume that this would be the last layer */
01227       elm = NULL;
01228          do {
01229             if (!elm) { SUMA_BEGINNING_OF_LAYER(list, (LayInd-1), elm); }
01230             else elm = elm->next;
01231             if (!elm) {
01232                SUMA_SL_Err("Could not find beginning of layer!");
01233                SUMA_RETURN(NULL);
01234             }
01235             dat = (SUMA_OFFSET_LL_DATUM *)elm->data;
01236             if (dat->layer == LayInd -1) {
01237                n_il = dat->ni;
01238                for (jne=0; jne < SO->FN->N_Neighb[n_il]; ++jne) { /* go over all the neighbours of node n_il */
01239                   n_jne = SO->FN->FirstNeighb[n_il][jne];        /* node that is an immediate neighbor to n_il */
01240                   SUMA_FIND_ELMENT_FOR_NODE(list, n_jne, elm_ne);
01241                   if (!elm_ne) { /* node not in any layer */
01242                      dat_ne = SUMA_New_Offset_ll_Datum(n_jne, LayInd); /* create an element for it */
01243                      dat_ne->off = 0.0;
01244                      dlist_ins_next(list, dlist_tail(list), (void*)dat_ne);
01245                      minSeg = 100000.0;
01246                      n_prec = -1; 
01247                      Seg = 0.0;
01248                      SegPres = 0.0;
01249                      for (k=0; k < SO->FN->N_Neighb[n_jne]; ++k) { /* calculate shortest distance of node to any precursor */  
01250                         n_k = SO->FN->FirstNeighb[n_jne][k];
01251                         SUMA_FIND_ELMENT_FOR_NODE(list, n_k, elm_nk); 
01252                         if (n_prec < 0 && elm_nk) { 
01253                            n_prec = n_k; elm_prec = elm_nk; 
01254                            dat_prec = (SUMA_OFFSET_LL_DATUM *)elm_prec->data;
01255                         }
01256                         if (elm_nk) {
01257                            dat_nk = (SUMA_OFFSET_LL_DATUM *)elm_nk->data;
01258                            if (dat_nk->layer == LayInd - 1) { /* this neighbor is a part of the previous layer, good */
01259                               a = &(SO->NodeList[3*n_k]); b = &(SO->NodeList[3*n_jne]);
01260                               /* this is the slow part, too many redundant computations. 
01261                                  Computation time is cut by a factor > 2 if Seg was set to a constant
01262                                  However, attempts at accessing pre-calculated segment lengths
01263                                  proved to be slower. See Comments in function help*/
01264                               SUMA_SEG_LENGTH_SQ (a, b, Seg);                    
01265                               if (dat_prec->off + Seg < minSeg) {
01266                                  minSeg = Seg + dat_prec->off;
01267                                  SegPres = Seg;
01268                                  n_prec = n_k;
01269                                  elm_prec = elm_nk;
01270                                  dat_prec = dat_nk;
01271                               }
01272                            }
01273                         } /* if elm_nk */
01274                      }/* for k */
01275                      if (n_prec < 0) { /* bad news */
01276                         SUMA_SL_Crit("No precursor found for node.");
01277                         SUMA_RETURN(NULL);
01278                      } else {
01279                         dat_ne->off = dat_prec->off + sqrt(SegPres); SegPres = 0.0;
01280                         if (!CoverThisNode) {
01281                            if (dat_ne->off < lim) { /* must go at least one more layer */
01282                               AllDone = NOPE;
01283                            }
01284                         } else {
01285                            if (CoverThisNode[n_jne]) {
01286                               CoverThisNode[n_jne] = 0; --N_CoverThisNode;
01287                            }
01288                            if (N_CoverThisNode > 0) {
01289                               AllDone = NOPE;
01290                            }
01291                         }
01292                      }
01293                   } /* if elm_ne */
01294                } /* for jne */
01295             } /* dat->layer == LayInd */
01296          }  while (dat->layer == (LayInd-1) && elm != dlist_tail(list));
01297       
01298       ++LayInd;
01299    } /* while AllDone */
01300    
01301    SUMA_RETURN(list);
01302 }

SUMA_PATCH* SUMA_getPatch int *    NodesSelected,
int    N_Nodes,
int *    Full_FaceSetList,
int    N_Full_FaceSetList,
SUMA_MEMBER_FACE_SETS   Memb,
int    MinHits
 

Given a set of node indices, return a patch of the original surface that contains them

Patch = SUMA_getPatch (NodesSelected, N_Nodes, Full_FaceSetList, N_Full_FaceSetList, Memb, MinHits)

Parameters:
NodesSelected  (int *) N_Nodes x 1 Vector containing indices of selected nodes. These are indices into NodeList making up the surface formed by Full_FaceSetList.
N_Nodes  (int) number of elements in NodesSelected
Full_FaceSetList  (int *) N_Full_FaceSetList x 3 vector containing the triangles forming the surface
N_Full_FaceSetList  (int) number of triangular facesets forming the surface
Memb  (SUMA_MEMBER_FACE_SETS *) structure containing the node membership information (result of SUMA_MemberFaceSets function)
MinHits  (int) minimum number of nodes to be in a patch before the patch is selected. Minimum is 1, Maximum logical is 3, assuming you do not have repeated node indices in NodesSelected. \ret Patch (SUMA_PATCH *) Structure containing the patch's FaceSetList, FaceSetIndex (into original surface) and number of elements. returns NULL in case of trouble. Free Patch with SUMA_freePatch(Patch);
See also:
SUMA_MemberFaceSets, SUMA_isinbox, SUMA_PATCH

Definition at line 5223 of file SUMA_GeomComp.c.

References SUMA_PATCH::FaceSetIndex, SUMA_PATCH::FaceSetList, i, SUMA_PATCH::N_FaceSet, SUMA_MEMBER_FACE_SETS::N_Memb, SUMA_PATCH::nHits, SUMA_MEMBER_FACE_SETS::NodeMemberOfFaceSet, SUMA_calloc, SUMA_ENTRY, SUMA_free, SUMA_malloc, and SUMA_RETURN.

Referenced by main(), SUMA_GetContour(), and SUMA_Pattie_Volume().

05226 {
05227    int * BeenSelected;
05228    int i, j, node, ip, ip2, NP;
05229    SUMA_PATCH *Patch;
05230    static char FuncName[]={"SUMA_getPatch"};
05231    
05232    SUMA_ENTRY;
05233    
05234    NP = 3;
05235    BeenSelected = (int *)SUMA_calloc (N_Full_FaceSetList, sizeof(int));
05236    Patch = (SUMA_PATCH *)SUMA_malloc(sizeof(SUMA_PATCH));
05237    
05238    if (!BeenSelected || !Patch) {
05239       fprintf (SUMA_STDERR,"Error %s: Could not allocate for BeenSelected or patch.\n", FuncName);
05240       SUMA_RETURN(NULL);
05241    }
05242    /* find out the total number of facesets these nodes are members of */
05243    Patch->N_FaceSet = 0; /* total number of facesets containing these nodes */
05244    for (i=0; i < N_Nodes; ++i) {
05245       node = NodesSelected[i];
05246       for (j=0; j < Memb->N_Memb[node]; ++j) {
05247          if (!BeenSelected[Memb->NodeMemberOfFaceSet[node][j]]) {
05248             /* this faceset has not been selected, select it */
05249             ++ Patch->N_FaceSet;
05250          }
05251          ++ BeenSelected[Memb->NodeMemberOfFaceSet[node][j]];
05252       }   
05253    }
05254    
05255    /* now load these facesets into a new matrix */
05256    
05257    Patch->FaceSetList = (int *) SUMA_calloc (Patch->N_FaceSet * 3, sizeof(int));
05258    Patch->FaceSetIndex = (int *) SUMA_calloc (Patch->N_FaceSet, sizeof(int));
05259    Patch->nHits = (int *) SUMA_calloc (Patch->N_FaceSet, sizeof(int));
05260    
05261    if (!Patch->FaceSetList || !Patch->FaceSetIndex || !Patch->nHits) {
05262       fprintf (SUMA_STDERR,"Error %s: Could not allocate for Patch->FaceSetList || Patch_FaceSetIndex.\n", FuncName);
05263       SUMA_RETURN(NULL);
05264    }
05265    
05266    j=0;
05267    for (i=0; i < N_Full_FaceSetList; ++i) {
05268       if (BeenSelected[i] >= MinHits) {
05269          Patch->nHits[j] = BeenSelected[i];
05270          Patch->FaceSetIndex[j] = i;
05271          ip = NP * j;
05272          ip2 = NP * i;
05273          Patch->FaceSetList[ip] = Full_FaceSetList[ip2];
05274          Patch->FaceSetList[ip+1] = Full_FaceSetList[ip2+1];
05275          Patch->FaceSetList[ip+2] = Full_FaceSetList[ip2+2];
05276          ++j;
05277       }
05278    }
05279    
05280    /* reset the numer of facesets because it might have changed given the MinHits condition,
05281    It won't change if MinHits = 1.
05282    It's OK not to change the allocated space as long as you are using 1D arrays*/
05283    Patch->N_FaceSet = j;
05284    
05285    if (BeenSelected) SUMA_free(BeenSelected);
05286    
05287    SUMA_RETURN(Patch);   
05288 }

SUMA_Boolean SUMA_GetVolDiffRange SUMA_VolDiffDataStruct   fdata,
double *    ap,
double *    bp
 

a function to find two values a and b such that DV(a) is < 0 and DV(b) is > 0 These two starting points are used for the optimization function SUMA_BinaryZeroSearch

Definition at line 1649 of file SUMA_GeomComp.c.

References a, LocalHead, SUMA_VolDiffDataStruct::R, SUMA_VolDiffDataStruct::Rref, SUMA_VolDiffDataStruct::SO, SUMA_VolDiffDataStruct::SOref, SUMA_Boolean, SUMA_ENTRY, SUMA_LH, SUMA_Mesh_Volume(), SUMA_NewVolumeAtRadius(), SUMA_RETURN, SUMA_SL_Err, SUMA_SO_RADIUS, SUMA_VolDiffDataStruct::tmpList, SUMA_VolDiffDataStruct::V, and SUMA_VolDiffDataStruct::Vref.

Referenced by SUMA_EquateSurfaceVolumes().

01650 {
01651    static char FuncName[]={"SUMA_GetVolDiffRange"};
01652    double a = 0.0, b = 0.0, nat=0, nbt=0;
01653    SUMA_Boolean LocalHead = NOPE;
01654 
01655    SUMA_ENTRY;
01656 
01657    /* decide on segment range */
01658    fdata->Vref = fabs((double)SUMA_Mesh_Volume(fdata->SOref, NULL, -1));
01659    SUMA_SO_RADIUS(fdata->SOref, fdata->Rref);
01660    fdata->V = fabs((double)SUMA_Mesh_Volume(fdata->SO, NULL, -1));
01661    SUMA_SO_RADIUS(fdata->SO, fdata->R);
01662 
01663    /* a very simple range setting. might very well fail at times */
01664    if (fdata->Vref - fdata->V < 0) { 
01665       a = fdata->R; /* choose 'a' such that Vref - V is < 0, Choose b later*/
01666       b = fdata->Rref;
01667       do {
01668          SUMA_LH("Looking for b");
01669          b *= 1.3; ++nbt; /* choose b that Vref - V is > 0 */
01670       } while ( fdata->Vref - SUMA_NewVolumeAtRadius(fdata->SO, b, fdata->Rref, fdata->tmpList) < 0 && nbt < 200);
01671    }else{
01672       b = fdata->R; /* choose 'b' such that Vref - V is > 0, Choose a later*/
01673       a = fdata->Rref;
01674       do {
01675          SUMA_LH("Looking for a");
01676          a *= 0.7; ++nat;
01677       } while ( fdata->Vref - SUMA_NewVolumeAtRadius(fdata->SO, a, fdata->Rref, fdata->tmpList) > 0 && nat < 200);
01678    }
01679 
01680    *ap = a; *bp = b;
01681 
01682    if (nat >= 200 || nbt >= 200) {
01683       SUMA_SL_Err("Failed to find segment.");
01684       SUMA_RETURN(NOPE);
01685    }
01686 
01687    SUMA_RETURN(YUP); 
01688 }

SUMA_VTI* SUMA_GetVoxelsIntersectingTriangle SUMA_SurfaceObject   SO,
SUMA_VOLPAR   VolPar,
float *    NodeIJKlist,
SUMA_VTI   vti
 

Function to return a set of voxels that are intersected by a triangle.

Parameters:
SO  (SUMA_SurfaceObject *)
VolPar  (SUMA_VOLPAR *)
NodeIJKlist  (float *) the equivalent of SO->NodeList only in i,j,k indices into VolPar's grid. In the future, might want to allow for this param to be NULL and have it be generated internally from SO->NodeList and VolPar.
vti  (SUMA_VTI *) properly initialized Voxel Triangle Intersection structure
Returns:
vti (SUMA_VTI *) filled up VTI structure.
  • Closely based on section in function SUMA_SurfGridIntersect If you find bugs here, fix them there too.

Definition at line 199 of file SUMA_GeomComp.c.

References SUMA_VOLPAR::dx, SUMA_VOLPAR::dy, SUMA_VOLPAR::dz, SUMA_SurfaceObject::FaceSetDim, SUMA_SurfaceObject::FaceSetList, SUMA_VOLPAR::filecode, SUMA_VOLPAR::Hand, SUMA_VTI::IntersectedVoxels, LocalHead, malloc, n1, n2, SUMA_VTI::N_IntersectedVoxels, SUMA_VTI::N_TriIndex, SUMA_SurfaceObject::NodeDim, SUMA_VOLPAR::nx, SUMA_VOLPAR::ny, nz, SUMA_VOLPAR::nz, p, SUMA_3D_2_1D_index, SUMA_ABS, SUMA_Boolean, SUMA_DIST_FROM_PLANE, SUMA_ENTRY, SUMA_IS_STRICT_NEG, SUMA_isVoxelIntersect_Triangle(), SUMA_malloc, SUMA_realloc, SUMA_RETURN, SUMA_SL_Crit, SUMA_SL_Err, SUMA_SL_Warn, SUMA_TRIANGLE_BOUNDING_BOX, SUMA_VoxelsInBox(), and SUMA_VTI::TriIndex.

00201 {
00202    static char FuncName[]={"SUMA_GetVoxelsIntersectingTriangle"};
00203    int ti, nx, ny, nz, nxy, nxyz, N_inbox, n1, n2, n3, nt, nt3, nijk, nf;
00204    int N_alloc, N_realloc, en, *voxelsijk=NULL, N_voxels1d = 0, *voxels1d = NULL;
00205    int *TriIndex=NULL, N_TriIndex;
00206    float dxyz[3];
00207    float tol_dist = 0; /* A way to fatten up the shell a little bit. Set to 0 if no fat is needed */
00208    float *p1, *p2, *p3, min_v[3], max_v[3], p[3], dist;
00209    FILE *fp=NULL;
00210    SUMA_Boolean LocalHead = YUP;
00211    
00212    SUMA_ENTRY;
00213       
00214    if (SO->FaceSetDim != 3 || SO->NodeDim != 3) {
00215       SUMA_SL_Err("SO->FaceSetDim != 3 || SO->NodeDim != 3"); 
00216       SUMA_RETURN(NULL);
00217    }
00218    if (!vti) {
00219       SUMA_SL_Err("vti must be non NULL");
00220       SUMA_RETURN(NULL);
00221    }
00222    if (vti->N_TriIndex <= 0) {
00223       SUMA_SL_Err("vti must be initialized");
00224       SUMA_RETURN(NULL);
00225    }
00226    
00227    TriIndex = vti->TriIndex;
00228    N_TriIndex = vti->N_TriIndex;
00229    
00230    nx = VolPar->nx; ny = VolPar->ny; nz = VolPar->nz; nxy = nx * ny; nxyz = nx * ny * nz;
00231    
00232    if (LocalHead) {
00233       fp = fopen("SUMA_GetVoxelsIntersectingTriangle.1D","w");
00234       if (fp) fprintf(fp, "# Voxels from %s that intersect the triangles \n", VolPar->filecode);
00235    }   
00236    /* cycle through all triangles and find voxels that intersect them */
00237    N_alloc = 2000; /* expected maximum number of voxels in triangle's bounding box */
00238    N_realloc = 0;
00239    voxelsijk = (int *)SUMA_malloc(sizeof(int)*N_alloc*3);
00240    if (!voxelsijk) { SUMA_SL_Crit("Failed to Allocate!"); SUMA_RETURN(NULL);  }   
00241    dxyz[0] = VolPar->dx; dxyz[1] = VolPar->dy; dxyz[2] = VolPar->dz;
00242    for (ti=0; ti<N_TriIndex; ++ti) {
00243       if (LocalHead) fprintf(SUMA_STDERR,"%s: Now processing %dth triangle\n", FuncName, ti);
00244       nf = TriIndex[ti];
00245       if (LocalHead) fprintf(SUMA_STDERR,"\t\tindexed %d, \n", nf);
00246       n1 = SO->FaceSetList[SO->FaceSetDim*nf]; n2 = SO->FaceSetList[SO->FaceSetDim*nf+1]; n3 = SO->FaceSetList[SO->FaceSetDim*nf+2];
00247       if (LocalHead) fprintf(SUMA_STDERR,"\t\tmade up of  nodes %d, %d. %d . \n", n1, n2, n3);
00248       /* find the bounding box of the triangle */
00249       p1 = &(NodeIJKlist[3*n1]); p2 = &(NodeIJKlist[3*n2]); p3 = &(NodeIJKlist[3*n3]); 
00250       SUMA_TRIANGLE_BOUNDING_BOX(p1, p2, p3, min_v, max_v);
00251       
00252       /* quick check of preallocate size of voxelsijk */
00253       en =((int)(max_v[0] - min_v[0] + 5) * (int)(max_v[1] - min_v[1] + 5) * (int)(max_v[2] - min_v[2] + 5)); 
00254       if ( en > N_alloc) {
00255          ++N_realloc; if (N_realloc > 5) { SUMA_SL_Warn("Reallocating, increase limit to improve speed.\nEither triangles too large or grid too small"); }
00256          N_alloc = 2*en;
00257          voxelsijk = (int *)SUMA_realloc(voxelsijk, 3*N_alloc*sizeof(int));
00258          if (!voxelsijk) { SUMA_SL_Crit("Failed to Allocate!"); SUMA_RETURN(NULL); }
00259       } 
00260       /* find the list of voxels inhabiting this box */
00261       N_inbox = 0;
00262       if (!SUMA_VoxelsInBox(voxelsijk, &N_inbox, min_v, max_v)) {
00263          SUMA_SL_Err("Unexpected error!"); SUMA_RETURN(NULL); 
00264       }
00265       if (!N_inbox) { SUMA_SL_Err("Unexpected error, no voxels in box!"); SUMA_RETURN(NULL);  }
00266       if (N_inbox >= N_alloc) { SUMA_SL_Err("Allocation trouble!"); SUMA_RETURN(NULL);  }
00267       if (LocalHead) fprintf(SUMA_STDERR,"\t\t%d nodes in box\n", N_inbox);
00268       
00269       /* allocate for 1D indices of voxels intersecting the triangle */
00270       if (voxels1d) {
00271          SUMA_SL_Err("NULL pointer expected here");
00272          SUMA_RETURN(NULL);
00273       }
00274       if (LocalHead) fprintf(SUMA_STDERR,"\t\tShit man, %d nodes in box\n", N_inbox);
00275       voxels1d = (int *)malloc(N_inbox * sizeof(int)); /* Too many SUMA_mallocs keep it simple here, this function is called many many times */
00276       if (LocalHead) fprintf(SUMA_STDERR,"\t\tWTF man, %d nodes in box\n", N_inbox);
00277       N_voxels1d=0;
00278       if (!voxels1d) {
00279          SUMA_SL_Crit("Failed to allocate voxels1d");
00280          SUMA_RETURN(NULL);
00281       }
00282       /* mark these voxels as inside the business */
00283       if (LocalHead) fprintf(SUMA_STDERR,"%s:\t\tabout to process %d voxels\n", FuncName, N_inbox);
00284       for (nt=0; nt < N_inbox; ++nt) {
00285          nt3 = 3*nt;
00286          if (voxelsijk[nt3] < nx &&  voxelsijk[nt3+1] < ny &&  voxelsijk[nt3+2] < nz) {
00287             nijk = SUMA_3D_2_1D_index(voxelsijk[nt3], voxelsijk[nt3+1], voxelsijk[nt3+2], nx , nxy);  
00288             { 
00289                /* what side of the plane is this voxel on ? */
00290                p[0] = (float)voxelsijk[nt3]; p[1] = (float)voxelsijk[nt3+1]; p[2] = (float)voxelsijk[nt3+2]; 
00291                SUMA_DIST_FROM_PLANE(p1, p2, p3, p, dist);
00292                /* Does voxel contain any of the nodes ? */
00293                if (tol_dist && SUMA_ABS(dist) < tol_dist) dist = tol_dist; /* Fatten the representation a little bit 
00294                                                              There are holes in the mask created using
00295                                                              the condition below alone. I am not sure
00296                                                              why that is the case but whatever gap there
00297                                                              is in one plane, results from a thick line in
00298                                                              the other. Don't know if that is a bug yet
00299                                                              or an effect of discretization. At any rate
00300                                                              it should not affect what I plan to do with
00301                                                              this. Could the bug be in 
00302                                                              SUMA_isVoxelIntersect_Triangle?*/
00303                if (!(SUMA_IS_STRICT_NEG(VolPar->Hand * dist))) { /* voxel is outside (along normal) */
00304                   /* does this triangle actually intersect this voxel ?*/
00305                   if (SUMA_isVoxelIntersect_Triangle (p, dxyz, p1, p2, p3)) {
00306                      /* looks good, store it */
00307                      if (LocalHead) fprintf(SUMA_STDERR,"nt %d, N_voxels1d %d\n", nt, N_voxels1d);
00308                      voxels1d[N_voxels1d] = nijk; ++N_voxels1d;
00309                      if (fp) fprintf(fp, "%d %d %d\n", voxelsijk[nt3], voxelsijk[nt3+1], voxelsijk[nt3+2]);
00310                   } 
00311                }
00312                
00313             }
00314          }
00315       }
00316       /* store the results */
00317       vti->IntersectedVoxels[ti] = voxels1d; 
00318       vti->N_IntersectedVoxels[ti] = N_voxels1d;
00319       voxels1d = NULL; N_voxels1d = 0; 
00320    }
00321    
00322    if (LocalHead) {
00323       if (fp) fclose(fp); fp = NULL;
00324    } 
00325    SUMA_RETURN(vti);
00326 }

SUMA_GET_OFFSET_STRUCT* SUMA_Initialize_getoffsets int    N_Node
 

Allocate and initialize SUMA_GET_OFFSET_STRUCT* struct OffS = SUMA_Initialize_getoffsets (N_Node);.

Parameters:
N_Node  (int) number of nodes forming mesh
Returns:
OffS (SUMA_GET_OFFSET_STRUCT *) allocate structure with initialized fields for zeroth order layer
See also:
SUMA_AddNodeToLayer , SUMA_Free_getoffsets , SUMA_Initialize_getoffsets

Definition at line 758 of file SUMA_GeomComp.c.

References i, SUMA_GET_OFFSET_STRUCT::layers, SUMA_GET_OFFSET_STRUCT::LayerVect, SUMA_NODE_NEIGHB_LAYER::N_AllocNodesInLayer, SUMA_GET_OFFSET_STRUCT::N_layers, SUMA_GET_OFFSET_STRUCT::N_Nodes, SUMA_NODE_NEIGHB_LAYER::N_NodesInLayer, SUMA_NODE_NEIGHB_LAYER::NodesInLayer, SUMA_GET_OFFSET_STRUCT::OffVect, SUMA_ENTRY, SUMA_free, SUMA_malloc, SUMA_RETURN, and SUMA_SL_Err.

Referenced by calcWithOffsets(), SUMA_Build_Cluster_From_Node(), SUMA_Build_Cluster_From_Node_NoRec(), SUMA_ClusterCenterofMass(), SUMA_EquateSurfaceSize(), and SUMA_FormNeighbOffset().

00759 {
00760    static char FuncName[]={"SUMA_Initialize_getoffsets"};
00761    int i;
00762    SUMA_GET_OFFSET_STRUCT *OffS = NULL;
00763    
00764    SUMA_ENTRY;
00765    
00766    if (N_Node <= 0) {
00767       SUMA_SL_Err("Bad values for N_Node");
00768       SUMA_RETURN (OffS);
00769    }
00770    
00771    OffS = (SUMA_GET_OFFSET_STRUCT *)SUMA_malloc(sizeof(SUMA_GET_OFFSET_STRUCT));
00772    if (!OffS) {
00773       SUMA_SL_Err("Failed to allocate for OffS");
00774       SUMA_RETURN (OffS);
00775    }
00776    
00777    OffS->OffVect = (float *) SUMA_malloc(N_Node * sizeof(float));
00778    OffS->LayerVect = (int *) SUMA_malloc(N_Node * sizeof(int));
00779    OffS->N_Nodes = N_Node;
00780    
00781    if (!OffS->LayerVect || !OffS->OffVect) {
00782       SUMA_SL_Err("Failed to allocate for OffS->LayerVect &/| OffS->OffVect");
00783       SUMA_free(OffS);
00784       SUMA_RETURN (OffS);
00785    }
00786    
00787    /* initialize vectors */
00788    for (i=0; i< N_Node; ++i) {
00789       OffS->OffVect[i] = 0.0;
00790       OffS->LayerVect[i] = -1;
00791    }
00792    
00793    /* add a zeroth layer for node n */
00794    OffS->N_layers = 1;
00795    OffS->layers = (SUMA_NODE_NEIGHB_LAYER *) SUMA_malloc(OffS->N_layers * sizeof(SUMA_NODE_NEIGHB_LAYER));
00796    OffS->layers[0].N_AllocNodesInLayer = 1;
00797    OffS->layers[0].NodesInLayer = (int *) SUMA_malloc(OffS->layers[0].N_AllocNodesInLayer * sizeof(int));
00798    OffS->layers[0].N_NodesInLayer = 0;   
00799    
00800    SUMA_RETURN (OffS);
00801    
00802 }

int* SUMA_IntersectionStrip SUMA_SurfaceObject   SO,
SUMA_SURF_PLANE_INTERSECT   SPI,
int *    nPath,
int    N_nPath,
float *    dinters,
float    dmax,
int *    N_tPath
 

This function determines the strip of triangles necessary to go from one node to another along intersected edges. tPath = SUMA_IntersectionStrip (SO, SPI, int *nPath, int N_nPath, float *dinters, float dmax, int *N_tPath).

Parameters:
SO  (SUMA_SurfaceObject *) pointer to Surface Object structure
SPI  (SUMA_SURF_PLANE_INTERSECT *) pointer surface/plane intersection structure
nPath  (int *) series of nodes forming the Dijkstra path between nodes Nx (nPath[0] and NynPath[N_nPath-1])
N_nPath  (int) number of nodes in nPath. Note: Only nPath[0], nPath[1] and nPath[N_nPath-1] are used by this function
dinters  (float *) pointer sum of distances between intersection points on intersected edges for all triangles in tPath. This distance is a better approximation for the distance along the cortical surface than the distance obtained along the shortest path.
dmax  (float) distance beyond which to quit searching. Usually this distance is slightly larger than the distance along the path returned by SUMA_Dijkstra but dinters should always be less than the distance along the shortest path.
N_tPath  (int *) pointer to the number of triangle indices in tPath
Returns:
tPath (int*) pointer to vector containing the indices of triangles travelled from nPath[0] to nPath[N_nPath] (or vice versa if nPath[0] = SO->N_Node-1).
NOTE: Although the number of elements in tPath may be small, the number of elements allocated for is SO->N_FaceSet Make sure you free tPath when you are done with it.

NOTE: This function can be used to create a node path formed by intersection points along edges but that is not implemented yet.

See also:
SUMA_Surf_Plane_Intersect , SUMA_Dijkstra , SUMA_FromIntEdgeToIntEdge

Definition at line 7284 of file SUMA_GeomComp.c.

References SUMA_SurfaceObject::EL, SUMA_EDGE_LIST::EL, SUMA_EDGE_LIST::ELloc, SUMA_EDGE_LIST::ELps, SUMA_SurfaceObject::FaceSetList, SUMA_SURF_PLANE_INTERSECT::isEdgeInters, SUMA_SURF_PLANE_INTERSECT::isTriHit, LocalHead, n2, SUMA_SurfaceObject::N_FaceSet, SUMA_SurfaceObject::N_Node, Nx, SUMA_Boolean, SUMA_calloc, SUMA_ENTRY, SUMA_FindEdgeInTri(), SUMA_free, SUMA_FromIntEdgeToIntEdge(), SUMA_Get_Incident(), SUMA_isSameEdge(), SUMA_RETURN, and SUMA_EDGE_LIST::Tri_limb.

Referenced by SUMA_Surf_Plane_Intersect_ROI().

07286 {
07287    static char FuncName[]={"SUMA_IntersectionStrip"};
07288    int *tPath1 = NULL, *tPath2 = NULL, Incident[50], N_Incident, Nx = -1, 
07289       Ny = -1, Tri = -1, Tri1 = -1, istart, n2 = -1, n3 = -1, E1, E2, cnt, N_tPath1, N_tPath2;
07290    float d1, d2;
07291    SUMA_Boolean *Visited = NULL, Found, LocalHead = NOPE;
07292    
07293    SUMA_ENTRY;
07294    
07295    /* find the edge containing the 1st 2 nodes of the Dijkstra path */
07296    /* find the triangle that contains the edge formed by the 1st 2 nodes of the Dijkstra path and is intersected by the plane*/
07297    Tri1 = -1;
07298    if (LocalHead) {
07299       fprintf (SUMA_STDERR, "%s: Looking for a triangle containing nodes [%d %d].\n", FuncName, nPath[0], nPath[1]);
07300    }
07301    
07302    Found = SUMA_Get_Incident(nPath[0], nPath[1], SO->EL, Incident, &N_Incident, 1);
07303    if (!Found) {
07304       /* no such triangle, get a triangle that contains nPath[0] and is intersected */
07305       fprintf (SUMA_STDERR, "%s: No triangle contains nodes [%d %d].\n", FuncName, nPath[0], nPath[1]);
07306       if (nPath[0] == SO->N_Node - 1) {
07307          fprintf (SUMA_STDERR, "Warning %s: 1st node is last node of surface, traversing path backwards.\n", FuncName);
07308          Nx = nPath[N_nPath - 1];
07309          Ny = nPath[0];
07310       }else {
07311          Nx = nPath[0];
07312          Ny = nPath[N_nPath - 1];
07313       }
07314       istart = SO->EL->ELloc[Nx];
07315       /* find an edge containing the first node and belonging to an intersected triangle */
07316       Found = NOPE;
07317       while (SO->EL->EL[istart][0] == Nx && !Found) {
07318          Tri = SO->EL->ELps[istart][1];
07319          if (SPI->isTriHit[Tri]) {
07320             Found = YUP;
07321             Tri1 = Tri;
07322          }
07323          ++istart;
07324       } 
07325    }else {
07326       Nx = nPath[0];
07327       Ny = nPath[N_nPath - 1];
07328       
07329       /* find which of these triangles was intersected */
07330       if (LocalHead) {
07331          fprintf (SUMA_STDERR, "%s: Found %d triangles containing nodes [%d %d].\n", FuncName, N_Incident, nPath[0], nPath[1]);
07332          for (cnt = 0; cnt < N_Incident; ++cnt) fprintf (SUMA_STDERR, "%d isHit %d\n", Incident[cnt], SPI->isTriHit[Incident[cnt]]);
07333          fprintf (SUMA_STDERR, "\n"); 
07334       }
07335       Found = NOPE;
07336       cnt = 0;
07337       while (cnt < N_Incident && !Found) {
07338          if (SPI->isTriHit[Incident[cnt]]) {
07339             Found = YUP;
07340             Tri1 = Incident[cnt];
07341          }
07342          ++cnt;
07343       }
07344    }
07345    
07346    if (!Found) {
07347       fprintf (SUMA_STDERR, "Error %s: Starting Edge could not be found.\n", FuncName);
07348       SUMA_RETURN (NULL);
07349    }else if (LocalHead) {
07350       fprintf (SUMA_STDERR, "%s: Starting with triangle %d.\n", FuncName, Tri1);
07351    }
07352 
07353    /* found starting triangle edge, begin with side 1 */
07354    if (SO->FaceSetList[3*Tri1] == Nx) {
07355       n2 = SO->FaceSetList[3*Tri1+1];
07356       n3 = SO->FaceSetList[3*Tri1+2];
07357    } else if (SO->FaceSetList[3*Tri1+1] == Nx) {
07358       n2 = SO->FaceSetList[3*Tri1];
07359       n3 = SO->FaceSetList[3*Tri1+2];
07360    } else if (SO->FaceSetList[3*Tri1+2] == Nx) {
07361       n2 = SO->FaceSetList[3*Tri1];
07362       n3 = SO->FaceSetList[3*Tri1+1];
07363    } else {
07364       fprintf (SUMA_STDERR, "Error %s: Triangle %d does not contain Nx %d.\n", FuncName, Tri1, Nx);
07365       SUMA_RETURN (NULL);
07366    }  
07367    
07368    
07369    
07370    E1 = SUMA_FindEdgeInTri (SO->EL, Nx, n2, Tri1);
07371    if (!SPI->isEdgeInters[E1]) {
07372       E1 = SUMA_FindEdgeInTri (SO->EL, Nx, n3, Tri1);
07373    }
07374    /* now choose E2 such that E2 is also intersected */
07375    if (!SUMA_isSameEdge (SO->EL, SO->EL->Tri_limb[Tri1][0], E1) && SPI->isEdgeInters[SO->EL->Tri_limb[Tri1][0]]) {
07376       E2 = SO->EL->Tri_limb[Tri1][0];
07377    }else if (!SUMA_isSameEdge (SO->EL, SO->EL->Tri_limb[Tri1][1], E1) && SPI->isEdgeInters[SO->EL->Tri_limb[Tri1][1]]) {
07378       E2 = SO->EL->Tri_limb[Tri1][1];
07379    }else if (!SUMA_isSameEdge (SO->EL, SO->EL->Tri_limb[Tri1][2], E1) && SPI->isEdgeInters[SO->EL->Tri_limb[Tri1][2]]) {
07380       E2 = SO->EL->Tri_limb[Tri1][2];
07381    }else {
07382       fprintf (SUMA_STDERR,"Error %s: No E2 found.\n", FuncName);
07383       SUMA_RETURN (NULL);
07384    }
07385 
07386    Visited = (SUMA_Boolean *) SUMA_calloc (SO->N_FaceSet, sizeof(SUMA_Boolean));
07387    tPath1 = (int *) SUMA_calloc (SO->N_FaceSet, sizeof(int));
07388    if (!Visited || !tPath1) {
07389       fprintf (SUMA_STDERR, "Error %s: Failed to allocate.\n", FuncName);
07390       if (Visited) SUMA_free(Visited);
07391       if (tPath2) SUMA_free(tPath1); 
07392       SUMA_RETURN (NULL);
07393    }
07394    
07395    N_tPath1 = 0;
07396    if (!SUMA_FromIntEdgeToIntEdge (Tri1, E1, E2, SO->EL, SPI, Ny, Visited, &d1, dmax, tPath1, &N_tPath1)) {
07397       fprintf (SUMA_STDERR, "Error %s: Failed in SUMA_FromIntEdgeToIntEdge.\n", FuncName);
07398       if (Visited) SUMA_free(Visited);
07399       if (tPath2) SUMA_free(tPath1);      
07400       SUMA_RETURN (NULL);
07401    }
07402    
07403    if (LocalHead) {
07404       fprintf (SUMA_STDERR, "%s: Found a distance of %f.\n\n\n", FuncName, d1);
07405    }
07406    
07407    /* Now try going in the other direction, E2->E1 */
07408    cnt = E2;
07409    E2 = E1;
07410    E1 = cnt;
07411    
07412    /* reset the values of Visited */
07413    for (cnt=0; cnt < SO->N_FaceSet; ++cnt) if (Visited[cnt]) Visited[cnt] = NOPE;
07414    
07415    tPath2 = (int *) SUMA_calloc (SO->N_FaceSet, sizeof(int));
07416    if (!Visited || !tPath2) {
07417       fprintf (SUMA_STDERR, "Error %s: Failed to allocate.\n", FuncName);
07418       if (Visited) SUMA_free(Visited);
07419       if (tPath1) SUMA_free(tPath1);
07420       if (tPath2) SUMA_free(tPath2);
07421       SUMA_RETURN (NULL);
07422    }
07423 
07424    N_tPath2 = 0;
07425    if (!SUMA_FromIntEdgeToIntEdge (Tri1, E1, E2, SO->EL, SPI, Ny, Visited, &d2, dmax, tPath2, &N_tPath2)) {
07426       fprintf (SUMA_STDERR, "Error %s: Failed in SUMA_FromIntEdgeToIntEdge.\n", FuncName);
07427       if (Visited) SUMA_free(Visited);
07428       if (tPath1) SUMA_free(tPath1);
07429       if (tPath2) SUMA_free(tPath2);
07430       SUMA_RETURN (NULL);
07431    }
07432    
07433    if (Visited) SUMA_free(Visited);
07434    
07435    if (LocalHead) {
07436       fprintf (SUMA_STDERR, "%s: Found a distance of %f.\n", FuncName, d2);
07437    }
07438    
07439    if (d2 < d1) {
07440       *N_tPath = N_tPath2;
07441       *dinters = d2;
07442       if (tPath1) SUMA_free(tPath1);
07443       SUMA_RETURN (tPath2);
07444    } else {
07445       *dinters = d1;
07446       *N_tPath = N_tPath1;
07447       if (tPath2) SUMA_free(tPath2);
07448       SUMA_RETURN (tPath1);
07449    }
07450    
07451 }

SUMA_Boolean SUMA_isSameEdge SUMA_EDGE_LIST   EL,
int    E1,
int    E2
 

determines whether to edges are identical or not. Recall that an edge can be represented multiple times in SO->EL, once for each triangle that uses it. Two edges are the same if and only if EL->EL[E1][0] == EL->EL[E2][0] && EL->EL[E1][1] == EL->EL[E2][1]

ans = SUMA_isSameEdge ( EL, E1, E2);

Parameters:
EL  (SUMA_EDGE_LIST *) Edge List structure.
E1  (int) edge index
E2  (int) edge index
Returns:
ans (SUMA_Boolean) YUP/NOPE

Definition at line 7242 of file SUMA_GeomComp.c.

References SUMA_EDGE_LIST::EL, SUMA_Boolean, SUMA_ENTRY, and SUMA_RETURN.

Referenced by SUMA_FromIntEdgeToIntEdge(), and SUMA_IntersectionStrip().

07243 {
07244    static char FuncName[]={"SUMA_isSameEdge"};
07245    
07246    SUMA_ENTRY;
07247 
07248    if (EL->EL[E1][0] == EL->EL[E2][0] && EL->EL[E1][1] == EL->EL[E2][1]) {
07249       SUMA_RETURN (YUP);
07250    } else {
07251       SUMA_RETURN (NOPE);
07252    }
07253    
07254 }

int SUMA_isSelfIntersect SUMA_SurfaceObject   SO,
int    StopAt
 

Function to detect surface self intersection returns -1 in case of error, 0 in case of no intersection 1 in case of intersection.

Definition at line 333 of file SUMA_GeomComp.c.

References SUMA_SurfaceObject::EL, SUMA_EDGE_LIST::EL, SUMA_EDGE_LIST::ELps, SUMA_SurfaceObject::FaceSetDim, SUMA_SurfaceObject::FaceSetList, SUMA_MT_INTERSECT_TRIANGLE::isHit, LocalHead, n1, n2, SUMA_EDGE_LIST::N_EL, SUMA_SurfaceObject::N_FaceSet, SUMA_SurfaceObject::N_Node, SUMA_SurfaceObject::NodeDim, SUMA_SurfaceObject::NodeList, p, SUMA_Boolean, SUMA_ENTRY, SUMA_Free_MT_intersect_triangle(), SUMA_FROM_BARYCENTRIC, SUMA_LH, SUMA_MIN_PAIR, SUMA_MT_intersect_triangle(), SUMA_RETURN, SUMA_SL_Err, SUMA_MT_INTERSECT_TRIANGLE::u, and SUMA_MT_INTERSECT_TRIANGLE::v.

00334 {
00335    static char FuncName[]={"SUMA_isSelfIntersect"};
00336    float *NodePos = NULL, *p1=NULL, *p2=NULL, *p3 = NULL, p[3], *ep1=NULL, *ep2=NULL;
00337    int hit = 0, k, t1, t2, it, it3, n1, n2, n3;
00338    SUMA_MT_INTERSECT_TRIANGLE *MTI = NULL;
00339    SUMA_Boolean LocalHead = NOPE;
00340    
00341    SUMA_ENTRY;
00342    
00343    if (!SO->EL) {
00344       SUMA_SL_Err("NULL SO->EL");
00345       SUMA_RETURN(-1);
00346    }
00347    
00348    if (StopAt < 1) StopAt = 1;
00349    
00350    hit = 0; k = 0;
00351    while (k < SO->EL->N_EL) {
00352          t1 = SO->EL->ELps[k][1]; t2 = SO->EL->ELps[SUMA_MIN_PAIR(k+1, SO->EL->N_EL-1)][1];
00353          ep1 = &(SO->NodeList[3*SO->EL->EL[k][0]]); ep2 = &(SO->NodeList[3*SO->EL->EL[k][1]]);
00354          /* find out if segment intersects */
00355          MTI = SUMA_MT_intersect_triangle(ep1, ep2, SO->NodeList, SO->N_Node, SO->FaceSetList, SO->N_FaceSet, MTI); 
00356          for (it=0; it<SO->N_FaceSet; ++it) {
00357             if (MTI->isHit[it] && it != t1 && it != t2) {
00358                /* ray hit triangle, is intersection inside segment ? */
00359                /* SUMA_LH("Checking hit..."); */
00360                it3 = SO->FaceSetDim*it;
00361                n1 = SO->FaceSetList[it3]; n2 = SO->FaceSetList[it3+1]; n3 = SO->FaceSetList[it3+2];
00362                p1 = &(SO->NodeList[SO->NodeDim*n1]); p2 = &(SO->NodeList[SO->NodeDim*n2]); p3 = &(SO->NodeList[SO->NodeDim*n3]);   
00363                SUMA_FROM_BARYCENTRIC(MTI->u[it], MTI->v[it], p1, p2, p3, p);
00364                if (p[0] > ep1[0] && p[0] < ep2[0]) {
00365                   if (p[1] > ep1[1] && p[1] < ep2[1]) {
00366                      if (p[2] > ep1[2] && p[2] < ep2[2]) {
00367                         /* point in segment, self intersection detected. */
00368                         if (LocalHead) fprintf(SUMA_STDERR,"%s: Triangle %d (%d, %d, %d) was hit by segment formed by nodes [%d, %d]\n", 
00369                            FuncName, it, n1, n2, n3, SO->EL->EL[k][0], SO->EL->EL[k][1]);
00370                            ++ hit;
00371                         break;
00372                      }
00373                   }
00374                }
00375             }
00376          }
00377          if (hit >= StopAt) break;
00378          /* skip duplicate edges */
00379          if (SO->EL->ELps[k][2] > 0) {
00380                k += SO->EL->ELps[k][2];
00381          } else ++k;
00382    }
00383    
00384    if (MTI) MTI = SUMA_Free_MT_intersect_triangle(MTI); 
00385    
00386    if (LocalHead) {
00387       if (!hit) {
00388          SUMA_LH("Surface does not self intersect.");
00389       } else {
00390          SUMA_LH("Surface self intersects.");
00391       }
00392    }
00393    SUMA_RETURN(hit);
00394 }

SUMA_Boolean SUMA_Mark_Tri SUMA_EDGE_LIST   EL,
int    E1,
int    iBranch,
int *    TriBranch,
int *    IsInter,
int *    N_IsInter,
int *    VisitationOrder,
int *    ivisit
 

Definition at line 6676 of file SUMA_GeomComp.c.

References SUMA_EDGE_LIST::EL, SUMA_EDGE_LIST::ELps, LocalHead, SUMA_Boolean, and SUMA_EDGE_LIST::Tri_limb.

Referenced by SUMA_AssignTriBranch().

06677 {
06678    static char FuncName[]={"SUMA_Mark_Tri"};
06679    int Tri = -1, Found, k, kedge = 0, E2, Ntri = 0;
06680    static int In = 0;
06681    SUMA_Boolean LocalHead = NOPE;
06682    
06683    /* this is a recursive function, you don't want to log every time it is called */
06684    /* SUMA_ENTRY;    */
06685    
06686    ++In;
06687    if (LocalHead) fprintf (SUMA_STDERR, "%s: Entered #%d.\n", FuncName, In);
06688    
06689    /* find the next triangle hosting E1, if possible, otherwise it is the end of the branch. */
06690    if (EL->ELps[E1][2] != 2) { /* reached a dead end , end of branch */
06691       /* mark triangle, remove E1 from list and return */
06692       if (LocalHead) fprintf (SUMA_STDERR, "%s: reached end of branch.\n", FuncName);
06693       kedge = 0;
06694       Found = NOPE;
06695       while (!Found && kedge < *N_IsInter) {
06696          if (IsInter[kedge] == E1) {
06697             Found = YUP;
06698             *N_IsInter = *N_IsInter - 1;
06699             IsInter[kedge] = IsInter[*N_IsInter];
06700          } else ++kedge;
06701       }
06702       return (YUP);
06703    }else {
06704       Tri = EL->ELps[E1][1];
06705       if (TriBranch[Tri]) { /* try second triangle */
06706          Tri = EL->ELps[E1+1][1];
06707       }
06708       if (LocalHead) fprintf (SUMA_STDERR, "%s: moving on to triangle %d.\n", FuncName, Tri);
06709    }
06710    
06711    if (!TriBranch[Tri]) { 
06712       /* unvisited, mark with iBranch */
06713       TriBranch[Tri] = iBranch;
06714       VisitationOrder[*ivisit] = Tri;
06715       ++(*ivisit);
06716       /* find other edges in this triangle that have been intersected */
06717       Found = NOPE; 
06718       k = 0;
06719       while (!Found && k < 3) {
06720          E2 = EL->Tri_limb[Tri][k]; /* this may not be the first occurence of this edge since the list contains duplicates */
06721          if (LocalHead) {
06722             fprintf (SUMA_STDERR, "%s: Trying edge E2 %d (%d %d), tiangle %d, edge %d.\n", 
06723                      FuncName, E2, EL->EL[E2][0], EL->EL[E2][1], Tri, k);
06724          }
06725          while (EL->ELps[E2][2] < 0) { /* find the first occurence of this edge in the list */
06726             E2--;
06727          }
06728          if (LocalHead) fprintf (SUMA_STDERR, "%s: E2 changed to %d. E1 is %d\n", FuncName, E2, E1);
06729          if (E2 != E1) {
06730             /* was E2 intersected ? */
06731             kedge = 0;
06732             while (!Found && kedge < *N_IsInter) {
06733                if (IsInter[kedge] == E2) {
06734                   Found = YUP;
06735                   if (LocalHead) fprintf (SUMA_STDERR, "%s: E2 is intersected.\n", FuncName);
06736                }
06737                else ++kedge;
06738             }
06739          }
06740          ++k;
06741       }
06742       
06743       if (!Found) {
06744          fprintf (SUMA_STDERR, "Error %s: No second edge found.\n", FuncName);
06745          return (NOPE);
06746       } else {
06747          if (LocalHead) fprintf (SUMA_STDERR, "%s: Removing E2 from List and calling SUMA_Mark_Tri.\n", FuncName);
06748          /* remove this new edge from the list */
06749          *N_IsInter = *N_IsInter - 1;
06750          IsInter[kedge] = IsInter[*N_IsInter];
06751          
06752          /* continue visitation */
06753          if (!SUMA_Mark_Tri (EL, E2, iBranch, TriBranch, IsInter, N_IsInter, VisitationOrder, ivisit)) {
06754             fprintf (SUMA_STDERR, "Error %s: Failed in SUMA_Mark_Tri.\n", FuncName);
06755             return (NOPE);
06756          } 
06757          return (YUP);
06758       }
06759    } else {
06760       if (TriBranch[Tri] != iBranch) {
06761          fprintf (SUMA_STDERR, "\a%s: Branches colliding, Must weld %d to %d.\n", FuncName, iBranch, TriBranch[Tri]);
06762          
06763          /* DO NOT MODIFY THE VALUE OF BRANCH or you will mistakingly link future branches*/ 
06764       }
06765       /* visited, end of branch return */
06766       if (LocalHead) fprintf (SUMA_STDERR, "%s: End of branch. Returning.\n", FuncName);
06767       return (YUP);
06768    }
06769    
06770    fprintf (SUMA_STDERR, "Error %s: Should not be here.\n", FuncName);
06771    return (NOPE);
06772 }

SUMA_Boolean* SUMA_MaskOfNodesInPatch SUMA_SurfaceObject   SO,
int *    N_NodesUsedInPatch
 

a function to return a mask indicating if a node is part of a patch or not isNodeInPatch = SUMA_MaskOfNodesInPatch( SUMA_SurfaceObject *SO, int * N_NodesUsedInPatch);

Parameters:
SO  (SUMA_SurfaceObject *) the surface object
N_NodesUsedInPatch  (int *) will contain the number of nodes used in the mesh of the patch (that is SO->FaceSetList) if *N_NodesUsedInPatch == SO->N_Node then all nodes in the nodelist are used in the mesh
Returns:
isNodeInPatch (SUMA_Boolean *) a vector SO->N_Node long such that if isNodeInPatch[n] = YUP then node n is used in the mesh

Definition at line 5169 of file SUMA_GeomComp.c.

References SUMA_SurfaceObject::FaceSetDim, SUMA_SurfaceObject::FaceSetList, SUMA_SurfaceObject::N_FaceSet, SUMA_SurfaceObject::N_Node, SUMA_Boolean, SUMA_calloc, SUMA_ENTRY, SUMA_RETURN, SUMA_SL_Crit, and SUMA_SL_Err.

Referenced by SUMA_FreeSurfer_WritePatch(), and SUMA_PrepSO_GeomProp_GL().

05170 {
05171    static char FuncName[]={"SUMA_MaskOfNodesInPatch"};
05172    int k;
05173    SUMA_Boolean *NodesInPatchMesh = NULL;
05174 
05175    SUMA_ENTRY;
05176 
05177    *N_NodesUsedInPatch = 0;
05178 
05179    if (!SO) {
05180       SUMA_SL_Err("NULL SO");
05181       SUMA_RETURN(NULL);
05182    }
05183    if (!SO->FaceSetList || !SO->N_FaceSet) {
05184       SUMA_SL_Err("NULL or empty SO->FaceSetList");
05185       SUMA_RETURN(NULL);
05186    }
05187 
05188    NodesInPatchMesh = (SUMA_Boolean *)SUMA_calloc(SO->N_Node, sizeof(SUMA_Boolean)); 
05189    if (!NodesInPatchMesh) {
05190       SUMA_SL_Crit("Failed to allocate for NodesInPatchMesh");
05191       SUMA_RETURN(NULL);
05192    }
05193    for (k=0; k<SO->FaceSetDim*SO->N_FaceSet; ++k) {
05194       if (!NodesInPatchMesh[SO->FaceSetList[k]]) { 
05195          ++*N_NodesUsedInPatch;
05196          NodesInPatchMesh[SO->FaceSetList[k]] = 1;         
05197       }
05198    }
05199 
05200    SUMA_RETURN(NodesInPatchMesh);  
05201 }

double SUMA_Mesh_Area SUMA_SurfaceObject   SO,
int *    FaceSets,
int    N_FaceSet
 

computes the total area of a surface. NOTE: This function will replace whatever values you have in SO->PolyArea. If SO->PolyArea is NULL, it will remain that way.

Definition at line 5820 of file SUMA_GeomComp.c.

References a, SUMA_SurfaceObject::FaceSetList, i, LocalHead, n0, n1, n2, SUMA_SurfaceObject::N_FaceSet, SUMA_SurfaceObject::NodeList, SUMA_SurfaceObject::PolyArea, SUMA_Boolean, SUMA_ENTRY, SUMA_RETURN, SUMA_SL_Err, and SUMA_TRI_AREA.

Referenced by SUMA_GetAreaDiffRange(), SUMA_NewAreaAtRadius(), and SUMA_StretchToFitLeCerveau().

05821 {
05822    static char FuncName[]={"SUMA_Mesh_Area"};
05823    double A = 0.0, a = 0.0;
05824    int i, i3;
05825    float *n0, *n1, *n2;
05826    SUMA_Boolean LocalHead = NOPE;
05827    
05828    SUMA_ENTRY;
05829 
05830    if (!SO) { SUMA_SL_Err("NULL SO"); SUMA_RETURN(A);  }
05831    if (!SO->FaceSetList) { SUMA_SL_Err("NULL SO->FaceSetList"); SUMA_RETURN(A);  }
05832       
05833    if (!FaceSets ) { 
05834       if (N_FaceSet != -1) {
05835          SUMA_SL_Err("With NULL FaceSets, use -1 for N_FaceSet");
05836          SUMA_RETURN(A);
05837       }
05838       N_FaceSet = SO->N_FaceSet; 
05839       FaceSets = SO->FaceSetList;    
05840    }else {
05841       if (N_FaceSet < 0) {
05842          SUMA_SL_Err("N_FaceSet < 0");
05843          SUMA_RETURN(A);
05844       }
05845    }
05846 
05847    A = 0.0;
05848    if (SO->PolyArea) {
05849       for (i=0;  i<N_FaceSet; ++i) {
05850          i3 = 3*i;
05851          n0 = &(SO->NodeList[3*FaceSets[i3]]);
05852          n1 = &(SO->NodeList[3*FaceSets[i3+1]]);
05853          n2 = &(SO->NodeList[3*FaceSets[i3+2]]);
05854          SUMA_TRI_AREA( n0, n1, n2, a);
05855          SO->PolyArea[i] = (float)a;
05856          A += a;
05857       }
05858    } else {
05859       for (i=0;  i<N_FaceSet; ++i) {
05860          i3 = 3*i;
05861          n0 = &(SO->NodeList[3*FaceSets[i3]]);
05862          n1 = &(SO->NodeList[3*FaceSets[i3+1]]);
05863          n2 = &(SO->NodeList[3*FaceSets[i3+2]]);
05864          SUMA_TRI_AREA( n0, n1, n2, a);
05865          A += a;
05866       }
05867    }
05868    if (LocalHead) {
05869       fprintf(SUMA_STDERR,"%s:\n   A = %f\n", FuncName, A);
05870    }
05871    SUMA_RETURN(A);
05872 }

double SUMA_Mesh_Volume SUMA_SurfaceObject   SO,
int *    FSI,
int    N_FaceSet
 

Calculate the volume of a mesh per the method in Hughes, S.W. et al. Phys. Med. Biol. 1996.

Tested with Icosahedron surface (see direct vol computation in CreateIcosahedron)

Tested with tetrahedron below, which has a volume of 0.166667 Also, the same volume was obtained with a rotated version of the same tetrahedron TetraFaceSetList.1D 0 1 2 0 3 1 0 2 3 2 1 3

TetraNodeList.1D 0 0 0 1 0 0 0 1 0 1 1 1 which should have a volume of (1/3)A*h of 1/3 * 0.5 * 1

Volume of smoothwm surface did not change if surface was rotated and shifted, a very good thing.

If you try to calculate the volume of a boxe's surface with the box's axes in alignment with the X, Y and Z directions, you will get nan for an answer because the sum of the weights is ~= 0 . If you rotate the surface, the problem will be solved.

  • It is extremely important that the surface mesh be consistently defined.
  • Detecting consistency must be done ahead of time (need program to do that) because doing it here will slow the computations a lot and consistency fix requires recalculating the normals and all that depends on them (quite a bit).

Definition at line 5743 of file SUMA_GeomComp.c.

References c, SUMA_CommonFields::DsetList, SUMA_SurfaceObject::FaceNormList, i, LocalHead, SUMA_SurfaceObject::N_FaceSet, SUMA_SurfaceObject::PolyArea, SUMA_Boolean, SUMA_ENTRY, SUMA_FACE_CENTROID, SUMA_RETURN, SUMA_SL_Err, SUMA_SL_Warn, and SUMA_SurfaceMetrics_eng().

Referenced by SUMA_GetVolDiffRange(), SUMA_NewVolumeAtRadius(), and SUMA_Pattie_Volume().

05744 {
05745    static char FuncName[]={"SUMA_Mesh_Volume"};
05746    double Vol = 0.0, c[3], anx, any, anz, sx, sy, sz, kx, ky, kz, kt;
05747    float *pa = NULL;
05748    int i, fc;
05749    SUMA_Boolean LocalHead = NOPE;
05750    
05751    SUMA_ENTRY;
05752    
05753    if (!SO) { SUMA_SL_Err("NULL SO"); SUMA_RETURN(Vol);  }
05754    if (!SO->FaceNormList) { SUMA_SL_Err("NULL SO->FaceNormList"); SUMA_RETURN(Vol);  }
05755    if (!SO->PolyArea) { 
05756       if (!SUMA_SurfaceMetrics_eng (SO, "PolyArea", NULL, 0, SUMAg_CF->DsetList)) {
05757          SUMA_SL_Err("Failed to compute SO->PolyArea"); SUMA_RETURN(Vol);  
05758       }
05759    }
05760    pa = SO->PolyArea;
05761    
05762    if (FSI || N_FaceSet != -1) {
05763       SUMA_SL_Err("FSI and N_FaceSet are two stupid options never to be used.\nUse NULL and -1, respectively.");
05764       SUMA_RETURN(Vol);
05765    }
05766    
05767    if (!FSI) { 
05768       N_FaceSet = SO->N_FaceSet;    
05769    }
05770 
05771    
05772    /* calculate vector of areas * normals */
05773    kx = ky = kz = sx = sy = sz = 0.0;
05774    for (i=0; i<N_FaceSet; ++i) {
05775       if (FSI) fc = FSI[i];
05776       else fc = i;
05777       SUMA_FACE_CENTROID(SO, fc, c);
05778       #if 0 
05779          if (LocalHead) fprintf(SUMA_STDERR,"Area: %f , normal (%f, %f, %f)\n", 
05780                pa[fc], SO->FaceNormList[3*fc], SO->FaceNormList[3*fc+1], SO->FaceNormList[3*fc+2]);
05781       #endif
05782       anx = pa[fc] * SO->FaceNormList[3*fc];   kx += anx;  sx += c[0] * anx;
05783       any = pa[fc] * SO->FaceNormList[3*fc+1]; ky += any;  sy += c[1] * any;
05784       anz = pa[fc] * SO->FaceNormList[3*fc+2]; kz += anz;  sz += c[2] * anz;
05785    }
05786    kt = (kx+ky+kz); /* need to normalize k so that sum is 1, kx, ky and kz are supposed to 
05787                   "weight the volume according to its orientation relative to the axes."
05788                   For a sphere, you can use 1/3 for kx, ky and kz...   */
05789    if (fabs(kt) < 1e-15) { 
05790       SUMA_SL_Warn("Weight constants sum to ~= 0.\n"
05791                    "Volume measurements may be off.\n"
05792                    "If your surface's axes are along\n"
05793                    "the X, Y and Z directions, as you \n"
05794                    "could have with a box's surface, rotating\n"
05795                    "the surface will solve the problem.");
05796       fprintf(SUMA_STDERR, "%s:\n"
05797                            "kx + ky + kz = kt\n"
05798                            "%f + %f + %f = %f\n"
05799                            "sx, sy, sz = %f, %f, %f\n",
05800                            FuncName, kx, ky, kz, kx+ky+kz, sx, sy, sz);   }
05801    kx /= kt;
05802    ky /= kt;
05803    kz /= kt;
05804    if (LocalHead) {
05805       fprintf(SUMA_STDERR, "%s:\n"
05806                            "%f + %f + %f = %f\n"
05807                            "sx, sy, sz = %f, %f, %f\n",
05808                            FuncName, kx, ky, kz, kx+ky+kz, sx, sy, sz);
05809    }
05810    Vol = kx * sx + ky *sy + kz * sz;
05811    
05812    SUMA_RETURN(Vol);
05813 }

SUMA_OFFSET_LL_DATUM* SUMA_New_Offset_ll_Datum int    n,
int    layer
 

Definition at line 1156 of file SUMA_GeomComp.c.

References SUMA_OFFSET_LL_DATUM::layer, SUMA_OFFSET_LL_DATUM::ni, SUMA_OFFSET_LL_DATUM::off, SUMA_ENTRY, SUMA_malloc, and SUMA_RETURN.

Referenced by SUMA_getoffsets_ll().

01157 {
01158    static char FuncName[]={"SUMA_New_Offset_ll_Datum"};
01159    SUMA_OFFSET_LL_DATUM * datum = NULL;
01160    
01161    SUMA_ENTRY;
01162    
01163    datum = (SUMA_OFFSET_LL_DATUM *)SUMA_malloc(sizeof(SUMA_OFFSET_LL_DATUM));
01164    datum->ni = n;
01165    datum->layer = layer;
01166    datum->off = -1.0;
01167    
01168    SUMA_RETURN(datum);
01169 }

double SUMA_NewAreaAtRadius SUMA_SurfaceObject   SO,
double    r,
double    Rref,
float *    tmpList
 

Changes the coordinates of SO's nodes so that the new average radius of the surface is equal to r.

This function is an integral part of the function for equating the areas of 2 surfaces. Nodes are stretched by a fraction equal to: (Rref - r) / Rref * Un where Un is the distance of the node from the center of the surface Rref is the reference radius, r is the desired radius

Parameters:
SO  (SUMA_SurfaceObject *) Surface object, obviously
r  (double) (see above)
Rref  (double) (see above) \pram tmpList (float *) a pre-allocated vector to contain the new coordinates of the surface
Returns:
A (double) the area of the new surface (post streching)
See also:
SUMA_AreaDiff

Definition at line 1340 of file SUMA_GeomComp.c.

References c, SUMA_SurfaceObject::Center, i, LocalHead, SUMA_SurfaceObject::N_Node, SUMA_SurfaceObject::NodeList, r, SUMA_Boolean, SUMA_COPY_VEC, SUMA_ENTRY, SUMA_Mesh_Area(), SUMA_POINT_AT_DISTANCE_NORM, SUMA_RETURN, SUMA_SL_Err, and SUMA_UNIT_VEC.

Referenced by SUMA_AreaDiff(), and SUMA_GetAreaDiffRange().

01341 {
01342    static char FuncName[]={"SUMA_NewAreaAtRadius"};
01343    double Dr, A=0.0,  Un, U[3], Dn, P2[2][3], c[3];
01344    float *fp;
01345    int i;
01346    SUMA_Boolean LocalHead = NOPE;
01347 
01348    SUMA_ENTRY;
01349 
01350    /* calculate Dr and normalize by the radius of SOref */
01351    Dr = ( Rref - r ) / Rref;
01352 
01353    /* Now loop over all the nodes in SO and add the deal */
01354    for (i=0; i<SO->N_Node; ++i) {
01355       /* change node coordinate of each node by Dr, along radial direction  */
01356       fp = &(SO->NodeList[3*i]); SUMA_UNIT_VEC(SO->Center, fp, U, Un);
01357       Dn = Dr*Un + Un;
01358       if (Un) {
01359          SUMA_COPY_VEC(SO->Center, c, 3, float, double);
01360          SUMA_POINT_AT_DISTANCE_NORM(U, c, Dn, P2);
01361          tmpList[3*i] = (float)P2[0][0]; tmpList[3*i+1] = (float)P2[0][1]; tmpList[3*i+2] = (float)P2[0][2];
01362       } else {
01363          SUMA_SL_Err("Identical points!\n"
01364                      "No coordinates modified");
01365          SUMA_RETURN(0);
01366       }
01367    }
01368 
01369 
01370    /* calculate the new Area */
01371    fp = SO->NodeList;/* save NodeList */
01372    SO->NodeList = tmpList; /* use new coordinates */
01373    A = fabs((double)SUMA_Mesh_Area(SO, NULL, -1));
01374    SO->NodeList = fp; fp = NULL;   /* make NodeList point to the original data */
01375 
01376    SUMA_RETURN(A);
01377 } 

double SUMA_NewVolumeAtRadius SUMA_SurfaceObject   SO,
double    r,
double    Rref,
float *    tmpList
 

Changes the coordinates of SO's nodes so that the new average radius of the surface is equal to r.

This function is an integral part of the function for equating the volumes of 2 surfaces. Nodes are stretched by a fraction equal to: (Rref - r) / Rref * Un where Un is the distance of the node from the center of the surface Rref is the reference radius, r is the desired radius

Parameters:
SO  (SUMA_SurfaceObject *) Surface object, obviously
r  (double) (see above)
Rref  (double) (see above) \pram tmpList (float *) a pre-allocated vector to contain the new coordinates of the surface
Returns:
V (double) the volume of the new surface (post streching)
See also:
SUMA_VolDiff

Definition at line 1394 of file SUMA_GeomComp.c.

References c, SUMA_SurfaceObject::Center, i, LocalHead, SUMA_SurfaceObject::N_Node, SUMA_SurfaceObject::NodeList, r, SUMA_Boolean, SUMA_COPY_VEC, SUMA_ENTRY, SUMA_Mesh_Volume(), SUMA_POINT_AT_DISTANCE_NORM, SUMA_RETURN, SUMA_SL_Err, and SUMA_UNIT_VEC.

Referenced by SUMA_GetVolDiffRange(), and SUMA_VolDiff().

01395 {
01396    static char FuncName[]={"SUMA_NewVolumeAtRadius"};
01397    double Dr, V=0.0,  Un, U[3], Dn, P2[2][3], c[3];
01398    float *fp;
01399    int i;
01400    SUMA_Boolean LocalHead = NOPE;
01401 
01402    SUMA_ENTRY;
01403 
01404    /* calculate Dr and normalize by the radius of SOref */
01405    Dr = ( Rref - r ) / Rref;
01406 
01407    /* Now loop over all the nodes in SO and add the deal */
01408    for (i=0; i<SO->N_Node; ++i) {
01409       /* change node coordinate of each node by Dr, along radial direction  */
01410       fp = &(SO->NodeList[3*i]); SUMA_UNIT_VEC(SO->Center, fp, U, Un);
01411       Dn = Dr*Un + Un;
01412       if (Un) {
01413          SUMA_COPY_VEC(SO->Center, c, 3, float, double);
01414          SUMA_POINT_AT_DISTANCE_NORM(U, c, Dn, P2);
01415          tmpList[3*i] = (float)P2[0][0]; tmpList[3*i+1] = (float)P2[0][1]; tmpList[3*i+2] = (float)P2[0][2];
01416       } else {
01417          SUMA_SL_Err("Identical points!\n"
01418                      "No coordinates modified");
01419          SUMA_RETURN(0);
01420       }
01421    }
01422 
01423 
01424    /* calculate the new volume */
01425    fp = SO->NodeList;/* save NodeList */
01426    SO->NodeList = tmpList; /* use new coordinates */
01427    V = fabs((double)SUMA_Mesh_Volume(SO, NULL, -1));
01428    SO->NodeList = fp; fp = NULL;   /* make NodeList point to the original data */
01429 
01430    SUMA_RETURN(V);
01431 } 

float* SUMA_NN_GeomSmooth SUMA_SurfaceObject   SO,
int    N_iter,
float *    fin_orig,
int    vpn,
SUMA_INDEXING_ORDER    d_order,
float *    fout_final_user,
SUMA_COMM_STRUCT   cs
 

Definition at line 2939 of file SUMA_GeomComp.c.

References SUMA_SurfaceObject::FN, fout, SUMA_SurfaceObject::N_Node, SUMA_COMM_STRUCT::Send, SUMA_calloc, SUMA_COLUMN_MAJOR, SUMA_ENTRY, SUMA_free, SUMA_INDEXING_ORDER, SUMA_NODE_XYZ, SUMA_RETURN, SUMA_ROW_MAJOR, SUMA_SendToSuma(), SUMA_SL_Crit, SUMA_SL_Err, SUMA_SL_Warn, SUMA_SmoothAttr_Neighb(), and vpn.

02942 {
02943    static char FuncName[]= {"SUMA_NN_GeomSmooth"};
02944    float *fout_final=NULL, *fbuf=NULL, *fin_next=NULL, *fin=NULL, *fout=NULL;
02945    int niter=0;
02946 
02947    SUMA_ENTRY;
02948    if (!SO) { SUMA_SL_Err("NULL SO"); SUMA_RETURN(NULL); }
02949    if (!SO->FN) {
02950       SUMA_SL_Err("NULL SO->FN");
02951       SUMA_RETURN(NULL);
02952    }   
02953    if (N_iter % 2) {
02954       SUMA_SL_Err("N_iter must be an even number\n");
02955       SUMA_RETURN(NULL);
02956    }
02957    if (vpn < 1) {
02958       SUMA_SL_Err("vpn < 1\n");
02959       SUMA_RETURN(NULL);
02960    }  
02961    
02962    if (fout_final_user == fin_orig) {
02963       SUMA_SL_Err("fout_final_user == fin_orig");
02964       SUMA_RETURN(NULL);
02965    }
02966    
02967    if (!fout_final_user) { /* allocate for output */
02968       fout_final = (float *)SUMA_calloc(SO->N_Node * vpn, sizeof(float));
02969       if (!fout_final) {
02970          SUMA_SL_Crit("Failed to allocate for fout_final\n");
02971          SUMA_RETURN(NULL);
02972       }
02973    }else {
02974       fout_final = fout_final_user; /* pre-allocated */
02975    }
02976    
02977    /* allocate for buffer */
02978    fbuf = (float *)SUMA_calloc(SO->N_Node * vpn, sizeof(float));
02979    if (!fbuf) {
02980       SUMA_SL_Crit("Failed to allocate for fbuf\n");
02981       SUMA_RETURN(NULL);
02982    }
02983    
02984    
02985    if (cs->Send) { /* send the first monster */
02986       if (!SUMA_SendToSuma (SO, cs, (void *)fin_orig, SUMA_NODE_XYZ, 1)) {
02987          SUMA_SL_Warn("Failed in SUMA_SendToSuma\nCommunication halted.");
02988       }
02989    }
02990    
02991    fin_next = fin_orig;
02992    switch (d_order) {
02993       case SUMA_ROW_MAJOR:
02994          for (niter=0; niter < N_iter; ++niter) {
02995             if ( niter % 2 ) { /* odd */
02996                fin = fin_next; /* input from previous output buffer */
02997                fout = fout_final; /* results go into final vector */
02998                fin_next = fout_final; /* in the next iteration, the input is from fout_final */
02999             } else { /* even */
03000                /* input data is in fin_new */
03001                fin = fin_next;
03002                fout = fbuf; /* results go into buffer */
03003                fin_next = fbuf; /* in the next iteration, the input is from the buffer */
03004             }
03005             fout = SUMA_SmoothAttr_Neighb ( fin, vpn*SO->N_Node, 
03006                                                  fout, SO->FN, vpn);
03007             if (cs->Send) {
03008                if (!SUMA_SendToSuma (SO, cs, (void *)fout, SUMA_NODE_XYZ, 1)) {
03009                   SUMA_SL_Warn("Failed in SUMA_SendToSuma\nCommunication halted.");
03010                }
03011             }
03012          }
03013          break;
03014       case SUMA_COLUMN_MAJOR:
03015          SUMA_SL_Err("Column Major not implemented");
03016          SUMA_RETURN(NULL);
03017          break;
03018       default:
03019          SUMA_SL_Err("Bad Major, very bad.\n");
03020          SUMA_RETURN(NULL);
03021          break;
03022    }
03023    
03024    if (fbuf) SUMA_free(fbuf); fbuf = NULL;
03025 
03026    SUMA_RETURN(fout);    
03027 }

int* SUMA_NodePath_to_EdgePath SUMA_EDGE_LIST   EL,
int *    Path,
int    N_Path,
int *    N_Edge
 

Converts a path formed by a series of connected nodes to a series of edges ePath = SUMA_NodePath_to_EdgePath (EL, Path, N_Path, N_Edge);.

Parameters:
EL  (SUMA_EDGE_LIST *) Pointer to edge list structure
Path  (int *) vector of node indices forming a path. Sequential nodes in Path must be connected on the surface mesh.
N_Path  (int) number of nodes in the path
N_Edge  (int *) pointer to integer that will contain the number of edges in the path usually equal to N_Path if path is a loop (closed) or N_Path - 1. 0 if function fails.
ePath  (int *) pointer to vector containing indices of edges forming the path. The indices are into EL->EL and represent the first occurence of the edge between Path[i] and Path[i+1]. NULL if trouble is encountered.
See also:
SUMA_NodePath_to_EdgePath_Inters , Path S in labbook NIH-2 page 153

Definition at line 7195 of file SUMA_GeomComp.c.

References i, LocalHead, SUMA_Boolean, SUMA_calloc, SUMA_ENTRY, SUMA_FindEdge(), SUMA_free, and SUMA_RETURN.

07196 {
07197    static char FuncName[]={"SUMA_NodePath_to_EdgePath"};
07198    int *ePath = NULL, i, i0;
07199    SUMA_Boolean LocalHead = NOPE;
07200    
07201    SUMA_ENTRY;
07202  
07203  
07204   *N_Edge = 0;
07205    ePath = (int *) SUMA_calloc(N_Path, sizeof(int));
07206    if (!ePath) {
07207       fprintf (SUMA_STDERR, "Error %s: Failed to allocate.\n", FuncName);
07208       SUMA_RETURN (NULL);
07209    }
07210 
07211    for (i=1; i<N_Path; ++i) {
07212       i0 = Path[i-1];
07213       /* find the location of the edge between i0 and i1 */
07214       ePath[i-1] = SUMA_FindEdge (EL, i0, Path[i]); 
07215       if (ePath[i-1] < 0) { /* error */
07216          fprintf (SUMA_STDERR, "Error %s: Failed in SUMA_FindEdge.\n", FuncName);
07217          SUMA_free(ePath);
07218          *N_Edge = 0;
07219          SUMA_RETURN (NULL);   
07220       }else {
07221          ++(*N_Edge);
07222       }
07223    }
07224 
07225    SUMA_RETURN (ePath);   
07226 }   

int* SUMA_NodePath_to_TriPath_Inters SUMA_SurfaceObject   SO,
SUMA_SURF_PLANE_INTERSECT   SPI,
int *    nPath,
int    N_nPath,
int *    N_tPath
 

Converts a series of connected nodes into a series of connected triangles that were intersected by the plane. There is no guarantee that two nodes that belong to triangles intersected by the plane and part of the shortest path (as returned by SUMA_Dijkstra) for an edge that belongs to a triangle intersected by the plane. See labbook NIH-2 page 158 for sketches illustrating this point. So the strip of triangles that you will get back may have holes in it since it only allows intersected triangles to be members of the path.

tPath = SUMA_NodePath_to_TriPath_Inters (SO, SPI, int *nPath, int N_nPath, int *N_tPath)

Parameters:
SO  (SUMA_SurfaceObject *) structure containing surface object
SPI  (SUMA_SURF_PLANE_INTERSECT *) surface plane intersection structure
nPath  (int *) vector containing the shortest path defined by its nodes (output of SUMA_Dijkstra)
N_nPath  (int) number of elements in nPath
N_tPath  (int *)pointer to number of elements returned in tPath
Returns:
tPath (int *) vector of *N_tPath indices of triangles that form a strip along the shortest path.
See also:
SUMA_Dijkstra , SUMA_NodePath_to_EdgePath , SUMA_Surf_Plane_Intersect
See also:
labbook NIH-2 pages 158, and 159 for MissingTriangles

Definition at line 7606 of file SUMA_GeomComp.c.

References E, SUMA_SurfaceObject::EL, SUMA_EDGE_LIST::ELps, SUMA_SurfaceObject::FaceSetList, i, SUMA_SURF_PLANE_INTERSECT::isTriHit, LocalHead, nc, SUMA_Boolean, SUMA_calloc, SUMA_ENTRY, SUMA_FindEdge(), SUMA_free, SUMA_isTriLinked(), SUMA_RETURN, and SUMA_whichTri().

07607 {
07608    static char FuncName[]={"SUMA_NodePath_to_TriPath_Inters"};
07609    int *tPath = NULL, e, i, N_nc, nc[3], N_HostTri, E, j, 
07610       HostTri, PrevTri, k, N1[2], N2[2], cnt, MissTri = 0, candidate;
07611    SUMA_Boolean Found, LocalHead = NOPE;
07612    
07613    SUMA_ENTRY;
07614    
07615    tPath = (int *) SUMA_calloc(2*N_nPath, sizeof(int));
07616    if (!tPath) {
07617       fprintf (SUMA_STDERR, "Error %s: Failed to allocate.\n", FuncName);
07618       SUMA_RETURN (NULL);
07619    }
07620    
07621    *N_tPath = 0;
07622    for (i=0; i < N_nPath - 1; ++i) {
07623       /* find the edge corresponding to two consecutive nodes in the path */
07624       E = SUMA_FindEdge (SO->EL, nPath[i], nPath[i+1]);
07625       if (E < 0) {
07626          fprintf (SUMA_STDERR, "Error %s: Failed in SUMA_FindEdge.\n", FuncName);
07627          SUMA_free(tPath);
07628          SUMA_RETURN(NULL);
07629       }
07630       /* find the triangles containing E and intersected by the plane */
07631       N_HostTri = SO->EL->ELps[E][2]; /* number of hosting triangles */
07632       if (N_HostTri > 2) {
07633          fprintf (SUMA_STDERR, "Warning %s: Surface is not a surface, Edge %d has more than %d hosting triangles.\n", FuncName, E, N_HostTri);
07634       }
07635       candidate = 0;
07636       /* search for a hosting triangle that was intersected */
07637       for (j=0; j < N_HostTri; ++j) {
07638          HostTri = SO->EL->ELps[E+j][1];
07639          if (SPI->isTriHit[HostTri]) { /* a candidate for adding to the path */
07640             ++candidate;
07641             if (*N_tPath > 2*N_nPath) {
07642                fprintf (SUMA_STDERR, "Error %s: N_tPath = %d > %d allocated.\n", FuncName, *N_tPath, 2*N_nPath);
07643             }  
07644             #if 1
07645             /* This block is an attempt to get All triangles intersected by plane AND having a node as part of the shortest path.
07646             It does not work well, probably because some of the functions called need fixing... */
07647             if (*N_tPath == 0) { /* if that is the first triangle in the path, add it without much fuss */
07648                tPath[*N_tPath] = HostTri; /* hosting triangle index */
07649                ++ (*N_tPath);
07650             } else { /* make sure there is continuation along edges */
07651                PrevTri = tPath[*N_tPath - 1];
07652                N_nc = SUMA_isTriLinked (&(SO->FaceSetList[3*PrevTri]), &(SO->FaceSetList[3*HostTri]), nc);
07653                if (!N_nc) {
07654                   fprintf (SUMA_STDERR, "Warning %s: Triangles %d and %d are not linked.\nAdding triangle %d anyway.\n", 
07655                      FuncName, PrevTri, HostTri, HostTri);
07656                   /* add triangle, anyway */
07657                   tPath[*N_tPath] = HostTri; 
07658                   ++ (*N_tPath);
07659                }else if (N_nc == 1) {
07660                   /* must fill triangle gap get the triangle with the common node and common edges*/
07661                   /* first, find remaining nodes in PrevTri  */
07662                   e = 0;
07663                   for (k=0; k <3; ++k) {
07664                      if (SO->FaceSetList[3*PrevTri+k] != nc[0]) {
07665                         N1[e] = SO->FaceSetList[3*PrevTri+k]; ++e;
07666                      }
07667                   }
07668                   /* then find remaining nodes in HostTri  */
07669                   e = 0;
07670                   for (k=0; k <3; ++k) {
07671                      if (SO->FaceSetList[3*HostTri+k] != nc[0]) {
07672                         N2[e] = SO->FaceSetList[3*HostTri+k]; ++e;
07673                      }
07674                   }
07675                   /* find a triangle that has either one of the following node combinations, in addition to nc[0]:
07676                   N1[0], N2[0] or N1[0], N2[1] or N1[1], N2[0] or N1[1], N2[1] */
07677                   Found = NOPE;
07678                   cnt = 0;
07679                   while (!Found && cnt < 4) {
07680                      switch (cnt) {
07681                         case 0:
07682                            MissTri = SUMA_whichTri (SO->EL, nc[0], N1[0], N2[0], 1);
07683                            if (LocalHead) fprintf (SUMA_STDERR, "%s: looking for triangle with nodes %d and %d... Tri = %d\n", 
07684                                  FuncName, N1[0], N2[0], MissTri);
07685                            break;
07686                         case 1:
07687                            MissTri = SUMA_whichTri (SO->EL, nc[0], N1[0], N2[1], 1);
07688                            if (LocalHead) fprintf (SUMA_STDERR, "%s: looking for triangle with nodes %d and %d... Tri = %d\n", 
07689                                  FuncName, N1[0], N2[1], MissTri);
07690                            break;
07691                         case 2:
07692                            MissTri = SUMA_whichTri (SO->EL, nc[0], N1[1], N2[0], 1);
07693                            if (LocalHead) fprintf (SUMA_STDERR, "%s: looking for triangle with nodes %d and %d... Tri = %d\n", 
07694                                  FuncName, N1[1], N2[0], MissTri);
07695                            break;
07696                         case 3:
07697                            MissTri = SUMA_whichTri (SO->EL, nc[0], N1[1], N2[1], 1);
07698                            if (LocalHead) fprintf (SUMA_STDERR, "%s: looking for triangle with nodes %d and %d... Tri = %d\n", 
07699                                  FuncName, N1[1], N2[1], MissTri);
07700                            break;
07701                      }
07702                      if (MissTri >= 0) {
07703                         Found = YUP;
07704                      }
07705                      ++cnt;
07706                   }
07707                   if (!Found) {
07708                      fprintf (SUMA_STDERR, "Warning %s: Failed to find missing triangle.\n", FuncName);
07709                      tPath[*N_tPath] = HostTri; 
07710                      ++ (*N_tPath);
07711                   }else {
07712                      /* add the missing triangle first, then the HostTri */
07713                      tPath[*N_tPath] = MissTri; 
07714                      ++ (*N_tPath);
07715                      tPath[*N_tPath] = HostTri; 
07716                      ++ (*N_tPath);
07717                   }
07718                }else if (N_nc == 2) {
07719                   /* Triangles share an edge so no problem, insert the new triangle in the path */
07720                   tPath[*N_tPath] = HostTri; 
07721                   ++ (*N_tPath);
07722                }else {
07723                   fprintf (SUMA_STDERR, "Error %s: Triangles %d and %d are identical.\n", FuncName, PrevTri, HostTri);
07724                   SUMA_free(tPath);
07725                   SUMA_RETURN(NULL);
07726                }
07727             }
07728             #else 
07729                tPath[*N_tPath] = HostTri; 
07730                ++ (*N_tPath);
07731             #endif   
07732          }
07733       }
07734       if (!candidate) {
07735          fprintf (SUMA_STDERR, "\aWarning %s: Nodes %d and %d of edge %d had no intersected hosting triangle.\n", FuncName, nPath[i], nPath[i+1], E);
07736          
07737       }
07738    }
07739    
07740    SUMA_RETURN (tPath);   
07741 }

int* SUMA_NodePath_to_TriPath_Inters_OLD SUMA_SurfaceObject   SO,
SUMA_TRI_BRANCH   Bv,
int *    Path,
int    N_Path,
int *    N_Tri
 

Converts a series of connected nodes into a series of connected triangles that belong to a branch. The function fails at times, picking the long instead of the short path but it is left here in case I need it in the future.

tPath = SUMA_NodePath_to_TriPath_Inters_OLD (SO, Bv, Path, N_Path, N_Tri);

Parameters:
SO  (SUMA_SurfaceObject *) Pointer to surface object
Bv  (SUMA_TRI_BRANCH*) Pointer to tiangle branch containing nodes in path.
Path  (int *) vector of node indices forming a path. Sequential nodes in Path must be connected on the surface mesh.
N_Path  (int) number of nodes in the path
N_Tri  (int *) pointer to integer that will contain the number of triangles in the path 0 if function fails.
Returns:
tPath (int *) pointer to vector containing indices of triangles forming the path. The indices are into SO->FaceSetList. NULL if trouble is encountered.
See also:
SUMA_NodePath_to_EdgePath , Path I in NIH-2, labbook page 153

Definition at line 7762 of file SUMA_GeomComp.c.

References SUMA_SurfaceObject::FaceSetList, i1, SUMA_TRI_BRANCH::list, LocalHead, SUMA_TRI_BRANCH::N_list, SUMA_Boolean, SUMA_calloc, SUMA_ENTRY, SUMA_free, and SUMA_RETURN.

07763 {
07764    static char FuncName[]={"SUMA_NodePath_to_TriPath_Inters_OLD"};
07765    int *tPath = NULL, ilist, i0, Tri, eTri, EdgeBuf, Tri0, Tri1, Direction, i1, loc2f, iDirSet;
07766    SUMA_Boolean LocalHead = NOPE, Found = NOPE;
07767    
07768    SUMA_ENTRY;
07769  
07770  
07771   *N_Tri = 0;
07772    tPath = (int *) SUMA_calloc(Bv->N_list+1, sizeof(int));
07773    if (!tPath) {
07774       fprintf (SUMA_STDERR, "Error %s: Failed to allocate.\n", FuncName);
07775       SUMA_RETURN (NULL);
07776    }
07777    
07778    /* the first triangle should contain the first node in the path */
07779       i0 = Path[0];
07780       Tri0 = Bv->list[0];
07781       if (SO->FaceSetList[3*Tri0] != i0 && SO->FaceSetList[3*Tri0+1] != i0 && SO->FaceSetList[3*Tri0+2] != i0) {
07782          fprintf (SUMA_STDERR, "Error %s: Did not find node %d in first triangle in branch.\n", FuncName, i0);
07783          SUMA_free(tPath);
07784          *N_Tri = 0;
07785          SUMA_RETURN (NULL);  
07786       }
07787    
07788    
07789    /* initiliaze first node results and look for the second node */
07790    tPath[0] = Tri0;
07791    *N_Tri = 1;
07792    Found = NOPE;
07793    ilist = 0;
07794 
07795    if (LocalHead)   fprintf(SUMA_STDERR, "%s: Going forward looking for third node\n", FuncName);
07796    if (N_Path > 2) {
07797       iDirSet = 2; /* search for third node in list, that helps determine the direction more reliably */
07798    }else {
07799       iDirSet = 1; /* settle for the second node */
07800    }
07801    
07802    ilist = 1;
07803    while (!Found && ilist < Bv->N_list) {
07804       tPath[*N_Tri] = Bv->list[ilist];
07805       if (SO->FaceSetList[3*Bv->list[ilist]] == Path[iDirSet] || 
07806          SO->FaceSetList[3*Bv->list[ilist]+1] == Path[iDirSet] ||
07807          SO->FaceSetList[3*Bv->list[ilist]+2] == Path[iDirSet]) {
07808             Found = YUP;
07809       }
07810       ++(*N_Tri);
07811       ++ilist;      
07812    }
07813     
07814    if (!Found) {
07815       fprintf (SUMA_STDERR, "Error %s: Did not find next node %d in branch.\n", FuncName, Path[iDirSet]);
07816       SUMA_free(tPath);
07817       *N_Tri = 0;
07818       SUMA_RETURN (NULL); 
07819    }
07820   
07821    loc2f = *N_Tri; /* number of steps to find second node in the forward direction */
07822 
07823    /* do the same in the backwards direction */
07824    tPath[0] = Tri0;
07825    *N_Tri = 1;
07826    Found = NOPE;
07827    ilist = 0;
07828    
07829    if (LocalHead) fprintf(SUMA_STDERR, "%s: Going backwards looking for third node\n", FuncName);
07830    ilist = Bv->N_list - 1;
07831    while (!Found && ilist >=  0) {
07832       tPath[*N_Tri] = Bv->list[ilist];
07833       if (LocalHead) fprintf(SUMA_STDERR, "%s: trying triangle %d for node %d.\n", FuncName, Bv->list[ilist], Path[N_Path-1]);
07834       if (SO->FaceSetList[3*Bv->list[ilist]] == Path[iDirSet] || 
07835          SO->FaceSetList[3*Bv->list[ilist]+1] == Path[iDirSet] ||
07836          SO->FaceSetList[3*Bv->list[ilist]+2] == Path[iDirSet]) {
07837             Found = YUP;
07838       }
07839       ++(*N_Tri);
07840       --ilist;      
07841    }
07842    
07843    if (*N_Tri < loc2f) { 
07844       /* go backwards, shorter. This is based on triangle count, 
07845          it would be more accurate based on distance of intersected edge */
07846       Direction = -1;
07847    } else Direction = 1;
07848    
07849    /* now do the whole thing */
07850    
07851    tPath[0] = Tri0;
07852    *N_Tri = 1;
07853    Found = NOPE;
07854    ilist = 0;
07855    if (Direction == 1) { /* move forward until you reach the last node */
07856      if (LocalHead)   fprintf(SUMA_STDERR, "%s: Going forward, final pass \n", FuncName);
07857      ilist = 1;
07858       while (!Found && ilist < Bv->N_list) {
07859          tPath[*N_Tri] = Bv->list[ilist];
07860          if (SO->FaceSetList[3*Bv->list[ilist]] == Path[N_Path-1] || 
07861             SO->FaceSetList[3*Bv->list[ilist]+1] == Path[N_Path-1] ||
07862             SO->FaceSetList[3*Bv->list[ilist]+2] == Path[N_Path-1]) {
07863                Found = YUP;
07864          }
07865          ++(*N_Tri);
07866          ++ilist;      
07867       }
07868    } else { /* move backwards */
07869       if (LocalHead) fprintf(SUMA_STDERR, "%s: Going backwards, final pass \n", FuncName);
07870       ilist = Bv->N_list - 1;
07871       while (!Found && ilist >=  0) {
07872          tPath[*N_Tri] = Bv->list[ilist];
07873          if (LocalHead) fprintf(SUMA_STDERR, "%s: trying triangle %d for node %d.\n", FuncName, Bv->list[ilist], Path[N_Path-1]);
07874          if (SO->FaceSetList[3*Bv->list[ilist]] == Path[N_Path-1] || 
07875             SO->FaceSetList[3*Bv->list[ilist]+1] == Path[N_Path-1] ||
07876             SO->FaceSetList[3*Bv->list[ilist]+2] == Path[N_Path-1]) {
07877                Found = YUP;
07878          }
07879          ++(*N_Tri);
07880          --ilist;      
07881       }
07882       
07883    }   
07884 
07885    if (!Found) {
07886       fprintf (SUMA_STDERR, "Error %s: Path not completed.\n", FuncName);
07887       SUMA_free(tPath);
07888       *N_Tri = 0;
07889       SUMA_RETURN (NULL);
07890    }else {
07891       if (LocalHead) {
07892          fprintf (SUMA_STDERR,"%s: Path is %d triangles long:\n", FuncName, *N_Tri); 
07893          for (ilist=0; ilist< *N_Tri; ++ilist) {
07894             fprintf (SUMA_STDERR,"t%d\t", tPath[ilist]);
07895          }
07896          fprintf (SUMA_STDERR,"\n");
07897       }
07898    }
07899    SUMA_RETURN (tPath);
07900 }   

float* SUMA_Offset_GeomSmooth SUMA_SurfaceObject   SO,
int    N_iter,
float    OffsetLim,
float *    fin_orig,
int    vpn,
SUMA_INDEXING_ORDER    d_order,
float *    fout_final_user,
SUMA_COMM_STRUCT   cs
 

A filtering function that is based on brute force estimates of node neighbor distance matrix. It is not finished because it makes no use of the neighbor distances to properly weigh the interpolation. It ends up being too slow because of the high memory load for computing OffS_out.

Definition at line 2824 of file SUMA_GeomComp.c.

References SUMA_SurfaceObject::FN, fout, i, LocalHead, SUMA_SurfaceObject::N_Node, SUMA_COMM_STRUCT::Send, SUMA_Boolean, SUMA_calloc, SUMA_COLUMN_MAJOR, SUMA_ENTRY, SUMA_etime(), SUMA_FormNeighbOffset(), SUMA_free, SUMA_free_NeighbOffset(), SUMA_INDEXING_ORDER, SUMA_LH, SUMA_NODE_XYZ, SUMA_RETURN, SUMA_ROW_MAJOR, SUMA_SendToSuma(), SUMA_SL_Crit, SUMA_SL_Err, SUMA_SL_Warn, and vpn.

02827 {
02828    
02829    static char FuncName[]= {"SUMA_Offset_GeomSmooth"};
02830    float *fout_final=NULL, *fbuf=NULL, *fin_next=NULL, *fin=NULL, *fout=NULL;
02831    int niter=0, i, il,jl, j, ii,  noffs;
02832    struct  timeval start_time;
02833    float etime_GetOffset, weight_tot;   
02834    SUMA_OFFSET_STRUCT *OffS_out=NULL;
02835    SUMA_Boolean LocalHead = NOPE;
02836    
02837    SUMA_ENTRY;
02838    if (!SO) { SUMA_SL_Err("NULL SO"); SUMA_RETURN(NULL); }
02839    if (!SO->FN) {
02840       SUMA_SL_Err("NULL SO->FN");
02841       SUMA_RETURN(NULL);
02842    }   
02843    if (N_iter % 2) {
02844       SUMA_SL_Err("N_iter must be an even number\n");
02845       SUMA_RETURN(NULL);
02846    }
02847    if (vpn < 1) {
02848       SUMA_SL_Err("vpn < 1\n");
02849       SUMA_RETURN(NULL);
02850    }  
02851    
02852    if (fout_final_user == fin_orig) {
02853       SUMA_SL_Err("fout_final_user == fin_orig");
02854       SUMA_RETURN(NULL);
02855    }
02856    
02857    if (!fout_final_user) { /* allocate for output */
02858       fout_final = (float *)SUMA_calloc(SO->N_Node * vpn, sizeof(float));
02859       if (!fout_final) {
02860          SUMA_SL_Crit("Failed to allocate for fout_final\n");
02861          SUMA_RETURN(NULL);
02862       }
02863    }else {
02864       fout_final = fout_final_user; /* pre-allocated */
02865    }
02866    
02867    /* allocate for buffer */
02868    fbuf = (float *)SUMA_calloc(SO->N_Node * vpn, sizeof(float));
02869    if (!fbuf) {
02870       SUMA_SL_Crit("Failed to allocate for fbuf\n");
02871       SUMA_RETURN(NULL);
02872    }
02873    
02874    
02875    if (cs->Send) { /* send the first monster */
02876       if (!SUMA_SendToSuma (SO, cs, (void *)fin_orig, SUMA_NODE_XYZ, 1)) {
02877          SUMA_SL_Warn("Failed in SUMA_SendToSuma\nCommunication halted.");
02878       }
02879    }
02880    SUMA_LH("Calculating OffS_out ...");
02881    OffS_out = SUMA_FormNeighbOffset (SO, OffsetLim);
02882    fin_next = fin_orig;
02883    switch (d_order) {
02884       case SUMA_ROW_MAJOR:
02885          for (niter=0; niter < N_iter; ++niter) {
02886             if ( niter % 2 ) { /* odd */
02887                fin = fin_next; /* input from previous output buffer */
02888                fout = fout_final; /* results go into final vector */
02889                fin_next = fout_final; /* in the next iteration, the input is from fout_final */
02890             } else { /* even */
02891                /* input data is in fin_new */
02892                fin = fin_next;
02893                fout = fbuf; /* results go into buffer */
02894                fin_next = fbuf; /* in the next iteration, the input is from the buffer */
02895             }
02896             
02897             SUMA_etime(&start_time,0);
02898             
02899             for (i=0; i < SO->N_Node; ++i) {
02900                for (j=0; j < vpn; ++j) {
02901                   /* do the averaging using OffS_out NO ATTENTION IS GIVEN TO PROPER WEIGHING YET!*/
02902                   fout[i*vpn+j] = fin[i*vpn+j];
02903                   for (il=0; il<OffS_out[i].N_Neighb; ++il) {
02904                      fout[i*vpn+j] += fin[OffS_out[i].Neighb_ind[il]*vpn+j];
02905                   }
02906                   fout[i*vpn+j] /= (OffS_out[i].N_Neighb+1);  
02907                }
02908             }
02909             
02910             etime_GetOffset = SUMA_etime(&start_time,1);
02911             fprintf(SUMA_STDERR, "%s: Smoothing at dist %f took %f seconds for %d nodes.\n",
02912                            FuncName, OffsetLim, etime_GetOffset, SO->N_Node);
02913             
02914             if (cs->Send) {
02915                if (!SUMA_SendToSuma (SO, cs, (void *)fout, SUMA_NODE_XYZ, 1)) {
02916                   SUMA_SL_Warn("Failed in SUMA_SendToSuma\nCommunication halted.");
02917                }
02918             }
02919          }
02920          break;
02921       case SUMA_COLUMN_MAJOR:
02922          SUMA_SL_Err("Column Major not implemented");
02923          SUMA_RETURN(NULL);
02924          break;
02925       default:
02926          SUMA_SL_Err("Bad Major, very bad.\n");
02927          SUMA_RETURN(NULL);
02928          break;
02929    }
02930    
02931    if (fbuf) SUMA_free(fbuf); fbuf = NULL;
02932 
02933    /* Have to free OffS_out */
02934    OffS_out = SUMA_free_NeighbOffset (SO, OffS_out);
02935       
02936    SUMA_RETURN(fout);    
02937 }

int SUMA_OrientTriangles float *    NodeList,
int    N_Node,
int *    FaceSetList,
int    N_FaceSet,
int    orient,
int    Force
 

determine overall orientation of triangle normals and change triangle orientation if required

Parameters:
NodeList  (float *) xyz vector of node coords
N_Node  (int) number of nodes
FaceSetList  (int *) [n1 n2 n3] vector of triangles
N_FaceSet  (int) number of triangles
orient  (int) 0: Do not change orientation 1: make sure most normals point outwards from center. Flip all triangles if necessary (unless Force is used) -1: make sure most normals point towards center. Flip all triangles if necessary (unless Force is used)
Force  (int) 1: Force the flipping of only those triangles whose normals point in the wrong direction (opposite to orient). With this option, you will destroy the winding consistency of a surface!
Returns:
ans (int): 0: error 1: most normals were pointing outwards -1: most normals were pointing inwards

Definition at line 4983 of file SUMA_GeomComp.c.

References c, flip(), fout, i, LocalHead, n1, n2, SUMA_Boolean, SUMA_calloc, SUMA_DOTP_VEC, SUMA_ENTRY, SUMA_free, SUMA_LH, SUMA_NORM_VEC, SUMA_RETURN, SUMA_SL_Crit, SUMA_SL_Err, SUMA_SL_Note, and SUMA_SL_Warn.

Referenced by main(), and SUMA_LoadPrepInVol().

04984 {
04985    static char FuncName[]={"SUMA_OrientTriangles"};
04986    int i, j, ip, negdot, posdot, sgn, NP, ND, n1, n2, n3, flip;
04987    float d1[3], d2[3], c[3], tc[3], U[3], dot, *norm, mag;
04988    FILE *fout = NULL;
04989    SUMA_Boolean LocalHead = NOPE;
04990    
04991    SUMA_ENTRY;
04992    
04993    
04994    if (!NodeList || !FaceSetList || !N_Node || !N_FaceSet) {
04995       SUMA_SL_Err("Null or no input");
04996       SUMA_RETURN(0);
04997    }
04998    norm = (float *)SUMA_calloc(3*N_FaceSet, sizeof(float));
04999    if (!norm) {
05000       SUMA_SL_Crit("Failed to allocate for norm"); SUMA_RETURN(0);
05001    }
05002    if (Force) {
05003       SUMA_SL_Warn("Using Force option! You might destroy triangulation consistency of surface!");
05004    }
05005    NP = ND = 3;
05006    /* calculate the center coordinate */
05007    c[0] = c[1] = c[2];
05008    for (i=0; i < N_Node; ++i) {
05009       ip = ND * i; c[0] += NodeList[ip]; c[1] += NodeList[ip+1]; c[2] += NodeList[ip+2];    
05010    }
05011    c[0] /= N_Node; c[1] /= N_Node; c[2] /= N_Node;
05012    
05013    /* calculate normals for each triangle, taken from SUMA_SurfNorm*/
05014    if (0 && LocalHead) {
05015       SUMA_SL_Note("Writing SUMA_OrientTriangles.1D");
05016       fout = fopen("SUMA_OrientTriangles.1D", "w");
05017    }
05018    negdot = 0; posdot = 0;
05019    for (i=0; i < N_FaceSet; i++) {
05020       ip = NP * i;
05021       n1 = FaceSetList[ip]; n2 = FaceSetList[ip+1]; n3 = FaceSetList[ip+2];   /* node indices making up triangle */
05022       tc[0] = (NodeList[3*n1]   + NodeList[3*n2]   + NodeList[3*n3]  )/3; /* centroid of triangle */
05023       tc[1] = (NodeList[3*n1+1] + NodeList[3*n2+1] + NodeList[3*n3+1])/3; 
05024       tc[2] = (NodeList[3*n1+2] + NodeList[3*n2+2] + NodeList[3*n3+2])/3; 
05025       /* calc normal */
05026       for (j=0; j < 3; j++) {
05027          d1[j] = NodeList[(ND*n1)+j] - NodeList[(ND*n2)+j];
05028          d2[j] = NodeList[(ND*n2)+j] - NodeList[(ND*n3)+j];
05029       }
05030       norm[ip] = d1[1]*d2[2] - d1[2]*d2[1];
05031       norm[ip+1] = d1[2]*d2[0] - d1[0]*d2[2];
05032       norm[ip+2] = d1[0]*d2[1] - d1[1]*d2[0];
05033       
05034       /* dot the normal with vector from center to node */
05035       U[0] = tc[0] - c[0]; U[1] = tc[1] - c[1]; U[2] = tc[2] - c[2];
05036       SUMA_DOTP_VEC(U, &(norm[ip]), dot, 3, float, float);
05037       if (dot < 0) {
05038          ++negdot;
05039          if (0 && LocalHead) { fprintf (SUMA_STDERR,"%s: Triangle %d has a negative dot product %f\nc  =[%.3f %.3f %.3f]\ntc =[%.3f %.3f %.3f]\nnorm=[%.3f %.3f %.3f]\n",
05040                       FuncName, i, dot, c[0], c[1], c[2], tc[0], tc[1], tc[2], norm[ip+0], norm[ip+1], norm[ip+2]); }
05041          
05042       } else {
05043          if (fout) { 
05044                SUMA_NORM_VEC(norm,3,mag); if (!mag) mag = 1; mag /= 5; 
05045                if (fout) fprintf (fout,"%.3f %.3f %.3f %.3f %.3f %.3f\n", tc[0], tc[1], tc[2], tc[0]+norm[ip+0]/mag, tc[1]+norm[ip+1]/mag, tc[2]+norm[ip+2]/mag);
05046          }
05047          ++posdot;
05048       }      
05049       
05050       if (Force) {
05051          if ( (dot < 0 && orient > 0) || (dot > 0 && orient < 0)) {
05052             n1 = FaceSetList[ip]; FaceSetList[ip] = FaceSetList[ip+2]; FaceSetList[ip+2] = n1;  
05053          }
05054       }
05055    }
05056    if (fout) fclose(fout); fout = NULL;
05057    flip = 0; sgn = 0;
05058    if (posdot >= negdot) {
05059       SUMA_LH("Normals appear to point away from center");
05060       sgn = 1;
05061       if (orient < 0) flip = 1;
05062    } else {
05063       SUMA_LH("Normals appear to point towards center");
05064       sgn = -1;
05065       if (orient > 0) flip = 1;
05066    }
05067    if (LocalHead) {
05068       fprintf(SUMA_STDERR,"%s:\n Found %d positive dot products and %d negative ones.\n", FuncName, posdot, negdot);
05069    }
05070    
05071    if (flip && !Force) {
05072       SUMA_LH("Flipping");
05073       for (i=0; i < N_FaceSet; i++) {
05074          ip = NP * i;
05075          n1 = FaceSetList[ip]; FaceSetList[ip] = FaceSetList[ip+2]; FaceSetList[ip+2] = n1;
05076       }
05077    }
05078    
05079    if (norm) SUMA_free(norm); norm = NULL;
05080    
05081    SUMA_RETURN(sgn);
05082 }

SUMA_SurfaceObject* SUMA_Patch2Surf float *    NodeList,
int    N_NodeList,
int *    PatchFaces,
int    N_PatchFaces,
int    PatchDim
 

Definition at line 5096 of file SUMA_GeomComp.c.

References SUMA_SurfaceObject::FaceSetDim, SUMA_SurfaceObject::FaceSetList, i, LocalHead, SUMA_SurfaceObject::N_FaceSet, SUMA_SurfaceObject::N_Node, SUMA_SurfaceObject::NodeDim, SUMA_SurfaceObject::NodeList, SUMA_Alloc_SurfObject_Struct(), SUMA_Boolean, SUMA_calloc, SUMA_ENTRY, SUMA_malloc, SUMA_RETURN, and SUMA_SL_Err.

Referenced by SUMA_ConvexHullSurface(), and SUMA_LoadPrepInVol().

05097 {
05098    static char FuncName[]={"SUMA_Patch2Surf"};
05099    SUMA_SurfaceObject *SO=NULL;
05100    int i = 0, cnt = 0;
05101    int *imask = NULL;
05102    int N_Node = 0;
05103    SUMA_Boolean LocalHead = NOPE;
05104    
05105    SUMA_ENTRY;
05106    
05107    if (!NodeList || !PatchFaces) {
05108       SUMA_SL_Err("Null input");
05109       SUMA_RETURN(SO);
05110    }
05111    
05112    imask = (int*)SUMA_calloc(N_NodeList , sizeof(int));
05113    if (!imask) {
05114       SUMA_SL_Err("Failed to allocate");
05115       SUMA_RETURN(SO);
05116    }  
05117    /* count the number of nodes and initialize imask*/
05118    SO = SUMA_Alloc_SurfObject_Struct(1);
05119    if (!SO) {
05120       SUMA_SL_Err("Failed to allocate");
05121       SUMA_RETURN(SO);
05122    }
05123    SO->N_FaceSet = N_PatchFaces;
05124    SO->N_Node = 0;
05125    for (i=0; i<3*N_PatchFaces; ++i) {
05126       if (!imask[PatchFaces[i]]) {
05127          imask[PatchFaces[i]] = -1;
05128          ++SO->N_Node;
05129       }
05130    }
05131    if (LocalHead) {
05132       fprintf (SUMA_STDERR,"%s: %d nodes in patch\n", FuncName, SO->N_Node);
05133    }
05134    SO->NodeList = (float *)SUMA_malloc(sizeof(float)*3*SO->N_Node);
05135    SO->FaceSetList = (int *)SUMA_malloc(sizeof(int)*PatchDim*N_PatchFaces);
05136    if (!SO->NodeList || !SO->FaceSetList) {
05137       SUMA_SL_Err("Failed to allocate");
05138       SUMA_RETURN(SO);
05139    }
05140    SO->NodeDim = 3;
05141    SO->FaceSetDim = PatchDim;
05142    
05143    cnt = 0;
05144    for (i=0; i<3*N_PatchFaces; ++i) {
05145       if (imask[PatchFaces[i]] < 0) {
05146          imask[PatchFaces[i]] = cnt;
05147          SO->NodeList[3*cnt  ] = NodeList[3*PatchFaces[i]  ];
05148          SO->NodeList[3*cnt+1] = NodeList[3*PatchFaces[i]+1];
05149          SO->NodeList[3*cnt+2] = NodeList[3*PatchFaces[i]+2];
05150          ++cnt;
05151       }
05152       SO->FaceSetList[i] = imask[PatchFaces[i]];
05153    }
05154    
05155    SUMA_RETURN(SO);
05156 }

double SUMA_Pattie_Volume SUMA_SurfaceObject   SO1,
SUMA_SurfaceObject   SO2,
int *    Nodes,
int    N_Node,
SUMA_SurfaceObject   UseThisSO,
int    minPatchHits
 

Stitch together two isotopic patches to calculate the volume between them.

Parameters:
SO1  : The first surface of the pattie
SO2  : The second surface of the pattie
Nodes  (int *): N_Node x 1 vector of indices containing nodes that form the patch
N_Node  (int): Number of nodes in SO.
UseThisSo  : If you send a pointer to an empty (but allocated) surface structure, The pattie's surface is returned in UseThisSo. Otherwise, the temporary surface is tossed in the trash can. \pram minPatchHits (int): Since you're forming a patch from nodes, you'll need to select the minimum number of nodes to be in a patch (triangle) before the patch is selected. Minimum is 1, Maximum logical is 3. If you choose 1, you will have nodes in the patch that are not included in Nodes vector. But that is the only way to get something back for just one node. If you choose 3, you will have the same number of nodes in the patch as you do in the vector Nodes. However, you'll get no patches formed if your Nodes vector contains, one or two nodes for example ...
Testing so far in /home/ziad/SUMA_test/afni: for a bunch of nodes: SurfMeasures -func node_vol -spec ../SurfData/SUMA/DemoSubj_lh.spec -surf_A lh.smoothwm.asc -surf_B lh.pial.asc -nodes_1D lhpatch.1D.roi'[0]' -out_1D SM_out.1D SurfPatch -spec ../SurfData/SUMA/DemoSubj_lh.spec -surf_A lh.smoothwm -surf_B lh.pial.asc -hits 3 -input lhpatch.1D.roi 0 1 answer is 326, 13% different from sum in SM_out.1D's second column (373)...

for a single node (remember change -hits option to 1): SurfMeasures -func node_vol -spec ../SurfData/SUMA/DemoSubj_lh.spec -surf_A lh.smoothwm.asc -surf_B lh.pial.asc -nodes_1D lhpatch_1node.1D'[0]' -out_1D SM_out_1node.1D SurfPatch -spec ../SurfData/SUMA/DemoSubj_lh.spec -surf_A lh.smoothwm -surf_B lh.pial.asc -hits 1 -input lhpatch_1node.1D 0 1 (divide answer of 2.219910 by 3 (0.73997), difference at 3rd signifcant digit from SM_out_1node.1D of 0.731866)

for a box: SurfMeasures -func node_vol -spec RectPly.spec -surf_A RectSurf.ply -surf_B RectSurf2.ply -nodes_1D RectAllPatch.1D'[1]' -out_1D SM_out_Rect.1D SurfPatch -spec RectPly.spec -surf_A RectSurf.ply -surf_B RectSurf2.ply -hits 3 -input RectAllPatch.1D 0 1 -vol_only

Definition at line 5520 of file SUMA_GeomComp.c.

References SUMA_CommonFields::DsetList, SUMA_SurfaceObject::EL, SUMA_SurfaceObject::FaceNormList, SUMA_SURF_NORM::FaceNormList, SUMA_SurfaceObject::FaceSetDim, SUMA_SurfaceObject::FaceSetList, SUMA_PATCH::FaceSetList, i, LocalHead, SUMA_EDGE_LIST::max_N_Hosts, SUMA_SurfaceObject::MF, SUMA_EDGE_LIST::min_N_Hosts, n1, n2, SUMA_SurfaceObject::N_FaceSet, SUMA_PATCH::N_FaceSet, SUMA_SurfaceObject::N_Node, SUMA_SurfaceObject::NodeDim, SUMA_SurfaceObject::NodeList, SUMA_SurfaceObject::NodeNormList, SUMA_SURF_NORM::NodeNormList, SUMA_Alloc_SurfObject_Struct(), SUMA_Boolean, SUMA_disp_vecdmat(), SUMA_disp_vecmat(), SUMA_ENTRY, SUMA_free, SUMA_Free_Surface_Object(), SUMA_freePatch(), SUMA_GetContour(), SUMA_getPatch(), SUMA_INIT_VEC, SUMA_LH, SUMA_MakeConsistent(), SUMA_malloc, SUMA_Mesh_Volume(), SUMA_RETURN, SUMA_ROW_MAJOR, SUMA_SL_Crit, SUMA_SL_Err, SUMA_SurfaceMetrics_eng(), and SUMA_SurfNorm().

05521 {
05522    static char FuncName[]={"SUMA_Pattie_Volume"};
05523    double Vol = 0.0;
05524    int N_ContEdges=0, i,  i3, n, NodesPerPatch, *NewIndex = NULL, inew3, cnt, n1, n2, trouble;
05525    SUMA_PATCH *P1 = NULL;
05526    FILE *fid=NULL;
05527    SUMA_CONTOUR_EDGES *CE = NULL;
05528    SUMA_SurfaceObject *SOc = NULL;
05529    SUMA_SURF_NORM SN;
05530    SUMA_Boolean LocalHead = NOPE;
05531    
05532    SUMA_ENTRY;
05533    
05534    if (!SO1 || !SO2 || !Nodes || !N_Node) {
05535       SUMA_SL_Err("Bad input.");
05536       SUMA_RETURN(Vol);
05537    }
05538    if (SO1->N_Node != SO2->N_Node || SO1->N_FaceSet != SO2->N_FaceSet) {
05539       SUMA_SL_Err("Surfaces Not Isotopic");
05540       SUMA_RETURN(Vol);
05541    }
05542    
05543    /* form the patch */
05544    SUMA_LH("Forming patch...");
05545    P1 = SUMA_getPatch (Nodes, N_Node, SO1->FaceSetList, SO1->N_FaceSet, SO1->MF, minPatchHits);
05546    if (!P1) {
05547       SUMA_SL_Err("Failed to create patches.\n");
05548       SUMA_RETURN(Vol);
05549    }
05550    if (!P1->N_FaceSet) {
05551       SUMA_SL_Err("No patch could be formed");
05552       SUMA_RETURN(Vol);
05553    }
05554    /* form the contour */
05555    SUMA_LH("Forming contour...");
05556    CE = SUMA_GetContour (SO1, Nodes, N_Node, &N_ContEdges, 1, P1);
05557    if (!N_ContEdges) {
05558       SUMA_SL_Err("No contour edges found.\n"
05559                   "It looks like patches form\n"
05560                   "closed surfaces.\n");
05561       SUMA_RETURN(Vol);
05562    }
05563    if (LocalHead) {
05564       fprintf(SUMA_STDERR,"%s:\n Found %d contour segments.\n", FuncName, N_ContEdges);
05565    }
05566    
05567    /* create a mapping from old numbering scheme to new one */
05568    SUMA_LH("Creating Mapping Index...");
05569    NewIndex = (int *)SUMA_malloc(SO1->N_Node * sizeof(int));
05570    if (!NewIndex) {
05571       SUMA_SL_Crit("Failed to allocate for NewIndex");
05572       SUMA_RETURN(Vol);
05573    }
05574    SUMA_INIT_VEC(NewIndex, SO1->N_Node, -1, int);
05575    NodesPerPatch = 0;
05576    for (i=0; i < P1->N_FaceSet; ++i) {
05577       i3 = 3*i;
05578       n = P1->FaceSetList[i3];   if (NewIndex[n] < 0) { NewIndex[n] = NodesPerPatch; ++NodesPerPatch; }   
05579       n = P1->FaceSetList[i3+1]; if (NewIndex[n] < 0) { NewIndex[n] = NodesPerPatch; ++NodesPerPatch; }   
05580       n = P1->FaceSetList[i3+2]; if (NewIndex[n] < 0) { NewIndex[n] = NodesPerPatch; ++NodesPerPatch; }
05581    }
05582    if (LocalHead) {
05583       fprintf(SUMA_STDERR,"%s:\n"
05584                   "Number of nodes in patch (%d), in N_Node (%d)\n"
05585                   , FuncName, NodesPerPatch, N_Node);
05586    }
05587    if (NodesPerPatch != N_Node) {
05588       fprintf(SUMA_STDERR, "Note:\n"
05589                            "Have %d nodes in patch, %d nodes in input.\n", NodesPerPatch, N_Node);
05590    }
05591    
05592    /* Building composite surface */
05593    SUMA_LH("Building composite surface...");
05594    if (UseThisSO) { 
05595       SOc = UseThisSO;
05596       if (SOc->NodeList || SOc->FaceSetList) {
05597          SUMA_SL_Err("You want me to use a filled SurfaceObject structure!\n"
05598                      "How rude!");
05599          SUMA_RETURN(Vol);
05600       }
05601    } else {
05602       SOc = SUMA_Alloc_SurfObject_Struct(1);
05603    }
05604    SOc->N_Node = NodesPerPatch*2;
05605    SOc->N_FaceSet = P1->N_FaceSet*2+2*N_ContEdges;
05606    SOc->NodeDim = 3;
05607    SOc->FaceSetDim = 3;
05608    SOc->NodeList = (float *)SUMA_malloc(SOc->NodeDim*SOc->N_Node*sizeof(float));
05609    SOc->FaceSetList = (int *)SUMA_malloc(SOc->FaceSetDim*SOc->N_FaceSet*sizeof(int));
05610    /* first create the NodeList from S01 && SO2*/
05611    for (i=0; i<SO1->N_Node; ++i) {
05612       if (NewIndex[i] >=0) { /* this node is used */
05613          i3 = 3*i;
05614          inew3 = 3 * NewIndex[i];
05615          SOc->NodeList[inew3  ] = SO1->NodeList[i3  ];
05616          SOc->NodeList[inew3+1] = SO1->NodeList[i3+2];
05617          SOc->NodeList[inew3+2] = SO1->NodeList[i3+1];
05618          inew3 = 3 * (NewIndex[i]+NodesPerPatch);
05619          SOc->NodeList[inew3  ] = SO2->NodeList[i3  ];
05620          SOc->NodeList[inew3+1] = SO2->NodeList[i3+2];
05621          SOc->NodeList[inew3+2] = SO2->NodeList[i3+1];
05622       }
05623    }
05624    /* Now add the pre-existing patches */
05625    cnt = 0;
05626    for (i=0; i<P1->N_FaceSet; ++i) {
05627       i3 = 3*i;
05628       n = P1->FaceSetList[i3  ]; SOc->FaceSetList[cnt] = NewIndex[n]; ++cnt;
05629       n = P1->FaceSetList[i3+1]; SOc->FaceSetList[cnt] = NewIndex[n]; ++cnt;
05630       n = P1->FaceSetList[i3+2]; SOc->FaceSetList[cnt] = NewIndex[n]; ++cnt;                     
05631    }
05632    for (i=0; i<P1->N_FaceSet; ++i) { /* Now for SO2's */
05633       i3 = 3*i;
05634       n = P1->FaceSetList[i3  ]; SOc->FaceSetList[cnt] = NewIndex[n]+NodesPerPatch; ++cnt;
05635       n = P1->FaceSetList[i3+1]; SOc->FaceSetList[cnt] = NewIndex[n]+NodesPerPatch; ++cnt;
05636       n = P1->FaceSetList[i3+2]; SOc->FaceSetList[cnt] = NewIndex[n]+NodesPerPatch; ++cnt;                     
05637    }
05638    
05639    /* Now you need to add the stitches, for each segment you'll need 2 triangles*/
05640    for (i=0; i<N_ContEdges; ++i) {
05641       n1 = NewIndex[CE[i].n1]; n2 = NewIndex[CE[i].n2];
05642       SOc->FaceSetList[cnt] = n1; ++cnt;
05643       SOc->FaceSetList[cnt] = n2; ++cnt;
05644       SOc->FaceSetList[cnt] = n2+NodesPerPatch; ++cnt;
05645       SOc->FaceSetList[cnt] = n1; ++cnt;
05646       SOc->FaceSetList[cnt] = n2+NodesPerPatch; ++cnt;
05647       SOc->FaceSetList[cnt] = n1+NodesPerPatch; ++cnt;
05648    }
05649    
05650    /* calculate EdgeList */
05651    if (!SUMA_SurfaceMetrics_eng(SOc, "EdgeList", NULL, 0, SUMAg_CF->DsetList)){
05652       SUMA_SL_Err("Failed to create EdgeList");
05653       SUMA_RETURN(Vol);
05654    }
05655    
05656    /* make sure that's a closed surface */
05657    if (SOc->EL->max_N_Hosts != 2 || SOc->EL->min_N_Hosts != 2) {
05658       SUMA_SL_Err("Created surface is not a closed one.\n"
05659                   "Or patches have tessellation problems.");
05660       SUMA_RETURN(Vol);
05661    }
05662    
05663    /* fix the winding */
05664    if (!SUMA_MakeConsistent(SOc->FaceSetList, SOc->N_FaceSet, SOc->EL, 0, &trouble)) {
05665       SUMA_SL_Err("Failed to make surface consistent");
05666       SUMA_RETURN(Vol);
05667    }
05668    
05669    /* Now calculate FaceSetNormals and triangle areas*/
05670    SN = SUMA_SurfNorm(SOc->NodeList,  SOc->N_Node, SOc->FaceSetList, SOc->N_FaceSet );
05671    SOc->NodeNormList = SN.NodeNormList;
05672    SOc->FaceNormList = SN.FaceNormList;
05673 
05674    if (!SUMA_SurfaceMetrics_eng(SOc, "PolyArea", NULL, 0, SUMAg_CF->DsetList)){
05675       SUMA_SL_Err("Failed to create EdgeList");
05676       SUMA_RETURN(Vol);
05677    }
05678       
05679    /* debug */
05680    if (LocalHead) {
05681       fid = fopen("Junk_NodeList.1D", "w");
05682       SUMA_disp_vecmat (SOc->NodeList, SOc->N_Node, SOc->NodeDim, 1, SUMA_ROW_MAJOR, fid, NOPE);
05683       fclose(fid);
05684       fid = fopen("Junk_FaceSetList.1D", "w");
05685       SUMA_disp_vecdmat(SOc->FaceSetList, SOc->N_FaceSet, SOc->FaceSetDim, 1, SUMA_ROW_MAJOR, fid , NOPE);
05686       fclose(fid);
05687    }
05688    
05689    /* calculate the volume */
05690    SUMA_LH("Calculating volume");
05691    Vol = SUMA_Mesh_Volume(SOc, NULL, -1);
05692    if (LocalHead) {
05693       fprintf (SUMA_STDERR,"%s:\n"
05694                            "Volume = %f\n", FuncName, Vol);
05695    }
05696    
05697    /* cleanup */
05698    SUMA_LH("Cleanup");
05699    if (P1) SUMA_freePatch(P1); P1 = NULL;
05700    if (NewIndex) SUMA_free(NewIndex); NewIndex = NULL;
05701    if (SOc != UseThisSO) SUMA_Free_Surface_Object(SOc); SOc = NULL;
05702    if (CE) SUMA_free(CE); CE=NULL;
05703    
05704    SUMA_RETURN(Vol);
05705 }

float* SUMA_Plane_Equation float *    P1,
float *    P2,
float *    P3,
float *    usethisEq
 

finds the plane passing through 3 points

From File : Plane_Equation.c Author : Ziad Saad Date : Thu Nov 19 14:55:54 CST 1998

Usage : Eq = SUMA_Plane_Equation (P1, P2, P3, thisEq)

Parameters:
P1  (float *) 1x3 vector Coordinates of Point1
P2  (float *) 1x3 vector Coordinates of Point2
P3  (float *) 1x3 vector Coordinates of Point3
thisEq  (float *) use this pointer to store Eq rather than create a new one (set to NULL if you want a new one)
Returns:
Eq (float *) 1x4 vector containing the equation of the plane containing the three points. The equation of the plane is : Eq[0] X + Eq[1] Y + Eq[2] Z + Eq[3] = 0
If the three points are colinear, Eq = [0 0 0 0]

Definition at line 5897 of file SUMA_GeomComp.c.

References SUMA_calloc, SUMA_ENTRY, and SUMA_RETURN.

Referenced by SUMA_Surf_Plane_Intersect_ROI().

05898 {/*SUMA_Plane_Equation*/
05899    float *Eq;
05900    static char FuncName[] = {"SUMA_Plane_Equation"}; 
05901     
05902    SUMA_ENTRY;
05903    if (usethisEq) Eq = usethisEq;
05904    else Eq = (float *) SUMA_calloc(4,sizeof(float));
05905    if (!Eq)
05906       {
05907          fprintf (SUMA_STDERR, "Error %s: Failed to allocate.\n", FuncName);
05908          SUMA_RETURN (NULL);
05909       }
05910    
05911    Eq[0] = P1[1] * (P2[2]-P3[2]) 
05912          + P2[1] * (P3[2]-P1[2]) 
05913          + P3[1] * (P1[2]-P2[2]);
05914          
05915    Eq[1] = P1[2] * (P2[0]-P3[0]) 
05916          + P2[2] * (P3[0]-P1[0]) 
05917          + P3[2] * (P1[0]-P2[0]);
05918          
05919    Eq[2] = P1[0] * (P2[1]-P3[1]) 
05920          + P2[0] * (P3[1]-P1[1]) 
05921          + P3[0] * (P1[1]-P2[1]);
05922          
05923    Eq[3] =  - P1[0] * (P2[1] * P3[2] - P3[1] * P2[2]) 
05924             - P2[0] * (P3[1] * P1[2] - P1[1] * P3[2]) 
05925             - P3[0] * (P1[1] * P2[2] - P2[1] * P1[2]);
05926 
05927    SUMA_RETURN (Eq);
05928 }/*SUMA_Plane_Equation*/

SUMA_Boolean SUMA_ProjectSurfaceToSphere SUMA_SurfaceObject   SO,
SUMA_SurfaceObject   SOref,
float    radius,
SUMA_COMM_STRUCT   cs
 

stretch each node along the center--node direction such that the new distance is = radius

Parameters:
SO  The surface to be modified. Adjust node coordinates of SO so that Node i on SO is repositioned such that |c i| = radius c is the centers of SO .
SOref  reference SurfaceObject, used to communicate with SUMA
radius , you  know what.
cs  the famed communication structure

Definition at line 1817 of file SUMA_GeomComp.c.

References a, SUMA_SurfaceObject::Center, free, i, LocalHead, SUMA_SurfaceObject::N_Node, SUMA_SurfaceObject::NodeList, SUMA_COMM_STRUCT::Send, SUMA_append_replace_string(), SUMA_Boolean, SUMA_ENTRY, SUMA_etime(), SUMA_Extension(), SUMA_NODE_XYZ, SUMA_POINT_AT_DISTANCE_NORM, SUMA_RETURN, SUMA_SEG_LENGTH, SUMA_SendToSuma(), SUMA_SL_Err, SUMA_SL_Warn, and SUMA_UNIT_VEC.

01818 {
01819    static char FuncName[]={"SUMA_ProjectSurfaceToSphere"};
01820    int i=0, j=0, cnt = 0, istrt, istp;
01821    struct timeval start_time, start_time_all;
01822    float etime_GetOffset, etime_GetOffset_all, ave_dist= 0.0, dj = 0.0, ave_dist_ref= 0.0, *a=NULL;
01823    float P2[2][3], U[3], Un;
01824    SUMA_Boolean LocalHead = NOPE;
01825    
01826    SUMA_ENTRY;
01827 
01828    if (!SO || !SOref) { SUMA_SL_Err("NULL surface"); SUMA_RETURN(NOPE); }
01829    
01830    if (LocalHead) {
01831       fprintf(SUMA_STDERR, "%s:\n"
01832                            " SO    Center: %f, %f, %f\n"
01833                            " radius = %f\n", FuncName, 
01834                            SO->Center[0], SO->Center[1], SO->Center[2],
01835                            radius);  
01836    }
01837       
01838    #ifdef FROM_THIS_NODE
01839    istrt = FROM_THIS_NODE;
01840    istp = TO_THIS_NODE+1;
01841    #else
01842    istrt = 0;
01843    istp = SO->N_Node;
01844    #endif
01845    ave_dist_ref =  radius;
01846    for (i =istrt ; i<istp; ++i) {
01847       if (i == 0) {
01848          SUMA_etime(&start_time,0);
01849       }
01850       /* move node i to the reference average location
01851       Do not travel along normals, you should travel along
01852       radial direction Center-->node*/
01853       a = &(SO->NodeList[3*i]); SUMA_UNIT_VEC(SO->Center, a, U, Un);
01854       if (Un) {
01855          SUMA_POINT_AT_DISTANCE_NORM(U, SO->Center, ave_dist_ref, P2);
01856          SO->NodeList[3*i] = P2[0][0]; SO->NodeList[3*i+1] = P2[0][1]; SO->NodeList[3*i+2] = P2[0][2];
01857       } else {
01858             SUMA_SL_Err("Identical points!\n"
01859                         "No coordinates modified");
01860       }
01861       
01862       if (LocalHead) {
01863          if (! (i%999)) {
01864             a = &(SO->NodeList[3*i]);
01865             SUMA_SEG_LENGTH(a, SO->Center, dj);
01866             fprintf(SUMA_STDERR, "%s:\n"
01867                            "node i=%d, avg_dist_ref = %f\ncnt = %d\n"
01868                            "Check on P2: New dist =%f ?=? %f\n", 
01869                            FuncName, i, ave_dist_ref, cnt, dj, ave_dist_ref);
01870             etime_GetOffset = SUMA_etime(&start_time,1);
01871             fprintf(SUMA_STDERR, "%s: Search to %f mm took %f seconds for %d nodes.\n"
01872                   "Projected completion time: %f minutes\n",
01873                   FuncName, radius, etime_GetOffset, i+1,
01874                   etime_GetOffset * SO->N_Node / 60.0 / (i+1));
01875          }
01876       }
01877       if (! (i%99) && cs) {
01878          if (cs->Send) { /* send the first monster (it's SOref  "in SUMA" that's being modified on the fly*/
01879             if (!SUMA_SendToSuma (SOref, cs, (void *)SO->NodeList, SUMA_NODE_XYZ, 1)) {
01880             SUMA_SL_Warn("Failed in SUMA_SendToSuma\nCommunication halted.");
01881             }
01882          }
01883       }
01884       
01885       #ifdef FROM_THIS_NODE
01886       {
01887          FILE *fid=NULL;
01888          char *outname=NULL, tmp[20];
01889          int ii;
01890          if (cs->Send) { /* send the first monster (it's SOref that's being modified on the fly*/
01891             if (!SUMA_SendToSuma (SOref, cs, (void *)SO->NodeList, SUMA_NODE_XYZ, 1)) {
01892             SUMA_SL_Warn("Failed in SUMA_SendToSuma\nCommunication halted.");
01893             }
01894          }
01895          sprintf(tmp,"offset_n%d", FROM_THIS_NODE);
01896          outname = SUMA_Extension("", ".1D", YUP);
01897          outname = SUMA_append_replace_string(outname, "offset.1D", "", 1);
01898          fid = fopen(outname, "w"); free(outname); outname = NULL;
01899          if (!fid) {
01900             SUMA_SL_Err("Could not open file for writing.\nCheck file permissions, disk space.\n");
01901          } else {
01902             fprintf (fid,"#Column 1 = Node index\n"
01903                          "#column 2 = Neighborhood layer\n"
01904                          "#Column 3 = Distance from node %d\n", 99);
01905             for (ii=0; ii<SO->N_Node; ++ii) {
01906                if (OffS->LayerVect[ii] >= 0) {
01907                   fprintf(fid,"%d\t%d\t%f\n", ii, OffS->LayerVect[ii], OffS->OffVect[ii]);
01908                }
01909             }
01910             fclose(fid);
01911          }
01912          { int jnk; fprintf(SUMA_STDOUT,"Pausing, next node is %d...", i+1); jnk = getchar(); fprintf(SUMA_STDOUT,"\n"); }
01913       }
01914       #endif
01915              
01916       
01917    }   
01918    
01919    
01920    SUMA_RETURN(YUP);
01921 }

SUMA_Boolean SUMA_Recycle_getoffsets SUMA_GET_OFFSET_STRUCT   OffS
 

reset the SUMA_GET_OFFSET_STRUCT after it has been used by a node

Parameters:
OffS  (SUMA_GET_OFFSET_STRUCT *) Offset structure that has node neighbor info and detail to be cleared
Returns:
(YUP/NOPE) success/failure

  • No memory is freed here
  • The used node layer indices are reset to -1
  • The number of nodes in each layer are reset to 0
See also:
SUMA_Free_getoffsets to free this structure once and for all , SUMA_Initialize_getoffsets

Definition at line 893 of file SUMA_GeomComp.c.

References i, SUMA_GET_OFFSET_STRUCT::layers, SUMA_GET_OFFSET_STRUCT::LayerVect, LocalHead, SUMA_GET_OFFSET_STRUCT::N_layers, SUMA_Boolean, and SUMA_RETURN.

Referenced by calcWithOffsets(), SUMA_Build_Cluster_From_Node_NoRec(), SUMA_EquateSurfaceSize(), and SUMA_FormNeighbOffset().

00894 {
00895    static char FuncName[]={"SUMA_Recycle_getoffsets"};
00896    int i, j;
00897    static SUMA_Boolean LocalHead = NOPE;
00898    
00899    for (i=0; i < OffS->N_layers; ++i) {
00900       /* reset the layer index of used nodes in LayerVect */
00901       for (j=0; j < OffS->layers[i].N_NodesInLayer; ++j) {
00902          OffS->LayerVect[OffS->layers[i].NodesInLayer[j]] = -1;
00903       }
00904       /* reset number of nodes in each layer */
00905       OffS->layers[i].N_NodesInLayer = 0;
00906    }
00907    
00908    SUMA_RETURN(YUP);
00909 }

SUMA_Boolean SUMA_Show_SPI SUMA_SURF_PLANE_INTERSECT   SPI,
FILE *    Out,
SUMA_SurfaceObject   SO
 

Show the SPI structure

Definition at line 6642 of file SUMA_GeomComp.c.

References SUMA_SurfaceObject::EL, SUMA_EDGE_LIST::EL, i, SUMA_SURF_PLANE_INTERSECT::IntersEdges, SUMA_SURF_PLANE_INTERSECT::IntersNodes, SUMA_SURF_PLANE_INTERSECT::IntersTri, SUMA_SURF_PLANE_INTERSECT::isEdgeInters, SUMA_EDGE_LIST::N_EL, SUMA_SURF_PLANE_INTERSECT::N_IntersEdges, SUMA_SURF_PLANE_INTERSECT::N_IntersTri, SUMA_Boolean, SUMA_ENTRY, and SUMA_RETURN.

06643 {
06644    static char FuncName[]={"SUMA_Show_SPI"};
06645    int i;
06646    
06647    SUMA_ENTRY;
06648    
06649    if (!Out) Out = SUMA_STDERR;
06650    
06651    if (!SPI) {
06652       fprintf (Out,"Error %s: NULL POINTER.\n", FuncName);
06653    }
06654    
06655    fprintf (Out,"Intersection Edges: %d\n[", SPI->N_IntersEdges);
06656    for (i=0; i < SPI->N_IntersEdges; ++i) {
06657       fprintf (Out, "%d, %d\n", SO->EL->EL[SPI->IntersEdges[i]][0], SO->EL->EL[SPI->IntersEdges[i]][1]);
06658    }
06659    fprintf (Out," ]\n");
06660    
06661    fprintf (Out,"Intersection Nodes: %d\n[", SPI->N_IntersEdges);
06662    for (i=0; i < SO->EL->N_EL; ++i) {
06663       if (SPI->isEdgeInters[i]) fprintf (Out, "%f, %f, %f, ", SPI->IntersNodes[3*i], SPI->IntersNodes[3*i+1], SPI->IntersNodes[3*i+2]);
06664    }
06665    fprintf (Out," ]\n");
06666    
06667    fprintf (Out,"Intersected Triangles: %d\n[", SPI->N_IntersTri);
06668    for (i=0; i < SPI->N_IntersTri; ++i) {
06669       fprintf (Out, "t%d\t", SPI->IntersTri[i]);
06670    }
06671    fprintf (Out," ]\n");
06672    SUMA_RETURN(YUP);
06673 }

SUMA_Boolean SUMA_show_STB SUMA_TRI_BRANCH   B,
FILE *    Out
 

Function to show the contents of a SUMA_TRI_BRANCH structure

Definition at line 6532 of file SUMA_GeomComp.c.

References i, SUMA_TRI_BRANCH::iBranch, SUMA_TRI_BRANCH::list, SUMA_TRI_BRANCH::N_list, SUMA_Boolean, SUMA_ENTRY, and SUMA_RETURN.

06533 {
06534    static char FuncName[]={"SUMA_show_STB"};
06535    int i;
06536    
06537    SUMA_ENTRY;
06538   
06539    if (!Out) Out = SUMA_STDERR;
06540    
06541    if (!B) {
06542       fprintf (Out, "%s: Empy structure.\n", FuncName);
06543    }
06544    
06545    fprintf (Out, "%s:\tBranch #%d. %d elements in list\nlist:\t", FuncName, B->iBranch, B->N_list);
06546    for (i=0; i < B->N_list; ++i) {
06547       fprintf (Out, "%d\t", B->list[i]);
06548    }
06549    fprintf (Out, "\n");
06550    
06551    SUMA_RETURN (YUP);
06552 }

char* SUMA_ShowOffset_Info SUMA_GET_OFFSET_STRUCT   OffS,
int    detail
 

Definition at line 2598 of file SUMA_GeomComp.c.

References SUMA_GET_OFFSET_STRUCT::layers, SUMA_GET_OFFSET_STRUCT::LayerVect, SUMA_GET_OFFSET_STRUCT::N_Nodes, SUMA_NODE_NEIGHB_LAYER::NodesInLayer, SUMA_GET_OFFSET_STRUCT::OffVect, SUMA_ENTRY, SUMA_free, SUMA_malloc, SUMA_RETURN, SUMA_SL_Crit, SUMA_SS2S, SUMA_StringAppend(), SUMA_StringAppend_va(), and SUMA_z_dqsort().

Referenced by SUMA_Build_Cluster_From_Node().

02599 {
02600    static char FuncName[]={"SUMA_ShowOffset_Info"};
02601    SUMA_STRING *SS = NULL;
02602    int ii, *ltmp=NULL, *imap = NULL;
02603    char *s=NULL;   
02604 
02605    SUMA_ENTRY;
02606 
02607    SS = SUMA_StringAppend (NULL, NULL);
02608 
02609    if (!OffS) {
02610       SS = SUMA_StringAppend (SS,"#NULL offset structure.\n");
02611    } else {
02612       SS = SUMA_StringAppend_va (SS,"#Node Offsets (graph distance) from node %d\n", OffS->layers[0].NodesInLayer[0]);
02613       SS = SUMA_StringAppend_va (SS,"#Column 0 = Node index\n"
02614                                     "#column 1 = Neighborhood layer\n"
02615                                     "#Column 2 = Distance from node %d\n", OffS->layers[0].NodesInLayer[0]);
02616       ltmp = (int *)SUMA_malloc(OffS->N_Nodes*sizeof(int)); /* make a copy to avoid disturbinh OffS's contents*/
02617       if (!ltmp) {
02618          SUMA_SL_Crit("Failed to allocate for ltmp");
02619          SUMA_RETURN(NULL);
02620       }
02621       for (ii=0; ii<OffS->N_Nodes; ++ii) ltmp[ii] = OffS->LayerVect[ii]; 
02622       imap = SUMA_z_dqsort(ltmp,OffS->N_Nodes); 
02623       for (ii=0; ii<OffS->N_Nodes; ++ii) {
02624          if (OffS->LayerVect[imap[ii]] >= 0) {
02625             SS = SUMA_StringAppend_va (SS,"%6d\t%6d\t%f\n", imap[ii], OffS->LayerVect[imap[ii]], OffS->OffVect[imap[ii]]);
02626          }
02627       }
02628    }
02629    if (ltmp) SUMA_free(ltmp); ltmp = NULL;
02630    if (imap) SUMA_free(imap); imap = NULL;
02631    SUMA_SS2S(SS,s);
02632 
02633    SUMA_RETURN(s);
02634 }

char* SUMA_ShowOffset_ll_Info DList   list,
int    detail
 

Definition at line 2636 of file SUMA_GeomComp.c.

References DListElmt_::data, dlist_head, dlist_tail, SUMA_OFFSET_LL_DATUM::layer, DListElmt_::next, SUMA_OFFSET_LL_DATUM::ni, SUMA_OFFSET_LL_DATUM::off, SUMA_ENTRY, SUMA_RETURN, SUMA_SS2S, SUMA_StringAppend(), and SUMA_StringAppend_va().

Referenced by SUMA_Build_Cluster_From_Node().

02637 {
02638    static char FuncName[]={"SUMA_ShowOffset_ll_Info"};
02639    SUMA_STRING *SS = NULL;
02640    DListElmt *elm = NULL;
02641    SUMA_OFFSET_LL_DATUM *dat=NULL;
02642    int ii;
02643    char *s=NULL;   
02644 
02645    SUMA_ENTRY;
02646 
02647    SS = SUMA_StringAppend (NULL, NULL);
02648 
02649    if (!list) {
02650       SS = SUMA_StringAppend (SS,"#NULL offset list.\n");
02651    } else {
02652       do {
02653          if (!elm) elm = dlist_head(list); 
02654          else elm = elm->next;
02655          dat = (SUMA_OFFSET_LL_DATUM *)elm->data;
02656          if (elm == dlist_head(list)) {
02657             SS = SUMA_StringAppend_va (SS,"#Node Offsets (graph distance) from node %d\n", dat->ni);
02658             SS = SUMA_StringAppend_va (SS,"#Column 0 = Node index\n"
02659                                        "#column 1 = Neighborhood layer\n"
02660                                        "#Column 2 = Distance from node %d\n", dat->ni);
02661          }
02662          SS = SUMA_StringAppend_va (SS,"%6d\t%6d\t%f\n", dat->ni, dat->layer, dat->off);
02663       } while (elm != dlist_tail(list));
02664    }
02665    SUMA_SS2S(SS,s);
02666 
02667    SUMA_RETURN(s);
02668 }

SUMA_Boolean SUMA_ShowPatch SUMA_PATCH   Patch,
FILE *    Out
 

Definition at line 5313 of file SUMA_GeomComp.c.

References SUMA_PATCH::FaceSetIndex, SUMA_PATCH::FaceSetList, i, SUMA_PATCH::N_FaceSet, SUMA_PATCH::nHits, SUMA_Boolean, SUMA_ENTRY, and SUMA_RETURN.

Referenced by SUMA_GetContour().

05314 {
05315    static char FuncName[]={"SUMA_freePatch"};
05316    int ip, i;
05317    
05318    SUMA_ENTRY;
05319    
05320    if (!Out) Out = stderr;
05321    
05322    fprintf (Out, "Patch Contains %d triangles:\n", Patch->N_FaceSet);
05323    fprintf (Out, "FaceIndex (nHits): FaceSetList[0..2]\n");
05324    for (i=0; i < Patch->N_FaceSet; ++i) {
05325       ip = 3 * i;   
05326       fprintf (Out, "%d(%d):   %d %d %d\n",
05327             Patch->FaceSetIndex[i], Patch->nHits[i], Patch->FaceSetList[ip],
05328             Patch->FaceSetList[ip+1], Patch->FaceSetList[ip+2]);
05329    }
05330    
05331    SUMA_RETURN(YUP);
05332 }

int SUMA_Subdivide_Mesh float **    NodeListp,
int *    N_Nodep,
int **    FaceSetListp,
int *    N_FaceSetp,
float    maxarea
 

function to subdivide triangles to meet a maxarea criterion Divisions are done by adding a node at the centroid of the triangle to be subdivided. Bad idea, for very large triangles, such as produced by convex hull, you could end up with nodes that have hundreds of neighbors...

Definition at line 56 of file SUMA_GeomComp.c.

References a, c, SUMA_SurfaceObject::FaceSetList, LocalHead, n0, n1, n2, SUMA_SurfaceObject::NodeList, SUMA_Boolean, SUMA_ENTRY, SUMA_FACE_CENTROID, SUMA_realloc, SUMA_RETURN, SUMA_SL_Crit, SUMA_SL_Err, and SUMA_TRI_AREA.

00057 {
00058    static char FuncName[]={"SUMA_Subdivide_Mesh"};
00059    int in, it, N_NodeAlloc, N_FaceSetAlloc, N_Node, N_FaceSet, it3, in0, in1, in2, inc3, inc, itn, itn3;
00060    float c[3];
00061    float *NodeList = NULL, a, *n1, *n2, *n0;
00062    int *FaceSetList = NULL;
00063    SUMA_SurfaceObject SObuf, *SO=NULL;
00064    SUMA_Boolean LocalHead = YUP;
00065    
00066    SUMA_ENTRY;
00067    
00068    SO = &SObuf;
00069    
00070    N_NodeAlloc = N_Node = *N_Nodep;
00071    N_FaceSetAlloc = N_FaceSet = *N_FaceSetp;
00072    NodeList = *NodeListp;
00073    FaceSetList = *FaceSetListp;
00074    SO->NodeList = NodeList; SO->FaceSetList = FaceSetList;
00075    if (!NodeList || !FaceSetList) { SUMA_SL_Err("NULL input"); SUMA_RETURN(NOPE); }
00076    
00077    it = 0; /* triangle index */
00078    while (it < N_FaceSet) {
00079       it3 = 3*it; 
00080       in0 = FaceSetList[it3]; in1 = FaceSetList[it3+1]; in2 = FaceSetList[it3+2]; /* node indices */
00081       n0 = &(NodeList[3*in0]); n1 = &(NodeList[3*in1]); n2 = &(NodeList[3*in2]);   /* node coordinates */
00082       SUMA_TRI_AREA(n0, n1, n2, a); /* area of triangle */
00083       if (a > maxarea) {
00084          if (N_NodeAlloc <= N_Node) { /* need to realloc ?*/
00085             N_NodeAlloc += 20000;
00086             NodeList = (float *)SUMA_realloc(NodeList, N_NodeAlloc * 3 * sizeof(float));
00087             /* you always add 2 triangles per new node here */
00088             N_FaceSetAlloc += 40000;
00089             FaceSetList = (int *)SUMA_realloc(FaceSetList, N_FaceSetAlloc * 3 * sizeof(int));
00090             if (!NodeList || !FaceSetList) { SUMA_SL_Crit("Failed to realloc"); SUMA_RETURN(NOPE); }
00091             SO->NodeList = NodeList; SO->FaceSetList = FaceSetList;
00092          }
00093          SUMA_FACE_CENTROID(SO, it, c); /* c is the centroid of triangle it */
00094          inc = N_Node; inc3 = inc*3;  ++N_Node; /* index of new centroid node */
00095          NodeList[inc3] = c[0]; NodeList[inc3+1] = c[1]; NodeList[inc3+2] = c[2];   /* add new centroid to bottom of list */
00096          FaceSetList[it3+2] = inc; /* old triangle is now 1st new triangle in0 in1 inc */
00097          itn = N_FaceSet; itn3 = 3 * itn; ++N_FaceSet; /* index of new second triangle */ 
00098          FaceSetList[itn3] = inc; FaceSetList[itn3+1] = in1; FaceSetList[itn3+2] = in2;
00099          itn = N_FaceSet; itn3 = 3 * itn; ++N_FaceSet; /* index of new third triangle */ 
00100          FaceSetList[itn3] = inc; FaceSetList[itn3+1] = in2; FaceSetList[itn3+2] = in0; 
00101       } else {
00102          ++it;
00103       }
00104    }
00105    
00106    /* reallocate */
00107    FaceSetList = (int *)SUMA_realloc(FaceSetList, N_FaceSet * 3 * sizeof(int));
00108    NodeList = (float *)SUMA_realloc(NodeList, N_Node * 3 * sizeof(float));
00109    
00110    *NodeListp = NodeList;
00111    *FaceSetListp = FaceSetList;
00112    *N_FaceSetp = N_FaceSet;
00113    *N_Nodep = N_Node;
00114    
00115    SUMA_RETURN(YUP);
00116 }

SUMA_SURF_PLANE_INTERSECT* SUMA_Surf_Plane_Intersect SUMA_SurfaceObject   SO,
float *    PlaneEq
 

Determines the intersection of a plane and a surface.

SPI = SUMA_Surf_Plane_Intersect (SO, PlaneEq)

Parameters:
SO  (SUMA_SurfaceObject *) Pointer to surface object structure.
PlaneEq  (float *) : 4x1 vector containing the 4 coefficients of the equation of the plane to intersect the surface PlaneEq[0] X + PlaneEq[1] Y + PlaneEq[2] Z + PlaneEq[3] = 0
Returns:
SPI (SUMA_SURF_PLANE_INTERSECT *) Pointer to intersection structure. See help on fields in SUMA_define.h NULL in case of error.
See also:
an older matlab version in Surf_Plane_Intersect_2.m , SUMA_PlaneEq , SUMA_Allocate_SPI , SUMA_free_SPI

Definition at line 5955 of file SUMA_GeomComp.c.

References SUMA_SurfaceObject::EL, SUMA_EDGE_LIST::EL, SUMA_EDGE_LIST::ELps, i, SUMA_SURF_PLANE_INTERSECT::IntersEdges, SUMA_SURF_PLANE_INTERSECT::IntersNodes, SUMA_SURF_PLANE_INTERSECT::IntersTri, SUMA_SURF_PLANE_INTERSECT::isEdgeInters, SUMA_SURF_PLANE_INTERSECT::isNodeInMesh, SUMA_SURF_PLANE_INTERSECT::isTriHit, LocalHead, n1, n2, SUMA_EDGE_LIST::N_EL, SUMA_SURF_PLANE_INTERSECT::N_IntersEdges, SUMA_SURF_PLANE_INTERSECT::N_IntersTri, SUMA_SurfaceObject::N_Node, SUMA_SURF_PLANE_INTERSECT::N_NodesInMesh, SUMA_SurfaceObject::NodeList, SUMA_Allocate_SPI(), SUMA_Boolean, SUMA_calloc, SUMA_ENTRY, SUMA_etime(), SUMA_free, SUMA_free_SPI(), SUMA_RETURN, and SUMA_SIGN.

Referenced by SUMA_Surf_Plane_Intersect_ROI().

05956 {/*SUMA_Surf_Plane_Intersect*/
05957    static char FuncName[]={"SUMA_Surf_Plane_Intersect"};
05958    int  i, k , k3, i3, n1, n2;
05959    float DT_ABVBEL, DT_POSNEG, u;
05960    float *NodePos;
05961    SUMA_SURF_PLANE_INTERSECT *SPI;
05962    struct  timeval start_time, start_time2;
05963    SUMA_Boolean LocalHead = NOPE;
05964    SUMA_Boolean  Hit;
05965    
05966    SUMA_ENTRY;
05967    
05968    /* Start timer for next function */
05969    SUMA_etime(&start_time2,0);
05970       
05971    if (LocalHead)   fprintf(SUMA_STDERR, "%s : Determining intersecting segments ...\n", FuncName);
05972    
05973    /* allocate for the return structure.
05974    NOTE: If (in a different form of this function) you do not allocate for SPI each time you call the function, make sure you reset all 
05975    elements of the following vector fields: 
05976    IsTriHit[] = NOPE;
05977    TriBranch[] = 0
05978    */
05979    SPI = SUMA_Allocate_SPI (SO);
05980    if (!SPI) {
05981       fprintf (SUMA_STDERR, "Error %s: Failed in SUMA_Allocate_SPI\n", FuncName);
05982       SUMA_RETURN (SPI);
05983    }
05984    
05985    /* allocate for temporary stuff */
05986    NodePos = (float *) SUMA_calloc (SO->N_Node , sizeof(float));
05987 
05988    if (!NodePos )
05989       {
05990          fprintf (SUMA_STDERR, "Error %s: Could not allocate in SUMA_Surf_Plane_Intersect\n", FuncName);
05991          SUMA_free_SPI (SPI); SPI = NULL;
05992          SUMA_RETURN (SPI);
05993       }
05994 
05995       
05996    /* Start timer for next function */
05997    SUMA_etime(&start_time,0);
05998                            
05999    /* Find out which nodes are above and which are below the plane */
06000    for (k=0;k<SO->N_Node; ++k)
06001       {
06002          k3 = 3*k;
06003          NodePos[k] = PlaneEq[0] * SO->NodeList[k3] + PlaneEq[1] * SO->NodeList[k3+1] 
06004                      +PlaneEq[2] * SO->NodeList[k3+2] + PlaneEq[3] ;
06005       }
06006       
06007    /* stop timer */
06008    DT_ABVBEL = SUMA_etime(&start_time,1);
06009                               
06010    
06011    /*
06012       NodePos is < 0 for nodes below the plane and > 0 for points above the plane
06013       Go through each connection and determine if it intersects the plane
06014       If a segment intersects the surface, it means that the sign
06015       of p  would be <= 0 (each point is on a different side of the plane)
06016    */
06017    
06018    /* Start timer for next function */
06019    SUMA_etime(&start_time,0);
06020    
06021    /*
06022       Determine the segments intersecting the surface,
06023       The triangles that contain these segments.
06024       The nodes that form the intersected segments 
06025    */
06026    SPI->N_IntersEdges = 0;
06027    SPI->N_IntersTri = 0;
06028    SPI->N_NodesInMesh = 0;
06029    k=0; 
06030    Hit = NOPE;
06031    while (k < SO->EL->N_EL)
06032       {
06033          /* find out if segment intersects */
06034          /* if (SUMA_IS_NEG(NodePos[SO->EL->EL[k][0]] * NodePos[SO->EL->EL[k][1]])) { *//* can speed this check by explicitly checking for sign difference: 
06035                                                                                     if (SUMA_SIGN(a) != SUMA_SIGN(b)) ... */   
06036          if (SUMA_SIGN(NodePos[SO->EL->EL[k][0]]) != SUMA_SIGN(NodePos[SO->EL->EL[k][1]]) ) {
06037             Hit = YUP;
06038             /* find the intersection point in that segment */
06039             u = -NodePos[SO->EL->EL[k][0]] / (NodePos[SO->EL->EL[k][1]] - NodePos[SO->EL->EL[k][0]]);
06040             i3 = 3 * k;
06041             n1 = 3 * SO->EL->EL[k][0];
06042             n2 = 3 * SO->EL->EL[k][1];
06043             
06044             SPI->IntersNodes[i3] = SO->NodeList[n1] + u * ( SO->NodeList[n2] - SO->NodeList[n1] ); ++i3; ++n2; ++n1;
06045             SPI->IntersNodes[i3] = SO->NodeList[n1] + u * ( SO->NodeList[n2] - SO->NodeList[n1] ); ++i3; ++n2; ++n1;
06046             SPI->IntersNodes[i3] = SO->NodeList[n1] + u * ( SO->NodeList[n2] - SO->NodeList[n1] ); ++i3; ++n2; ++n1;
06047             
06048             /* 
06049             fprintf (SUMA_STDERR,"%s: Edge %d, IntersNodes[%d]= [%f, %f, %f]\n", 
06050                FuncName, k, 3*k, SPI->IntersNodes[3*k], SPI->IntersNodes[3*k+1], SPI->IntersNodes[3*k+2]);
06051             */
06052                
06053             /* Store the intersected segment */
06054             SPI->IntersEdges[SPI->N_IntersEdges] = k;
06055             ++SPI->N_IntersEdges;
06056             
06057             /* mark this segment in the boolean vector to speed up some other functions */
06058             SPI->isEdgeInters[k] = YUP;
06059                   
06060             /* Store the index of the triangle hosting this edge*/
06061             if (!SPI->isTriHit[SO->EL->ELps[k][1]]) {
06062                SPI->IntersTri[SPI->N_IntersTri] = SO->EL->ELps[k][1];
06063                ++(SPI->N_IntersTri);
06064                SPI->isTriHit[SO->EL->ELps[k][1]] = YUP;
06065             }
06066             
06067             /* mark the nodes forming the intersection edges */
06068             if (!SPI->isNodeInMesh[SO->EL->EL[k][0]]) {
06069                SPI->isNodeInMesh[SO->EL->EL[k][0]] = YUP;
06070                ++(SPI->N_NodesInMesh);
06071             }
06072             if (!SPI->isNodeInMesh[SO->EL->EL[k][1]]) {
06073                SPI->isNodeInMesh[SO->EL->EL[k][1]] = YUP;
06074                ++(SPI->N_NodesInMesh);
06075             } 
06076          } else {
06077             Hit = NOPE;
06078          }
06079             
06080             /*  skip ahead of duplicate edge listings */
06081             if (SO->EL->ELps[k][2] > 0) {
06082                if (Hit) { /* you must mark these triangles */
06083                   i3 = 3 * k;
06084                   for (i=1; i < SO->EL->ELps[k][2]; ++i) {
06085                      SPI->isEdgeInters[k+i] = YUP;
06086                      n1 = 3 * (k+i);
06087                      SPI->IntersNodes[n1] = SPI->IntersNodes[i3]; ++i3; ++n1;
06088                      SPI->IntersNodes[n1] = SPI->IntersNodes[i3]; ++i3; ++n1;
06089                      SPI->IntersNodes[n1] = SPI->IntersNodes[i3]; ++i3; ++n1;
06090                      /*
06091                      fprintf (SUMA_STDERR,"%s: Edge %d, IntersNodes[%d]= [%f, %f, %f]\n", 
06092                         FuncName, k+i, n1, SPI->IntersNodes[3*(k+i)], SPI->IntersNodes[3*(k+i)+1], SPI->IntersNodes[3*(k+i)+2]);
06093                      */
06094                      if (!SPI->isTriHit[SO->EL->ELps[k+i][1]]) {
06095                         SPI->IntersTri[SPI->N_IntersTri] = SO->EL->ELps[k+i][1];
06096                         ++(SPI->N_IntersTri);
06097                         SPI->isTriHit[SO->EL->ELps[k+i][1]] = YUP;   
06098                      }
06099                   }
06100                }
06101                k += SO->EL->ELps[k][2];
06102             } else ++k;
06103       }
06104             
06105       
06106    /* stop timer */
06107    DT_POSNEG = SUMA_etime(&start_time,1);
06108    
06109    if (LocalHead) fprintf (SUMA_STDERR, "%s: Found %d intersect segments, %d intersected triangles, %d nodes in mesh (exec time %f + %f = %f secs).\n", 
06110       FuncName, SPI->N_IntersEdges, SPI->N_IntersTri, SPI->N_NodesInMesh, DT_ABVBEL, DT_POSNEG, DT_ABVBEL + DT_POSNEG);
06111    
06112 /* free locally allocated memory */
06113 if (NodePos) SUMA_free (NodePos);
06114    
06115 
06116 SUMA_RETURN (SPI);
06117 }/*SUMA_Surf_Plane_Intersect*/

SUMA_ROI_DATUM* SUMA_Surf_Plane_Intersect_ROI SUMA_SurfaceObject   SO,
int    Nfrom,
int    Nto,
float *    P
 

a wrapper function for SUMA_Surf_Plane_Intersect that returns the intersection in the form of an ROI datum

Parameters:
SO  (SUMA_SurfaceObject *)
Nfrom  (int) index of node index on SO from which the path should begin
Nto  (int) index of node index on SO where the path will end
P  (float *) XYZ of third point that will form the cutting plane with Nfrom and Nto's coordinates This point is usually, the Near Plane clipping point of Nto's picking line.
Returns:
ROId (SUMA_ROI_DATUM *) pointer to ROI datum structure which contains the NodePath from Nfrom to Nto along with other goodies.

Definition at line 6131 of file SUMA_GeomComp.c.

References SUMA_SurfaceObject::idcode_str, SUMA_SURF_PLANE_INTERSECT::IntersEdges, SUMA_SURF_PLANE_INTERSECT::IntersTri, SUMA_SURF_PLANE_INTERSECT::isNodeInMesh, LocalHead, SUMA_CommonFields::MessageList, SUMA_SURF_PLANE_INTERSECT::N_IntersEdges, SUMA_SURF_PLANE_INTERSECT::N_IntersTri, SUMA_ROI_DATUM::N_n, SUMA_SURF_PLANE_INTERSECT::N_NodesInMesh, SUMA_ROI_DATUM::N_t, SUMA_ROI_DATUM::nDistance, SUMA_SurfaceObject::NodeList, SUMA_ROI_DATUM::nPath, ROIO_type, SMA_LogAndPopup, SMT_Critical, SUMA_AddDO(), SUMA_AllocateROI(), SUMA_AllocROIDatum(), SUMA_Boolean, SUMA_calloc, SUMA_Dijkstra(), SUMA_ENTRY, SUMA_free, SUMA_free_SPI(), SUMA_freeROI(), SUMA_FreeROIDatum(), SUMA_IntersectionStrip(), SUMA_LOCAL, SUMA_Plane_Equation(), SUMA_RegisterMessage(), SUMA_RETURN, SUMA_ROI_EdgeGroup, SUMA_ROI_FaceGroup, SUMA_ROI_NodeGroup, SUMA_ROI_NodeSegment, SUMA_Surf_Plane_Intersect(), SUMAg_N_DOv, SUMA_ROI_DATUM::tDistance, SUMA_ROI_DATUM::tPath, and SUMA_ROI_DATUM::Type.

Referenced by SUMA_cb_DrawROI_Join(), SUMA_LinkTailNodeToNodeStroke(), SUMA_LinkThisNodeToNodeInStroke(), and SUMA_ProcessBrushStroke().

06132 {
06133    static char FuncName[]={"SUMA_Surf_Plane_Intersect_ROI"};
06134    SUMA_ROI_DATUM *ROId=NULL;
06135    SUMA_Boolean LocalHead = NOPE;
06136    int N_left;
06137    SUMA_SURF_PLANE_INTERSECT *SPI = NULL;
06138    SUMA_ROI *ROIe = NULL, *ROIt = NULL, *ROIn = NULL, *ROIts = NULL;
06139    float *Eq = NULL;
06140    /* The 3 flags below are for debugging. */
06141    SUMA_Boolean DrawIntersEdges=NOPE; /* Draw edges intersected by plane   */
06142    SUMA_Boolean DrawIntersTri = NOPE; /* Draw triangles intersected by plane */
06143    SUMA_Boolean DrawIntersNodeStrip = NOPE; /* Draw intersection node strip which is the shortest path between beginning and ending nodes */ 
06144    SUMA_Boolean DrawIntersTriStrip=NOPE; /* Draw intersection triangle strip which is the shortest path between beginning and ending nodes */
06145    
06146    SUMA_ENTRY;
06147    
06148    /* computing plane's equation */
06149    Eq = SUMA_Plane_Equation ( &(SO->NodeList[3*Nfrom]), 
06150                               P,
06151                               &(SO->NodeList[3*Nto]) , NULL);
06152    
06153    if (!Eq) {
06154       fprintf(SUMA_STDOUT,"Error %s: Failed in SUMA_Plane_Equation.\n", FuncName);
06155       SUMA_RETURN(ROId);
06156    } 
06157    
06158    if (LocalHead) fprintf (SUMA_STDERR, "%s: Computing Intersection with Surface.\n", FuncName);
06159    SPI = SUMA_Surf_Plane_Intersect (SO, Eq);
06160    if (!SPI) {
06161       fprintf(SUMA_STDOUT,"Error %s: Failed in SUMA_Surf_Plane_Intersect.\n", FuncName);
06162       SUMA_RETURN(ROId);
06163    }
06164    
06165    if (DrawIntersEdges) {
06166       /* Show all intersected edges */
06167       ROIe =  SUMA_AllocateROI (SO->idcode_str, SUMA_ROI_EdgeGroup, "SurfPlane Intersection - Edges", SPI->N_IntersEdges, SPI->IntersEdges);
06168       if (!ROIe) {
06169          fprintf(SUMA_STDERR,"Error %s: Failed in SUMA_AllocateROI.\n", FuncName);
06170       } else {
06171          if (!SUMA_AddDO (SUMAg_DOv, &SUMAg_N_DOv, (void *)ROIe, ROIO_type, SUMA_LOCAL)) {
06172             fprintf(SUMA_STDERR,"Error %s: Failed in SUMA_AddDO.\n", FuncName);
06173          }
06174       }
06175    }
06176    
06177    if (DrawIntersTri) {
06178       /* Show all intersected triangles */
06179       ROIt =  SUMA_AllocateROI (SO->idcode_str, SUMA_ROI_FaceGroup, "SurfPlane Intersection - Triangles", SPI->N_IntersTri, SPI->IntersTri);
06180       if (!ROIt) {
06181          fprintf(SUMA_STDERR,"Error %s: Failed in SUMA_AllocateROI.\n", FuncName);
06182       } else {
06183          if (!SUMA_AddDO (SUMAg_DOv, &SUMAg_N_DOv, (void *)ROIt, ROIO_type, SUMA_LOCAL)) {
06184             fprintf(SUMA_STDERR,"Error %s: Failed in SUMA_AddDO.\n", FuncName);
06185          }
06186       }
06187    }
06188 
06189    /* create ROId */
06190    ROId = SUMA_AllocROIDatum ();
06191    ROId->Type = SUMA_ROI_NodeSegment;
06192 
06193    /* calculate shortest path */
06194    N_left = SPI->N_NodesInMesh;
06195    ROId->nPath = SUMA_Dijkstra (SO, Nfrom, Nto, SPI->isNodeInMesh, &N_left, 1, &(ROId->nDistance), &(ROId->N_n));
06196    if (ROId->nDistance < 0 || !ROId->nPath) {
06197       fprintf(SUMA_STDERR,"\aError %s: Failed in fast SUMA_Dijkstra.\n*** Two points are not connected by intersection. Repeat last selection.\n", FuncName);
06198 
06199       /* clean up */
06200       if (SPI) SUMA_free_SPI (SPI); 
06201       SPI = NULL;
06202       if (ROId) SUMA_FreeROIDatum (ROId);
06203       SUMA_RETURN(NULL);   
06204    }
06205    
06206    if (LocalHead) fprintf (SUMA_STDERR, "%s: Shortest inter nodal distance along edges between nodes %d <--> %d (%d nodes) is %f.\n", 
06207       FuncName, Nfrom, Nto, ROId->N_n, ROId->nDistance);
06208    
06209 
06210    #if 0
06211    
06212       /* FOR FUTURE USAGE:
06213          When drawing on the surface, it is possible to end up with node paths for which the 
06214          triangle strip tracing routines fail. That's paretly because it is possible for these
06215          node paths to visit one node more than once, eg: ... 34 23 34 .... 
06216          That is OK for drawing purposes but not for say, making measurements on the surface.
06217       */
06218       
06219       /* calculate shortest path along the intersection of the plane with the surface */
06220       /* get the triangle path corresponding to shortest distance between Nx and Ny */
06221 
06222       /* Old Method: Does not result is a strip of triangle that is continuous or connected
06223       by an intersected edge. Function is left here for historical reasons. 
06224          tPath = SUMA_NodePath_to_TriPath_Inters (SO, SPI, Path, N_Path, &N_Tri); */
06225 
06226       /* you should not need to go much larger than NodeDist except when you are going for 
06227       1 or 2 triangles away where discrete jumps in d might exceed the limit. 
06228       Ideally, you want this measure to be 1.5 NodeDist or say, 15 mm, whichever is less.... */
06229 
06230       /* THIS SHOULD BE OPTIONAL */
06231       ROId->tPath = SUMA_IntersectionStrip (SO, SPI, ROId->nPath, ROId->N_n, &(ROId->tDistance), 2.5 *ROId->nDistance, &(ROId->N_t));                      
06232       if (!ROId->tPath) {
06233          fprintf(SUMA_STDERR,"Error %s: Failed in SUMA_IntersectionStrip. Proceeding\n", FuncName);
06234          /* do not stop here, it is OK if you can't find the triangle strip */
06235          /* if (ROId) SUMA_FreeROIDatum (ROId);
06236          SUMA_RETURN(NULL);   */
06237       } else {
06238          /* ROId->tPath has a potentially enourmous chunk of memory allocated for it. Trim the fat. */
06239          {
06240             int *tPath_tmp=NULL, i_tmp=0;
06241             tPath_tmp = (int *)SUMA_calloc (ROId->N_t, sizeof(int));
06242             if (!tPath_tmp) {
06243                SUMA_RegisterMessage (SUMAg_CF->MessageList, "Failed to allocate for tpath_tmp", FuncName, SMT_Critical, SMA_LogAndPopup);
06244                SUMA_RETURN(NULL);
06245             }
06246             for (i_tmp=0; i_tmp<ROId->N_t; ++i_tmp) tPath_tmp[i_tmp] = ROId->tPath[i_tmp];
06247             SUMA_free(ROId->tPath);
06248             ROId->tPath = tPath_tmp;
06249          } 
06250 
06251          fprintf (SUMA_STDERR, "%s: Shortest inter nodal distance along surface between nodes %d <--> %d is %f.\nTiangle 1 is %d\n", 
06252             FuncName, Nfrom, Nto, ROId->tDistance, ROId->tPath[0]);
06253 
06254          if (DrawIntersTriStrip) {
06255             /* Show intersected triangles, along shortest path */
06256             ROIts =  SUMA_AllocateROI (SO->idcode_str, SUMA_ROI_FaceGroup, "SurfPlane Intersection - Triangles- Shortest", ROId->N_t, ROId->tPath);
06257             if (!ROIts) {
06258                fprintf(SUMA_STDERR,"Error %s: Failed in SUMA_AllocateROI.\n", FuncName);
06259                if (ROIn) SUMA_freeROI(ROIn);
06260                if (ROIts) SUMA_freeROI(ROIts);
06261                if (ROId) SUMA_FreeROIDatum (ROId);
06262                SUMA_RETURN(NULL);   
06263             }
06264             if (!SUMA_AddDO (SUMAg_DOv, &SUMAg_N_DOv, (void *)ROIts, ROIO_type, SUMA_LOCAL)) {
06265                fprintf(SUMA_STDERR,"Error %s: Failed in SUMA_AddDO.\n", FuncName);
06266                if (ROIn) SUMA_freeROI(ROIn);
06267                if (ROIts) SUMA_freeROI(ROIts);
06268                if (ROId) SUMA_FreeROIDatum (ROId);
06269                SUMA_RETURN(NULL);
06270             }
06271          }
06272 
06273          if (ROId->nPath && DrawIntersNodeStrip) {
06274             #if 0
06275                /* Show me the Path */
06276                for (ii=0; ii < ROId->N_n; ++ii) fprintf(SUMA_STDERR," %d\t", ROId->nPath[ii]);
06277             #endif
06278 
06279             /* Show Path */
06280             ROIn =  SUMA_AllocateROI (SO->idcode_str, SUMA_ROI_NodeGroup, "SurfPlane Intersection - Nodes", ROId->N_n, ROId->nPath);
06281             if (!ROIn) {
06282                fprintf(SUMA_STDERR,"Error %s: Failed in SUMA_AllocateROI.\n", FuncName);
06283                if (ROIn) SUMA_freeROI(ROIn);
06284                if (ROIts) SUMA_freeROI(ROIts);
06285                if (ROId) SUMA_FreeROIDatum (ROId);
06286                SUMA_RETURN(NULL);
06287             }
06288             if (!SUMA_AddDO (SUMAg_DOv, &SUMAg_N_DOv, (void *)ROIn, ROIO_type, SUMA_LOCAL)) {
06289                fprintf(SUMA_STDERR,"Error %s: Failed in SUMA_AddDO.\n", FuncName);
06290                if (ROIn) SUMA_freeROI(ROIn);
06291                if (ROIts) SUMA_freeROI(ROIts);
06292                if (ROId) SUMA_FreeROIDatum (ROId);
06293                SUMA_RETURN(NULL);
06294             }
06295 
06296          }
06297       }                        
06298    #endif
06299    
06300    if (LocalHead) fprintf(SUMA_STDERR,"%s: Freeing Eq...\n", FuncName);
06301    if (Eq) SUMA_free(Eq);
06302 
06303    if (LocalHead) fprintf(SUMA_STDERR,"%s: Freeing SPI...\n", FuncName);
06304    if (SPI) SUMA_free_SPI (SPI);
06305    
06306    if (LocalHead) fprintf(SUMA_STDERR,"%s:Done Freeing...\n", FuncName);      
06307    
06308    SUMA_RETURN(ROId);
06309 }

float* SUMA_Taubin_Smooth SUMA_SurfaceObject   SO,
float **    wgt,
float    lambda,
float    mu,
float *    fin_orig,
int    N_iter,
int    vpn,
SUMA_INDEXING_ORDER    d_order,
float *    fout_final_user,
SUMA_COMM_STRUCT   cs,
byte   nmask
 

performs smoothing based on Taubin's smoothing algorithm in Geometric Signal Processing on Polygonal Meshes (Eurographics 2000)

fout = SUMA_Taubin_Smooth (SUMA_SurfaceObject *SO, float **wgt, float lambda, float mu, float *fin, int N_iter, int vpn, d_order, float *fout_user, SUMA_COMM_STRUCT *cs);

Parameters:
SO  (SUMA_SurfaceObject *SO) The surface, with NodeList, FaceSetList and FN fields present
wgt  (float **) interpolation weights for each node. The dimentions of wgt are equal to those of SO->FN->FirstNeighb These weights may need to be re-evaluated for each iteration For equal weights (1/SO->FN->N_FirstNeighb[n]), just pass NULL
lambda  (float) postive scaling factor
mu  (float) negative scaling factor
fin  (float *) vector containing node data. The length of this vector is vpn x SO->N_Node , where vpn is the number of values per node.
N_iter  (int) number of iterations (same weights are used in each iteration)
vpn  (int) number of values per node in fin
d_order  (SUMA_INDEXING_ORDER) Indicates how multiple values per node are stored in fin SUMA_ROW_MAJOR: The data in fin is stored in *** Row Major *** order. The ith value (start at 0) for node n is at index fin[vpn*n+i] SUMA_COLUMN_MAJOR: The data in fin is stored in *** Column Major *** order. The ith (start at 0) value for node n is at index fin[n+SO->N_Node*i]; etc...
fout_user  (float *) a pointer to the vector where the smoothed version of fin will reside You can pass NULL and the function will do the allocation for you and return the pointer to the smoothed data in fout. If you already have space allocated for the result, then pass the pointer in fout_user and save on allocation time and space. In that case, fout is equal to fout_user. Either way, you are responsible for freeing memory pointed to by fout. DO NOT PASS fout_user = fin
cs  (SUMA_COMM_STRUCT *) See SUMA_Chung_Smooth
nmask  (byte *) NULL == filter all nodes else filter node n if nmask[n]
Returns:
fout (float *) A pointer to the smoothed data (vpn * SO->N_Node values). You will have to free the memory allocated for fout yourself.

Definition at line 2363 of file SUMA_GeomComp.c.

References SUMA_NODE_FIRST_NEIGHB::FirstNeighb, SUMA_SurfaceObject::FN, fout, ftmp, i, LocalHead, SUMA_NODE_FIRST_NEIGHB::N_Neighb, SUMA_SurfaceObject::N_Node, SUMA_COMM_STRUCT::Send, SUMA_Boolean, SUMA_calloc, SUMA_COLUMN_MAJOR, SUMA_ENTRY, SUMA_free, SUMA_INDEXING_ORDER, SUMA_malloc, SUMA_NODE_XYZ, SUMA_RETURN, SUMA_ROW_MAJOR, SUMA_SendToSuma(), SUMA_SL_Crit, SUMA_SL_Err, SUMA_SL_Warn, and vpn.

Referenced by SUMA_Reposition_Touchup(), and SUMA_SkullMask().

02368 {
02369    static char FuncName[]={"SUMA_Taubin_Smooth"};
02370    float *fout_final=NULL, *fbuf=NULL, *fin=NULL, *fout=NULL, *fin_next=NULL, *ftmp=NULL;
02371    float fp, dfp, fpj;
02372    int i, n , k, j, niter, vnk, n_offset, DoThis; 
02373    SUMA_Boolean LocalHead = NOPE;
02374    
02375    SUMA_ENTRY;
02376 
02377    if (N_iter % 2) {
02378       SUMA_SL_Err("N_iter must be an even number\n");
02379       SUMA_RETURN(NULL);
02380    }
02381    
02382    if (!SO || !fin_orig) {
02383       SUMA_SL_Err("NULL SO or fin_orig\n");
02384       SUMA_RETURN(NULL);
02385    }
02386    if (!SO->FN) {
02387       SUMA_SL_Err("NULL SO->FN\n");
02388       SUMA_RETURN(NULL);
02389    }
02390    
02391    if (vpn < 1) {
02392       SUMA_SL_Err("vpn < 1\n");
02393       SUMA_RETURN(NULL);
02394    }  
02395    
02396    if (fout_final_user == fin_orig) {
02397       SUMA_SL_Err("fout_final_user == fin_orig");
02398       SUMA_RETURN(NULL);
02399    }
02400    
02401    if (!fout_final_user) { /* allocate for output */
02402       fout_final = (float *)SUMA_calloc(SO->N_Node * vpn, sizeof(float));
02403       if (!fout_final) {
02404          SUMA_SL_Crit("Failed to allocate for fout_final\n");
02405          SUMA_RETURN(NULL);
02406       }
02407    }else {
02408       fout_final = fout_final_user; /* pre-allocated */
02409    }
02410    
02411    if (d_order == SUMA_COLUMN_MAJOR) {
02412          SUMA_SL_Warn("SUMA_COLUMN_MAJOR has not been thoroughly tested.");
02413    }
02414    
02415    if (cs->Send) {
02416       if(vpn != 3) {
02417          SUMA_SL_Warn("It does not look like you are smoothing coordinates!\nCommunication halted.");
02418          cs->Send = NOPE;
02419       }
02420       if (d_order == SUMA_COLUMN_MAJOR) {
02421          SUMA_SL_Warn("Talking with SUMA_COLUMN_MAJOR has not been tested.");
02422       }
02423    }
02424    
02425    /* allocate for buffer */
02426    fbuf = (float *)SUMA_calloc(SO->N_Node * vpn, sizeof(float));
02427    if (!fbuf) {
02428       SUMA_SL_Crit("Failed to allocate for fbuf\n");
02429       SUMA_RETURN(NULL);
02430    }
02431    
02432    if (LocalHead) {
02433       fprintf (SUMA_STDERR,"%s: Mu = %f, Lambda = %f\nShould have M(%f)< -L(%f) < 0\nN_iter=%d\n", 
02434          FuncName, mu, lambda, mu, -lambda, N_iter);
02435    }
02436    
02437    if (cs->Send) { /* send the first monster */
02438       if (!SUMA_SendToSuma (SO, cs, (void *)fin_orig, SUMA_NODE_XYZ, 1)) {
02439          SUMA_SL_Warn("Failed in SUMA_SendToSuma\nCommunication halted.");
02440       }
02441    }
02442    
02443    fin_next = fin_orig;
02444    switch (d_order) {
02445       case SUMA_COLUMN_MAJOR:
02446          for (niter=0; niter < N_iter; ++niter) {
02447             if ( niter % 2 ) { /* odd */
02448                fin = fin_next; /* input from previous output buffer */
02449                fout = fout_final; /* results go into final vector */
02450                fin_next = fout_final; /* in the next iteration, the input is from fout_final */
02451             } else { /* even */
02452                /* input data is in fin_new */
02453                fin = fin_next;
02454                fout = fbuf; /* results go into buffer */
02455                fin_next = fbuf; /* in the next iteration, the input is from the buffer */
02456             }
02457             for (k=0; k < vpn; ++k) {
02458                n_offset = k * SO->N_Node;  /* offset of kth node value in fin */
02459                for (n=0; n < SO->N_Node; ++n) {
02460                   DoThis = 1;
02461                   if (nmask && !nmask[n]) DoThis = 0;
02462                   vnk = n+n_offset; 
02463                   if (DoThis) {
02464                      fp = fin[vnk]; /* kth value at node n */
02465                      dfp = 0.0;
02466                      for (j=0; j < SO->FN->N_Neighb[n]; ++j) { /* calculating the laplacian */
02467                         fpj = fin[SO->FN->FirstNeighb[n][j]+n_offset]; /* value at jth neighbor of n */
02468                         if (wgt) dfp += wgt[n][j] * (fpj - fp); 
02469                         else dfp += (fpj - fp); /* will apply equal weight later */
02470                      }/* for j*/
02471                      if (niter%2) { /* odd */
02472                         if (wgt) fout[vnk] = fin[vnk] + mu * dfp;
02473                         else fout[vnk] = fin[vnk] + mu * dfp / (float)SO->FN->N_Neighb[n];   /* apply equal weight factor here */
02474                      }else{ /* even */
02475                        if (wgt) fout[vnk] = fin[vnk] + lambda * dfp;
02476                        else fout[vnk] = fin[vnk] + lambda * dfp / (float)SO->FN->N_Neighb[n];  /* apply equal weight factor here */
02477                      }
02478                   } else {
02479                      fout[vnk] = fin[vnk];
02480                   }      
02481                }/* for n */   
02482             }/* for k */
02483             if (cs->Send) {
02484                /* SUMA_SendToSuma does not deal with such COLUMN_MAJOR order.
02485                Must flip things here, boooooring */
02486                if (!niter) { /* allocate for buffer */
02487                   ftmp = (float *) SUMA_malloc(3*SO->N_Node*sizeof(float));
02488                   if (!ftmp) { SUMA_SL_Err("Failed to allocate. Communication Off.\n"); cs->Send = NOPE; }
02489                }
02490                if (ftmp) {
02491                   for (i=0; i<SO->N_Node; ++i) { ftmp[3*i] = fout[i]; ftmp[3*i+1] = fout[i+SO->N_Node];  ftmp[3*i+2] = fout[i+2*SO->N_Node];}
02492                   if (!SUMA_SendToSuma (SO, cs, (void *)ftmp, SUMA_NODE_XYZ, 1)) {
02493                      SUMA_SL_Warn("Failed in SUMA_SendToSuma\nCommunication halted.");
02494                   }
02495                }
02496                if (niter == N_iter -1) { /* free the buffer */
02497                   if (ftmp) { SUMA_free(ftmp); ftmp = NULL; }
02498                }
02499             }
02500          }/* for niter */
02501          break;
02502       case SUMA_ROW_MAJOR:
02503          for (niter=0; niter < N_iter; ++niter) {
02504             if ( niter % 2 ) { /* odd */
02505                fin = fin_next; /* input from previous output buffer */
02506                fout = fout_final; /* results go into final vector */
02507                fin_next = fout_final; /* in the next iteration, the input is from fout_final */
02508             } else { /* even */
02509                /* input data is in fin_new */
02510                fin = fin_next;
02511                fout = fbuf; /* results go into buffer */
02512                fin_next = fbuf; /* in the next iteration, the input is from the buffer */
02513             }
02514             for (n=0; n < SO->N_Node; ++n) {
02515                DoThis = 1;
02516                if (nmask && !nmask[n]) DoThis = 0;
02517                vnk = n * vpn; /* index of 1st value at node n */
02518                for (k=0; k < vpn; ++k) {
02519                   if (DoThis) {
02520                      fp = fin[vnk]; /* kth value at node n */
02521                      dfp = 0.0;
02522                      for (j=0; j < SO->FN->N_Neighb[n]; ++j) { /* calculating the laplacian */
02523                         fpj = fin[SO->FN->FirstNeighb[n][j]*vpn+k]; /* value at jth neighbor of n */
02524                         if (wgt) dfp += wgt[n][j] * (fpj - fp); 
02525                         else dfp += (fpj - fp); /* will apply equal weight later */
02526                      }/* for j*/
02527                      if (niter%2) { /* odd */
02528                         if (wgt) fout[vnk] = fin[vnk] + mu * dfp;
02529                         else fout[vnk] = fin[vnk] + mu * dfp / (float)SO->FN->N_Neighb[n];   /* apply equal weight factor here */
02530                      }else{ /* even */
02531                        if (wgt) fout[vnk] = fin[vnk] + lambda * dfp;
02532                        else fout[vnk] = fin[vnk] + lambda * dfp / (float)SO->FN->N_Neighb[n];  /* apply equal weight factor here */
02533                      }
02534                   } else {
02535                      fout[vnk] = fin[vnk];
02536                   } 
02537                   ++vnk; /* index of next value at node n */
02538                } /* for k */
02539             }/* for n */
02540             if (cs->Send) {
02541                if (!SUMA_SendToSuma (SO, cs, (void *)fout, SUMA_NODE_XYZ, 1)) {
02542                   SUMA_SL_Warn("Failed in SUMA_SendToSuma\nCommunication halted.");
02543                }
02544             }
02545          }/* for niter */
02546          break;
02547       default:
02548          SUMA_SL_Err("Bad Major, very bad.\n");
02549          SUMA_RETURN(NULL);
02550          break;
02551    }
02552    
02553    if (fbuf) SUMA_free(fbuf); fbuf = NULL;
02554       
02555    SUMA_RETURN(fout);
02556 }

SUMA_Boolean SUMA_Taubin_Smooth_Coef float    k,
float *    l,
float *    m
 

Calculates Mu(m) and Lambda(l) smoothing coefficients based on Taubin's smoothing algorithm in Geometric Signal Processing on Polygonal Meshes (Eurographics 2000).

Parameters:
k  (float) the pass-band frequency (typically 0.1)
l  (float) what will be the postive scaling factor
m  (float) what will be the negative scaling factor (for avoiding the shrinkage of surfaces)
Returns:
ans (SUMA_Boolean) YUP, good solution found NOPE, solution could not be found
k, l and m are related by the following equations:

k = 1/l + 1/m (eq 8) 0 = 1 - 3(l+m) + 5lm (eq 9)

the solutions must verify the following: l > 0 m < -l < 0

See also:
SUMA_Taubin_Smooth_TransferFunc , SUMA_Taubin_Smooth

Definition at line 2270 of file SUMA_GeomComp.c.

References i, l, LocalHead, SUMA_Boolean, SUMA_ENTRY, SUMA_RETURN, and SUMA_SL_Err.

02271 {
02272    static char FuncName[]={"SUMA_Taubin_Smooth_Coef"};
02273    int i;
02274    float ls[2], delta;
02275    SUMA_Boolean Done = NOPE;
02276    SUMA_Boolean LocalHead = NOPE;
02277    
02278    SUMA_ENTRY;
02279    
02280    if (k < 0) { SUMA_SL_Err("k < 0"); SUMA_RETURN(NOPE); }
02281    
02282    /* l1 and l2 are solutions of the quadratic equation:
02283       (5 - 3 k) l^2 + k l - 1 = 0 */
02284    delta = ( k * k - 12.0 * k + 20 );
02285    if (delta < 0) { SUMA_SL_Err("Delta is < 0 for specified k"); SUMA_RETURN(NOPE); }
02286    
02287    ls[0] = ( -k + sqrt(delta) ) / ( 10 - 6 * k );
02288    ls[1] = ( -k - sqrt(delta) ) / ( 10 - 6 * k );
02289    if (ls[0] < 0 && ls[1] < 0) { SUMA_SL_Err("No positive solution for l"); SUMA_RETURN(NOPE); }
02290    
02291    if (ls[1] > ls[0]) { /* swap them */
02292       *l = ls[0]; ls[0] = ls[1]; ls[1] = *l;
02293    }
02294    
02295    Done = NOPE;
02296    i = 0;
02297    while (!Done && i < 2) {
02298       /* calculate mu */
02299       *l = ls[i]; 
02300       *m = *l / ( k * *l - 1.0 );
02301       if (*m < 0) Done = YUP;
02302       ++i;
02303    }
02304    
02305    if (!Done) { SUMA_SL_Err("No good solutions found."); SUMA_RETURN(NOPE); }
02306    
02307    if ( ! ( ( *m < -1.0 * *l ) && ( -1.0 * *l < 0 ) ) ) {
02308       SUMA_SL_Err("Solution did not meet m < -l < 0"); SUMA_RETURN(NOPE);
02309    }
02310    
02311    SUMA_RETURN(YUP);
02312 }

SUMA_Boolean SUMA_Taubin_Smooth_TransferFunc float    l,
float    m,
int    N,
FILE *    Out
 

Show the transfer function (f(k)) for the Taubin smoothing algorithm for a combination of scaling factors and number of iterations.

Parameters:
l  (float) postive scaling factor
m  (float) negative scaling factor (for avoiding the shrinkage of surfaces) The band-pass frequency (kbp) is 1/m + 1/l f(kbp) = 1
N_iter  (int) number of iterations
Out  (FILE *) pointer to output file. If NULL, output is to stdout
Returns:
ans (SUMA_Boolean) YUP, no problems NOPE, yes problems
The output is of the form: k f(k)

where k is the normalized frequency and f(k) is the value of the transfer function at k

See also:
figure 4 in Geometric Signal Processing on Polygonal Meshes (Taubin G, Eurographics 2000) , SUMA_Taubin_Smooth , SUMA_Taubin_Smooth_Coef

Definition at line 2217 of file SUMA_GeomComp.c.

References i, l, LocalHead, SUMA_Boolean, SUMA_ENTRY, SUMA_RETURN, and SUMA_SL_Err.

02218 {
02219    static char FuncName[]={"SUMA_Taubin_Smooth_TransferFunc"};
02220    FILE *Outp = NULL;
02221    int i, imax = 100;
02222    float fk, k;
02223    SUMA_Boolean LocalHead = NOPE;
02224    
02225    SUMA_ENTRY;
02226 
02227    if (N % 2) {
02228       SUMA_SL_Err("N_iter must be even");
02229       SUMA_RETURN(NOPE);
02230    }
02231    
02232    if (!Out) Outp = stdout;
02233    else Outp = Out;
02234    
02235    k = 0.0;
02236    for (i=0; i< imax; ++i) {
02237       fk = pow( ( ( 1-m*k ) * ( 1-l*k ) ) , N / 2 );
02238       fprintf (Outp,"%f %f\n", k, fk);
02239       k += (float)i/(float)imax;
02240    }
02241    
02242    
02243    SUMA_RETURN(YUP);
02244 }

double SUMA_VolDiff double    r,
void *    fvdata
 

Definition at line 1488 of file SUMA_GeomComp.c.

References SUMA_VolDiffDataStruct::cs, i, LocalHead, SUMA_SurfaceObject::NodeList, r, SUMA_VolDiffDataStruct::Rref, SUMA_COMM_STRUCT::Send, SUMA_VolDiffDataStruct::SO, SUMA_VolDiffDataStruct::SOref, SUMA_Boolean, SUMA_ENTRY, SUMA_LH, SUMA_NewVolumeAtRadius(), SUMA_NODE_XYZ, SUMA_RETURN, SUMA_SendToSuma(), SUMA_SL_Warn, SUMA_VolDiffDataStruct::tmpList, and SUMA_VolDiffDataStruct::Vref.

Referenced by SUMA_EquateSurfaceVolumes().

01489 {
01490    static char FuncName[]={"SUMA_VolDiff"};
01491    double dv, *fp, Dr, V;
01492    static int ncall=0;
01493    int i;
01494    static double Rref = 0.0, Vref = 0.0;
01495    SUMA_SurfaceObject *SO, *SOref;
01496    SUMA_COMM_STRUCT *cs=NULL;
01497    SUMA_VolDiffDataStruct *fdata = (SUMA_VolDiffDataStruct*)fvdata ;
01498    SUMA_Boolean LocalHead = NOPE;
01499 
01500    SUMA_ENTRY;
01501    
01502    if (!fdata) {
01503       SUMA_LH("Reset");
01504       Rref = 0.0; Vref = 0.0;
01505       ncall = 0;
01506       SUMA_RETURN(0.0);
01507    }
01508    
01509    SO = fdata->SO;
01510    SOref = fdata->SOref;
01511    cs = fdata->cs;
01512    
01513    if (!ncall) {
01514       SUMA_LH("Initializing, calculating Vref and Rref");
01515       Vref = fdata->Vref;
01516       Rref = fdata->Rref;
01517       if (LocalHead) { fprintf(SUMA_STDERR,"%s: Reference volume = %f, radius = %f \n", FuncName, Vref, Rref); }
01518       if (cs->Send) { /* send the first monster (it's SOref "in SUMA" that's being modified on the fly) */
01519          if (!SUMA_SendToSuma (SOref, cs, (void *)SO->NodeList, SUMA_NODE_XYZ, 1)) {
01520          SUMA_SL_Warn("Failed in SUMA_SendToSuma\nCommunication halted.");
01521          }
01522       }
01523    }
01524    
01525    V = SUMA_NewVolumeAtRadius(SO, r, Rref, fdata->tmpList);
01526    dv = Vref - V; /* the volume difference */
01527       
01528    /* need an update ? */
01529    if (cs->Send) { /* send the update (it's SOref "in SUMA" that's being modified on the fly) */
01530       if (!SUMA_SendToSuma (SOref, cs, (void *)fdata->tmpList, SUMA_NODE_XYZ, 1)) {
01531       SUMA_SL_Warn("Failed in SUMA_SendToSuma\nCommunication halted.");
01532       }
01533    }
01534 
01535    ++ncall;
01536    
01537    SUMA_RETURN(dv);
01538 }

int SUMA_VoxelNeighbors int    ijk,
int    ni,
int    nj,
int    nk,
SUMA_VOX_NEIGHB_TYPES    ntype,
int *    nl
 

find the neighbors to a voxel.

Parameters:
ijk  (int) a voxel's 1D index
ni, nj, nk  (int) number of voxels in each of the three directions
ntype  (SUMA_VOX_NEIGHB_TYPES) neighborhood type SUMA_VOX_NEIGHB_FACE a maximum total of 6 neighbors SUMA_VOX_NEIGHB_EDGE a maximum total of 6 + 12 neighbors SUMA_VOX_NEIGHB_CORNER a maximum total of 6 + 12 + 8 neighbors
nl  (int *) vector to contain the 1D indices of neighboring voxels. Voxels outside the volume boundaries are not considered. You should make sure nl can hold a total of 26 values.
N_n  (int) number of neighbors.

Definition at line 409 of file SUMA_GeomComp.c.

References i, SUMA_1D_2_3D_index, SUMA_3D_2_1D_index, SUMA_ENTRY, SUMA_RETURN, SUMA_SL_Err, SUMA_VOX_NEIGHB_CORNER, SUMA_VOX_NEIGHB_EDGE, and SUMA_VOX_NEIGHB_TYPES.

Referenced by SUMA_FillToVoxelMask().

00410 {
00411    static char FuncName[]={"SUMA_VoxelNeighbors"};
00412    int i, j, k;
00413    int nij, N_n;
00414    
00415    SUMA_ENTRY;
00416    
00417    N_n = 0; nij = ni * nj;
00418    
00419    /* change ijk to 3D */
00420    SUMA_1D_2_3D_index(ijk, i, j, k, ni, nij);
00421    
00422    if (i >= ni || i < 0) { SUMA_SL_Err("Voxel out of bounds along i direction"); SUMA_RETURN(N_n); }
00423    if (j >= nj || j < 0) { SUMA_SL_Err("Voxel out of bounds along j direction"); SUMA_RETURN(N_n); }
00424    if (k >= nk || k < 0) { SUMA_SL_Err("Voxel out of bounds along k direction"); SUMA_RETURN(N_n); }
00425   
00426    /* start with the face neighbors */
00427    if (i-1 >= 0) { nl[N_n] = SUMA_3D_2_1D_index(i-1, j, k, ni, nij); ++N_n; }
00428    if (j-1 >= 0) { nl[N_n] = SUMA_3D_2_1D_index(i, j-1, k, ni, nij); ++N_n; } 
00429    if (k-1 >= 0) { nl[N_n] = SUMA_3D_2_1D_index(i, j, k-1, ni, nij); ++N_n; } 
00430    if (i+1 < ni) { nl[N_n] = SUMA_3D_2_1D_index(i+1, j, k, ni, nij); ++N_n; } 
00431    if (j+1 < nj) { nl[N_n] = SUMA_3D_2_1D_index(i, j+1, k, ni, nij); ++N_n; } 
00432    if (k+1 < nk) { nl[N_n] = SUMA_3D_2_1D_index(i, j, k+1, ni, nij); ++N_n; } 
00433    
00434    if ( ntype < SUMA_VOX_NEIGHB_EDGE) { SUMA_RETURN(N_n); }
00435    
00436    /* add edge neighbors */
00437    if (i-1 >= 0 && j-1 >= 0) { nl[N_n] = SUMA_3D_2_1D_index(i-1, j-1, k, ni, nij); ++N_n; }
00438    if (i-1 >= 0 && j+1 < nj) { nl[N_n] = SUMA_3D_2_1D_index(i-1, j+1, k, ni, nij); ++N_n; }
00439    if (i-1 >= 0 && k-1 >= 0) { nl[N_n] = SUMA_3D_2_1D_index(i-1, j, k-1, ni, nij); ++N_n; }
00440    if (i-1 >= 0 && k+1 < nk) { nl[N_n] = SUMA_3D_2_1D_index(i-1, j, k+1, ni, nij); ++N_n; }
00441    if (j-1 >= 0 && k-1 >= 0) { nl[N_n] = SUMA_3D_2_1D_index(i, j-1, k-1, ni, nij); ++N_n; } 
00442    if (j-1 >= 0 && k+1 < nk) { nl[N_n] = SUMA_3D_2_1D_index(i, j-1, k+1, ni, nij); ++N_n; } 
00443    if (i+1 < ni && j-1 >= 0) { nl[N_n] = SUMA_3D_2_1D_index(i+1, j-1, k, ni, nij); ++N_n; }
00444    if (i+1 < ni && j+1 < nj) { nl[N_n] = SUMA_3D_2_1D_index(i+1, j+1, k, ni, nij); ++N_n; }
00445    if (i+1 < ni && k-1 >= 0) { nl[N_n] = SUMA_3D_2_1D_index(i+1, j, k-1, ni, nij); ++N_n; }
00446    if (i+1 < ni && k+1 < nk) { nl[N_n] = SUMA_3D_2_1D_index(i+1, j, k+1, ni, nij); ++N_n; }
00447    if (j+1 < nj && k-1 >= 0) { nl[N_n] = SUMA_3D_2_1D_index(i, j+1, k-1, ni, nij); ++N_n; } 
00448    if (j+1 < nj && k+1 < nk) { nl[N_n] = SUMA_3D_2_1D_index(i, j+1, k+1, ni, nij); ++N_n; } 
00449    
00450    if ( ntype < SUMA_VOX_NEIGHB_CORNER) { SUMA_RETURN(N_n); }
00451    
00452    /* add corner neighbors */
00453    if (i-1 >= 0 && j-1 >= 0 && k-1 >= 0) { nl[N_n] = SUMA_3D_2_1D_index(i-1, j-1, k-1, ni, nij); ++N_n; }
00454    if (i-1 >= 0 && j-1 >= 0 && k+1 < nk) { nl[N_n] = SUMA_3D_2_1D_index(i-1, j-1, k+1, ni, nij); ++N_n; }
00455    if (i-1 >= 0 && j+1 < nj && k-1 >= 0) { nl[N_n] = SUMA_3D_2_1D_index(i-1, j+1, k-1, ni, nij); ++N_n; }
00456    if (i-1 >= 0 && j+1 < nj && k+1 < nk) { nl[N_n] = SUMA_3D_2_1D_index(i-1, j+1, k+1, ni, nij); ++N_n; }
00457    if (i+1 < ni && j-1 >= 0 && k-1 >= 0) { nl[N_n] = SUMA_3D_2_1D_index(i+1, j-1, k-1, ni, nij); ++N_n; }
00458    if (i+1 < ni && j-1 >= 0 && k+1 < nk) { nl[N_n] = SUMA_3D_2_1D_index(i+1, j-1, k+1, ni, nij); ++N_n; }
00459    if (i+1 < ni && j+1 < nj && k-1 >= 0) { nl[N_n] = SUMA_3D_2_1D_index(i+1, j+1, k-1, ni, nij); ++N_n; }
00460    if (i+1 < ni && j+1 < nj && k+1 < nk) { nl[N_n] = SUMA_3D_2_1D_index(i+1, j+1, k+1, ni, nij); ++N_n; }
00461 
00462    
00463    SUMA_RETURN(N_n);
00464 }

SUMA_Boolean SUMA_VoxelsInBox int *    voxelsijk,
int *    N_in,
float *    c1,
float *    c2
 

find voxels whose centers are inside the box with corners c1 and c2 c1, c2 are in voxel index coordinates. c1 is the minimum coordinates point. c2 is the maximum coordinates point.

Definition at line 567 of file SUMA_GeomComp.c.

References i, SUMA_Boolean, SUMA_CEIL, SUMA_ENTRY, SUMA_RETURN, SUMA_ROUND, and SUMA_SL_Err.

Referenced by SUMA_GetVoxelsIntersectingTriangle(), and SUMA_SurfGridIntersect().

00568 {
00569    static char FuncName[]={"SUMA_VoxelsInBox"};
00570    int n3, i, j, k;
00571    
00572    SUMA_ENTRY;
00573    
00574    if (!voxelsijk) { 
00575       SUMA_SL_Err("NULL voxelsijk");
00576       SUMA_RETURN(NOPE); 
00577    }
00578    
00579    *N_in = 0;
00580    
00581    #if 0
00582    for (k = SUMA_ROUND(c1[2]); k <= SUMA_ROUND(c2[2]); ++k) {
00583       for (j = SUMA_ROUND(c1[1]); j <= SUMA_ROUND(c2[1]); ++j) {
00584          for (i = SUMA_ROUND(c1[0]); i <= SUMA_ROUND(c2[0]); ++i) {
00585             n3 = 3*(*N_in);
00586             voxelsijk[n3] = i; voxelsijk[n3+1] = j; voxelsijk[n3+2] = k; 
00587             ++(*N_in); 
00588          }
00589       }
00590    }
00591    #else
00592    for (k = (int)(c1[2]); k <= SUMA_CEIL(c2[2]); ++k) {
00593       for (j = (int)(c1[1]); j <= SUMA_CEIL(c2[1]); ++j) {
00594          for (i = (int)(c1[0]); i <= SUMA_CEIL(c2[0]); ++i) {
00595             n3 = 3*(*N_in);
00596             voxelsijk[n3] = i; voxelsijk[n3+1] = j; voxelsijk[n3+2] = k; 
00597             ++(*N_in); 
00598          }
00599       }
00600    }
00601    #endif     
00602    SUMA_RETURN(YUP); 
00603 }

Variable Documentation

SUMA_CommonFields* SUMAg_CF  
 

Global pointer to structure containing info common to all viewers

Definition at line 23 of file SUMA_GeomComp.c.

SUMA_DO* SUMAg_DOv  
 

Global pointer to Displayable Object structure vector

Definition at line 24 of file SUMA_GeomComp.c.

int SUMAg_N_DOv  
 

Number of DOs stored in DOv

Definition at line 27 of file SUMA_GeomComp.c.

Referenced by SUMA_Surf_Plane_Intersect_ROI().

int SUMAg_N_SVv  
 

Number of SVs stored in SVv

Definition at line 26 of file SUMA_GeomComp.c.

SUMA_SurfaceViewer* SUMAg_SVv  
 

Global pointer to the vector containing the various Surface Viewer Structures

Definition at line 25 of file SUMA_GeomComp.c.

 

Powered by Plone

This site conforms to the following standards: