AR多标签识别

在ARToolKit5的基础上,对check_id.c文件进行修改,对识别到的标签添加相对应的文字显示信息。代码有两个c文件组成keydakMAR.c和BasicInfo.c

keydakMAR.c的代码如下:

// ============================================================================
//    Includes
// ============================================================================

#include <stdio.h>
#include <string.h>
#ifdef _WIN32
#  define snprintf _snprintf
#endif
#include <stdlib.h>                    // malloc(), free()
#ifdef __APPLE__
#  include <GLUT/glut.h>
#else
#  include <GL/glut.h>
#endif
#include <AR/config.h>
#include <AR/video.h>
#include <AR/param.h>            // arParamDisp()
#include <AR/ar.h>
#include <AR/gsub_lite.h>
#include <AR/arMulti.h>

#include "GLFont.h"
#include "BasicInfo.h"

// ============================================================================
//    Constants
// ============================================================================

#define VIEW_DISTANCE_MIN        1.0            // Objects closer to the camera than this will not be displayed.
#define VIEW_DISTANCE_MAX        10000.0        // Objects further away from the camera than this will not be displayed.

typedef struct _cutoffPhaseColours {
    int cutoffPhase;
    GLubyte colour[3];
} cutoffPhaseColours_t;
//设置的截止相位颜色有10种
const cutoffPhaseColours_t cutoffPhaseColours[AR_MARKER_INFO_CUTOFF_PHASE_DESCRIPTION_COUNT] = {
    { AR_MARKER_INFO_CUTOFF_PHASE_NONE, { 0xff, 0x0, 0x0 } },  // Red.  红色
    { AR_MARKER_INFO_CUTOFF_PHASE_PATTERN_EXTRACTION, { 0x95, 0xd6, 0xf6 } },  // Light blue. 浅蓝
    { AR_MARKER_INFO_CUTOFF_PHASE_MATCH_GENERIC, { 0x0, 0x0, 0xff } },  // Blue. 蓝
    { AR_MARKER_INFO_CUTOFF_PHASE_MATCH_CONTRAST, { 0x99, 0x66, 0x33 } },  // Brown. 棕色
    { AR_MARKER_INFO_CUTOFF_PHASE_MATCH_BARCODE_NOT_FOUND, { 0x7f, 0x0, 0x7f } },  // Purple.紫色
    { AR_MARKER_INFO_CUTOFF_PHASE_MATCH_BARCODE_EDC_FAIL, { 0xff, 0x0, 0xff } },  // Magenta. 品红
    { AR_MARKER_INFO_CUTOFF_PHASE_MATCH_CONFIDENCE, { 0x0, 0xff, 0x0 } },  // Green. 绿色
    { AR_MARKER_INFO_CUTOFF_PHASE_POSE_ERROR, { 0xff, 0x7f, 0x0 } },  // Orange. 橙色
    { AR_MARKER_INFO_CUTOFF_PHASE_POSE_ERROR_MULTI, { 0xff, 0xff, 0x0 } },  // Yellow. 黄色
    { AR_MARKER_INFO_CUTOFF_PHASE_HEURISTIC_TROUBLESOME_MATRIX_CODES, { 0xc6, 0xdc, 0x6a } },  // Khaki. 卡其色,土黄色
};

// ============================================================================
//    Global variables
// ============================================================================

static int windowed = TRUE;                     // Use windowed (TRUE) or fullscreen mode (FALSE) on launch.
static int windowWidth = 640;                    // Initial window width, also updated during program execution.
static int windowHeight = 480;                  // Initial window height, also updated during program execution.
static int windowDepth = 32;                    // Fullscreen mode bit depth.
static int windowRefresh = 0;                    // Fullscreen mode refresh rate. Set to 0 to use default rate.

// Image acquisition.
static ARUint8        *gARTImage = NULL;
static int          gARTImageSavePlease = FALSE;  //是否保存图片

// Marker detection.
static ARHandle        *gARHandle = NULL;   //标识检测
static ARPattHandle    *gARPattHandle = NULL;
static long            gCallCountMarkerDetect = 0;
static int          gPattSize = AR_PATT_SIZE1;  //标识检测
static int          gPattCountMax = AR_PATT_NUM_MAX;

// Transformation matrix retrieval.
static AR3DHandle    *gAR3DHandle = NULL;  //3维处理矩阵
static int          gRobustFlag = TRUE;
#define CHECK_ID_MULTIMARKERS_MAX 16
static int gMultiConfigCount = 0;
static ARMultiMarkerInfoT *gMultiConfigs[CHECK_ID_MULTIMARKERS_MAX] = { NULL };
static ARdouble gMultiErrs[CHECK_ID_MULTIMARKERS_MAX];

// Drawing.
static ARParamLT *gCparamLT = NULL;   //画图函数
static ARGL_CONTEXT_SETTINGS_REF gArglSettings = NULL;
static GLint gViewport[4];

// ============================================================================
//    Function prototypes.
// ============================================================================

static int setupCamera(const char *cparam_name, char *vconf, ARParamLT **cparamLT_p, ARHandle **arhandle, AR3DHandle **ar3dhandle);
static int setupMarkers(const int patt_count, const char *patt_names[], ARMultiMarkerInfoT *multiConfigs[], ARHandle *arhandle, ARPattHandle **pattHandle_p);
static void cleanup(void);
static void Visibility(int visible);
static void Reshape(int w, int h);
static void Display(void);
static void print(const char *text, const float x, const float y, int calculateXFromRightEdge, int calculateYFromTopEdge);  //计算屏幕中点的正确距离
// ============================================================================
//    Functions
// ============================================================================

