Vaa3D 3D-Viewer 代码结构概览

结构概览

Vaa3D的3d viewer中,所有跟图像渲染和标注相关的代码,基本都在3drenderer文件夹内,基础数据结构、IO函数、部分类的规范定义在basic_c_fun文件夹内,主要代码结构概览本人整理如下几幅图用以直观理解。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

注:笔记中出现的代码,都经过一定的删减。

UI

3d viewer窗口类

3drenderer/v3dr_mainwindow.h中,定义了3d viewer窗口类。

class V3dR_MainWindow : public QWidget

QWidget窗口实例可以通过下面语句激活,

mainwindow_sample->activateWindow();

3d viewer窗口中,定义了,

V3dR_GLWidget * getGLWidget() {return glWidget;}

是图形窗口。

GL窗口类

3drenderer/v3dr_glwidget.h中,定义了gl窗口类,用来显示、标注图像。

class V3dR_GLWidget :  public QOpenGLWidget, protected QOpenGLFunctions , public View3DControl

这里的View3DControl,定义在basic_c_fun/basic_view3d.h中,里面声明了3D图像基础操作的一系列虚函数。
V3dR_GLWidget中定义的主要对象有,

iDrawExternalParameter* _idep;//
QWidget *mainwindow;
Renderer* renderer;//
QString data_title;
QString dropUrl;
static V3dr_colormapDialog* colormapDlg;
static V3dr_surfaceDialog*  surfaceDlg;
int neuronIndex;
bool show_progress_bar;
MainWindow *v3d_mainwindow;
int currentPluginState;
map<int, void(*)(void*)> pluginLeftMouseFuncs;

此外,注意所有包含在,

#ifdef _NEURON_ASSEMBLER_
/*一堆代码*/
#endif

中的代码,都是跟Terafly相关的。

渲染器相关的成员函数

V3dR_GLWidget类中,首先声明了一些列跟渲染器相关的方法。

void V3dR_GLWidget::deleteRenderer() {makeCurrent(); DELETE_AND_ZERO(renderer);} //删除渲染器
void V3dR_GLWidget::createRenderer() {makeCurrent(); deleteRenderer(); initializeGL();} //创建渲染器(初始化)
void V3dR_GLWidget::choiceRenderer()//根据OpenGL的版本选择渲染器
{
    /*...*/
    if (1 && supported_GLSL())
    {
        renderer = new Renderer_gl2(this);
    }
    else  // this comment for special version without GL 2.0 support
    if (1) //strlen(glversion)>3 && glversion[0]>='1' && glversion[1]=='.' && glversion[2]>='0')
    {
        renderer = new Renderer_gl1(this);
    }
    else
    {
        renderer = new Renderer(this);
    }
}
void V3dR_GLWidget::settingRenderer()//在渲染器导入数据(renderer->setupData)前需要先设置参数
void V3dR_GLWidget::preparingRenderer()//渲染器导入数据

视图窗口相关的成员函数

之后是视图窗口的各种方法。

void V3dR_GLWidget::initializeGL()

这个方法是视图窗口的初始化,该方法最后调用了choiceRenderer()、settingRenderer()和preparingRenderer()。

void V3dR_GLWidget::resizeGL(int width, int height)

这个方法用于调整视图窗口的大小,里面调用了renderer->setupView()。

void V3dR_GLWidget::paintGL()

暂时还没学过OpenGL,只知道里面有旋转和平移。

void V3dR_GLWidget::customEvent(QEvent* e)

应该涉及自定义事件的控制。

bool V3dR_GLWidget::event(QEvent* e)

应该涉及鼠标悬停事件的处理,里面用pos保存了鼠标位置。

void V3dR_GLWidget::enterEvent(QEvent*)

鼠标进入视图。

void V3dR_GLWidget::leaveEvent(QEvent*)

鼠标离开视图。

void V3dR_GLWidget::focusInEvent(QFocusEvent*)

猜测是,鼠标在拖动中(点击移动,例如绘画等)。

void V3dR_GLWidget::focusOutEvent(QFocusEvent*)

猜测是,鼠标离开拖动状态。

绘图相关的成员函数

void V3dR_GLWidget::paintEvent(QPaintEvent *event)
{
    //QOpenGLWidget_proxy::paintEvent(event);
//	if (! mouse_in_view) //TODO:  use change of viewing matrix
//	{
//		_still = true;
//		QOpenGLWidget_proxy::paintEvent(event);
//		_still = false;
//	}
//	else
    {
        _still = false;
        QOpenGLWidget::paintEvent(event);

        if (needStillPaint()) //pending
        {
            _stillpaint_pending=true;
        }
    }
}

绘图事件,注释掉的部分是因为不需要判断鼠标是否在视图窗口内。猜测是在一个绘图步骤结束后调用触发的事件,内部调用了QOpenGLWidget::paintEvent。

bool V3dR_GLWidget::needStillPaint()
{
    return  (renderer && renderer->tryTexStream == 1);
}
//注释了
void V3dR_GLWidget::stillPaint()
{
    if (_still)  return; // avoid re-enter
    if (! _stillpaint_pending) return;

//	if (QCoreApplication::hasPendingEvents())
//	{
//		_still = false;
//		_stillpaint_pending = true;
//		return;    //continue pending if event loop is busy
//	}
//	else // here system must be idle
    {
        qDebug()<<"debug in v3dr_glwidget.cpp V3dR_GLWidget::stillPaint()";
        still_timer.stop();
        _still = true;
            DO_updateGL(); // update at once, stream texture for full-resolution
        _still = false;
        _stillpaint_pending = false;
        still_timer.start(still_timer_interval); //restart timer
    }
}

这里,涉及到的变量,

bool _still, _stillpaint_pending;

还没弄懂,猜测stillpaint是指静态绘画,也就是执行完完整的鼠标移动步骤后进行绘画,猜测这三部分代码,将一个绘画步骤分为多个stillpaint,_still变量代表是否动作未完成,_stillpaint_pending变量代表是否stillpaint未完成(待定)。但还需要看应用的代码,这里实在不确定。

鼠标事件相关的成员函数

void V3dR_GLWidget::mousePressEvent(QMouseEvent *event)
{
    mouse_held = 1;

    if (event->button()==Qt::LeftButton)
    {
        lastPos = event->pos();
        t_mouseclick_left = clock();
        if(pluginLeftMouseFuncs.find(currentPluginState) != pluginLeftMouseFuncs.end())
        {
            void(*mouse_func)(void*);
            mouse_func = pluginLeftMouseFuncs[currentPluginState];
            (*mouse_func)((void*)this);
        }
    }

    if (!isoperating&&event->button()==Qt::RightButton && renderer) //right-click
    {
        int x = event->x();
        int y = event->y();
        #ifdef _ENABLE_MACX_DRAG_DROP_FIX_
        x = 2 * x;
        y = 2 * y;
        #endif

        if (renderer->hitPoint(x,y))  //pop-up menu (selectObj) or marker definition (hitPen)
        {
           updateTool();
           //POST_updateGL();
        }
        //updateTool();
        POST_updateGL(); //display result after menu   //csz solve the blue screen don't know the reason
    }
}

鼠标点击事件,左键点击时,调用鼠标左键点击反应函数列表中,对应当前状态的函数。右键点击时,打开工具栏。

void V3dR_GLWidget::mouseReleaseEvent(QMouseEvent *event)
{
    mouse_held = 0;

    if (event->button()==Qt::RightButton && renderer) //right-drag end
    {
        (renderer->movePen(event->x(), event->y(), false)); //create curve or nothing
        //qDebug() << "done drawing\n";
        updateTool();

        POST_updateGL(); //update display of curve
    }
}

鼠标松开事件,如果是右键移动松开触发的,创建曲线,更新工具栏,显示曲线。

void V3dR_GLWidget::mouseMoveEvent(QMouseEvent *event)
{
    int dx = event->x() - lastPos.x();
    int dy = event->y() - lastPos.y();
    lastPos = event->pos();

    if ((event->buttons() & Qt::RightButton) && renderer) //right-drag for 3d curve
        if ( ABS(dx) + ABS(dy) >=2 )
    {
        /*一些代码*/
    }

    if (event->buttons() & Qt::LeftButton)
    {
        int xRotStep = MOUSE_ROT(dy, MIN(viewW,viewH));
        int yRotStep = MOUSE_ROT(dx, MIN(viewW,viewH));
        int xShiftStep = MOUSE_SHIFT(dx, viewW);
        int yShiftStep = MOUSE_SHIFT(dy, viewH);

        alt_rotation = (IS_ALT_MODIFIER); // alt+mouse control alternate marker center rotation, 081104

        // mouse control view space, transformed to model space, 081026
        if (IS_TRANSLATE_MODIFIER) // shift+mouse control view space translation, 081104
        {
            setXShift(_xShift + xShiftStep);// move +view -model
            setYShift(_yShift - yShiftStep);// move -view +model
        }
        else if (IS_MODEL_MODIFIER) // ctrl+mouse control model space rotation, 081104
        {
            //modelRotation(yRotStep, xRotStep, 0); //swap y,x
            modelRotation(xRotStep, yRotStep, 0);
        }
        else // default mouse controls view space rotation
        {
            viewRotation(xRotStep, yRotStep, 0);
        }
    }
}

鼠标移动事件,如果是鼠标右键按住移动则创建曲线,如果是鼠标左键按住移动则先计算旋转移动角度和平移移动长度,之后根据情况,判断是旋转标记中心,还是平移,还是旋转,还是普通的视角转动。

void V3dR_GLWidget::wheelEvent(QWheelEvent *event)
{
    /*一大堆代码*/
}

滚轮事件,一般是触发缩放。但按住shift或alt则触发z轴平移或旋转。

键盘事件相关的成员函数

键盘事件分为键盘按压事件和键盘释放事件,但只有数字键有释放事件。

void V3dR_GLWidget::handleKeyPressEvent(QKeyEvent * e)
{
    switch (e->key())
    {
    /*一堆case语句*/
    }
    default:
        QOpenGLWidget_proxy::keyPressEvent(e);
        break;
}
update(); //must be here for correct MarkerPos's view matrix
}

e->key()的值有如下几种情况,

基础操作
case Qt::Key_BracketLeft:
    {
        if (IS_MODEL_MODIFIER) // alt-mouse to control model space rotation
            modelRotation(0, 0, +5);
        else
            viewRotation(0, 0, +5);
    }
    break;
case Qt::Key_BracketRight:
/*一串代码*/

左方括号键,视角沿z方向旋转,或IS_MODEL_MODIFIER条件下,模型沿z方向旋转。与之对应的有Qt::Key_BracketRight。

case Qt::Key_Left: //arrows key must use WITH_?_MODIFIER
    {
        if (WITH_MODEL_MODIFIER)
            modelRotation(0, -5, 0);
        else if (WITH_TRANSLATE_MODIFIER)
            setXShift(_xShift -1);// move -model
        else
            setXShift(_xShift +1);// move +view
    }
    break;
