// SpineAngulated.c #include "SpineAngulated.h" #include #include "utils.h" // CP# means Control Point or Handle // // // // CP0 CP1 // ************************** // * * // * Rect0 * // * * // CP2 ********************************** CP3 // * * // * * // * Poly1 * // * * // * * // CP4 ********************************** CP5 // * * // * Poly2 * // * * // * * // CP6 ********************************** CP7 // * * // * Poly3 * // * * // CP8 ************************** CP9 //************************************************************************************** // // Functions for SpineAngulated // //************************************************************************************* //************************************************************************************** // // AddUserHandles_AngulatedSpine--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 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 AngulatedSpine_AddTwoHandles(HANNOBJECT hObjectMain, HANNOBJECT hObject, pHANDLEDEF pHandleDef1, pHANDLEDEF pHandleDef2, L_BOOL bTop) { L_UINT uFlags = ANNHANDLE_LOCATION | ANNHANDLE_CONTAINER_COORDINATES | ANNHANDLE_ID | ANNHANDLE_PEN_COLOR | ANNHANDLE_FILL_COLOR | ANNHANDLE_SHAPE; ANNHANDLE AnnHandle; QUADHANDLES QuadHandles; AnnHandle.uStructSize = sizeof(ANNHANDLE); AnnHandle.crPen = RGB(0,0,0); AnnHandle.hCursor= NULL; AnnHandle.uFlags = uFlags; QuadHandles.nCount = 0; L_AnnEnumerateHandles(hObject, 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; 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; L_AnnAddUserHandle(hObjectMain, &AnnHandle); } #define ANGULATEDSPINE_NUMPOINTS 10 HANDLEDEF AngulatedSpine_HandleDef[ANGULATEDSPINE_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) , HANDLE_ID_CP6, ANNHANDLE_SHAPE_CIRCLE, RGB( 0,255,255) , HANDLE_ID_CP7, ANNHANDLE_SHAPE_CIRCLE, RGB(255, 0,255) , HANDLE_ID_CP8, ANNHANDLE_SHAPE_CIRCLE, RGB( 0, 0, 0) , HANDLE_ID_CP9, ANNHANDLE_SHAPE_CIRCLE, RGB(255,255,255) , }; L_VOID AngulatedSpine_AddUserHandles(HANNOBJECT hObject) { L_INT nCount; HANNOBJECT AnnObjectNeighbors[4]; // this object is made of four polygons AnnGetNeighborObjects(hObject, AnnObjectNeighbors, &nCount); AnnSortNeighborObjects(hObject, AnnObjectNeighbors, nCount); // Add user handles AngulatedSpine_AddTwoHandles(AnnObjectNeighbors[0], AnnObjectNeighbors[0], AngulatedSpine_HandleDef+0, AngulatedSpine_HandleDef+1, TRUE); AngulatedSpine_AddTwoHandles(AnnObjectNeighbors[0], AnnObjectNeighbors[0], AngulatedSpine_HandleDef+2, AngulatedSpine_HandleDef+3, FALSE); AngulatedSpine_AddTwoHandles(AnnObjectNeighbors[0], AnnObjectNeighbors[1], AngulatedSpine_HandleDef+4, AngulatedSpine_HandleDef+5, FALSE); AngulatedSpine_AddTwoHandles(AnnObjectNeighbors[0], AnnObjectNeighbors[2], AngulatedSpine_HandleDef+6, AngulatedSpine_HandleDef+7, FALSE); AngulatedSpine_AddTwoHandles(AnnObjectNeighbors[0], AnnObjectNeighbors[3], AngulatedSpine_HandleDef+8, AngulatedSpine_HandleDef+9, FALSE); } //*************** SpineAngulated Create functions HANNOBJECT 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 SpineAngulated_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 SpineAngulated_LButtonUp(LPCHILDDATA pData, L_UINT uTool) { RECT rc; HANNOBJECT hPoly[5]; L_INT i; LONG y[5]; LONG dy; L_AnnDefine(pData->hRect, &pData->ptEnd, ANNDEFINE_END); y[0] = min(pData->ptStart.y, pData->ptEnd.y); y[4] = max(pData->ptStart.y, pData->ptEnd.y); dy = (y[4]-y[0])/4; y[1] = 1*dy + y[0]; y[2] = 2*dy + y[0]; y[3] = 3*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<4; i++) { rc.top = y[i]; rc.bottom = y[i+1]; hPoly[i] = 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); AngulatedSpine_AddUserHandles(hPoly[0]); DebugClipCursor(&pData->rcOldClip); } //*************** SpineAngulated Update functions #define MIN_DIST (4) L_VOID SpineAngulated_RestrictPoint(HANNOBJECT hObject, HANNOBJECT hObjectNeighbors[], LPCHILDDATA pData, pANNMOUSEPOS pMousePos) { ANNRECT arcContainer; RECT rcClip; POINT pt[ANGULATEDSPINE_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); GetHandleInfo(pData->AnnObjectNeighbors[0], HANDLE_ID_CP6, pt + 6, NULL, NULL); GetHandleInfo(pData->AnnObjectNeighbors[0], HANDLE_ID_CP7, pt + 7, NULL, NULL); GetHandleInfo(pData->AnnObjectNeighbors[0], HANDLE_ID_CP8, pt + 8, NULL, NULL); GetHandleInfo(pData->AnnObjectNeighbors[0], HANDLE_ID_CP9, pt + 9, 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 + 1; 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; rcClip.bottom = min(pt[6].y, pt[7].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; rcClip.bottom = min(pt[6].y, pt[7].y) - MIN_DIST; break; case HANDLE_ID_CP6: rcClip.right = pt[7].x - MIN_DIST; rcClip.top = max(pt[4].y, pt[5].y) + MIN_DIST; rcClip.bottom = min(pt[8].y, pt[9].y) - MIN_DIST; break; case HANDLE_ID_CP7: rcClip.left = pt[6].x + MIN_DIST; rcClip.top = max(pt[4].y, pt[5].y) + MIN_DIST; rcClip.bottom = min(pt[8].y, pt[9].y) - MIN_DIST; break; case HANDLE_ID_CP8: rcClip.right = pt[9].x - MIN_DIST; rcClip.top = max(pt[6].y, pt[7].y) + MIN_DIST; break; case HANDLE_ID_CP9: rcClip.left = pt[8].x + MIN_DIST; rcClip.top = max(pt[6].y, pt[7].y) + MIN_DIST; break; } rcClip.right++; rcClip.bottom++; L_AnnRestrictCursor(pData->hContainer, &rcClip, NULL, NULL, FALSE); } L_VOID SpineAngulated_Handle_LButtonDown(LPCHILDDATA pData, pANNMOUSEPOS pMousePos) { L_INT32 nCount; AnnGetNeighborObjects( pData->hObjectChange, pData->AnnObjectNeighbors, &nCount); AnnSortNeighborObjects(pData->hObjectChange, pData->AnnObjectNeighbors, nCount); SpineAngulated_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); L_AnnDefine(pData->AnnObjectNeighbors[2], &pMousePos->pt, ANNDEFINE_BEGINMOVEPOINT); break; case HANDLE_ID_CP6: case HANDLE_ID_CP7: L_AnnDefine(pData->AnnObjectNeighbors[2], &pMousePos->pt, ANNDEFINE_BEGINMOVEPOINT); L_AnnDefine(pData->AnnObjectNeighbors[3], &pMousePos->pt, ANNDEFINE_BEGINMOVEPOINT); break; case HANDLE_ID_CP8: case HANDLE_ID_CP9: L_AnnDefine(pData->AnnObjectNeighbors[3], &pMousePos->pt, ANNDEFINE_BEGINMOVEPOINT); break; } } L_VOID SpineAngulated_Handle_MouseMove(LPCHILDDATA pData, pANNMOUSEPOS pMousePos) { SpineAngulated_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); L_AnnDefine(pData->AnnObjectNeighbors[2], &pMousePos->pt, ANNDEFINE_APPEND); break; case HANDLE_ID_CP6: case HANDLE_ID_CP7: L_AnnDefine(pData->AnnObjectNeighbors[2], &pMousePos->pt, ANNDEFINE_APPEND); L_AnnDefine(pData->AnnObjectNeighbors[3], &pMousePos->pt, ANNDEFINE_APPEND); break; case HANDLE_ID_CP8: case HANDLE_ID_CP9: L_AnnDefine(pData->AnnObjectNeighbors[3], &pMousePos->pt, ANNDEFINE_APPEND); break; } } L_VOID SpineAngulated_Handle_LButtonUp(LPCHILDDATA pData, pANNMOUSEPOS pMousePos) { SpineAngulated_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); L_AnnDefine(pData->AnnObjectNeighbors[2], &pMousePos->pt, ANNDEFINE_END); MoveHandle(pData->AnnObjectNeighbors[0], pData->nUserHandleID, pMousePos->pt); break; case HANDLE_ID_CP6: case HANDLE_ID_CP7: L_AnnDefine(pData->AnnObjectNeighbors[2], &pMousePos->pt, ANNDEFINE_END); L_AnnDefine(pData->AnnObjectNeighbors[3], &pMousePos->pt, ANNDEFINE_END); MoveHandle(pData->AnnObjectNeighbors[0], pData->nUserHandleID, pMousePos->pt); break; case HANDLE_ID_CP8: case HANDLE_ID_CP9: L_AnnDefine(pData->AnnObjectNeighbors[3], &pMousePos->pt, ANNDEFINE_END); MoveHandle(pData->AnnObjectNeighbors[0], pData->nUserHandleID, pMousePos->pt); break; } }