int main(int argc, char** argv)
{
    char glutGamemode[32];
    char *cpara = NULL;
    //相机参数
    char cparaDefault[] = "C:/Program Files (x86)/ARToolKit5/bin/Data/camera_para.dat";  //相机参数文件
    char *vconf = NULL;
    int patt_names_count = 0;
    //最大的类型数据
    char *patt_names[CHECK_ID_MULTIMARKERS_MAX] = { NULL };
    ARdouble pattRatio = (ARdouble)AR_PATT_RATIO;
    AR_MATRIX_CODE_TYPE matrixCodeType = AR_MATRIX_CODE_4x4; //AR_MATRIX_CODE_TYPE_DEFAULT
    int labelingMode = AR_DEFAULT_LABELING_MODE; //AR默认的标签形式
    int patternDetectionMode = AR_DEFAULT_PATTERN_DETECTION_MODE;
    int i, gotTwoPartOption;
    float tempF; //浮点数暂存型
    int tempI; //整数暂存型
    //
    // Library inits.
    //
    glutInit(&argc, argv); //glut初始化
    //
    // Video setup.
    //
    //摄像头配置
    if (!cpara) cpara = cparaDefault;
    if (!setupCamera(cpara, vconf, &gCparamLT, &gARHandle, &gAR3DHandle)) {
        ARLOGe("main(): Unable to set up AR camera.\n");
        exit(-1);
    }
    //
    // AR init.
    //
    //设置需要识别的标签类型
    arSetPatternDetectionMode(gARHandle, patternDetectionMode);
    //设置标签模式
    arSetLabelingMode(gARHandle, labelingMode);
    //设置类型标记比例
    arSetPattRatio(gARHandle, pattRatio);
    //设置需要检测的二维码类型
    arSetMatrixCodeType(gARHandle, matrixCodeType);

    //
    // Graphics setup.
    //

    // Set up GL context(s) for OpenGL to draw into.
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH);
    //设置opengl的显示环境
    if (!windowed) {
        if (windowRefresh) sprintf(glutGamemode, "%ix%i:%i@%i", windowWidth, windowHeight, windowDepth, windowRefresh);
        else sprintf(glutGamemode, "%ix%i:%i", windowWidth, windowHeight, windowDepth);
        glutGameModeString(glutGamemode);
        glutEnterGameMode();
    }
    else {
        glutInitWindowSize(gCparamLT->param.xsize, gCparamLT->param.ysize);
        glutCreateWindow(argv[0]);
    }

    // Setup ARgsub_lite library for current OpenGL context.
    if ((gArglSettings = arglSetupForCurrentContext(&(gCparamLT->param), arVideoGetPixelFormat())) == NULL) {
        ARLOGe("main(): arglSetupForCurrentContext() returned error.\n");
        cleanup();
        exit(-1);
    }
    arglSetupDebugMode(gArglSettings, gARHandle);
    arUtilTimerReset();

    // Load marker(s).
    //装载类型数据
    if (!setupMarkers(patt_names_count, (const char **)patt_names, gMultiConfigs, gARHandle, &gARPattHandle)) {
        ARLOGe("main(): Unable to set up AR marker(s).\n");
        cleanup();
        exit(-1);
    }

    gMultiConfigCount = patt_names_count;
    // Register GLUT event-handling callbacks.
    // NB: mainLoop() is registered by Visibility.
    glutDisplayFunc(Display);
    glutReshapeFunc(Reshape);
    glutVisibilityFunc(Visibility);
    glutMainLoop();

    return (0);
}



//设置相机参数
static int setupCamera(const char *cparam_name, char *vconf, ARParamLT **cparamLT_p, ARHandle **arhandle, AR3DHandle **ar3dhandle)
{
    ARParam            cparam;
    int                xsize, ysize;
    AR_PIXEL_FORMAT pixFormat;

    // Open the video path.
    if (arVideoOpen(vconf) < 0) {
        ARLOGe("setupCamera(): Unable to open connection to camera.\n");
        return (FALSE);
    }


    // Find the size of the window.
    if (arVideoGetSize(&xsize, &ysize) < 0) {
        ARLOGe("setupCamera(): Unable to determine camera frame size.\n");
        arVideoClose();
        return (FALSE);
    }
    ARLOGi("Camera image size (x,y) = (%d,%d)\n", xsize, ysize);

    // Get the format in which the camera is returning pixels.
    pixFormat = arVideoGetPixelFormat();
    if (pixFormat == AR_PIXEL_FORMAT_INVALID) {
        ARLOGe("setupCamera(): Camera is using unsupported pixel format.\n");
        arVideoClose();
        return (FALSE);
    }

    // Load the camera parameters, resize for the window and init.
    if (arParamLoad(cparam_name, 1, &cparam) < 0) {
        ARLOGe("setupCamera(): Error loading parameter file %s for camera.\n", cparam_name);
        arVideoClose();
        return (FALSE);
    }
    if (cparam.xsize != xsize || cparam.ysize != ysize) {
        ARLOGw("*** Camera Parameter resized from %d, %d. ***\n", cparam.xsize, cparam.ysize);
        arParamChangeSize(&cparam, xsize, ysize, &cparam); //改变相机参数
    }
#ifdef DEBUG
    ARLOG("*** Camera Parameter ***\n");
    arParamDisp(&cparam);
#endif
    if ((*cparamLT_p = arParamLTCreate(&cparam, AR_PARAM_LT_DEFAULT_OFFSET)) == NULL) {
        ARLOGe("setupCamera(): Error: arParamLTCreate.\n");
        return (FALSE);
    }

    if ((*arhandle = arCreateHandle(*cparamLT_p)) == NULL) {
        ARLOGe("setupCamera(): Error: arCreateHandle.\n");
        return (FALSE);
    }
    if (arSetPixelFormat(*arhandle, pixFormat) < 0) {
        ARLOGe("setupCamera(): Error: arSetPixelFormat.\n");
        return (FALSE);
    }
    if (arSetDebugMode(*arhandle, AR_DEBUG_DISABLE) < 0) {
        ARLOGe("setupCamera(): Error: arSetDebugMode.\n");
        return (FALSE);
    }
    if ((*ar3dhandle = ar3DCreateHandle(&cparam)) == NULL) {
        ARLOGe("setupCamera(): Error: ar3DCreateHandle.\n");
        return (FALSE);
    }

    if (arVideoCapStart() != 0) {
        ARLOGe("setupCamera(): Unable to begin camera data capture.\n");
        return (FALSE);
    }

    return (TRUE);
}

