www.pudn.com > SurfaceConstructor-1.1.rar > align.c
/***************************************************************************** * align.c is the source file for the slice alignment portion of an * application to construct surfaces from serial secions * Oliver Hinds2004-02-04 * * * *****************************************************************************/ #include"align.h" #include"contour.extern" /****************************************************** * globals ******************************************************/ /* pointers to the two current images */ static image *ref; static image *mov; /* pointers to the two current image textures */ static GLuint *refTex; static GLuint *movTex; /* the slice image quads for positions */ static quadri refImgBounds; static quadri movImgBounds; /* pointer to the current action list */ static list *actions; /* flag to tell which image to display, 0 or 1 */ static int displayImg = 0; /* flags for rotation and motion */ static int moving = 0; static int rotating = 0; static int settingRotCenter = FALSE; /* current image rotation and translation */ static double curRotAngle = 0; static vector curRotCenter; static vector curTransAction; /* sensitivity modifiers */ static double coarseSensitivity = 1.0; static double fineSensitivity = 0.1; static double curSensitivity = 1.0; /* increments for actions */ static double transIncrX = 0.001; static double transIncrY = 0.001; static double scaleIncrX = 0.001; static double scaleIncrY = 0.001; /* flag for animation or not */ static int animate = TRUE; static int framePeriod = 10; /* flags for display of tacks */ static int showPrevTacks = FALSE; static int showCurTacks = FALSE; /* msecs between image switches */ int switchPeriod = 10; static int switchPerIncrement = 10; static const int MAX_SWITCH_PERIOD = 1000; /* size of stuff */ static const int rotCenterSize = 4; /****************************************************** * functions ******************************************************/ /** initialization and display ops **/ /** * prepare the images and perform init on local vars */ void alignImgInit() { static int firstRun = TRUE; image *img; /* validate the curSlice */ curSlice %= curDataset->numSlices; if(curSlice < 0) curSlice += curDataset->numSlices; /* assign the reference and moving images and textures */ if(curSlice > 0) { /* load the textures if dynamic textures is on */ if(dynamicTextures) { img = loadImage(curDataset, curSlice-1); curDataset->slices[curSlice-1] = *img; free(img); } ref = &curDataset->slices[curSlice-1]; refTex = (GLuint*) &curDataset->sliceTextures[curSlice-1]; } /* zero the translation and rotation */ curTransAction.x = 0.0; curTransAction.y = 0.0; /* initialize things that only need it the first run */ if(firstRun == TRUE) { /* get a quadric object */ if(quad == NULL) { quad = gluNewQuadric(); gluQuadricDrawStyle(quad, GLU_FILL); } curRotCenter.x = (movImgBounds.v1.x+movImgBounds.v3.x)/2.0; curRotCenter.y = (movImgBounds.v1.y+movImgBounds.v3.y)/2.0; firstRun = FALSE; } /* load the textures if dynamic textures is on */ if(dynamicTextures) { img = loadImage(curDataset, curSlice); curDataset->slices[curSlice] = *img; free(img); } mov = &curDataset->slices[curSlice]; movTex = (GLuint*)&curDataset->sliceTextures[curSlice]; } /** * initialize general properties */ void alignInit() { //vector mid; listNode *ln; /* apply the moving actions if this isn't the first image */ if(curSlice > 0) { /* find the initial placement of the ref image */ refImgBounds.v1.x = 0; refImgBounds.v1.y = 0; refImgBounds.v2.x = ref->width; refImgBounds.v2.y = 0; refImgBounds.v3.x = ref->width; refImgBounds.v3.y = ref->height; refImgBounds.v4.x = 0; refImgBounds.v4.y = ref->height; /* get the action list to apply/modify, create if it doesn't exist */ while(NULL == (ln=getListNode(curDataset->sliceActionLists,curSlice-1))) { actions = newList(LIST); enqueue(curDataset->sliceActionLists, actions); } actions = (list*) ln->data; /* apply the actions */ refImgBounds = applyActions(actions,refImgBounds); } /* find the initial placement of the moving image */ movImgBounds.v1.x = 0; movImgBounds.v1.y = 0; movImgBounds.v2.x = mov->width; movImgBounds.v2.y = 0; movImgBounds.v3.x = mov->width; movImgBounds.v3.y = mov->height; movImgBounds.v4.x = 0; movImgBounds.v4.y = mov->height; curDataset->width = mov->width; curDataset->height = mov->height; curRotCenter.x = (movImgBounds.v1.x+movImgBounds.v3.x)/2.0; curRotCenter.y = (movImgBounds.v1.y+movImgBounds.v3.y)/2.0; /* get the moving action list to apply/modify, create if it doesn't exist */ while(NULL == (ln = getListNode(curDataset->sliceActionLists,curSlice))) { actions = newList(LIST); enqueue(curDataset->sliceActionLists, actions); } actions = (list*) ln->data; /* apply the actions */ movImgBounds = applyActions(actions,movImgBounds); /* turn on animation */ animate = TRUE; strcpy(alertString,""); alignTimerEvent(0); } /** * uninitializes the align drawing and imaging stuff */ void alignUninit() { /* load the texture if dynamic textures is on */ if(dynamicTextures) { unloadTexture(curSlice-1); if(refTex) { unloadTexture(curSlice); } } /* turn off animation */ animate = FALSE; } /** * cleans up */ void alignDestroy() { gluDeleteQuadric(quad); quad = NULL; } /** * check to see if a repaint is needed */ int alignRepaintNeeded(long now) { static long nextSwitch = 0; if(animate && now >= nextSwitch) { nextSwitch = now + switchPeriod; displayImg = !displayImg; return TRUE; } return FALSE; } /** * do align specific drawing */ void alignDraw() { list *l, *cList = NULL; listNode *i,*j; vertex *t, *prev; quadri curPos; /* to hold current pos image to be displayed */ vector rc; /* world coords of rotation center */ //char slicefile1[MAX_STR_LEN]; float maxTexX, maxTexY; GLenum textureMethod = getTextureMethod(); /* draw the current referrence image */ if(curSlice != 0 && animate && displayImg == 0) { /* just display the reference image */ maxTexX = (float) ref->width; maxTexY = (float) ref->height; if(curDataset->imageSource != VP_NOIMAGES) { /* turn on texture mapping */ glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); glEnable(textureMethod); /* bind the texture */ glBindTexture(textureMethod, *refTex); /* get the window coordinates of the reference image */ curPos = getWindowCoordsQ(refImgBounds); if(textureMethod == GL_TEXTURE_2D) { maxTexX = ref->width/(float)(ref->width+ref->padX); maxTexY = ref->height/(float)(ref->height+ref->padY); } /* make a quadrilateral and provide texture coords */ glBegin(GL_QUADS); { glTexCoord2d(0.0,0.0); glVertex3d(curPos.v1.x, curPos.v1.y, 0.0); glTexCoord2d(maxTexX,0.0); glVertex3d(curPos.v2.x, curPos.v2.y, 0.0); glTexCoord2d(maxTexX,maxTexY); glVertex3d(curPos.v3.x, curPos.v3.y, 0.0); glTexCoord2d(0.0,maxTexY); glVertex3d(curPos.v4.x, curPos.v4.y, 0.0); } glEnd(); glDisable(textureMethod); } } else if(curSlice == 0 || !animate || displayImg == 1) { /* apply the current rot & trans */ /* calculate transformed coordinates based on current rot and trans */ if(moving) { curPos = getQuadTranslation(movImgBounds, curTransAction); } else if(rotating) { /* rotate the movImg coords bu the current angle */ curPos = getQuadRotation(movImgBounds, curRotCenter, curRotAngle); } else { /* no current transformation, draw at expected location */ curPos = movImgBounds; } curPos = getWindowCoordsQ(curPos); maxTexX = (float) mov->width; maxTexY = (float) mov->height; if(curDataset->imageSource != VP_NOIMAGES) { if(textureMethod == GL_TEXTURE_2D) { maxTexX = mov->width/(float)(mov->width+mov->padX); maxTexY = mov->height/(float)(mov->height+mov->padY); } /* turn on texture mapping */ glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); glEnable(textureMethod); /* bind the texture */ glBindTexture(textureMethod, *movTex); /* get the window coordinates of the moving image */ //curPos = getWindowCoordsQ(curPos); /* make a quadrilateral and provide texture coords */ glBegin(GL_QUADS); { glTexCoord2f(0,0); glVertex3d(curPos.v1.x, curPos.v1.y, 0); glTexCoord2f(maxTexX,0); glVertex3d(curPos.v2.x, curPos.v2.y, 0); glTexCoord2f(maxTexX,maxTexY); glVertex3d(curPos.v3.x, curPos.v3.y, 0); glTexCoord2f(0,maxTexY); glVertex3d(curPos.v4.x, curPos.v4.y, 0); } glEnd(); glDisable(textureMethod); } } /* cur slice contours and markers */ if(showCurTacks && listSize(curDataset->sliceContourLists) > curSlice) { glColor3fv(COLORS[DARK_GRAY]); /* iterate over contours, drawing each */ l = (list*)getListNode(curDataset->sliceContourLists,curSlice)->data; for(i = getListNode(l,0); i; i = (listNode*) i->next) { /* get the contour at index */ cList = ((contour*)i->data)->vertices; /* draw the contour lines, if we need to */ glPointSize(pixelSize*tackWidth); glBegin(GL_LINES); { /* iterate over tacks, drawing lines between each */ prev = listSize(cList) > 1 ? (vertex*) getListNode(cList,0)->data : NULL; for(j = getListNode(cList,1); prev && j; j = (listNode*) j->next) { t = (vertex*) j->data; drawLine(prev,t); prev = t; } } glEnd(); /* draw the tacks in the contour */ for(j = getListNode(cList,0); j; j = (listNode*) j->next) { t = (vertex*) j->data; /* draw the tack */ drawTack(t); } } /* cur slice markers */ glColor3fv(COLORS[GRAYED_LIGHT_ORANGE]); l = (list*)getListNode(curDataset->sliceMarkerLists,curSlice-1)->data; for(i = getListNode(l,0); i; i = (listNode*) i->next) { t = (vertex*) i->data; /* draw the tack */ drawTack(t); } } /* prev slice contours and markers */ if(showPrevTacks && curSlice > 0 && listSize(curDataset->sliceContourLists) > curSlice-1) { glColor3fv(COLORS[GRAY]); /* iterate over contours, drawing each */ l = ((contour*)getListNode(curDataset->sliceContourLists,curSlice-1)->data)->vertices; for(i = getListNode(l,0); i; i = (listNode*) i->next) { /* get the contour at index */ cList = (list*)i->data; /* draw the contour lines, if we need to */ glPointSize(pixelSize*tackWidth); glBegin(GL_LINES); { /* iterate over tacks, drawing lines between each */ prev = listSize(cList) > 1 ? (vertex*) getListNode(cList,0)->data : NULL; for(j = getListNode(cList,1); prev && j; j = (listNode*) j->next) { t = (vertex*) j->data; drawLine(prev,t); prev = t; } } glEnd(); /* draw the tacks in the contour */ for(j = getListNode(cList,0); j; j = (listNode*) j->next) { t = (vertex*) j->data; /* draw the tack */ drawTack(t); } } /* cur slice markers */ glColor3fv(COLORS[GRAYED_LIGHT_ORANGE]); l = (list*)getListNode(curDataset->sliceMarkerLists,curSlice-1)->data; for(i = getListNode(l,0); i; i = (listNode*) i->next) { t = (vertex*)i->data; /* draw the tack */ drawTack(t); } } /* draw the center of rotation */ glPointSize(rotCenterSize); glBegin(GL_POINTS); { glColor3fv(COLORS[RED]); rc = getWindowCoordsV(curRotCenter); glVertex3d(rc.x, rc.y, 0); } glEnd(); /* build info and alert strings */ //getSliceFilename(curDataset, curSlice, slicefile1); //getSliceFilename(curDataset, curSlice+1, slicefile2); strcpy(modeString,"align: "); sprintf(modeString,"slice %d ",curSlice); //strcat(modeString,slicefile1); //strcat(modeString," to "); //strcat(modeString,slicefile1); } /** * handles timer events */ void alignTimerEvent(int value) { /* repaint if necessary */ if(alignRepaintNeeded(glutGet(GLUT_ELAPSED_TIME))) { redisplay(); } /* draw again in the future */ if(animate) { glutTimerFunc(framePeriod, alignTimerEvent, 0); } } /** geometric calcs **/ /** * gets the midpoint of a bounding box of a quad */ vector getMidPoint(quadri q) { vector mid, minXY = getMinXY(q), maxXY = getMaxXY(q); mid.x = 0.5*(minXY.x+maxXY.x); mid.y = 0.5*(minXY.y+maxXY.y); mid.z = 0.0; return mid; } /** * gets the size of a bounding box of a quad */ vector getSize(quadri q) { vector siz, minXY = getMinXY(q), maxXY = getMaxXY(q); siz.x = maxXY.x-minXY.x; siz.y = maxXY.y-minXY.y; siz.z = 0.0; return siz; } /** * get the minimum xy coordinates of a bounding box of a quad */ vector getMinXY(quadri q) { vector minXY; minXY.z = 0.0; minXY.x = q.v1.x; minXY.y = q.v1.y; minXY.x = q.v2.x < minXY.x ? q.v2.x : minXY.x; minXY.y = q.v2.y < minXY.y ? q.v2.y : minXY.y; minXY.x = q.v3.x < minXY.x ? q.v3.x : minXY.x; minXY.y = q.v3.y < minXY.y ? q.v3.y : minXY.y; minXY.x = q.v4.x < minXY.x ? q.v4.x : minXY.x; minXY.y = q.v4.y < minXY.y ? q.v4.y : minXY.y; return minXY; } /** * get the maximum xy coordinates of a bounding box of a quad */ vector getMaxXY(quadri q) { vector maxXY; maxXY.z = 0.0; maxXY.x = q.v1.x; maxXY.y = q.v1.y; maxXY.x = q.v2.x > maxXY.x ? q.v2.x : maxXY.x; maxXY.y = q.v2.y > maxXY.y ? q.v2.y : maxXY.y; maxXY.x = q.v3.x > maxXY.x ? q.v3.x : maxXY.x; maxXY.y = q.v3.y > maxXY.y ? q.v3.y : maxXY.y; maxXY.x = q.v4.x > maxXY.x ? q.v4.x : maxXY.x; maxXY.y = q.v4.y > maxXY.y ? q.v4.y : maxXY.y; return maxXY; } /** * translates a point */ void doTranslateAction(double *x, double *y, vector transAction) { *x += transAction.x; *y += transAction.y; } /** * rotates of a point around a specified center by a specified angle */ void doRotateAction(double *x, double *y, vector rotCenter, double angle) { double theta = angle*PI/180.0; /* rotation angle in radians */ double diffX, diffY; vector rc = rotCenter; /* multiply the coordinates by a rotation matrix */ diffX = *x-rc.x; diffY = *y-rc.y; *x = rc.x + cos(theta)*diffX - sin(theta)*diffY; *y = rc.y + sin(theta)*diffX + cos(theta)*diffY; } /** * scales a point */ void doScaleAction(double *x, double *y, vector scaleAction) { *x = scaleAction.x*(*x); *y = scaleAction.y*(*y); } /** * gets a scaling of a quad */ quadri getQuadScale(quadri base, vector scaleAction) { vector c; /* center of quad */ quadri s; /* new quad */ double imW = length(base.v4,base.v3); double imH = length(base.v4,base.v1); double sx = 1 + scaleAction.x/imW; double sy = 1 + scaleAction.y/imH; /* get the params */ c = getMidPoint(base); /* new vertices are scaled from the center of the current loaction */ s.v1.x = c.x + sx*(base.v1.x-c.x); s.v1.y = c.y + sy*(base.v1.y-c.y); s.v2.x = c.x + sx*(base.v2.x-c.x); s.v2.y = c.y + sy*(base.v2.y-c.y); s.v3.x = c.x + sx*(base.v3.x-c.x); s.v3.y = c.y + sy*(base.v3.y-c.y); s.v4.x = c.x + sx*(base.v4.x-c.x); s.v4.y = c.y + sy*(base.v4.y-c.y); return s; } /** * gets a translation of a quad */ quadri getQuadTranslation(quadri base, vector transAction) { quadri t; /* just add an offset to each vertex */ t.v1.x = base.v1.x+transAction.x; t.v1.y = base.v1.y+transAction.y; t.v2.x = base.v2.x+transAction.x; t.v2.y = base.v2.y+transAction.y; t.v3.x = base.v3.x+transAction.x; t.v3.y = base.v3.y+transAction.y; t.v4.x = base.v4.x+transAction.x; t.v4.y = base.v4.y+transAction.y; return t; } /** * gets a rotation of a quad around a specified center by a specified angle */ quadri getQuadRotation(quadri base, vector rotCenter, double angle) { quadri r; double theta = angle*PI/180.0; /* rotation angle in radians */ double diffX, diffY; vector rc = rotCenter; /* multiply the coordinates by a rotation matrix */ diffX = base.v1.x-rc.x; diffY = base.v1.y-rc.y; r.v1.x = rc.x + cos(theta)*diffX - sin(theta)*diffY; r.v1.y = rc.y + sin(theta)*diffX + cos(theta)*diffY; diffX = base.v2.x-rc.x; diffY = base.v2.y-rc.y; r.v2.x = rc.x + cos(theta)*diffX - sin(theta)*diffY; r.v2.y = rc.y + sin(theta)*diffX + cos(theta)*diffY; diffX = base.v3.x-rc.x; diffY = base.v3.y-rc.y; r.v3.x = rc.x + cos(theta)*diffX - sin(theta)*diffY; r.v3.y = rc.y + sin(theta)*diffX + cos(theta)*diffY; diffX = base.v4.x-rc.x; diffY = base.v4.y-rc.y; r.v4.x = rc.x + cos(theta)*diffX - sin(theta)*diffY; r.v4.y = rc.y + sin(theta)*diffX + cos(theta)*diffY; return r; } /** * sets the center of rotation */ void setRotationCenterV(vector rc) { curRotCenter = rc; } /** * sets the center of rotation */ void setRotationCenter2D(double x, double y) { curRotCenter.x = x; curRotCenter.y = y; } /** action application functions */ /** * applies a translation to the moving image and adds one to the list. * propagates the change through the align actions and tacks of all * images after this one to maintain consistency */ void applyTranslation(vector transAction) { list *postActions, *postContour, *postTackList; listNode *i,*j,*k; vertex *curTack; /* add the action */ if(!addTranslationAction(actions, transAction)) { fprintf(stderr, "error: can't allocate memory to store a translation action\n"); } else { /* successful allocation */ /* consolodate the action list */ consolidateActions(actions); /* apply the action to the movImg */ movImgBounds = getQuadTranslation(movImgBounds, transAction); /* apply the translation to all future action lists */ for(i = getListNode(curDataset->sliceActionLists,curSlice+1); i; i = (listNode*) i->next) { postActions = (list*) i->data; if(!addTranslationAction(postActions, transAction)) { fprintf(stderr, "error: can't allocate memory to store a translation action\n"); } else { /* successful allocation, consolodate */ consolidateActions(postActions); } } /* apply the translation to all tacks on & after this slice */ for(i = getListNode(curDataset->sliceContourLists,curSlice); i; i = (listNode*) i->next) { postContour = (list*) i->data; for(j = getListNode(postContour,0); j; j = (listNode*) j->next) { postTackList = ((contour*) j->data)->vertices; for(k = getListNode(postTackList,0); k; k = (listNode*) k->next) { curTack = (vertex*) k->data; doTranslateAction(&curTack->x, &curTack->y, transAction); } } } /* apply the translation to all markers on & after this slice */ for(i = getListNode(curDataset->sliceMarkerLists,curSlice); i; i = (listNode*) i->next) { postContour = (list*) i->data; for(j = getListNode(postContour,0); j; j = (listNode*) j->next) { curTack = (vertex*) j->data; doTranslateAction(&curTack->x, &curTack->y, transAction); } } } } /** * applies a rotation to the image and adds one to the list * propagates the change through the align actions of all images after * this one to maintain consistency */ void applyRotation(vector rotCenter, double angle) { listNode *i,*j,*k; list *postActions, *postContour, *postTackList; vertex *curTack; /* add the action */ if(!addRotationAction(actions,rotCenter,angle)) { fprintf(stderr, "error: can't allocate memory to store a rotation action\n"); } else { /* consolodate the action list */ consolidateActions(actions); /* apply the rotation to the moving image */ movImgBounds = getQuadRotation(movImgBounds, rotCenter, angle); /* apply the rotation to all future action lists */ for(i = getListNode(curDataset->sliceActionLists,curSlice+1); i; i = (listNode*) i->next) { postActions = (list*) i->data; if(!addRotationAction(postActions, rotCenter, angle)) { fprintf(stderr, "error: can't allocate memory to store a rotation action\n"); } else { /* successful allocation, consolodate */ consolidateActions(postActions); } } /* apply the rotation to all tacks on & after this slice */ for(i = getListNode(curDataset->sliceContourLists,curSlice); i; i = (listNode*) i->next) { postContour = (list*) i->data; for(j = getListNode(postContour,0); j; j = (listNode*) j->next) { postTackList = ((contour*) j->data)->vertices; for(k = getListNode(postTackList,0); k; k = (listNode*) k->next) { curTack = (vertex*) k->data; doRotateAction(&curTack->x, &curTack->y, rotCenter, angle); } } } /* apply the rotation to all markers on & after this slice */ for(i = getListNode(curDataset->sliceMarkerLists,curSlice); i; i = (listNode*) i->next) { postContour = (list*) i->data; for(j = getListNode(postContour,0); j; j = (listNode*) j->next) { curTack = (vertex*) j->data; doRotateAction(&curTack->x, &curTack->y, rotCenter, angle); } } } } /** * adds a specified number of pixels to the image in each direction, * adds action to the list * propagates the change through the align actions of all images after * this one to maintain consistency */ void applyScale(vector scaleAction) { listNode *i,*j,*k; list *postActions, *postContour, *postTackList; vertex *curTack; /* try to add the action to the list */ if(!addScaleAction(actions,scaleAction)) { fprintf(stderr, "error: can't allocate memory to store a scale action\n"); } else { /* consolodate the action list */ consolidateActions(actions); /* apply the rotation to the moving image */ movImgBounds = getQuadScale(movImgBounds, scaleAction); /* apply the scale to all future action lists */ for(i = getListNode(curDataset->sliceActionLists,curSlice+1); i; i = (listNode*) i->next) { postActions = (list*) i->data; if(!addScaleAction(postActions, scaleAction)) { fprintf(stderr, "error: can't allocate memory to store a scale action\n"); } else { /* successful allocation, consolodate */ consolidateActions(postActions); } } /* apply the scale to all tacks on & after this slice */ for(i = getListNode(curDataset->sliceContourLists,curSlice); i; i = (listNode*) i->next) { postContour = (list*) i->data; for(j = getListNode(postContour,0); j; j = (listNode*) j->next) { postTackList = ((contour*) j->data)->vertices; for(k = getListNode(postTackList,0); k; k = (listNode*) k->next) { curTack = (vertex*) k->data; doScaleAction(&curTack->x, &curTack->y, scaleAction); } } } /* apply the scale to all markers on & after this slice */ for(i = getListNode(curDataset->sliceMarkerLists,curSlice); i; i = (listNode*) i->next) { postContour = (list*) i->data; for(j = getListNode(postContour,0); j; j = (listNode*) j->next) { curTack = (vertex*) j->data; doScaleAction(&curTack->x, &curTack->y, scaleAction); } } } } /** * apply a set of actions to an image coordinate */ quadri applyActions(list *l, quadri base) { listNode *i; action *a; quadri res = base; /* apply each action in turn, add them to the current list */ for(i = getListNode(l,0); i; i = (listNode*) i->next) { /* get the action */ a = (action*) i->data; /* apply action and add it to the list */ switch(a->type) { case TRANSLATION: res = getQuadTranslation(res, a->trans); break; case ROTATION: res = getQuadRotation(res, a->rotCenter, a->angle); break; case SCALE: res = getQuadScale(res, a->scale); break; default: fprintf(stderr, "error: unrecognized action type %d\n", a->type); } } return res; } /** event handlers **/ /** * align actions */ void alignAction(int action) { vector actionVector; switch(action) { case 'a': /* turn animation on or off */ if(TRUE == (animate = !animate)) { glutTimerFunc(framePeriod, alignTimerEvent, 0); } else { displayImg = 1; } redisplay(); break; case 'c': /* set the rotation center */ settingRotCenter = TRUE; break; case 'y': /* speed up the flickering */ switchPeriod -= switchPerIncrement; if(switchPeriod < 0) switchPeriod = 0; break; case 't': /* slow down the flickering */ switchPeriod += switchPerIncrement; if(switchPeriod > MAX_SWITCH_PERIOD) switchPeriod = MAX_SWITCH_PERIOD; break; case 'e': /* toggle previous slice tack display */ showPrevTacks = !showPrevTacks; redisplay(); break; case 'w': /* toggle curent slice tack display */ showCurTacks = !showCurTacks; redisplay(); break; case 'Q': displayImg = !displayImg; redisplay(); break; case 'p': /* print the action list */ case 'P': fprintf(stdout,"---------------------------------------\n"); dumpActionList(actions); fprintf(stdout,"---------------------------------------\n"); break; /* case 'r': /\* reset the position of the reference image to unmoved *\/ */ /* resetImage(); */ /* break; */ /* case 'u': /\* undo the last action *\/ */ /* case 'U': */ /* undoLastAction(); */ /* break; */ /* fine direction stuff using numeric keypad */ case '1': /* down and left */ actionVector.x = -transIncrX; actionVector.y = -transIncrY; applyTranslation(actionVector); break; case '2': /* down */ actionVector.x = 0; actionVector.y = -transIncrY; applyTranslation(actionVector); break; case '3': /* down and right */ actionVector.x = transIncrX; actionVector.y = -transIncrY; applyTranslation(actionVector); break; case '4': /* left */ actionVector.x = -transIncrX; actionVector.y = 0; applyTranslation(actionVector); break; case '6': /* right */ actionVector.x = transIncrX; actionVector.y = 0; applyTranslation(actionVector); break; case '7': /* up and left */ actionVector.x = -transIncrX; actionVector.y = transIncrY; applyTranslation(actionVector); break; case '8': /* up */ actionVector.x = 0; actionVector.y = transIncrY; applyTranslation(actionVector); break; case '9': /* up and right */ actionVector.x = transIncrX; actionVector.y = transIncrY; applyTranslation(actionVector); break; case '=': /* grow the slice */ case '+': actionVector.x = scaleIncrX; actionVector.y = scaleIncrY; applyScale(actionVector); break; case '-': /* shrink the slice */ case '_': actionVector.x = -scaleIncrX; actionVector.y = -scaleIncrY; applyScale(actionVector); break; default: break; } } /** * menu creation */ void createAlignMenu() { /* add the menu items */ glutAddMenuEntry("-- Align Specific Actions ---",0); glutAddMenuEntry("'c' set rotation center",'c'); glutAddMenuEntry("'a' toggle animation",'a'); glutAddMenuEntry("'w' toggle current contour visibility",'w'); glutAddMenuEntry("'e' toggle previous contour visibility",'e'); glutAddMenuEntry("'y' speed up flicker",'['); glutAddMenuEntry("'t' slow down flicker",']'); glutAddMenuEntry("'=' scale the slice up",'='); glutAddMenuEntry("'-' scale the slice down",'-'); } /** * keyboard handler */ void alignKeyboard(unsigned char key, int x, int y) { alignAction(key); } /** * mouse handler determines what kind of actions are being performed */ void alignMouse(int button, int state, vector mousePos) { /* set the sensitivity */ curSensitivity = GLUT_ACTIVE_CTRL == glutGetModifiers() ? fineSensitivity : coarseSensitivity; /* choose action based on button */ switch(button) { case GLUT_LEFT_BUTTON: /* if we are setting the rotation center, set it and break */ if(settingRotCenter == TRUE) { setRotationCenterV(mousePos); if(DEBUG) fprintf(stdout,"current rotation center is (%g,%g)\n", curRotCenter.x, curRotCenter.y); settingRotCenter = FALSE; break; } /* left button: translation */ switch(state) { case GLUT_DOWN: /* translation start */ moving = TRUE; break; case GLUT_UP: /* translation end, apply it */ moving = FALSE; applyTranslation(curTransAction); curTransAction.x = curTransAction.y = 0; break; } break; case GLUT_MIDDLE_BUTTON: /* rotation */ switch(state) { case GLUT_DOWN: /* rotation start */ rotating = TRUE; break; case GLUT_UP: /* rotation end, apply rotation */ rotating = FALSE; applyRotation(curRotCenter, curRotAngle); /* reset the rot angle */ curRotAngle = 0; break; } break; } /* store the last positions for the up */ if(state == GLUT_DOWN) { lastPos = mousePos; } redisplay(); } /** * mouse motion handler determines the parameters of the action */ void alignMouseMotion(vector mousePos) { double lastAngle, curAngle; vector rc; /* world coordinates of rotation center */ if(moving) { /* translate by the amount the mouse was moved */ /* update the current translation */ curTransAction.x += curSensitivity*(mousePos.x-lastPos.x); curTransAction.y += curSensitivity*(mousePos.y-lastPos.y); } if(rotating) { /* rotate based on mouse motion wrt center of rotation */ /* get world coords */ rc = curRotCenter; /* get the angles in question */ lastAngle = atan2(lastPos.y-rc.y, lastPos.x-rc.x); curAngle = atan2(mousePos.y-rc.y, mousePos.x-rc.x); /* store the current rotation */ if(fabs(lastAngle-curAngle) < PI) { curRotAngle -= 180/PI * curSensitivity*(lastAngle-curAngle); } else { curRotAngle -= 180/PI * curSensitivity*(lastAngle+curAngle); } curRotAngle = fmod(curRotAngle,360.0); } lastPos = mousePos; redisplay(); }