case Qt::Key_Right:
/*一串代码*/
case Qt::Key_Up:
/*一串代码*/
case Qt::Key_Down:
/*一串代码*/

左方向键,注释中提到,方向键必须用WITH_?_MODIFIER。WITH_MODEL_MODIFIER下模型沿y方向旋转,WITH_TRANSLATE_MODIFIER下模型沿x方向平移,否则视角沿x方向平移。与之对应的有Qt::Key_Right、Qt::Key_Up、Qt::Key_Down。

case Qt::Key_Minus:
    {
        setZoom(_zoom - 10); // zoom out
    }
    break;
case Qt::Key_Equal:
/*一串代码*/

减号键(-),缩小。与之对应的有 Qt::Key_Equal。

case Qt::Key_Underscore:
    {
        emit changeMarkerSize(_markerSize - 1);
    }
    break;
case Qt::Key_Plus:
/*一串代码*/

下划线键,缩小标记尺寸。与之对应的有Qt::Key_Plus。
还有一些按键不一一列举解释,见下表。

Qt对象按键
Qt::Key_Backspace退格键
Qt::Key_Backslash反斜杠键
Qt::Key_Comma逗号键
Qt::Key_Period句号键
Qt::Key_Slash斜杠键
Qt::Key_Less小于号键
Qt::Key_Greater大于号键
Qt::Key_Question问号键

这些按键在定义的时候,很多会通过发送信号来执行对应操作(emit语句)。

之后是一些快捷键的定义,

OpenGL快捷键
case Qt::Key_B:
    if (IS_CTRL_MODIFIER)
    {
        setBright();
    }else if (IS_ALT_MODIFIER)
    {
        emit changeEditinput("Alt+B: Drawing BBox");
    if(!isoperating)
        isoperating=true;
        callStrokeCurveDrawingBBoxes();//For serial BBoxes curve drawing shortcut
    }
    break;

alt+B时,发送 changeEditinput(“Alt+B: Drawing BBox”) 信号(使右下角的文本框显示输入的字符串),进入标记模式。

case Qt::Key_R:
    if (IS_CTRL_MODIFIER)
    {
        reloadData();
    }
        else
    {
        returncheckmode();
    }
    break;

按R键进入检查模型(我自己用的时候显示没找到文件),ctrl+R重新载入数据。

case Qt::Key_U:
    if (IS_CTRL_MODIFIER)
    {
        updateWithTriView();
    }
    break;

ctrl+U更新三视图。

高级OpenGL快捷键
case Qt::Key_I:
    if ( WITH_SHIFT_MODIFIER && //advanced
        WITH_CTRL_MODIFIER
        )
    {
        showGLinfo();
    }
    else if (renderer)
    {
        Renderer_gl1* thisRenderer = static_cast<Renderer_gl1*>(this->getRenderer());
        if (thisRenderer->selectMode == Renderer::smDeleteMultiNeurons)
        {
            thisRenderer->setDeleteKey(1);
            thisRenderer->deleteMultiNeuronsByStroke();
        }
    }
    break;

shift+ctrl+I显示GL窗口信息,其他有什么用暂时不知道。

case Qt::Key_G:
    if ( WITH_SHIFT_MODIFIER && //advanced
         WITH_CTRL_MODIFIER
        )
    {
        toggleShader();
    }else if (IS_ALT_MODIFIER)
    {
        emit changeEditinput("Alt+G: Drawing Global");
        if(!isoperating)
            isoperating=true;
        callStrokeCurveDrawingGlobal();//For Global optimal curve drawing shortcut
    }else
    {
        emit changeEditinput("Alt+G: GDTraing");
        if(!isoperating)
            isoperating=true;
        callGDTracing();
    }
    break;

shift+ctrl+G对图像做toggleShader(切换着色器)并显示。alt+G也是标注神经元,但目前只知道是global模式的标注,具体是什么还不知道。其他方式按G进入GDTracing标注模式,但具体怎么用还是不知道。

case Qt::Key_F:
    if (IS_CTRL_MODIFIER)
    {
        toggleTexFilter();
    }
    else if (IS_ALT_MODIFIER)
    {
    /*非常长的一大串代码*/
    }
    break;
纹理操作

ctrl+F对图像做toggleTexFilter(切换纹理过滤器)并显示。alt+F跟Terafly有关。

case Qt::Key_F1:
/*一串代码*/
case Qt::Key_F2:
/*一串代码*/
case Qt::Key_F3:
/*一串代码*/

这三个也都跟Terafly有关,暂时不看。

case Qt::Key_E:
    if (IS_ALT_MODIFIER)
    {
        emit changeEditinput("Alt+E");
        if(!isoperating)
            isoperating=true;
        toggleEditMode();
    }
    else if (IS_SHIFT_MODIFIER)
    {
    /*一串代码*/
    }
    else
    {
        callcheckmode();
    }
    break;

alt+E切换编辑/非编辑模式,shift+E跟Terafly有关,暂时不看。

case Qt::Key_T:
    if ( WITH_SHIFT_MODIFIER && //advanced
         WITH_CTRL_MODIFIER
        )
    {
        toggleTex2D3D();
    }else if (IS_ALT_MODIFIER)
    {
        emit changeEditinput("Alt+T");
        if(!isoperating)
            isoperating=true;
        callStrokeRetypeMultiNeurons();//For multiple segments retyping shortcut
    }
    else if (renderer)
    {
        /*一串代码*/
    }
    else
        callAutoTracers();
    break;

shift+ctrl+T调用toggleTex2D3D()但暂时不知道什么用,alt+T进入多类型的标注模式,可以画线后选择标记的类型(官方叫法是多神经元片段重新标注类型)。

case Qt::Key_D:
    if (IS_ALT_MODIFIER)
    {
        emit changeEditinput("Alt+D: Deleting");
        if(!isoperating)
            isoperating=true;
        callStrokeDeleteMultiNeurons(); //For multiple segments deleting shortcut,
    }
    else
    {
        // delete connected segments that have been highlighted,
        Renderer_gl1* thisRenderer = static_cast<Renderer_gl1*>(this->getRenderer());
        if (thisRenderer->selectMode == Renderer::smShowSubtree)
        {
        /*一串代码*/
        }
    }
    break;

alt+D进入删除模式。

case Qt::Key_S:
    if (IS_ALT_MODIFIER)
    {
        emit changeEditinput("Alt+S");
        if(!isoperating)
            isoperating=true;
        callStrokeSplitMultiNeurons();//For multiple segments spliting shortcut, by ZZ,02212018
    }
    /*一串代码*/
    break;

alt+S激活多神经元片段分割函数。

case Qt::Key_C:
    if ( WITH_SHIFT_MODIFIER && //advanced
            WITH_CTRL_MODIFIER
        )
    {
        toggleTexCompression();
    }else if (IS_ALT_MODIFIER)
    {
        emit changeEditinput("Alt+C: Connecting");
        if(!isoperating)
            isoperating=true;
        callStrokeConnectMultiNeurons();//For multiple segments connection shortcut
    }
    else if (IS_SHIFT_MODIFIER)
    {
    /*一串代码*/
    }
    else
    {
        neuronColorMode = (neuronColorMode==0)?5:0; //0 default display mode, 5 confidence level mode
        updateColorMode(neuronColorMode);
    }
    break;

shift+ctrl+C调用toggleTexCompression(),alt+C激活多神经元片段连接函数。

case Qt::Key_V:
    if ( WITH_SHIFT_MODIFIER && //advanced
            WITH_CTRL_MODIFIER
        )
    {
        toggleTexStream();
    }
    else if (IS_ALT_MODIFIER)
    {
        emit changeEditinput("Alt+V");
        if(!isoperating)
            isoperating=true;
        changeVolShadingOption();
    }
    else if (IS_CTRL_MODIFIER)
    {
        emit changeEditinput("Ctl+V");
        if(!isoperating)
            isoperating=true;
        updateImageData();
    }
    else
    {
        callLoadNewStack();
    }
    break;

alt+V打开纹理/渲染器窗口。

对象(surface object)操作
case Qt::Key_P:
    if ( WITH_SHIFT_MODIFIER && //advanced
            WITH_CTRL_MODIFIER
        )
    {
        toggleObjShader();
    }
    else if (IS_CTRL_MODIFIER)
    {
        emit changeEditinput("Ctl+P");
        if(!isoperating)
            isoperating=true;
        togglePolygonMode();
    }
    else if (IS_ALT_MODIFIER)
    {
        emit changeEditinput("Alt+P");
        if(!isoperating)
            isoperating=true;
        changeObjShadingOption();
    }
    break;

shift+ctrl+P切换标注的渲染方式(点表示轮廓和面表示轮廓),ctrl+P也是切换标注的渲染方式(填充、线、节点)。alt+P打开标注高级设置窗口,和ctrl+P功能一样。

case Qt::Key_Y:
    if (IS_ALT_MODIFIER)
    {
        callDefine3DPolyline();//For 3D polyline shortcut, by ZZ,03262018
    }
    break;

这个函数看不懂,不知道怎么用。

case Qt::Key_Q:
    if(IS_CTRL_MODIFIER){
        qDebug()<<"call special marker---------------------------------------------";
        callCreateSpecialMarkerNearestNode(); //add special marker,
    }
    else
    {
        callCreateMarkerNearestNode();
    }
    break;

ctrl+Q在最近的标记处创建特殊标记。

其他操作
case Qt::Key_Escape:
    {
        emit changeEditinput("Esc: cancelled selection");
        if(isoperating)
            isoperating=false;
        cancelSelect();
        /*_NEURON_ASSEMBLER_*/
    }
    break;

退出键,退出所有模式。

case Qt::Key_N:
    if (IS_CTRL_MODIFIER)
    {
        emit changeEditinput("Ctl+N: toggle cell name");
        if(!isoperating)
            isoperating=true;
        toggleCellName();
    }
    else if (IS_SHIFT_MODIFIER) // toggle marker name display. by Lei Qu, 110425
    {
        toggleMarkerName();
    }
    else if (IS_ALT_MODIFIER)
    {
        emit changeEditinput("Alt+N: show connected segs");
        if(!isoperating)
            isoperating=true;
        callShowConnectedSegs();
    }
    else if (WITH_ALT_MODIFIER && WITH_CTRL_MODIFIER)
    {
        cout << "wp_debug" << __LINE__ << __FUNCTION__ << endl;
        callShowBreakPoints();
    }
    break;

更改名称,但具体怎么用还不知道。

case Qt::Key_L:
    if (IS_CTRL_MODIFIER)
    {
        toggleLineType();
    }
    /*一串代码*/
    break;

ctrl+L调整神经元线标注的显示方式(是否显示半径)。

case Qt::Key_W:
    if (IS_ALT_MODIFIER)
    {
        setDragWinSize(+2);
    }
    else if(IS_SHIFT_MODIFIER)
    {
        setDragWinSize(-2);
    }
    /*一串代码*/
    break;

作用不知道。