//设置标识 patt_names 标记文件  多配置文件 多标签识别
static int setupMarkers(const int patt_count, const char *patt_names[], ARMultiMarkerInfoT *multiConfigs[], ARHandle *arhandle, ARPattHandle **pattHandle_p)
{
    int i;
    //如果没有设置类型检测的数量,则检测二维码标识
    if (!patt_count) {
        // Default behaviour is to default to matrix mode.
        *pattHandle_p = NULL;
        arSetPatternDetectionMode(arhandle, AR_MATRIX_CODE_DETECTION); // If no markers specified, default to matrix mode.
    }
    else {
        // If marker configs have been specified, attempt to load them.        
        int mode = -1, nextMode;
        // Need a pattern handle because the config file could specify matrix or template markers.
        if ((*pattHandle_p = arPattCreateHandle2(gPattSize, gPattCountMax)) == NULL) {  //gPattCountMax为50个
            ARLOGe("setupMarkers(): Error: arPattCreateHandle2.\n");
            return (FALSE);
        }

        for (i = 0; i < patt_count; i++) {

            if (!(multiConfigs[i] = arMultiReadConfigFile(patt_names[i], *pattHandle_p))) {
                ARLOGe("setupMarkers(): Error reading multimarker config file '%s'.\n", patt_names[i]);
                for (i--; i >= 0; i--) {
                    arMultiFreeConfig(multiConfigs[i]);
                }
                arPattDeleteHandle(*pattHandle_p);
                return (FALSE);
            }

            if (multiConfigs[i]->patt_type == AR_MULTI_PATTERN_DETECTION_MODE_TEMPLATE) {
                nextMode = AR_TEMPLATE_MATCHING_COLOR;  //颜色匹配
            }
            else if (multiConfigs[i]->patt_type == AR_MULTI_PATTERN_DETECTION_MODE_MATRIX) {
                nextMode = AR_MATRIX_CODE_DETECTION;   //二维码匹配
            }
            else { // AR_MULTI_PATTERN_DETECTION_MODE_TEMPLATE_AND_MATRIX or mixed.
                nextMode = AR_TEMPLATE_MATCHING_COLOR_AND_MATRIX; //颜色和二维码匹配
            }
            if (mode == -1) {
                mode = nextMode;
            }
            else if (mode != nextMode) {
                mode = AR_TEMPLATE_MATCHING_COLOR_AND_MATRIX;
            }
        }
        arSetPatternDetectionMode(arhandle, mode);

        arPattAttach(arhandle, *pattHandle_p);
    }

    return (TRUE);
}
//清理缓存
static void cleanup(void)
{
    int i;

    arglCleanup(gArglSettings);
    gArglSettings = NULL;

    arPattDetach(gARHandle);
    for (i = 0; i < gMultiConfigCount; i++) {
        arMultiFreeConfig(gMultiConfigs[i]);
    }
    if (gARPattHandle) arPattDeleteHandle(gARPattHandle);

    arVideoCapStop();
    arDeleteHandle(gARHandle);
    arParamLTFree(&gCparamLT);
    arVideoClose();
}

