// AnalysisLateralSpine.c // CP# means Control Point or Handle // // // CP0 ********************************* CP1 // * * // * * // * * // * * // * * // CP2 ********************************* CP3 // * * // * * // * * // * * // * * // ********************************* // CP4 CP5 #include "AnalysisLateralSpine.h" #include #include "utils.h" //************************************************************************************** // // Functions for AnalysisLateralSpine // //************************************************************************************* //************************************************************************************** // // AddUserHandles_AnalysisLateralSpine--adds user handles for Angulated Spine annotation // hObject is any one of the grouped objects // //************************************************************************************* typedef struct tag_QUADHANDLES { int nCount; ANNPOINT AnnPoints[4]; } QUADHANDLES, *pQUADHANDLES; L_INT L_EXPORT EXT_CALLBACK AnalysisLateralSpine_QuadrilateralHandlesCallback(HANNOBJECT hObject, pANNHANDLEINFO pHandleInfo, L_VOID L_FAR * pUserData) { pQUADHANDLES pQuadHandles = (pQUADHANDLES)pUserData; if (pHandleInfo->nType == ANNHANDLETYPE_DEFAULT_HANDLE) { pQuadHandles->AnnPoints[pQuadHandles->nCount] = pHandleInfo->ptLocationContainer; pQuadHandles->nCount++; } return SUCCESS_NOCHANGE; } // bTop--TRUE means create handles for the top two points // FALSE means create handles forthe bottom two points L_VOID AnalysisLateralSpine_AddTwoHandles(HANNOBJECT hObjectMain, HANNOBJECT hObject, pHANDLEDEF pHandleDef1, pHANDLEDEF pHandleDef2, L_BOOL bTop) { ANNHANDLE AnnHandle; QUADHANDLES QuadHandles; L_UINT uFlags = ANNHANDLE_LOCATION | ANNHANDLE_CONTAINER_COORDINATES | ANNHANDLE_ID | ANNHANDLE_PEN_COLOR | ANNHANDLE_FILL_COLOR | ANNHANDLE_SHAPE; AnnHandle.uStructSize = sizeof(ANNHANDLE); AnnHandle.crPen = RGB(0,0,0); AnnHandle.hCursor= NULL; QuadHandles.nCount = 0; L_AnnEnumerateHandles(hObject, AnalysisLateralSpine_QuadrilateralHandlesCallback, &QuadHandles); if (bTop) AnnHandle.aptContainer = QuadHandles.AnnPoints[0]; else AnnHandle.aptContainer = QuadHandles.AnnPoints[1]; AnnHandle.nShape = pHandleDef1->nShape; AnnHandle.nID = pHandleDef1->nID; AnnHandle.crFill = pHandleDef1->crFill; AnnHandle.uFlags = uFlags; L_AnnAddUserHandle(hObjectMain, &AnnHandle); if (bTop) AnnHandle.aptContainer = QuadHandles.AnnPoints[3]; else AnnHandle.aptContainer = QuadHandles.AnnPoints[2]; AnnHandle.nShape = pHandleDef2->nShape; AnnHandle.nID = pHandleDef2->nID; AnnHandle.crFill = pHandleDef2->crFill; AnnHandle.uFlags = uFlags; L_AnnAddUserHandle(hObjectMain, &AnnHandle); } #define ANALYSIS_LATERAL_SPINE_NUMPOINTS 6 HANDLEDEF AnalysisLateralSpine_HandleDef[ANALYSIS_LATERAL_SPINE_NUMPOINTS] = { HANDLE_ID_CP0, ANNHANDLE_SHAPE_CIRCLE, RGB( 0, 0, 0) , HANDLE_ID_CP1, ANNHANDLE_SHAPE_CIRCLE, RGB(100,100,100) , HANDLE_ID_CP2, ANNHANDLE_SHAPE_CIRCLE, RGB(255, 0, 0) , HANDLE_ID_CP3, ANNHANDLE_SHAPE_CIRCLE, RGB( 0,255, 0) , HANDLE_ID_CP4, ANNHANDLE_SHAPE_CIRCLE, RGB( 0, 0,255) , HANDLE_ID_CP5, ANNHANDLE_SHAPE_CIRCLE, RGB(255,255, 0) , }; L_VOID AnalysisLateralSpine_AddUserHandles(HANNOBJECT hObject) { L_INT nCount; HANNOBJECT AnnObjectNeighbors[2]; // this object is made of four polygons AnnGetNeighborObjects(hObject, AnnObjectNeighbors, &nCount); AnnSortNeighborObjects(hObject, AnnObjectNeighbors, nCount); // Add user handles AnalysisLateralSpine_AddTwoHandles(AnnObjectNeighbors[0], AnnObjectNeighbors[0], AnalysisLateralSpine_HandleDef+0, AnalysisLateralSpine_HandleDef+1, TRUE); AnalysisLateralSpine_AddTwoHandles(AnnObjectNeighbors[0], AnnObjectNeighbors[0], AnalysisLateralSpine_HandleDef+2, AnalysisLateralSpine_HandleDef+3, FALSE); AnalysisLateralSpine_AddTwoHandles(AnnObjectNeighbors[0], AnnObjectNeighbors[1], AnalysisLateralSpine_HandleDef+4, AnalysisLateralSpine_HandleDef+5, FALSE); } //*************** AnalysisLateralSpine Create functions HANNOBJECT AnalysisLateralSpine_CreatePolygon(HANNOBJECT hContainer, RECT rc, L_BOOL bClosed) { POINT pt; HANNOBJECT hPolygon; L_UINT uType; if (bClosed) uType = ANNOBJECT_POLYGON; else uType = ANNOBJECT_POLYLINE; L_AnnCreateItem(hContainer, uType, TRUE, &hPolygon); pt.x = rc.left; pt.y = rc.top; L_AnnDefine(hPolygon, &pt, ANNDEFINE_BEGINSET); pt.y = rc.bottom; L_AnnDefine(hPolygon, &pt, ANNDEFINE_APPEND); pt.x = rc.right; L_AnnDefine(hPolygon, &pt, ANNDEFINE_APPEND); pt.y = rc.top; L_AnnDefine(hPolygon, &pt, ANNDEFINE_APPEND); L_AnnDefine(hPolygon, &pt, ANNDEFINE_END); return hPolygon; } L_VOID AnalysisLateralSpine_LButtonDown(HWND hWnd, LPCHILDDATA pData) { L_AnnAddUndoNode(pData->hAutomation); L_AnnCreateItem(pData->hContainer, ANNOBJECT_RECT, FALSE, &pData->hRect); L_AnnDefine(pData->hRect, &pData->ptStart, ANNDEFINE_BEGINSET); pData->fCapture = TRUE; L_AnnRestrictCursor(pData->hContainer, NULL, NULL, &pData->rcOldClip, TRUE); } L_VOID AnalysisLateralSpine_LButtonUp(LPCHILDDATA pData, L_UINT uTool) { RECT rc; HANNOBJECT hPoly[2]; L_INT i; LONG y[3]; LONG dy; L_AnnDefine(pData->hRect, &pData->ptEnd, ANNDEFINE_END); y[0] = min(pData->ptStart.y, pData->ptEnd.y); y[2] = max(pData->ptStart.y, pData->ptEnd.y); dy = (y[2]-y[0])/2; y[1] = 1*dy + y[0]; rc.left = min(pData->ptStart.x, pData->ptEnd.x); rc.right = max(pData->ptStart.x, pData->ptEnd.x); for (i=0; i<2; i++) { rc.top = y[i]; rc.bottom = y[i+1]; hPoly[i] = AnalysisLateralSpine_CreatePolygon(pData->hContainer, rc, i==0); AnnSetID(hPoly[i], uTool, i); //Set tag to identify poly 0,1,2,3 L_AnnSetSelected(hPoly[i], TRUE, 0); HideDefaultHandles(hPoly[i]); } //Bring the first polygon to the front of the z-order //This polygon will have all the user handles L_AnnBringToFront(hPoly[0]); // Remove original rectangle from container and free L_AnnRemove(pData->hRect); L_AnnDestroy(pData->hRect, 0); // set the default settings from the automation object, and group the objects L_AnnSetAutoDefaults(pData->hAutomation, pData->hContainer, ANNFLAG_SELECTED|ANNFLAG_RECURSE); L_AnnGroup(pData->hContainer, ANNFLAG_SELECTED|ANNFLAG_RECURSE, NULL); L_AnnDumpObject(pData->hContainer); AnalysisLateralSpine_AddUserHandles(hPoly[0]); DebugClipCursor(&pData->rcOldClip); } //*************** AnalysisLateralSpine Update functions #define MIN_DIST (4) L_VOID AnalysisLateralSpine_RestrictPoint(HANNOBJECT hObject, HANNOBJECT hObjectNeighbors[], LPCHILDDATA pData, pANNMOUSEPOS pMousePos) { ANNRECT arcContainer; RECT rcClip; POINT pt[ANALYSIS_LATERAL_SPINE_NUMPOINTS]; GetHandleInfo(pData->AnnObjectNeighbors[0], HANDLE_ID_CP0, pt + 0, NULL, NULL); GetHandleInfo(pData->AnnObjectNeighbors[0], HANDLE_ID_CP1, pt + 1, NULL, NULL); GetHandleInfo(pData->AnnObjectNeighbors[0], HANDLE_ID_CP2, pt + 2, NULL, NULL); GetHandleInfo(pData->AnnObjectNeighbors[0], HANDLE_ID_CP3, pt + 3, NULL, NULL); GetHandleInfo(pData->AnnObjectNeighbors[0], HANDLE_ID_CP4, pt + 4, NULL, NULL); GetHandleInfo(pData->AnnObjectNeighbors[0], HANDLE_ID_CP5, pt + 5, NULL, NULL); L_AnnGetRect(pData->hContainer, &arcContainer, NULL); L_AnnConvert(pData->hContainer, (LPPOINT)&rcClip, (pANNPOINT)&arcContainer, 2, ANNCONVERT_TO_CLIENT); switch(pData->nUserHandleID) { case HANDLE_ID_CP0: rcClip.right = pt[1].x - MIN_DIST; rcClip.bottom = min(pt[2].y, pt[3].y) - MIN_DIST; break; case HANDLE_ID_CP1: rcClip.left = pt[0].x + MIN_DIST; rcClip.bottom = min(pt[2].y, pt[3].y) - MIN_DIST; break; case HANDLE_ID_CP2: rcClip.right = pt[3].x - MIN_DIST; rcClip.top = max(pt[0].y, pt[1].y) + MIN_DIST; rcClip.bottom = min(pt[4].y, pt[5].y) - MIN_DIST; break; case HANDLE_ID_CP3: rcClip.left = pt[2].x + MIN_DIST; rcClip.top = max(pt[0].y, pt[1].y) + MIN_DIST; rcClip.bottom = min(pt[4].y, pt[5].y) - MIN_DIST; break; case HANDLE_ID_CP4: rcClip.right = pt[5].x - MIN_DIST; rcClip.top = max(pt[2].y, pt[3].y) + MIN_DIST; break; case HANDLE_ID_CP5: rcClip.left = pt[4].x + MIN_DIST; rcClip.top = max(pt[2].y, pt[3].y) + MIN_DIST; break; } rcClip.right++; rcClip.bottom++; L_AnnRestrictCursor(pData->hContainer, &rcClip, NULL, NULL, FALSE); } L_VOID AnalysisLateralSpine_Handle_LButtonDown(LPCHILDDATA pData, pANNMOUSEPOS pMousePos) { L_INT32 nCount; AnnGetNeighborObjects( pData->hObjectChange, pData->AnnObjectNeighbors, &nCount); AnnSortNeighborObjects(pData->hObjectChange, pData->AnnObjectNeighbors, nCount); AnalysisLateralSpine_RestrictPoint(pData->hObjectChange, pData->AnnObjectNeighbors, pData, pMousePos); switch (pData->nUserHandleID) { case HANDLE_ID_CP0: case HANDLE_ID_CP1: L_AnnDefine(pData->AnnObjectNeighbors[0], &pMousePos->pt, ANNDEFINE_BEGINMOVEPOINT); break; case HANDLE_ID_CP2: case HANDLE_ID_CP3: L_AnnDefine(pData->AnnObjectNeighbors[0], &pMousePos->pt, ANNDEFINE_BEGINMOVEPOINT); L_AnnDefine(pData->AnnObjectNeighbors[1], &pMousePos->pt, ANNDEFINE_BEGINMOVEPOINT); break; case HANDLE_ID_CP4: case HANDLE_ID_CP5: L_AnnDefine(pData->AnnObjectNeighbors[1], &pMousePos->pt, ANNDEFINE_BEGINMOVEPOINT); break; } } L_VOID AnalysisLateralSpine_Handle_MouseMove(LPCHILDDATA pData, pANNMOUSEPOS pMousePos) { AnalysisLateralSpine_RestrictPoint(pData->hObjectChange, pData->AnnObjectNeighbors, pData, pMousePos); switch (pData->nUserHandleID) { case HANDLE_ID_CP0: case HANDLE_ID_CP1: L_AnnDefine(pData->AnnObjectNeighbors[0], &pMousePos->pt, ANNDEFINE_APPEND); break; case HANDLE_ID_CP2: case HANDLE_ID_CP3: L_AnnDefine(pData->AnnObjectNeighbors[0], &pMousePos->pt, ANNDEFINE_APPEND); L_AnnDefine(pData->AnnObjectNeighbors[1], &pMousePos->pt, ANNDEFINE_APPEND); break; case HANDLE_ID_CP4: case HANDLE_ID_CP5: L_AnnDefine(pData->AnnObjectNeighbors[1], &pMousePos->pt, ANNDEFINE_APPEND); break; } } L_VOID AnalysisLateralSpine_Handle_LButtonUp(LPCHILDDATA pData, pANNMOUSEPOS pMousePos) { AnalysisLateralSpine_RestrictPoint(pData->hObjectChange, pData->AnnObjectNeighbors, pData, pMousePos); switch(pData->nUserHandleID) { case HANDLE_ID_CP0: case HANDLE_ID_CP1: L_AnnDefine(pData->AnnObjectNeighbors[0], &pMousePos->pt, ANNDEFINE_END); MoveHandle(pData->AnnObjectNeighbors[0], pData->nUserHandleID, pMousePos->pt); break; case HANDLE_ID_CP2: case HANDLE_ID_CP3: L_AnnDefine(pData->AnnObjectNeighbors[0], &pMousePos->pt, ANNDEFINE_END); L_AnnDefine(pData->AnnObjectNeighbors[1], &pMousePos->pt, ANNDEFINE_END); MoveHandle(pData->AnnObjectNeighbors[0], pData->nUserHandleID, pMousePos->pt); break; case HANDLE_ID_CP4: case HANDLE_ID_CP5: L_AnnDefine(pData->AnnObjectNeighbors[1], &pMousePos->pt, ANNDEFINE_END); MoveHandle(pData->AnnObjectNeighbors[0], pData->nUserHandleID, pMousePos->pt); break; } }