case Qt::Key_Z:
    //Also allow redo with CTRL+SHIFT+Z
    if (KM.testFlag(Qt::ShiftModifier) && (KM.testFlag(Qt::ControlModifier) || KM.testFlag(Qt::MetaModifier)))
    {
        if (!V3dR_GLWidget::disableUndoRedo && v3dr_getImage4d(_idep) && renderer)
        {
            v3dr_getImage4d(_idep)->proj_trace_history_redo();
            v3dr_getImage4d(_idep)->update_3drenderer_neuron_view(this, (Renderer_gl1*)renderer);//090924
        }
    }
    //undo the last tracing step if possible. by PHC, 090120
    else if (IS_CTRL_MODIFIER)
    {
        if (!V3dR_GLWidget::disableUndoRedo && v3dr_getImage4d(_idep) && renderer)
        {
            v3dr_getImage4d(_idep)->proj_trace_history_undo();
            v3dr_getImage4d(_idep)->update_3drenderer_neuron_view(this, (Renderer_gl1*)renderer);//090924
        }
    }
    break;

ctrl+Z撤销。

case Qt::Key_X: //redo
    if (IS_CTRL_MODIFIER)
    {
        if (!V3dR_GLWidget::disableUndoRedo && v3dr_getImage4d(_idep) && renderer)
        {
            v3dr_getImage4d(_idep)->proj_trace_history_redo();
            v3dr_getImage4d(_idep)->update_3drenderer_neuron_view(this, (Renderer_gl1*)renderer);//090924
        }
    }
    break;

ctrl+X重做。

数字键

case语句最前面,是一些按下数字键时,触发修改对应状态变量的语句,

case Qt::Key_1:		_holding_num[1] = true; 	break;
case Qt::Key_2:		_holding_num[2] = true; 	break;
case Qt::Key_3:		_holding_num[3] = true; 	break;

在键盘释放事件的成员函数中,

void V3dR_GLWidget::handleKeyReleaseEvent(QKeyEvent * e)

同样有对应的松开数字键时,修改状态变量的语句。

case Qt::Key_1:		_holding_num[1] = false; 	break;
case Qt::Key_2:		_holding_num[2] = false; 	break;
case Qt::Key_3:		_holding_num[3] = false; 	break;
/*等等*/

显示模式相关的成员函数

QString V3dR_GLWidget::Cut_altTip(int dim_i, int v, int minv, int maxv, int offset)

暂时不知道。

int V3dR_GLWidget::setVolumeTimePoint(int t)
void V3dR_GLWidget::incVolumeTimePoint(float step)

5D数据时间条控制相关的函数。

void V3dR_GLWidget::setRenderMode_Mip(bool b, bool useMin)
{
    if (b) {
        if (!useMin) {	//max IP
            _renderMode = int(Renderer::rmMaxIntensityProjection);
            if (renderer) renderer->setRenderMode(Renderer::rmMaxIntensityProjection);
        } else {   //mIP
            _renderMode = int(Renderer::rmMinIntensityProjection);
            if (renderer) renderer->setRenderMode(Renderer::rmMinIntensityProjection);
        }
        if (renderer) renderer->setXCut0(_xCut0);
        if (renderer) renderer->setYCut0(_yCut0);
        if (renderer) renderer->setZCut0(_zCut0);
        POST_updateGL();
    }
    if (!useMin)
        emit changeDispType_maxip(b);
    else
        emit changeDispType_minip(b);
    emit changeTransparentSliderLabel("Threshold");
    emit changeEnableCut0Slider(b);
    emit changeEnableCut1Slider( !b);
    if (b) emit changeCurrentTabCutPlane(0);
    emit changeEnableTabCutPlane(0, b);
    emit changeEnableTabCutPlane(1, !b);
}
void V3dR_GLWidget::setRenderMode_Alpha(bool b)
{
/*省略,用了renderer->setRenderMode(Renderer::rmAlphaBlendingProjection)*/
}
void V3dR_GLWidget::setRenderMode_Cs3d(bool b)
{
/*省略,用了renderer->setRenderMode(Renderer::rmCrossSection)*/
}

设置渲染模式的成员函数。

void V3dR_GLWidget::setCSTransparent(int t)
{
    if (_CStransparency != t) {
        _CStransparency = t;
        if (renderer) renderer->CSbeta = CLAMP(0,1, float(t)/TRANSPARENT_RANGE);
        POST_updateGL();
    }
}
void V3dR_GLWidget::setContrast(int t)
void V3dR_GLWidget::setThickness(double t)
void V3dR_GLWidget::setCurChannel(int t)
void V3dR_GLWidget::setChannelR(bool s)
void V3dR_GLWidget::setChannelG(bool s)
void V3dR_GLWidget::setChannelB(bool s)
void V3dR_GLWidget::setVolCompress(bool s)//toggleTexCompression()
void V3dR_GLWidget::enableFrontSlice(bool s)//renderer->bFSlice = (s)
void V3dR_GLWidget::enableXSlice(bool s)//renderer->bXSlice = (s);
void V3dR_GLWidget::enableYSlice(bool s)//renderer->bYSlice = (s);
void V3dR_GLWidget::enableZSlice(bool s)//renderer->bZSlice = (s);

设置透明度,CLAMP(0,1,x)控制x范围不超过 (0,1)。POST_updateGL()更新GL窗口。此外还有设置对比度、厚度,设置当前颜色通道的数值(这个CurChannel猜测是当前通道,具体怎么用还不知道)。设置RGB通道的权限(是否显示)。设置纹理压缩,设置Front、X、Y、Z四个slice,估计跟切面视图有关。

工具栏相关的成员函数

void V3dR_GLWidget::showTool()
{
    if (surfaceDlg)  surfaceDlg->show();
    if (colormapDlg)  colormapDlg->show();
}
void V3dR_GLWidget::hideTool()//上面的show改为hide
void V3dR_GLWidget::updateTool()
{
    if (surfaceDlg && !(surfaceDlg->isHidden()) )
    {
        //int i = surfaceDlg->getCurTab();
        surfaceDlg->linkTo(this);
        surfaceDlg->setCurTab(-1);  //-1 = last tab
    }
    if (colormapDlg && !(colormapDlg->isHidden()) )
    {
        colormapDlg->linkTo(this);
    }
}

工具栏的显示、隐藏、更新。

void V3dR_GLWidget::volumeColormapDialog()//colormapDlg = new V3dr_colormapDialog(this)
void V3dR_GLWidget::surfaceSelectDialog(int curTab)//surfaceDlg = new V3dr_surfaceDialog(this)
void V3dR_GLWidget::surfaceSelectTab(int curTab)//surfaceDlg->setCurTab(curTab)
void V3dR_GLWidget::surfaceDialogHide()//surfaceDlg->hide()
void V3dR_GLWidget::annotationDialog(int dc, int st, int i)//renderer->editSurfaceObjAnnotation(dc, st, i)

一些对话框的显示。
注:跟VR模式相关的成员函数就先不整理了。

交互控制相关的成员函数

void V3dR_GLWidget::setXRotation(int angle)
void V3dR_GLWidget::setXRotation(float angle)
void V3dR_GLWidget::setYRotation(int angle)
void V3dR_GLWidget::setYRotation(float angle)
void V3dR_GLWidget::setZRotation(int angle)
void V3dR_GLWidget::setZRotation(float angle)
void V3dR_GLWidget::resetRotation(bool b_emit)
void V3dR_GLWidget::modelRotation(int xRotStep, int yRotStep, int zRotStep)
void V3dR_GLWidget::viewRotation(int xRotStep, int yRotStep, int zRotStep)
void V3dR_GLWidget::absoluteRotPose()
void V3dR_GLWidget::doAbsoluteRot(int xRot, int yRot, int zRot)
void V3dR_GLWidget::doAbsoluteRot(float xRot, float yRot, float zRot)
void V3dR_GLWidget::lookAlong(float xLook, float yLook, float zLook)

以上为旋转操作相关的函数,最后四个函数实现根据旋转矩阵(mRot)旋转,见附录。

void V3dR_GLWidget::resetAltCenter()//默认情况下,为0,0,1
void V3dR_GLWidget::setAltCenter(float xC, float yC, float zC)
//emit zoomChanged(int(zr))
void V3dR_GLWidget::resetZoomShift()
void V3dR_GLWidget::setZoom(int zr)
void V3dR_GLWidget::setZoom(float zr)
//emit yShiftChanged(int(s))进行平移
void V3dR_GLWidget::setXShift(int s)
void V3dR_GLWidget::setXShift(float s)
void V3dR_GLWidget::setYShift(int s)
void V3dR_GLWidget::setYShift(float s)
void V3dR_GLWidget::setZShift(int s)
void V3dR_GLWidget::setZShift(float s)
//emit changeFrontCut(s), emit changeXCut0(s), ...
void V3dR_GLWidget::setFrontCut(int s)
void V3dR_GLWidget::setXCut0(int s)
void V3dR_GLWidget::setXCut1(int s)
void V3dR_GLWidget::setYCut0(int s)
//...
//setXYZSurfure,setXCutLock,setYCutLock,setZCutLock,setXCS,setYCS,setZCS不展开写
//emit changeXClip0(s), emit changeXClip1(s)...
void V3dR_GLWidget::setXClip0(int s)
void V3dR_GLWidget::setXClip1(int s)
void V3dR_GLWidget::setYClip0(int s)
//...

设置Alt中心,估计是旋转中心。设置缩放(zr的值在0-100,会自动调整)。设置平移量。设置cut、clip(应该是裁剪范围)等。

void V3dR_GLWidget::confidenceDialog()
void V3dR_GLWidget::setConfCut(int s)
void V3dR_GLWidget::setBright()
void V3dR_GLWidget::setBackgroundColor()
void V3dR_GLWidget::switchBackgroundColor()
/*_NEURON_ASSEMBLER_*/
void V3dR_GLWidget::setVoxSize()
void V3dR_GLWidget::callUpBrainAtlas()
void V3dR_GLWidget::enableShowAxes(bool s)
void V3dR_GLWidget::enableClipBoundingBox(bool b)
void V3dR_GLWidget::enableShowBoundingBox(bool s)
//emit changeOrthoView(s)
void V3dR_GLWidget::enableOrthoView(bool s)

置信度对话框,设置置信度cut,设置亮度,设置背景色,切换背景色。设置体素大小,调用BrainAtlas插件,显示坐标轴,显示clip边界,显示展示边界,正交显示(不知道orthoview什么意思)。

void V3dR_GLWidget::setShowMarkers(int s)
void V3dR_GLWidget::setShowSurfObjects(int s)
void V3dR_GLWidget::enableMarkerLabel(bool s)
void V3dR_GLWidget::setMarkerSize(int s)
void V3dR_GLWidget::enableSurfStretch(bool s)
void V3dR_GLWidget::enableSurfZLock(bool s)//用了setXYZSurfure(s)
void V3dR_GLWidget::toggleCellName()
void V3dR_GLWidget::toggleMarkerName()
void V3dR_GLWidget::createSurfCurrentR()
void V3dR_GLWidget::createSurfCurrentG()
void V3dR_GLWidget::createSurfCurrentB()
void V3dR_GLWidget::updateColorMode(int colorMode)
int V3dR_GLWidget::getLocalStartPosX()//return _idep->local_start.x
int V3dR_GLWidget::getLocalEndPosX()//return _idep->local_start.x + _idep->local_size.x - 1
//...对应Y/Z