//主循环
static void mainLoop(void)
{
    int i;
    static int imageNumber = 0;//图片的数量索引
    static int ms_prev;
    int ms;
    float s_elapsed;
    ARUint8 *image;

    // Find out how long since mainLoop() last ran.
    ms = glutGet(GLUT_ELAPSED_TIME); //计算主程序运行时间
    s_elapsed = (float)(ms - ms_prev) * 0.001f;
    if (s_elapsed < 0.01f) return; // Don't update more often than 100 Hz. 以100Hz的频率对图像进行刷新
    ms_prev = ms;

    // Grab a video frame. 抓取视频帧
    if ((image = arVideoGetImage()) != NULL) {
        gARTImage = image;    // Save the fetched image.
        //如果gARTImageSavePlease为真,则保存图片
        if (gARTImageSavePlease) {
            char imageNumberText[15];
            sprintf(imageNumberText, "image-%04d.jpg", imageNumber++);
            //保存图片
            if (arVideoSaveImageJPEG(gARHandle->xsize, gARHandle->ysize, gARHandle->arPixelFormat, gARTImage, imageNumberText, 75, 0) < 0) {
                ARLOGe("Error saving video image.\n");
            }
            gARTImageSavePlease = FALSE;
        }

        gCallCountMarkerDetect++; // Increment ARToolKit FPS counter.

        // Detect the markers in the video frame.
        //检测标识算法
        if (arDetectMarker(gARHandle, gARTImage) < 0) {
            exit(-1);
        }
        //寻找到所有的标识标签

        // If  marker config files were specified, evaluate detected patterns against them now.
        for (i = 0; i < gMultiConfigCount; i++) {
            if (gRobustFlag) gMultiErrs[i] = arGetTransMatMultiSquareRobust(gAR3DHandle, arGetMarker(gARHandle), arGetMarkerNum(gARHandle), gMultiConfigs[i]);
            else gMultiErrs[i] = arGetTransMatMultiSquare(gAR3DHandle, arGetMarker(gARHandle), arGetMarkerNum(gARHandle), gMultiConfigs[i]);
            //if (gMultiConfigs[i]->prevF != 0) ARLOGe("Found multimarker set %d, err=%0.3f\n", i, gMultiErrs[i]);
        }
        // Tell GLUT the display has changed.
        glutPostRedisplay();
    }
}

//
//    This function is called on events when the visibility of the
//    GLUT window changes (including when it first becomes visible).
//
static void Visibility(int visible)
{
    if (visible == GLUT_VISIBLE) {
        glutIdleFunc(mainLoop);
    }
    else {
        glutIdleFunc(NULL);
    }
}

//
//    This function is called when the
//    GLUT window is resized.
//
static void Reshape(int w, int h)
{
    windowWidth = w;
    windowHeight = h;

    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    gViewport[0] = 0;
    gViewport[1] = 0;
    gViewport[2] = w;
    gViewport[3] = h;
    glViewport(0, 0, (GLsizei)w, (GLsizei)h);

    // Call through to anyone else who needs to know about window sizing here.
}