标记显示设置,表面对象显示设置,显示标记标签值,设置标记大小,表面拉伸(不知道),SurfZLock(不知道),切换是否显示细胞名字,切换是否显示标记名字,创建当前表面对象(R/G/B),更新颜色模式,获取当前范围坐标。

void V3dR_GLWidget::loadObjectFromFile(QString url)
{
    if (renderer)
    {
        if (url.size())
            renderer->loadObjectFromFile(Q_CSTR(url));
        else
            renderer->loadObjectFromFile(0);
        updateTool();
        POST_updateGL();
    }
}
void V3dR_GLWidget::loadObjectListFromFile()
{
/*一些代码*/
}

void V3dR_GLWidget::saveSurfFile()
{
    if (renderer) renderer->saveSurfFile();
}

打开文件和保存标注文件。

渲染器设置相关的成员函数

void V3dR_GLWidget::changeLineOption()//用来设置线宽度,节点大小,根节点大小
void V3dR_GLWidget::changeVolShadingOption()//像素纹理设置
void V3dR_GLWidget::changeObjShadingOption()//对象纹理设置
void V3dR_GLWidget::updateControl()//emit changeVolCompress(renderer->tryTexCompress>0)
void V3dR_GLWidget::togglePolygonMode()//renderer->togglePolygonMode()
void V3dR_GLWidget::toggleNStrokeCurveDrawing()//renderer->toggleNStrokeCurveDrawing() N笔画曲线?
void V3dR_GLWidget::callStrokeCurveDrawingBBoxes()//renderer->callStrokeCurveDrawingBBoxes() 打开曲线绘制工具箱?
void V3dR_GLWidget::callStrokeCurveDrawingGlobal()//renderer->callStrokeCurveDrawingGlobal()
void V3dR_GLWidget::callStrokeRetypeMultiNeurons()//renderer->callStrokeRetypeMultiNeurons()
void V3dR_GLWidget::callStrokeDeleteMultiNeurons()//renderer->callStrokeDeleteMultiNeurons()
void V3dR_GLWidget::callStrokeSplitMultiNeurons()//renderer->callStrokeSplitMultiNeurons()
void V3dR_GLWidget::callStrokeConnectMultiNeurons()//renderer->callStrokeConnectMultiNeurons()
void V3dR_GLWidget::callShowBreakPoints()//renderer->callShowBreakPoints()
void V3dR_GLWidget::callShowSubtree()//renderer->callShowSubtree()
void V3dR_GLWidget::callShowConnectedSegs()//renderer->callShowConnectedSegs()
void V3dR_GLWidget::subtreeHighlightModeMonitor()//子树高亮模式监视
{
    if (!this->getRenderer()) return;
    Renderer_gl1* thisRenderer = static_cast<Renderer_gl1*>(this->getRenderer());
    if (thisRenderer->selectMode != Renderer::smShowSubtree) thisRenderer->escPressed_subtree();
    else
    {
        int pressedNumber = this->getNumKeyHolding();
        if (thisRenderer->connectEdit == Renderer::loopEdit)
        /*很长的一堆代码*/
        QTimer::singleShot(50, this, SLOT(subtreeHighlightModeMonitor()));
    }
}
void V3dR_GLWidget::callDefine3DPolyline()//renderer->callDefine3DPolyline()
void V3dR_GLWidget::callGDTracing()//renderer->callGDTracing()
void V3dR_GLWidget::callCreateMarkerNearestNode()//renderer->callCreateMarkerNearestNode(x,y)
void V3dR_GLWidget::callCreateSpecialMarkerNearestNode()//renderer->callCreateSpecialMarkerNearestNode(gpos.x(),gpos.y())
//以下函数不展开写了
//callCurveLineDetector(int option)、callLoadNewStack、callAutoTracers、callcheckmode、returncheckmode
//setDragWinSize(int csize)、toggleLineType、toggleEditMode、setEditMode、toggleTexFilter、toggleTex2D3D
//toggleTexCompression、toggleTexStream、toggleShader、toggleObjShader、showGLinfo

更新和重载相关的成员函数

void V3dR_GLWidget::updateWithTriView()
{
    if (renderer)
    try
    {
        renderer->updateLandmark();
        renderer->updateTracedNeuron();
        update();
    }
    catch(...)
    {
        printf("Fail to run the V3dR_GLWidget::updateLandmark() function.\n");
    }
}
void V3dR_GLWidget::updateLandmark()
{
    /*...*/
        renderer->updateLandmark();
        POST_updateGL();
    /*...*/
}
void V3dR_GLWidget::updateImageData()
{
    /*...省略加载进度条相关代码*/
            renderer->setupData(this->_idep);
            if (renderer->hasError())	POST_CLOSE(this);
            renderer->getLimitedDataSize(_data_size); //for update slider size
    /*...*/
            renderer->reinitializeVol(renderer->class_version()); //100720
            if (renderer->hasError())	POST_CLOSE(this);
    /*...*/
    emit signalVolumeCutRange(); //100809
    POST_updateGL();
}

更新窗口。

void V3dR_GLWidget::reloadData()
{
    /*...省略是否重新加载相关的弹窗代码*/
    this->_idep->labelfield_file.clear();
    this->_idep->swc_file_list.clear();
    this->_idep->surface_file.clear();
    this->_idep->pointcloud_file_list.clear();
    makeCurrent(); //ensure right context when concurrent animation
    /*...省略加载进度条相关代码*/
        if (renderer)
        {
            renderer->setupData(this->_idep);
            if (renderer->hasError())	POST_CLOSE(this);
            renderer->getLimitedDataSize(_data_size); //for update slider size
        }
    /*...*/
        if (renderer)
        {
            renderer->initialize(1);
            if (renderer->hasError())	POST_CLOSE(this);
        }
    }
    /*...*/
    emit signalVolumeCutRange();
    POST_EVENT(this, QEvent::Type(QEvent_OpenFiles)); // open objects after loading volume
    POST_EVENT(this, QEvent::Type(QEvent_Ready));
    updateTool();
    POST_updateGL();
}

重新加载数据相关的函数。

void V3dR_GLWidget::cancelSelect()
{
    if (renderer) renderer->endSelectMode();
}

关闭select模式。

find3DViewer

mainwindow.cpp文件中,

V3dR_MainWindow * MainWindow::find3DViewer(QString fileName)

用来找到指定的3DViewer窗口并返回。

loadV3DFile

void MainWindow::loadV3DFile(QString fileName, bool b_putinrecentfilelist, bool b_forceopen3dviewer)

用来打开V3D文件,
其中,首先,第一部分,

XFormWidget *existing_imgwin = findMdiChild(fileName);
if (existing_imgwin)
{
   workspace->setActiveSubWindow(existing_imgwin);

   return;
}
V3dR_MainWindow *existing_3dviewer = find3DViewer(fileName);
if (existing_3dviewer)
{
    existing_3dviewer->activateWindow();
    return;
}

用来激活两个窗口,第一个应该是打开图片时的那个三视图窗口,第二个是3d viewer的窗口。
之后,第二部分,

QFileInfo curfile_info(fileName);
QString cur_suffix = curfile_info.suffix().toUpper();
if (cur_suffix=="ANO")
{
    P_ObjectFileType cc;
    if (!loadAnoFile(fileName, cc))
    {
        v3d_msg("Fail to load useful info from the specified anofile. Do nothing.\n");
        return;
    }
    /*这里有一大堆代码*/
}
else if (cur_suffix=="MARKER" ||  cur_suffix=="CSV")
{
    /*这里有一大堆代码*/
}
else if (cur_suffix=="APO" ||
         cur_suffix=="SWC" ||
         cur_suffix=="ESWC" ||
         cur_suffix=="ASC" ||
         cur_suffix=="OBJ" ||
         cur_suffix=="VAA3DS" ||
         cur_suffix=="V3DS" ||
         cur_suffix=="NULL3DVIEWER")
{
    /*这里有一大堆代码*/
}
/*后面还有一大堆else*/

用来打开标注文件。
最后,第三部分,

if (b_putinrecentfilelist)
{
    setCurrentFile(fileName);
    emit imageLoaded2Plugin(); //这里有个注释说,没必要发送这个信号
}

渲染器

跟渲染器定义有关的文件有renderer_gl1.h(定义在renderer_tex.cpp中实现)和renderer_gl2.h(定义在renderer_gl2.cpp中实现)。
renderer_gl1.h中定义了,

class Renderer_gl1 : public Renderer

renderer_gl2.h又继承定义了,

class Renderer_gl2 : public Renderer_gl1

Renderer_gl2类包含的主要对象有,

RGBA8 colormap[FILL_CHANNEL][256];      // [n-channel][256-intensity]
cwc::glShaderManager SMgr;
cwc::glShader *shader, *shaderTex2D, *shaderTex3D, *shaderObj;
GLuint texColormap; // nearest filter, [x-coord for intensity][y-coord for channel]
QPolygonF colormap_curve[N_CHANNEL][4]; // [n-channel][RGBA]
GLuint pboZ, pboY, pboX;
GLenum pbo_texture_format, pbo_image_format, pbo_image_type;

这部分目前仅需要应用,就仅作简单结构分析。

Renderer_gl类

对话框(友类)

friend class V3dr_surfaceDialog; //for accessing all surface data structure
friend class V3dr_colormapDialog;

数据相关

void setupData(void* data);
void cleanData();
const bool has_image()   {return (size4>0);}
const BoundingBox getDataBox() {return dataBox;}

GL窗口相关

void initialize(int version=1);
void reinitializeVol(int version=1);					//MUST makeCurrent for concurrent contexts
void paint();
int hitPen(int x, int y); //return 0 means not processed
int movePen(int x, int y, bool b_move); //return 0 means not processed
void _appendMarkerPos(int x, int y);
int hitWheel(int x, int y);
void blendTrack();       // called by paint()
void setRenderTextureLast(bool renderTextureLast);

渲染函数相关

int processHit(int namelen, int names[], int x, int y, bool b_menu, char* pTip=0);	// called by selectObj. add the x and y parameters
void loadObj();  	// called by initialize()  	// makeCurrent
void cleanObj(); 	// called by ~Renderer_gl1	// makeCurrent
void drawObj();  	// called by paint()
void loadObj_meshChange(int new_mesh); // maybe naming neuronTube_meshChange is better
void loadVol();  	// called by initialize()  	// makeCurrent
void cleanVol();	// called by ~Renderer_gl1	// makeCurrent
void drawVol(); 	// called by paint()
void prepareVol();
void renderVol();

void subloadTex(V3DLONG timepoint, bool bfisrt=false);	// called by loadVol, drawVol
void equAlphaBlendingProjection();			// for blending equation
void equMaxIntensityProjection();	// for blending equation
void equMinIntensityProjection();	// for blending equation
void equCrossSection();				// for blending equation
void shaderTexBegin(bool stream) 	{};		// for texture2D/3D shader
void shaderTexEnd()	 				{};		// for texture2D/3D shader

void updateVolCutRange();
void updateBoundingBox();
void updateThicknessBox();

渲染运行函数

void setMarkerSpace();
void drawMarker();  // called by paint(), not by drawObj()
void MarkerSpaceToNormalizeSpace(XYZ & p);

void setSurfaceStretchSpace();
void setObjLighting();
void disObjLighting();
void beginHighlight();
void endHighlight();

void setUnitVolumeSpace();
void drawUnitVolume();
void setupStackTexture(bool bfirst);
int  _getBufFillSize(int w);
int  _getTexFillSize(int w);
void setTexParam3D();
void setTexParam2D();
void drawStackZ(float direction, int section, bool t3d, bool stream);
void drawStackY(float direction, int section, bool t3d, bool stream);
void drawStackX(float direction, int section, bool t3d, bool stream);
void _drawStack( double ts, double th, double tw,
                 double s0, double s1, double h0, double h1, double w0, double w1,
                 double ds, int slice0, int slice1, int thickness,
                 GLuint tex3D, GLuint texs[], int stack_i,
                 float direction, int section, bool t3d, bool stream);

bool supported_TexStream()								{return false;}
void setupTexStreamBuffer()							{tex_stream_buffer = false;};
void cleanTexStreamBuffer()							{tex_stream_buffer = false;};
void _streamTex(int stack_i, int slice_i, int step, int slice0, int slice1) {};
void _streamTex_end()													 	{};
bool _streamTex_ready()									{return false;}

void setupFrontSliceBuffer();
void drawUnitFrontSlice(int line=0);
void drawBackFillVolCube();
void drawCrossLine(float lineWidth=1);

窗口控制接口

void setRenderMode(RenderMode);
void setThickness(double t);
void toggleTexFilter();
void toggleTex2D3D();
void toggleTexCompression();
void togglePolygonMode() {polygonMode = (polygonMode +1) %4;} // FILL,LINE,POINT, transparent
void toggleLineType();

void createSurfCurrent(int ch=0);                 // updateBoundingBox
void loadObjectFilename(const QString& filename); // updateBoundingBox // makeCurrent
void loadObjectListFromFile();             // call loadObjectFilename
void loadObjectFromFile(const char* url);  // call loadObjectFilename
void saveSurfFile();
void loadV3DSFile(const QString& filename);

void endSelectMode();
void updateLandmark();
void updateTracedNeuron();

int zoomview_wheel_event();
int zoomview_currentviewport();

void callStrokeCurveDrawingBBoxes(); // call serial BBoxes curve drawing
void callStrokeRetypeMultiNeurons();//  call multiple segments retyping
void callStrokeDeleteMultiNeurons();//  call multiple segments deleting
void callStrokeSplitMultiNeurons();//  call multiple segments spliting
void callStrokeConnectMultiNeurons();//  call multiple segments connection
void callShowSubtree(); // highlight the selected segment and its downstream subtree
void callShowBreakPoints();
void rc_findConnectedSegs_continue(My4DImage* curImg, size_t inputSegID);
void callShowConnectedSegs();
void callStrokeCurveDrawingGlobal(); // call Global optimal curve drawing
void callDefine3DPolyline(); // call 3D polyline defining
void callCreateMarkerNearestNode(int x, int y); // call creating marker
void callCreateSpecialMarkerNearestNode(int x,int y); //add special marker
void callGDTracing();

void toggleEditMode();
void setEditMode();

点击事件处理

QString info_Marker(int marker_i);
QString info_NeuronNode(int node_i, NeuronTree * ptree);
QString info_SurfVertex(int vertex_i, Triangle * triangle, int label);
QList <NeuronTree> * getHandleNeuronTrees() {return &listNeuronTree;}
V3DLONG findNearestNeuronNode_WinXY(int cx, int cy, NeuronTree * ptree, double & best_dist);	
//find the nearest node in a neuron in XY project of the display window.
//return the index of the respective neuron node

LandmarkList * getHandleLandmark();
void setHandleLandmark(LandmarkList & landmark_list);
QList <CellAPO> *getHandleAPOCellList() {return &listCell;}
Triangle * findNearestSurfTriangle_WinXY(int cx, int cy, int & vertex_i, Triangle * plist);
double computeSurfaceArea(int dataClass, int surfaceType, int index);
double computeSurfaceVolume(int dataClass, int surfaceType, int index);
void showLineProfile(int marker1, int marker2);
QVector<int> getLineProfile(XYZ p1, XYZ p2, int chno=0);
void setDeleteKey(int key);

标注对象

坐标定义
GLint viewport[4];
GLdouble projectionMatrix[16];
GLdouble markerViewMatrix[16];
GLint currViewport[4];
GLdouble currPmatrix[16];
GLdouble currMviewMatrix[16];

struct MarkerPos {
    double x, y;		// input point coordinates
    int view[4];        // view-port
    double P[16];		// 4x4 projection matrix
    double MV[16];		// 4x4 model-view matrix
    bool drawn;			// has this marker already been drawn to the screen?
};
QList <MarkerPos> listMarkerPos; //screen projection position
QList< QList <MarkerPos> > list_listCurvePos; //screen projection position list for curve
MarkerPos wheelPos; //a one time record of the last wheel/cursor location
QList <LocationSimple> listCurveMarkerPool; //used for curve drawing from marker pool
计算相关函数
void _MarkerPos_to_NearFarPoint(const MarkerPos & pos, XYZ &loc0, XYZ &loc1);
double distanceOfMarkerPos(const MarkerPos & pos0, const MarkerPos & pos);
XYZ getLocationOfListMarkerPos();
XYZ getTranslateOfMarkerPos(const MarkerPos &pos, const ImageMarker &S);
XYZ getPointOnPlane(XYZ P1, XYZ P2, double plane[4]);
XYZ getPointOnSections(XYZ P1, XYZ P2, double F_plane[4]=0);
XYZ getCenterOfLineProfile(XYZ p1, XYZ p2,
        double clipplane[4]=0,	//clipplane==0 means no clip plane
        int chno=0,    			//must be a valid channel number
        float *value=0			//if value!=0, output value at center
        );
XYZ getCenterOfLocal(XYZ loc);

int getVolumeXsectPosOfMarkerLine(XYZ & locA, XYZ & locB, const MarkerPos& pos, int defaultChanno=-1);//by PHC 20130425
int getVolumeXsectPosOfMarkerLine(XYZ P1, XYZ P2,
        double clipplane[4],	//clipplane==0 means no clip plane
        int chno,    			//must be a valid channel number
        XYZ & posCloseToP1, XYZ & posCloseToP2 //output
        ); //by PHC 20130425

int checkCurChannel();
bool isInBound(const XYZ & loc, float factor=0.001, bool b_message=true);
Marker标记点
QCursor oldCursor;
int lastSliceType; //for cross-section
int currentMarkerName;
XYZ getCenterOfMarkerPos(const MarkerPos& pos, int defaultChanno=-1);
double solveMarkerCenter();
double solveMarkerCenterMaxIntensity();
void solveMarkerViews();
void refineMarkerTranslate();
void refineMarkerCenter();
void refineMarkerLocal(int marker_id);

void addMarker(XYZ &loc);
void addMarkerUnique(XYZ &loc);
void addSpecialMarker(XYZ &loc); //add special marker
void updateMarkerLocation(int marker_id, XYZ &loc);
Curve曲线
int cntCur3DCurveMarkers; //marker cnt when define a curve using marker clicking
bool b_addthiscurve; //for 1-stroke curve based zoom-in
bool b_addthismarker; //for 1-click based zoom-in
bool b_grabhighrez; //for v3d_largedataviz
bool b_imaging; //for v3d_imaging
bool b_ablation; //for 3D imaging
bool b_lineAblation; // for line cutting ablation
void solveCurveCenter(vector <XYZ> & loc_vec_input);
void solveCurveViews();
void solveCurveFromMarkers();
Segment片段

定义

QHash<V3DLONG, V3DLONG> segmentLengthDict;
QHash<V3DLONG, V3DLONG> segmentParentDict;
QHash<V3DLONG, V3DLONG> segmentLevelDict;
QList<V3DLONG> loopSegs; // a list of segments involved in a loop
QList<V3DLONG> debugSegs; // a list of segments in debug mode
QList<V3DLONG> childSegs; // a list of child segments (for a TBD node)
QHash<V3DLONG, DoublyLinkedNeuronsList*> dict_dlnh; //  A list of segments, hases seg_id  to doubly-linked segments

相关函数

void updateMarkerList(QList <ImageMarker> markers, int i); // sync markers with object_manager

void initColorMaps();
bool colorByAncestry;
bool colorByTypeOnlyMode; //This is only checked if colorByAncestry is enabled
bool setColorAncestryInfo();

void addToListOfLoopingSegs(V3DLONG firstParent, V3DLONG secondParent, V3DLONG violationSeg);
void setColorByAncestry(NeuronSWC s, time_t seconds); // colorByAncestry mode

void addToListOfChildSegs(V3DLONG segID); // add this segment and all of its children to the list of child segments

bool cuttingZ;
void setBBZcutFlag(bool cuttingZ);
void updateNeuronBoundingBoxWithZCut(float zMin, float zMax);
void setBBZ(float zMinIn, float zMaxIn);
float zMin, zMax;

bool cuttingXYZ;
void setBBcutFlag(bool cuttingXYZ);
void updateNeuronBoundingBoxWithXYZCut(float xMin, float xMax,float yMin, float yMax, float zMin, float zMax);
void setBBXYZ(float xMinIn, float xMaxIn,float yMinIn, float yMaxIn,float zMinIn, float zMaxIn);
float xMin, xMax, yMin, yMax;

void setNeuronColor(NeuronSWC s, time_t seconds);  // method to set different color modes.
// this will call setColorByAncestry if needed.
void setNeuronReviewColors(NeuronSWC s); // review mode
void setHighlightColors(NeuronSWC s); // highlight only the children of a selected node
void setBasicNeuronColors(NeuronSWC s);
void setConfidenceLevelColors(NeuronSWC s); //confidence level mode
bool childHighlightMode;
int deleteKey; // 1: key_i; 2: key_t
对象处理算法
void getPerpendPointDist(XYZ &P, XYZ &P0, XYZ &P1, XYZ &Pb, double &dist);
void getRgnPropertyAt(XYZ &pos, LocationSimple &pt);

void solveCurveCenterV2(vector <XYZ> & loc_vec_input, vector <XYZ> &loc_vec, int index);
void solveCurveRefineLast();
void solveCurveExtendGlobal(); //extends the closest seg. By ZMS for neuron game 20151106
void reorderNeuronIndexNumber(V3DLONG curSeg_id, V3DLONG NI, bool newInLower);
void blendRubberNeuron();
void solveCurveRubberDrag();