//
// This function is called when the window needs redrawing.
// 核心部分 窗口重画需要的核心部分
//
static void Display(void)
{
    ARdouble p[16];
    ARdouble m[16];
#ifdef ARDOUBLE_IS_FLOAT
    GLdouble p0[16];
    GLdouble m0[16];
#endif
    int i, j, k;
    GLfloat  w, bw, bh, vertices[6][2]; //六个顶点
    GLubyte pixels[300];
    char text[256];  //字符串数组长度
    GLdouble winX, winY, winZ;
    int showMErr[CHECK_ID_MULTIMARKERS_MAX]; //显示错误
    GLdouble MX[CHECK_ID_MULTIMARKERS_MAX];
    GLdouble MY[CHECK_ID_MULTIMARKERS_MAX];
    int pattDetectMode;  //类型检测模式
    AR_MATRIX_CODE_TYPE matrixCodeType; //二维码类型


    // Select correct buffer for this context.
    glDrawBuffer(GL_BACK);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Clear the buffers for new frame.

    //将图像设置纹理显示
    arglPixelBufferDataUpload(gArglSettings, gARTImage);
    arglDispImage(gArglSettings);

    if (gMultiConfigCount) {
        arglCameraFrustumRH(&(gCparamLT->param), VIEW_DISTANCE_MIN, VIEW_DISTANCE_MAX, p);
        glMatrixMode(GL_PROJECTION); //GL映射
#ifdef ARDOUBLE_IS_FLOAT
        glLoadMatrixf(p);
#else
        glLoadMatrixd(p);//长度为16的double数组
#endif
        glMatrixMode(GL_MODELVIEW);
        glEnable(GL_DEPTH_TEST);

        // If we have multi-configs, show their origin onscreen.
        for (k = 0; k < gMultiConfigCount; k++) {
            showMErr[k] = FALSE;
            if (gMultiConfigs[k]->prevF != 0) {
                arglCameraViewRH((const ARdouble(*)[4])gMultiConfigs[k]->trans, m, 1.0);
#ifdef ARDOUBLE_IS_FLOAT
                glLoadMatrixf(m);
#else
                glLoadMatrixd(m);
#endif
                
#ifdef ARDOUBLE_IS_FLOAT
                for (i = 0; i < 16; i++) m0[i] = (GLdouble)m[i];
                for (i = 0; i < 16; i++) p0[i] = (GLdouble)p[i];
                if (gluProject(0, 0, 0, m0, p0, gViewport, &winX, &winY, &winZ) == GL_TRUE)
#else           //将物体坐标转为窗口坐标
                if (gluProject(0, 0, 0, m, p, gViewport, &winX, &winY, &winZ) == GL_TRUE)
#endif
                {
                    showMErr[k] = TRUE;
                    MX[k] = winX; MY[k] = winY;
                }
            }

        } // for k
    }

    // Any 2D overlays go here.
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glOrtho(0, (GLdouble)windowWidth, 0, (GLdouble)windowHeight, -1.0, 1.0); //正交
    glMatrixMode(GL_MODELVIEW);
    glDisable(GL_LIGHTING);
    glDisable(GL_DEPTH_TEST);

    arGetPatternDetectionMode(gARHandle, &pattDetectMode);
    arGetMatrixCodeType(gARHandle, &matrixCodeType);

    // For all markers, draw onscreen position.
    // Colour based on cutoffPhase.
    glLoadIdentity();
    glVertexPointer(2, GL_FLOAT, 0, vertices);
    glEnableClientState(GL_VERTEX_ARRAY);
    glLineWidth(2.0f);
    for (j = 0; j < gARHandle->marker_num; j++) {
        printf("一共有%d个标识\n", gARHandle->marker_num);
        //Sets the current color from an already existing array of color values.
        //根据截止相位来设置颜色
        //glColor3ubv(cutoffPhaseColours[gARHandle->markerInfo[j].cutoffPhase].colour);
        if (gARHandle->markerInfo->cf < 0.6)
            continue;
        //要是只设置绿色
        glColor3ubv(cutoffPhaseColours[6].colour);

        for (i = 0; i < 5; i++) {
            int dir = gARHandle->markerInfo[j].dir;
            vertices[i][0] = (float)gARHandle->markerInfo[j].vertex[(i + 4 - dir) % 4][0] * (float)windowWidth / (float)gARHandle->xsize;
            vertices[i][1] = ((float)gARHandle->ysize - (float)gARHandle->markerInfo[j].vertex[(i + 4 - dir) % 4][1]) * (float)windowHeight / (float)gARHandle->ysize;
        }
        vertices[i][0] = (float)gARHandle->markerInfo[j].pos[0] * (float)windowWidth / (float)gARHandle->xsize;
        vertices[i][1] = ((float)gARHandle->ysize - (float)gARHandle->markerInfo[j].pos[1]) * (float)windowHeight / (float)gARHandle->ysize;
        glDrawArrays(GL_LINE_STRIP, 0, 5);
        // For markers that have been identified, draw the ID number.
        if (gARHandle->markerInfo[j].id >= 0) {
            glColor3ub(0, 255, 0);
            
            if (gARHandle->markerInfo[j].id == 5){    
                snprintf(text, sizeof(text), " %s",getAirInfo());                
            }
            else if (gARHandle->markerInfo[j].id == 10){
                snprintf(text, sizeof(text)," %s", getHotChannelInfo());
                //dispContent = getHotChannelInfo();
            }
            else if (gARHandle->markerInfo[j].id == 99){    
                snprintf(text, sizeof(text)," %s", getColdChannelInfo());
                //dispContent = getColdChannelInfo();
            }
            else if (gARHandle->markerInfo[j].id == 512){
                snprintf(text, sizeof(text)," %s", getCabinetInfo());
                //dispContent = getCabinetInfo();
            }
            else if (gARHandle->markerInfo[j].id==1011){
                snprintf(text, sizeof(text)," %s", getPDUInfo());
                //dispContent = getPDUInfo();
            }
            else if (gARHandle->markerInfo[j].id==2047){
                snprintf(text,sizeof(text)," %s",getShortColdChannelInfo());
                //dispContent = getShortColdChannelInfo();
            }
            else{
                snprintf(text, sizeof(text), " 标识%d未定义", gARHandle->markerInfo[j].id);
                //dispContent = "标识未定义";
            }    

            /*根据字符串里面是否包含\n对字符串进行行分割并进行多行显示*/
            char delims[] = "\n";
            char *lineStr = NULL;
            //将字符串常量转为字符串变量
            char *dispContentStr = (char *)malloc(sizeof(char)*(strlen(text) + 1));
            
            if (dispContentStr != NULL){
                strcpy(dispContentStr, text);
                lineStr = strtok(dispContentStr, delims); //strtok中的char *Str为非常量指针,而非常量指针可以隐式转换为常量指针,由于strtok会对指针指向值进行修改,
                int lineCnt = 0;
                while (lineStr != NULL){        //所以当Str为常量指针时,编译时没有问题,但运行时会报错
                    //打印字母或者汉字
                    float topLeftVertexPosX = (float)gARHandle->markerInfo[j].vertex[(4 - gARHandle->markerInfo[j].dir) % 4][0];
                    float topLeftVertexPosY = (float)gARHandle->markerInfo[j].vertex[(4 - gARHandle->markerInfo[j].dir) % 4][1];
                    print(lineStr, topLeftVertexPosX * (float)windowWidth / (float)gARHandle->xsize+12.0f, ((float)gARHandle->ysize - topLeftVertexPosY) * (float)windowHeight / (float)gARHandle->ysize - lineCnt*16.0f-12.0f, 0, 0);
                    lineStr = strtok(NULL, delims);
                    lineCnt++;
                }
            }
            else{
                printf("mallocerror\n");
                exit(-1);
            }            
            
            free(dispContentStr);
            dispContentStr = NULL;
            //打印字母或者汉字
            //print(text, (float)gARHandle->markerInfo[j].pos[0] * (float)windowWidth / (float)gARHandle->xsize, ((float)gARHandle->ysize - (float)gARHandle->markerInfo[j].pos[1]) * (float)windowHeight / (float)gARHandle->ysize, 0, 0);
        }
    }
    glDisableClientState(GL_VERTEX_ARRAY);
    glutSwapBuffers();
}