void adaptiveCurveResampling(vector <XYZ> &loc_vec, vector <XYZ> &loc_vec_resampled, int stepsize);
void adaptiveCurveResamplingRamerDouglasPeucker(vector <XYZ> &loc_vec, vector <XYZ> &loc_vec_resampled, float epsilon);
void recursiveRamerDouglasPeucker(vector <XYZ> &loc_vec, vector <XYZ> &loc_vec_resampled, int start_i, int end_i, float epsilon);
//void resampleCurveStrokes(QList <MarkerPos> &listCurvePos, int chno, vector<int> &ids);
void resampleCurveStrokes2(QList <MarkerPos> &listCurvePos, int chno, vector<int> &ids);

void resampleCurveStrokes(int index, int chno, vector<int> &ids);

bool boundingboxFromStroke(XYZ& minloc, XYZ& maxloc);
//Using boundingboxFromStroke() get boundingbox and then get subvol
void getSubVolFromStroke(double* &pSubdata, int chno, XYZ &sub_orig, V3DLONG &sub_szx, V3DLONG &sub_szy, V3DLONG &sub_szz);
void getSubVolFrom2MarkerPos(vector<MarkerPos> & pos, int chno, double* &pSubdata, XYZ &sub_orig, XYZ &max_loc, V3DLONG &sub_szx,
      V3DLONG &sub_szy, V3DLONG &sub_szz);
void getSubVolFrom3Points(XYZ & loc0_last, XYZ & loc0, XYZ & loc1, int chno, double* &pSubdata,
      XYZ &sub_orig, V3DLONG &sub_szx, V3DLONG &sub_szy, V3DLONG &sub_szz);

bool pickSeedpointFromExistingCurves(const MarkerPos &pos, XYZ &nearest_loc); //change to this name

void getMidRandomLoc(MarkerPos pos, int chno, XYZ &mid_loc);
double distance_between_2lines(NeuronTree &line1, NeuronTree &line2);

V3DLONG findNearestNeuronNode_Loc(XYZ &loc, NeuronTree *ptree);

V3DLONG findNearestMarker_Loc(XYZ &loc, QList <LocationSimple> &listlandmarks,int mode); //add the function to deal with find nearestmarker

bool lineLineIntersect( XYZ p1,XYZ p2,XYZ p3,XYZ p4,XYZ *pa,XYZ *pb,
                               double *mua, double *mub);
void getSubVolInfo(XYZ lastloc, XYZ loc0, XYZ loc1, XYZ &sub_orig, double* &pSubdata,
  V3DLONG &sub_szx, V3DLONG &sub_szy, V3DLONG &sub_szz);

void solveCurveDirectionInter(vector <XYZ> & loc_vec_input, vector <XYZ> &loc_vec, int index);
double solveCurveMarkerLists_fm(vector <XYZ> & loc_vec_input, vector <XYZ> &loc_vec, int index);

void deleteMultiNeuronsByStroke();//Multiple neuron segments delete by one-mouse stroke.

对象连接、切割算法

struct segInfoUnit
{
    segInfoUnit() { hierarchy = 0; }
    long segID;
    long head_tail;
    long nodeCount;
    bool refine;

    int branchID, paBranchID;
    int hierarchy;
};

NeuronTree treeOnTheFly;
bool isLoadFromFile;
bool hierarchyRelabel;

void simpleConnect();
void simpleConnectExecutor(My4DImage* curImg, vector<segInfoUnit>& segInfo);
void showSubtree();
void showConnectedSegs();
void sort_tracedNeuron(My4DImage* curImg, size_t rootID);  // Sort swc

bool fragmentTrace; // Fragment tracing mode switch
map<string, float> fragTraceParams;
void connectSameTypeSegs(map<int, vector<int> >& inputSegMap, My4DImage*& curImgPtr);

void connectNeuronsByStroke();
void connectPointCloudByStroke();
void connectMarkerByStroke();

void segmentStraighten(vector<V_NeuronSWC_unit>& inputSeg, My4DImage*& curImgPtr, vector<segInfoUnit>::iterator& refineIt);
void cutNeuronsByStroke();

循环保护和高亮

int gridLength;
map<string, set<size_t> > wholeGrid2segIDmap;
multimap<string, size_t> segEnd2segIDmap;

set<size_t> subtreeSegs;
map<size_t, vector<V_NeuronSWC_unit> > originalSegMap;
map<size_t, vector<V_NeuronSWC_unit> > highlightedSegMap;

void segEnd2SegIDmapping(My4DImage* curImg);
void seg2GridMapping(My4DImage* curImg);
void rc_findConnectedSegs(My4DImage* curImg, size_t startSegID);
set<size_t> segEndRegionCheck(My4DImage* curImg, size_t inputSegID);
bool pressedShowSubTree;
void escPressed_subtree();

set<vector<size_t> > detectedLoops;
set<set<size_t> > detectedLoopsSet;
set<set<size_t> > finalizedLoopsSet;
set<set<size_t> > nonLoopErrors;
map<size_t, set<size_t> > seg2SegsMap;
map<size_t, set<size_t> > segTail2segIDmap;
void loopDetection();
void rc_loopPathCheck(size_t inputSegID, vector<size_t> curPathWalk, My4DImage* curImg);

bool isTera;
map<size_t, size_t> branchSegIDmap;
map<string, size_t> tail2segIDmap;
multimap<size_t, string> segID2gridMap;

multimap<string, size_t> grid2segIDmap;
multimap<string, size_t> head2segIDmap;
multimap<string, size_t> tail2SegIDmap;

void hierarchyReprofile(My4DImage* curImg, long mainSegID, long branchSegID);
void rc_downstreamRelabel(My4DImage* curImg, size_t curStemSegID);
void upstreamRelabel(My4DImage* curImg, V_NeuronSWC* startingSegPtr, V_NeuronSWC* newPaSegPtr);
void rc_downstreamSeg(My4DImage* curImg, size_t segID);
void rc_downstream_segID(My4DImage* curImg, size_t segID);
void segTreeFastReprofile(My4DImage* curImg);
void rc_findDownstreamSegs(My4DImage* curImg, size_t inputSegID, string gridKey, int gridLength);

bool FragTraceMarkerDetector3Dviewer;
bool NAeditingMode;
v3dr_SurfaceType surType;

//Called when "Esc" key is pressed and tracedNeuron must be updated.
void deleteMultiNeuronsByStrokeCommit();
//Select multiple markers by one-mouse stroke.
void selectMultiMarkersByStroke();
void retypeMultiNeuronsByStroke();
// forceSingleCut, split was splitting more segments than desired so best cut option added
void breakMultiNeuronsByStrokeCommit();
void breakMultiNeuronsByStroke(); //no args for master implementation //(bool forceSingleCut=false);
void breakTwoNeuronsByStroke();   //make a separate function for mozak to prevent confusion and interference

bool withinLineSegCheck( XYZ p1,XYZ p2,XYZ pa); // check wether pa is within the line seg (p1,p1)
XYZ getLocUsingMassCenter(bool firstloc, XYZ lastpos, XYZ p1, XYZ p2,
    double clipplane[4]=0,	//clipplane==0 means no clip plane
    int chno=0,    			//must be a valid channel number
    float *value=0			//if value!=0, output value at center
    );

nstroke_tracing辅助对象

template <int N>
struct IntersectResult {
    bool success[N];
    XYZ hit_locs[N];
};

struct NearFarPoints {
    bool valid;
    XYZ near_pt;
    XYZ far_pt;
};

IntersectResult<1> directedIntersectPoint(const XYZ &loc0, const XYZ &loc1) const
/*...*/
IntersectResult<2> intersectPointsWithData(const XYZ &loc0_t, const XYZ &loc1_t) const
/*...*/
NearFarPoints markerPosToNearFarLocs(int curveIndex, int pointIndex)
/*...*/

其他

renderer_obj.cpp中实现的函数:

void addCurveSWC(vector<XYZ> &loc_list, int chno=0, double creatmode=0); //if no chno is specified, then assume to be the first channel //if no creatmode specified set to 0
//for local view
bool produceZoomViewOf3DRoi(vector <XYZ> & loc_vec, int ops_type=0);
void ablate3DLocationSeries(vector <XYZ> & loc_vec);
参数
void* _idep;
bool isSimulatedData;
int data_unitbytes;
unsigned char* data4dp;
unsigned char**** data4d_uint8;
// data4d_uint8[dim4][dim3][dim2][dim1]
V3DLONG dim1, dim2, dim3, dim4, dim5;
V3DLONG start1, start2, start3, start4, start5;
V3DLONG size1, size2, size3, size4, size5;
BoundingBox dataBox;
BoundingBox dataViewProcBox; //current clip box that data are visible (and thus are processable).

bool texture_unit0_3D, tex_stream_buffer, drawing_fslice;
GLenum texture_format, image_format, image_type;
GLuint tex3D, texFslice;
GLuint *Ztex_list, *Ytex_list, *Xtex_list;
RGBA8 *Zslice_data, *Yslice_data, *Xslice_data, *Fslice_data;
RGBA8 *rgbaBuf_Yzx, *rgbaBuf_Xzy;
float thicknessX, thicknessY, thicknessZ;
float sampleScaleX, sampleScaleY, sampleScaleZ;
int imageX, imageY, imageZ, imageT;
int safeX, safeY, safeZ;
int realX, realY, realZ, realF;
int fillX, fillY, fillZ, fillF;
GLdouble volumeViewMatrix[16]; // for choosing stack direction
float VOL_X1, VOL_X0, VOL_Y1, VOL_Y0, VOL_Z1, VOL_Z0;
int VOLUME_FILTER;
RGBA32f SLICE_COLOR; // proxy geometry color+alpha
 bool b_renderTextureLast;
double currentTraceType;
bool useCurrentTraceTypeForRetyping;

RGBA8 currentMarkerColor;

float zThick;
Surface Object
// landmark
QList <ImageMarker> listMarker;
// 0-pxUnknown, 1-pxLocaNotUseful, 2-pxLocaUseful, 3-pxLocaUnsure, 4-pxTemp
#define NTYPE_MARKER  5
GLuint glistMarker[NTYPE_MARKER];
RGBA8 marker_color[NTYPE_MARKER];
// cell apo
QList <CellAPO> listCell;
GLuint glistCell;
QMap <QString, QList<int> > map_APOFile_IndexList;
QMap <int, QString>         map_CellIndex_APOFile;
BoundingBox apoBB;

// neuron swc
QList <NeuronTree>         listNeuronTree;
QList <NeuronTree>         listNeuronTree_old;
bool b_editDroppedNeuron;

GLuint glistTube, glistTubeEnd;
BoundingBox swcBB;
int curEditingNeuron;
int realCurEditingNeuron_inNeuronTree;

// dragged neuron
// the neuron is copied from original and pos is changed
QList <V_NeuronSWC_unit> DraggedNeurons; // ZJL 110921
V3DLONG draggedCenterIndex; // ZJL 110921

//overlay grid
QList <ImageMarker> gridList;
QList<long> gridIndexList;
float gridSpacing;
bool showingGrid;

// labelfield surf
QList <LabelSurf> listLabelSurf;
QList <Triangle*> list_listTriangle;
QList <GLuint> list_glistLabel;
BoundingBox labelBB;

创建、加载、保存函数:

void createMarker_atom();  					// makeCurrent & called in loadObj
virtual void drawMarkerList();
void loadLandmarks_from_file(const QString & filename);
void saveLandmarks_to_file(const QString & filename);

void createCell_atom();    					// makeCurrent & called in loadObj
void saveCellAPO(const QString& filename);
QList <CellAPO> listFromAPO_file(const QString& filename);
void loadCellAPO(const QString& filename);
virtual void drawCellList();

void createNeuron_tube(); 				// makeCurrent & called in loadObj
void drawDynamicNeuronTube(float rb, float rt, float length);
void saveNeuronTree(int kk, const QString& filename); //kk is the cur number of the tree to save
void loadNeuronTree(const QString& filename);
void updateNeuronBoundingBox();
virtual void drawNeuronTree(int i);
virtual void drawNeuronTreeList();
virtual void drawGrid();

void setLocalGrid(QList<ImageMarker> inputGridList,QList<long> inputGridNumber, float gridside);
QList<ImageMarker> getLocalGrid();

int highlightedNode; //highlight initial node we are going to extend.
int selectedStartNode; //for selecting start node for joining two nodes
int highlightedNodeType; //highlight initial node type we are going to extend.
V3DLONG highlightedEndNode; //highlight final node we are going to extend.
bool highlightedEndNodeChanged;
XYZ rotateAxisBeginNode; //for wriggle feature. The first node of the last-drawn segment.
XYZ rotateAxisEndNode; //for wriggle feature. The final node of the last-drawn segment.

V3DLONG highlightedStartNode; // this is for highlighting all children of selected node

void loadLabelfieldSurf(const QString& filename, int ch=0);
void constructLabelfieldSurf(int mesh_method, int mesh_density);
void compileLabelfieldSurf(int update=0);  					// makeCurrent
virtual void drawLabelfieldSurf();
void cleanLabelfieldSurf();
void loadWavefrontOBJ(const QString& filename);
void saveWavefrontOBJ(const QString& filename);
void loadV3DSurface(const QString& filename);
void saveV3DSurface(const QString& filename);
纹理渲染
static RGBA8* _safe3DBuf;
static void _safeRelease3DBuf()
static RGBA8* _safeReference3DBuf(RGBA8* rgbaBuf, int bufX, int bufY, int bufZ,
                 int &safeX, int &safeY, int &safeZ)
全局定义的辅助函数
void _copySliceFromStack(RGBA8* rgbaBuf, int imageX, int imageY, int imageZ,
                        RGBA8* slice, int copyW, int stack_i, int slice_i,
                        RGBA8* rgbaYzx=0, RGBA8* rgbaXzy=0);
void _copyXzyFromZyx(RGBA8* rgbaXzy, RGBA8* rgbaZyx, int imageX, int imageY, int imageZ);
void _copyYzxFromZyx(RGBA8* rgbaYzx, RGBA8* rgbaZyx, int imageX, int imageY, int imageZ);
#define HIGHLIGHT_ON()   {\
    glPushAttrib(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_POLYGON_BIT); \
    glBlendColorEXT(1, 1, 1, 1); glEnable(GL_DEPTH_TEST); glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); \
    beginHighlight();\
    }
#define HIGHLIGHT_OFF()  {\
    endHighlight();\
    glPopAttrib();\
    }

数据结构

basic_4dimage.h

声明了Image4DSimple类和Image4DProxy类模板,并在basic_4dimage.cpp中实现。
此外,v3d_core.h中声明了My4DImage类,继承自Image4DSimple,并在my4dimage.cpp中实现。

basic_surf_objs.h

里面定义了文件IO时用到的结构体,例如BasicSurfObj(所有标记对象的基类),ImageMarker,CellAPO,NeuronSWC,NeuronTree和IO函数的声明。

struct ImageMarker : public BasicSurfObj
{
	int type;			// 0-pxUnknown, 1-pxLocaNotUseful, 2-pxLocaUseful, 3-pxLocaUnsure, 4-pxTemp
	int shape;			// 0-pxUnset, 1-pxSphere, 2-pxCube, 3-pxCircleX, 4-pxCircleY, 5-pxCircleZ,
	// 6-pxSquareX, 7-pxSquareY, 8-pxSquareZ, 9-pxLineX, 10-pxLineY, 11-pxLineZ,
	// 12-pxTriangle, 13-pxDot;
	float x, y, z;		// point coordinates
	float radius;

	operator XYZ() const { return XYZ(x, y, z); }
	ImageMarker() {type=shape=0; radius=x=y=z=0;}
    ImageMarker(float x0, float y0, float z0) {type=shape=0; x=x0; y=y0; z=z0; radius=0;}
    ImageMarker(int t0, int s0, float x0, float y0, float z0, float r0) {type=t0; shape=s0; x=x0; y=y0; z=z0; radius=r0;}
};

basic_surf_objs.cpp

里面都是标注文件的IO操作定义,例如第288行的NeuronTree readSWC_file函数中,

NeuronTree nt;
/*...*/
int count = 0;
QList <NeuronSWC> listNeuron;
QHash <int, int>  hashNeuron;
listNeuron.clear();
hashNeuron.clear();
QString name = "";
QString comment = "";
/*...*/
for (int i=0; i<qsl.size(); i++)
{
    qsl[i].truncate(99);
    if (i==0) S.n = qsl[i].toInt();
    else if (i==1) S.type = qsl[i].toInt();
    else if (i==2) S.x = qsl[i].toFloat();
    else if (i==3) S.y = qsl[i].toFloat();
    else if (i==4) S.z = qsl[i].toFloat();
    else if (i==5) S.r = qsl[i].toFloat();
    else if (i==6) S.pn = qsl[i].toInt();
    //the ESWC extension
    else if (i==7) S.seg_id = qsl[i].toLong();
    else if (i==8) S.level = qsl[i].toLong();
    else if (i==9) S.creatmode = qsl[i].toLong();
    else if (i==10) S.timestamp = qsl[i].toDouble();
    else if (i==11) S.tfresindex = qsl[i].toDouble();
    //change ESWC format to adapt to flexible feature number
    else
        S.fea_val.append(qsl[i].toFloat());
}
nt.n = 1; //only one neuron if read from a file
nt.listNeuron = listNeuron;
nt.hashNeuron = hashNeuron;
nt.color = XYZW(0,0,0,0); /// alpha==0 means using default neuron color
nt.on = true;
nt.name = name.remove('\n'); if (nt.name.isEmpty()) nt.name = QFileInfo(filename).baseName();
nt.comment = comment.remove('\n');

return nt;

basic_landmark.h

定义了结构体 LocationSimple。

struct LocationSimple
{
	float x, y, z;
	float radius;
	PxLocationUsefulness inputProperty;
	PxLocationMarkerShape shape;

	double pixval;
	double ave, sdev, skew, curt;
	double size, mass, pixmax;
        double ev_pc1, ev_pc2, ev_pc3; //the eigen values of principal components
        XYZ mcenter; //mass center

	string name; //the name of a landmark
	string comments; //other info of the landmark
	int category; //the type of a particular landmark
	RGBA8 color;
	bool on;
	/*...*/
}

color_xyz.h

定义了结构体XYZ、XYZW、BoundingBox。

附录(部分函数具体代码分析)

v3dr_glwidget.cpp

V3dR_GLWidget::doAbsoluteRot

void V3dR_GLWidget::doAbsoluteRot(float xRot, float yRot, float zRot)
{
    NORMALIZE_angle(xRot);
    NORMALIZE_angle(yRot);
    NORMALIZE_angle(zRot);

    emit xRotationChanged(xRot);
    emit yRotationChanged(yRot);
    emit zRotationChanged(zRot);

    _xRot = xRot;
    _yRot = yRot;
    _zRot = zRot;

    glMatrixMode(GL_MODELVIEW);
    glPushMatrix();
    glLoadIdentity();
        // rotation order X--Y--Z
        glRotated( _xRot,  1,0,0);
        glRotated( _yRot,  0,1,0);
        glRotated( _zRot,  0,0,1);
    glGetDoublev(GL_MODELVIEW_MATRIX, mRot);
    glPopMatrix();

    dxRot=dyRot=dzRot= 0;
    _absRot = true;

    POST_updateGL();
}

这段代码是一个名为 doAbsoluteRot 的函数,它执行绝对旋转操作。以下是对代码的解释:

  1. NORMALIZE_angle(xRot);NORMALIZE_angle(yRot);NORMALIZE_angle(zRot);

    • 这些函数调用可能是用于将旋转角度规范化到一定的范围内,例如 0 到 360 度之间。
  2. emit xRotationChanged(xRot);emit yRotationChanged(yRot);emit zRotationChanged(zRot);

    • 这些语句发出了信号,表示 x、y 和 z 轴的旋转角度发生了变化。
  3. xRotyRotzRot 赋值给 _xRot_yRot_zRot,保存旋转角度。

  4. 调用 OpenGL 函数以执行旋转变换:

    • 使用 glMatrixMode(GL_MODELVIEW) 设置模型视图矩阵为当前矩阵操作。
    • 使用 glPushMatrix() 压栈保存当前矩阵。
    • 使用 glLoadIdentity() 将当前矩阵设置为单位矩阵,以清空之前的变换。
    • 连续执行绕 x、y 和 z 轴的旋转变换,分别使用 _xRot_yRot_zRot 作为旋转角度。
    • 使用 glGetDoublev(GL_MODELVIEW_MATRIX, mRot); 获取模型视图矩阵,并将其存储在 mRot 数组中。
    • 使用 glPopMatrix() 弹出之前保存的矩阵。
  5. dxRotdyRotdzRot 设置为 0,可能是为了清除之前的增量旋转角度。

  6. _absRot 设置为真,可能是表示进行了绝对旋转。

  7. 调用 POST_updateGL(),可能是用于触发 OpenGL 的重新绘制操作,以显示旋转后的效果。

总的来说,这段代码执行绝对旋转操作,将旋转角度应用于 x、y 和 z 轴,然后根据变换矩阵进行绘图更新。可能的应用场景包括在三维渲染中应用绝对旋转变换,以修改物体的角度和方向。你需要了解代码中涉及的函数和变量的含义和作用,以适应具体的场景。

V3dR_GLWidget::absoluteRotPose