//
// The following functions provide the onscreen help text and mode info.
//

static void print(const char *text, const float x, const float y, int calculateXFromRightEdge, int calculateYFromTopEdge)
{
    int i, len;
    GLfloat x0, y0;

    if (!text) return;

    if (calculateXFromRightEdge) {
        x0 = windowWidth - x - (float)glutBitmapLength(GLUT_BITMAP_HELVETICA_10, (const unsigned char *)text);
    }
    else {
        x0 = x;
    }
    if (calculateYFromTopEdge) {
        y0 = windowHeight - y - 10.0f;
    }
    else {
        y0 = y;
    }
    glRasterPos2f(x0, y0);
    drawCNString(text);    
}

GLFont3D.c的代码如下

//主要在opengl下画中文字符 2D或者3D

#include "GLFont.h"

void c3dtext(LPCTSTR str, HFONT hFont, float z)
{
    glDisable(GL_TEXTURE_2D);
    glDisable(GL_LIGHTING);
    Printfc3d(TEXT(str), hFont, z);
    glEnable(GL_LIGHTING);
    glEnable(GL_TEXTURE_2D);

}

void Printfc3d(LPCTSTR strText, HFONT hFont, float z)
{
    HDC hdc = wglGetCurrentDC();
    HFONT hOldFont = (HFONT)SelectObject(hdc, hFont);
    UCHAR * pChar = (UCHAR*)strText/*.GetBuffer(strText.GetLength())*/;
    int   nListNum;
    DWORD dwChar;
    GLYPHMETRICSFLOAT pgmf[1];
    glPushMatrix();
    float m_dXOffset = -1.0;
    float m_dYOffset = 1.0;
    float m_dZOffset = 2.0;

    float m_dXScale = 0.10;
    float m_dYScale = 0.10;
    float m_dZScale = 0.10;

    float m_dXRotate = -90.0;
    float m_dYRotate = 0.0;
    float m_dZRotate = 0.0;

    glTranslatef(m_dXOffset, m_dYOffset, m_dZOffset);
    //glScalef(1000.0, 1000.0, 10000.0);
    //Scale
    glScaled(m_dXScale, m_dYScale, m_dZScale);
    //Rotate around X-axis
    glRotated(m_dXRotate, 1.0, 0.0, 0.0);
    //Rotate around Y-axis
    glRotated(m_dYRotate, 0.0, 1.0, 0.0);
    //Rotate around Z-axis
    glRotated(m_dZRotate, 0.0, 0.0, 1.0);

    glColor3f(0.0, 1.0, 1.0);
    for (int i = 0; i < _tcslen(strText)/*strText.GetLength()*/; i++)
    {
        if (IsDBCSLeadByte((BYTE)pChar[i]))
        {
            dwChar = (DWORD)((pChar[i] << 8) | pChar[i + 1]);
            i++;
        }
        else dwChar = pChar[i];
        nListNum = glGenLists(1);
        wglUseFontOutlines(hdc,
            dwChar,
            1,
            nListNum,
            0.0f,
            z,
            WGL_FONT_POLYGONS, //WGL_FONT_POLYGONS
            pgmf
            );
        glCallList(nListNum);
        glDeleteLists(nListNum, 1);
    }

    //restore the original angle around Z-axis
    glRotated(-1.0f * m_dZRotate, 0.0, 0.0, 1.0);
    //restore the original angle around Y-axis
    glRotated(-1.0f * m_dYRotate, 0.0, 1.0, 0.0);
    //restore the original scale
    glScaled(1.0 / m_dXScale, 1.0 / m_dYScale, 1.0 / m_dZScale);
    //restore the original angle around X-axis
    glRotated(-1.0f * m_dXRotate, 1.0, 0.0, 0.0);

    glTranslated(-m_dXOffset, -m_dYOffset, -m_dZOffset);
    glPopMatrix();
    //strText.ReleaseBuffer();
    SelectObject(hdc, hOldFont);
}


void draw3dtextWithCloseLight(LPCTSTR str, HFONT hFont, float cDepth, float dXoffset, float dYoffset, float dZoffset, float dXscale, float dYscale, float dZscale,
    float dXrotate, float dYrotate, float dZrotate)
{
    glDisable(GL_TEXTURE_2D);
    glDisable(GL_LIGHTING);
    draw3dtextIgnoreLight(TEXT(str), hFont, cDepth, dXoffset, dYoffset, dZoffset, dXscale, dYscale, dZscale, dXrotate, dYrotate, dZrotate);
    glEnable(GL_LIGHTING);
    glEnable(GL_TEXTURE_2D);
}