void V3dR_GLWidget::absoluteRotPose() //100723 RZC
{
    //mRot --> (xRot,yRot,zRot)
    double M[4][4];
    MAT16_TO_MAT4x4( mRot, M );
    // NOTE:  M is column-first-index & 0-based

#define A(i,j)   M[j-1][i-1]
#define PI 3.14159265
    double rx, ry, rz;

    if (A(1,3) == -1)
    {
        ry = PI*0.5;
        rz = 0;
        //rx = atan2( A(2,1), A(3,1) ) + rz; // this is wrong
        rx = asin( A(2,1) );
    }
    if (A(1,3) == 1)
    {
        ry = PI*1.5;
        rz = 0;
        //rx = atan2( A(2,1), A(3,1) ) - rz; // this is wrong
        rx = asin( -A(2,1) );
    }
    else
    {
        ry = asin( -A(1,3) );
        rz = atan2( A(1,2), A(1,1) );
        rx = atan2( A(2,3), A(3,3) );
    }

    int xRot = round(- rx/PI*180); //must need be negative?
    int yRot = round(- ry/PI*180);
    int zRot = round(- rz/PI*180);
    NORMALIZE_angle(xRot);
    NORMALIZE_angle(yRot);
    NORMALIZE_angle(zRot);

    doAbsoluteRot(xRot, yRot, zRot);
}

这段代码是一个名为 absoluteRotPose 的函数,它根据模型视图矩阵 mRot 中的旋转信息计算 x、y 和 z 轴的绝对旋转角度,然后通过 doAbsoluteRot 函数执行绝对旋转操作。以下是对代码的详细分析:

  1. mRot 矩阵转换为一个 4x4 的数组 M

    • MAT16_TO_MAT4x4 可能是一个宏,将一个 16 元素的矩阵转换为 4x4 数组。
  2. 定义了宏 A(i,j),用于访问 M 数组中的元素。

    • ij 是索引,注意这里的索引是从 1 开始,而 C++ 数组索引是从 0 开始。
    • 定义了 PI 作为圆周率。
  3. 声明并初始化 rxryrz,用于存储计算得到的旋转角度。

  4. 根据矩阵 M 中的元素判断旋转情况,执行不同的计算:

    • 如果 A(1,3) 等于 -1,则表示某种情况下 y 轴旋转为 PI*0.5,z 轴旋转为 0
    • 如果 A(1,3) 等于 1,则表示某种情况下 y 轴旋转为 PI*1.5,z 轴旋转为 0
    • 否则,根据一般情况计算 y、z 和 x 轴的旋转角度。
  5. 将弧度制的旋转角度 rxryrz 转换为度数,并进行角度规范化。

  6. 调用 doAbsoluteRot 函数,传递计算得到的 x、y 和 z 轴旋转角度,执行绝对旋转操作。

总的来说,这段代码用于根据给定的模型视图矩阵中的旋转信息,计算出三个轴的绝对旋转角度,并通过 doAbsoluteRot 函数进行实际的绝对旋转操作。这可能是用于在三维渲染中应用已有的旋转变换,以修改物体的姿态。你需要了解代码中的宏、变量和函数的含义和作用,以适应具体的渲染场景。

V3dR_GLWidget::lookAlong

void V3dR_GLWidget::lookAlong(float xLook, float yLook, float zLook) //100812 RZC
{
    if (!renderer)  return;

    //XYZ view(-xLook, -yLook, -zLook);
    XYZ view(-xLook*flip_X, -yLook*flip_Y, -zLook*flip_Z);
    normalize(view);
    XYZ eye = view * (renderer->getViewDistance());
    XYZ at(0,0,0);
    XYZ up(0,1,0);
    if (cross(up, view)==0) up = up + 0.01;   //make sure that cross(up,view)!=0

    glMatrixMode(GL_MODELVIEW);
    glPushMatrix();
    glLoadIdentity();
        gluLookAt(eye.x,eye.y,eye.z,
                at.x,at.y,at.z,
                up.x,up.y,up.z);
    glGetDoublev(GL_MODELVIEW_MATRIX, mRot);
    glPopMatrix();

    absoluteRotPose();
}

这段代码是一个名为 lookAlong 的函数,用于根据指定的视线方向实现观察方向的调整。以下是对代码的详细分析:

  1. 首先进行了一个条件判断,如果 renderer 不存在,就直接返回。这可能是确保只有在存在渲染器对象的情况下才执行后续操作。

  2. 创建一个 XYZ 类型的 view 向量,其分量等于 -xLook-yLook-zLook,并乘以可能存在的翻转系数 flip_Xflip_Yflip_Z。这里可能是构建了一个表示视线方向的向量,并确保其被规范化。

  3. 使用 normalize(view) 函数将视线方向向量规范化,确保其长度为 1。

  4. 根据视线方向计算 eye 点,其位置为 view 方向乘以 renderer 对象的视距(距离)。

  5. 初始化 at 点为坐标原点 (0,0,0)。

  6. 初始化 up 向量为 (0,1,0) 表示上方向。

  7. 如果 up 向量与 view 向量的叉乘结果为零,即平行或共线的情况,就将 up 向量微调一小部分(加上 0.01),以确保它们不平行。这可能是为了避免 upview 方向平行导致 gluLookAt 函数无法正常工作。

  8. 设置 OpenGL 的模型视图矩阵为单位矩阵,以准备进行矩阵变换。

  9. 使用 gluLookAt 函数,根据计算得到的 eyeatup 参数设置观察矩阵。这会根据视线方向调整观察的位置和方向。

  10. 使用 glGetDoublev(GL_MODELVIEW_MATRIX, mRot); 获取模型视图矩阵,并将其存储在 mRot 数组中。

  11. 弹出之前保存的矩阵。

  12. 调用 absoluteRotPose() 函数,根据旋转矩阵计算 x、y 和 z 轴的旋转角度,并执行绝对旋转操作,可能是为了保持观察方向的变化而不影响其他方向的旋转。

总的来说,这段代码根据给定的视线方向调整观察方向,首先计算观察矩阵,然后根据旋转矩阵计算并执行绝对旋转操作,以保持观察方向的一致性。你需要了解所涉及的矢量和矩阵操作,以及 gluLookAtabsoluteRotPose 函数的作用,以适应具体的渲染场景。

renderer.cpp

Renderer::paint

void Renderer::paint()
{
    // normalized space of [-1,+1]^3;
    makeCurrent();
    //glClearColor(0.f, 0.f, 0.5f, 1.0f);
    glClearColor(color_background.r, color_background.g, color_background.b, color_background.a);
    glDepthFunc(GL_LESS);
    glEnable(GL_DEPTH_TEST);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    if (polygonMode==1)	      glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
    else if (polygonMode==2)  glPolygonMode(GL_FRONT_AND_BACK, GL_POINT);
    else                      glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
    //{
        glPushMatrix();

        glEnable(GL_LIGHT0);
        glEnable(GL_LIGHTING);

        setObjectSpace();
        //surfBoundingBox = boundingBox; // initialized in init()

        enableClipBoundingBox(surfBoundingBox, true, 0.001);
        //drawObj();
        //{
            GLUquadric* Q = gluNewQuadric();
            gluQuadricOrientation( Q, GLU_OUTSIDE);
            gluQuadricNormals(Q, GLU_SMOOTH);

            glTranslatef(.5f, .5f, .5f);
            glPushName(1);
            gluSphere( Q, .2,  36, 36);
            glPopName();

            gluDeleteQuadric(Q);
       // }
        disableClipBoundingBox();

        glDisable(GL_LIGHTING);

        glPopMatrix();
    //}

    if (!b_selecting) if (bShowBoundingBox || bShowAxes || bShowXYTranslateArrows)// a frame box [-1,+1]^3
    {
        setBoundingBoxSpace(boundingBox);
        drawBoundingBoxAndAxes(boundingBox);
    }

    return;
}

这段代码是一个使用OpenGL库进行渲染的函数。下面我将分析每个部分的作用:

  1. makeCurrent():这个函数可能是为了确保OpenGL上下文处于活动状态。在多线程或多上下文环境中,必须确保正确的上下文是活动的,以便在此上下文中执行OpenGL命令。

  2. glClearColor(color_background.r, color_background.g, color_background.b, color_background.a):设置背景颜色,这里使用了一个自定义的颜色 color_background

  3. glDepthFunc(GL_LESS):设置深度测试函数,这里使用 GL_LESS,表示只有当新像素的深度值小于当前深度缓冲区中的值时才进行绘制。

  4. glEnable(GL_DEPTH_TEST):启用深度测试,这将允许OpenGL在渲染时考虑深度信息,以进行遮挡和正确的深度排序。

  5. glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT):清除颜色缓冲区和深度缓冲区,准备进行新的渲染。

  6. 接下来的一段代码根据 polygonMode 变量的值设置多边形渲染模式,可以是线框模式、点模式或填充模式。

  7. glPushMatrix():将当前模型视图矩阵入栈,以便稍后可以通过 glPopMatrix() 恢复它。

  8. 启用光照和光源 GL_LIGHT0,然后设置对象空间(可能是为了确保后续的绘制仅影响这一部分场景)。

  9. enableClipBoundingBox(surfBoundingBox, true, 0.001):启用裁剪框,这可能是为了限制渲染的区域。surfBoundingBox 可能是一个用于定义裁剪区域的变量。

  10. 使用 gluSphere 绘制一个球体,可能是一个简单的渲染示例。

  11. glDisable(GL_LIGHTING):禁用光照,确保后续的绘制不受光照影响。

  12. glPopMatrix():从模型视图矩阵堆栈中弹出之前入栈的矩阵,恢复之前的模型视图矩阵状态。

  13. 最后的一段代码根据条件是否绘制包围盒和坐标轴,可能用于调试或可视化。

总的来说,这段代码的作用是配置OpenGL的渲染状态,设置背景颜色,绘制一个球体,并根据一些条件绘制包围盒和坐标轴。根据你的需求,你可以在这个函数中添加更多的渲染操作来绘制其他对象和场景元素。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
假设你有一个 `vector<vector<da>>` 类型的容器 `vAA`,其中 `da` 是一个结构体类型。你可以使用以下代码循环删除指定结构体元素 `vector<da>`: ```c++ #include <iostream> #include <vector> using namespace std; struct da { int value; }; int main() { vector<vector<da>> vAA = {{{{1}, {2}}, {{3}, {4}}}, {{{5}, {6}}, {{7}, {8}}}}; // 一个示例容器 int target_value = 3; // 假设你要删除值为 3 的元素 // 循环删除元素 for (auto it = vAA.begin(); it != vAA.end(); ) { auto &v = *it; auto remove_it = v.end(); for (auto it2 = v.begin(); it2 != v.end(); ++it2) { if (it2->value == target_value) { remove_it = it2; break; } } if (remove_it != v.end()) { v.erase(remove_it); } else { ++it; } } // 输出结果 for (auto &v : vAA) { for (auto &d : v) { cout << d.value << " "; } cout << endl; } return 0; } ``` 在上面的代码中,我们使用了两个循环来遍历 `vector<vector<da>>` 中的每个元素。外层循环遍历每个 `vector<da>`,内层循环遍历每个 `da`。如果遇到值为 `target_value` 的 `da`,则将其从 `vector<da>` 中删除,否则继续遍历。如果整个 `vector<da>` 中没有值为 `target_value` 的 `da`,则将其从 `vector<vector<da>>` 中删除。 需要注意的是,在循环中我们使用了迭代器来遍历元素,因为我们需要在循环中修改容器中的元素。此外,在循环中我们使用了引用 `&` 来修改元素,因为 `auto` 推导出的类型是 const 引用,无法修改元素。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值