void draw3dtextIgnoreLight(LPCTSTR strText, HFONT hFont, float cDepth, float dXoffset, float dYoffset, float dZoffset, float dXscale, float dYscale, float dZscale,
    float dXrotate, float dYrotate, float dZrotate)
{
    HDC hdc = wglGetCurrentDC();
    HFONT hOldFont = (HFONT)SelectObject(hdc, hFont);
    UCHAR * pChar = (UCHAR*)strText/*.GetBuffer(strText.GetLength())*/;
    int   nListNum;
    DWORD dwChar;
    GLYPHMETRICSFLOAT pgmf[1];
    glPushMatrix();
    float m_dXOffset = dXoffset;
    float m_dYOffset = dYoffset;
    float m_dZOffset = dZoffset;

    float m_dXScale = dXscale;
    float m_dYScale = dYscale;
    float m_dZScale = dZscale;

    float m_dXRotate = dXrotate;
    float m_dYRotate = dYrotate;
    float m_dZRotate = dZrotate;

    glTranslatef(m_dXOffset, m_dYOffset, m_dZOffset);
    //Scale
    glScaled(m_dXScale, m_dYScale, m_dZScale);
    //Rotate around X-axis
    glRotated(m_dXRotate, 1.0, 0.0, 0.0);
    //Rotate around Y-axis
    glRotated(m_dYRotate, 0.0, 1.0, 0.0);
    //Rotate around Z-axis
    glRotated(m_dZRotate, 0.0, 0.0, 1.0);

    glColor4f(0.0, 1.0, 0.0,0.5); //绿色 半透明
    for (int i = 0; i < _tcslen(strText)/*strText.GetLength()*/; i++)
    {
        if (IsDBCSLeadByte((BYTE)pChar[i]))
        {
            dwChar = (DWORD)((pChar[i] << 8) | pChar[i + 1]);
            i++;
        }
        else dwChar = pChar[i];
        nListNum = glGenLists(1);
        /*可以用于创建三维的字体
          hdc 字体的设备上下文
          first 要转换为显示列表的第一个字符
          count 要转化为显示列表字符的个数
          listBase 显示列表的基数
          deviation 指定与实际轮廓的最大偏移量
          extrusion 指定字体在z轴负方向的值。通过修改这个值就可以显示3D字符,字体的深度
          format 指定显示列表线段或多边形
          lpgmf 接受字符的地址,用于保存创建字体的一些信息,通常其指向的空间长度是不小于创建的显示列表数的
        */
        wglUseFontOutlines(hdc,
            dwChar,
            1,
            nListNum,
            0.0f,
            cDepth,
            WGL_FONT_POLYGONS, //WGL_FONT_POLYGONS
            pgmf
            );
        glCallList(nListNum);
        glDeleteLists(nListNum, 1);
    }

    //restore the original angle around Z-axis
    glRotated(-1.0f * m_dZRotate, 0.0, 0.0, 1.0);
    //restore the original angle around Y-axis
    glRotated(-1.0f * m_dYRotate, 0.0, 1.0, 0.0);
    //restore the original angle around X-axis
    glRotated(-1.0f * m_dXRotate, 1.0, 0.0, 0.0);
    //restore the original scale
    glScaled(1.0 / m_dXScale, 1.0 / m_dYScale, 1.0 / m_dZScale);
    glTranslated(-m_dXOffset, -m_dYOffset, -m_dZOffset);
    glPopMatrix();
    //strText.ReleaseBuffer();
    SelectObject(hdc, hOldFont);
}

//检测换行符,如果有换行符,则把字符分行
void draw3dMultiLineText(){
}

//画二维中文字体
void drawCNString(const char* str){
    int len, i;
    wchar_t* wstring;
    HDC hDC = wglGetCurrentDC();
    GLuint list = glGenLists(1);    
    //计算字符的个数
    //如果是双字节字符(比如中文字符),两个字节才算一个字符
    len = 0;
    for (i = 0; str[i] != '\0'; ++i){        
        if (IsDBCSLeadByte(str[i]))
            ++i;
        ++len;
    }
    //将混合字符转为宽字符
    wstring = (wchar_t*)malloc((len + 1)*sizeof(wchar_t));
    MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, str, -1, wstring,len);
    wstring[len] = L'\0';

    //逐个输出字符
    for (i = 0; i < len; ++i){
        wglUseFontBitmapsW(hDC,wstring[i],1,list);
        glCallList(list);
    
    }
    //回收所有临时资源
    free(wstring);
    glDeleteLists(list, 1);

}

BasicInfo.c的代码如下:

/*
  动态获取获取各种设备信息
*/
#include "BasicInfo.h"

/*
   获取空调信息
*/
char *getAirInfo(){
    //给空调信息分配100个字节
    char *airInfoStr=(char *)malloc(sizeof(char)*100);
    if (airInfoStr != NULL){
        strcpy(airInfoStr,"名称:空调\n温度:");
        char buf[10];
        float temperature = generateTemp(10, 40);
        //snprintf(buf, sizeof(buf)-1, "%5.1f ℃\n", temperature);
        sprintf(buf,"%5.1f ℃\n", temperature);
        strcat(airInfoStr, buf);
        return airInfoStr;
    }else{
        printf("airInfoStr 内存分配失败\n");
        exit(-1);
    }
    
}

/*
  获取热通道信息
*/
char *getHotChannelInfo(){
    char *channelInfoStr;
    channelInfoStr = (char *)malloc(sizeof(char)* 200);    
    if (channelInfoStr != NULL){        
        int idleLocationCnt = generateInteger(10, 40);        
        sprintf(channelInfoStr, "名称:热通道\n空闲位置数量 : %d \n", idleLocationCnt);        
        return channelInfoStr;
    }
    else{
        printf("channelInfoStr 内存分配失败\n");
        exit(-1);
    }

}

/*
  获取冷通道消息
*/
char *getColdChannelInfo(){
    char *channelInfoStr;
    channelInfoStr = (char *)malloc(sizeof(char)* 200);    
    if (channelInfoStr != NULL){
        //strcpy(channelInfoStr, "名称:冷通道\n空闲位置数量:");
        //char buf[50];
        int idleLocationCnt = generateInteger(0, 40);
        sprintf(channelInfoStr, "名称:冷通道\n空闲位置数量:%3d个\n", idleLocationCnt);
        return channelInfoStr;
    }
    else{
        printf("channelInfoStr 内存分配失败\n");
        exit(-1);
    }
}

/*
  获取机柜信息
*/

char *getCabinetInfo(){
    char *cabinetInfoStr=(char *)malloc(sizeof(char)* 350);
    //cabinetInfoStr = (char *)malloc(sizeof(char)* 350);
    if (cabinetInfoStr != NULL){
        strcpy(cabinetInfoStr,"名称:机柜\n");
        char buf[300];
        float frontDoorUpTemp = generateTemp(20, 40);
        float frontDoorBottomTemp = generateTemp(20,40);
        float backDoorUpTemp = generateTemp(20, 40);
        float backDoorBottomTemp = generateTemp(20,40);

        int frontDoorUpHumidity = generateInteger(50, 70);
        int frontDoorBottomHumidity = generateInteger(50, 70);
        int backDoorUpHumidity = generateInteger(50, 70);
        int backDoorBottomHUmidity = generateInteger(50, 70);
        /*
        snprintf(buf,sizeof(buf)-1,"前门上部温度:%5.1f ℃\n\
            前门上部湿度:%d\%\n\
            前门底部温度:%5.1f ℃\n\
            前门底部湿度:%d %%\n\
            后门上部温度:%5.1f ℃\n\
            后门上部湿度:%d %%\n\
            后门底部温度:%5.1f ℃\n\
            后门底部湿度:%d %%\n",frontDoorUpTemp,frontDoorUpHumidity,frontDoorBottomTemp,frontDoorBottomHumidity,
                    backDoorUpTemp,backDoorUpHumidity,backDoorBottomTemp,backDoorBottomHUmidity);
        */

        sprintf(buf, "前门上部温度:%5.1f℃\n前门上部湿度:%d%%\n前门底部温度:%5.1f℃\n前门底部湿度:%d%%\n后门上部温度:%5.1f℃\n后门上部湿度:%d%%\n后门底部温度:%5.1f℃\n\
后门底部湿度:%d %%\n", frontDoorUpTemp, frontDoorUpHumidity, frontDoorBottomTemp, frontDoorBottomHumidity,
                      backDoorUpTemp, backDoorUpHumidity, backDoorBottomTemp, backDoorBottomHUmidity);
        strcat(cabinetInfoStr,buf);
        return cabinetInfoStr;
    }
    else{
        printf("cabinetInfoStr  分配失败\n");
        exit(-1);
    }
}

/*
   获取pdu信息
*/

char* getPDUInfo(){
    char *pduInfoStr;
    pduInfoStr = (char*)malloc(sizeof(char)* 300);
    if (pduInfoStr != NULL){
        strcpy(pduInfoStr,"名称:PDU\n");
        float temp = generateTemp(20, 40);
        int voltage = generateInteger(210, 240);
        int eCurrent = generateInteger(0, 15);
        int humidity = generateInteger(50, 70);
        int activePower = generateInteger(70, 100);
        char buf[150];
        /*snprintf(buf,sizeof(buf)-1,"温度:%5.1f℃\n\
            湿度:%d%%\n\
            电压:%dV\n\
            电流:%dA\n\
            有功功率:%dW",temp,humidity,voltage,eCurrent,activePower);*/
        sprintf(buf, "温度:%5.1f℃\n湿度:%d%%\n电压:%dV\n电流:%dA\n有功功率:%dW", temp, humidity, voltage, eCurrent, activePower);
        strcat(pduInfoStr,buf);
        return pduInfoStr;
    }else{
        printf("pduInfoStr 内存分配失败\n");
        exit(-1);
    }

}

char *getShortColdChannelInfo(){
    char *shortColdChannelInfo;
    shortColdChannelInfo = (char*)malloc(sizeof(char)* 300);
    if (shortColdChannelInfo != NULL){
        strcpy(shortColdChannelInfo,"名称:短冷通道\n位置1:机柜B02\n位置2:机柜A04\n\
            位置3:布线机柜B\n位置4:机柜A02\n位置5:机柜A01\n位置6:机柜A03位置7:机柜A05\n\
            位置8:B列行间空调\n位置9:配电柜\n位置10:A列行间空调\n位置11:布线机柜A\n位置12:UPS柜\n\
            位置13:机柜B01\n位置14:机柜B03");
        return shortColdChannelInfo;
    }
    else{
        printf("shortColdChannelInfo内存分配失败\n");
        exit(-1);
    }
}

/*随机产生一个温度值
  lowTemperatur 指定最低温度
  highTemperature 指定最高温度
*/
float generateTemp(int lowTemperature,int highTemperature){
    int range = highTemperature - lowTemperature;
    float randF = (rand() % (range * 10)) / 10.0;
    return (lowTemperature + randF);

}

/*
  随机产生一个整数,用来表示通道里面的空闲数量
  lowNum:产生的最小整数
  highNum:产生的最大整数
*/
int generateInteger(int lowInt,int highInt){
    int range = highInt - lowInt;
    int rangeInt = rand()%range;
    return lowInt + rangeInt;
}

运行效果如下:




  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值