KINECT STATS GENERATOR FOR SPORTS VISUALISATION
1.0
|
00001 #include "StatsVisualization.h" 00002 #include "KinectInterface.h" 00003 00004 00005 #include <iostream> 00006 #include <ngl/Camera.h> 00007 #include <ngl/Light.h> 00008 #include <ngl/Transformation.h> 00009 #include <ngl/TransformStack.h> 00010 #include <ngl/Material.h> 00011 #include <ngl/NGLInit.h> 00012 #include <ngl/VAOPrimitives.h> 00013 00014 #include <ngl/Random.h> 00015 #include <ngl/Util.h> 00016 #include <ngl/Texture.h> 00017 00018 //#include <boost/foreach.hpp> 00019 00020 /* 00021 LICENSING: You are free to use any part of this project provided I am informed about it via email 00022 at santoshwins@hotmail.com and referenced appropriately in your works 00023 */ 00024 00025 //---------------------------------------------------------------------------------------------------------------------- 00027 //---------------------------------------------------------------------------------------------------------------------- 00028 const static float INCREMENT=0.01; 00029 //---------------------------------------------------------------------------------------------------------------------- 00031 //---------------------------------------------------------------------------------------------------------------------- 00032 const static float ZOOM=0.3; 00033 //---------------------------------------------------------------------------------------------------------------------- 00034 00035 const GLubyte indices[]= { 00036 3,2,7,2,6,7, // back 00037 0,4,1,1,4,5, // front 00038 3,0,2,2,0,1, // top 00039 6,4,7,5,4,6, // bottom 00040 3,7,4,3,4,0, // left 00041 1,5,2,2,5,6 //right 00042 }; 00043 00044 const ngl::Vec3 normals[] = { 00045 ngl::Vec3(0.0f,0.0f,-1.0f), //back 00046 ngl::Vec3(0.0f,0.0f,1.0f), // front 00047 ngl::Vec3(0.0f,1.0f,0.0f), // top 00048 ngl::Vec3(0.0f,-1.0f,0.0f), // bottom 00049 ngl::Vec3(-1.0f,0.0f,0.0f), // left 00050 ngl::Vec3(1.0f,0.0f,0.0f) // right 00051 }; 00052 00053 StatsVisualization::StatsVisualization() 00054 { 00055 m_importFlag = false; 00056 m_vao = 0; 00057 m_text = 0; 00058 } 00059 00060 StatsVisualization::StatsVisualization( 00061 QWidget *_parent,PlayerData *_playerA, PlayerData *_playerB 00062 ) : QGLWidget( new CreateCoreGLContext(QGLFormat::defaultFormat()), _parent ), 00063 m_playerA(_playerA),m_playerB(_playerB) 00064 { 00065 00066 00067 // set this widget to have the initial keyboard focus 00068 //setFocus(); 00069 // re-size the widget to that of the parent (in this case the GLFrame passed in on construction) 00070 this->resize(_parent->size()); 00071 00072 m_importFlag = false; 00073 // Now set the initial StatsVisualization attributes to default values 00074 // Roate is false 00075 m_rotate=false; 00076 // mouse rotation values set to 0 00077 m_spinXFace=0; 00078 m_spinYFace=0; 00079 m_origX=0; 00080 m_origY=0; 00081 00082 // m_depthObject = _inputDepthWindow; 00083 00084 m_impactPtsFilled = false; 00085 00086 // by default when process stats is clicked, the first stat displayed is the impact point 00087 // of both the players 00088 00089 m_whichPlayer = BOTH; 00090 m_whichStat = IMPACT_POINTS_VIEW; 00091 m_whichQuad = ALL; 00092 00093 m_width = m_height = m_midTopX = m_midTopY = m_midBottomX = m_midBottomY = m_midLeftX = 0; 00094 m_midLeftY= m_midRightX = m_midRightY = 0; 00095 00096 m_percentageABL = m_percentageATL = m_percentageATR = m_percentageABR = -1.0; 00097 m_percentageBBL = m_percentageBTL = m_percentageBTR = m_percentageBBR = -1.0; 00098 00099 m_playerAImpactData.clear(); 00100 m_playerBImpactData.clear(); 00101 m_quadSpecABL.clear(); 00102 m_quadSpecATL.clear(); 00103 m_quadSpecATR.clear(); 00104 m_quadSpecABR.clear(); 00105 m_quadSpecBBL.clear(); 00106 m_quadSpecBTL.clear(); 00107 m_quadSpecBTR.clear(); 00108 m_quadSpecBBR.clear(); 00109 m_dataVertsA.clear(); 00110 m_dataVertsB.clear(); 00111 00112 m_playerAInterpPtsMappedToRallies.clear(); 00113 m_playerBInterpPtsMappedToRallies.clear(); 00114 m_playerATrajectoryFromFile.clear(); 00115 m_playerBTrajectoryFromFile.clear(); 00116 00117 m_speedAData.clear(); 00118 m_speedBData.clear(); 00119 m_playerAImpactPtsAllRalliesIn3D.clear(); 00120 m_playerBImpactPtsAllRalliesIn3D.clear(); 00121 m_playerARPM.clear(); 00122 m_playerBRPM.clear(); 00123 00124 m_vao = 0; 00125 m_text = 0; 00126 00127 m_3dFlag = false; 00128 m_speedMapBuilt = false; 00129 m_rpmDataBuilt = false; 00130 m_quadMapBuilt = false; 00131 m_trajectoryBuilt = false; 00132 // this is the exacct distance in meters as measured by the kinect 00133 // to the playing tt table 00134 m_kinectToPlayAreaInMeters = 0.76; 00135 m_diameterOfBAllInMeters = 0.044; 00136 m_finalCourtWidthWorld = m_finalCourtDepthWorld = 0.0; 00137 00138 m_lightPos.set(0,2,0); 00139 } 00140 00141 StatsVisualization::StatsVisualization( 00142 QWidget *_parent,bool _importFlag 00143 ) : QGLWidget( new CreateCoreGLContext(QGLFormat::defaultFormat()), _parent ),m_importFlag(_importFlag) 00144 00145 { 00146 00147 // set this widget to have the initial keyboard focus 00148 //setFocus(); 00149 // re-size the widget to that of the parent (in this case the GLFrame passed in on construction) 00150 this->resize(_parent->size()); 00151 // Now set the initial StatsVisualization attributes to default values 00152 // Roate is false 00153 m_rotate=false; 00154 // mouse rotation values set to 0 00155 m_spinXFace=0; 00156 m_spinYFace=0; 00157 m_origX=0; 00158 m_origY=0; 00159 00160 // m_depthObject = _inputDepthWindow; 00161 00162 m_impactPtsFilled = false; 00163 00164 // by default when process stats is clicked, the first stat displayed is the impact point 00165 // of both the players 00166 00167 m_whichPlayer = BOTH; 00168 m_whichStat = IMPACT_POINTS_VIEW; 00169 m_whichQuad = ALL; 00170 m_3dFlag = false; 00171 00172 m_width = m_height = m_midTopX = m_midTopY = m_midBottomX = m_midBottomY = m_midLeftX = 0; 00173 m_midLeftY= m_midRightX = m_midRightY = 0; 00174 00175 m_percentageABL = m_percentageATL = m_percentageATR = m_percentageABR = -1.0; 00176 m_percentageBBL = m_percentageBTL = m_percentageBTR = m_percentageBBR = -1.0; 00177 00178 m_playerAImpactData.clear(); 00179 m_playerBImpactData.clear(); 00180 m_quadSpecABL.clear(); 00181 m_quadSpecATL.clear(); 00182 m_quadSpecATR.clear(); 00183 m_quadSpecABR.clear(); 00184 m_quadSpecBBL.clear(); 00185 m_quadSpecBTL.clear(); 00186 m_quadSpecBTR.clear(); 00187 m_quadSpecBBR.clear(); 00188 m_dataVertsA.clear(); 00189 m_dataVertsB.clear(); 00190 m_playerAInterpPtsMappedToRallies.clear(); 00191 m_playerBInterpPtsMappedToRallies.clear(); 00192 m_speedAData.clear(); 00193 m_speedBData.clear(); 00194 m_playerAImpactPtsAllRalliesIn3D.clear(); 00195 m_playerBImpactPtsAllRalliesIn3D.clear(); 00196 m_playerARPM.clear(); 00197 m_playerBRPM.clear(); 00198 00199 m_vao = 0; 00200 m_text = 0; 00201 00202 m_speedMapBuilt = false; 00203 m_rpmDataBuilt = false; 00204 m_quadMapBuilt = false; 00205 m_trajectoryBuilt = false; 00206 // this is the exacct distance in meters as measured by the kinect 00207 // to the playing tt table 00208 m_kinectToPlayAreaInMeters = 0.76; 00209 m_diameterOfBAllInMeters = 0.044; 00210 m_finalCourtWidthWorld = m_finalCourtDepthWorld = 0.0; 00211 00212 m_lightPos.set(0,2,0); 00213 00214 //m_text->setScreenSize(640,480); 00215 } 00216 00217 StatsVisualization::~StatsVisualization() 00218 { 00219 // ngl::NGLInit *Init = ngl::NGLInit::instance(); 00220 // std::cout<<"Shutting down NGL, removing VAO's and Shaders\n"; 00221 // Init->NGLQuit(); 00222 00223 if(m_2DScreen) 00224 { 00225 delete m_2DScreen; 00226 } 00227 00228 if(m_vao) 00229 { 00230 m_vao->removeVOA(); 00231 //delete m_vao; 00232 00233 } 00234 00235 if(m_text) 00236 { 00237 delete m_text; 00238 m_text = 0; 00239 } 00240 // if(m_text1) 00241 // { 00242 // delete m_text1; 00243 // } 00244 } 00245 00246 00247 // This virtual function is called once before the first call to paintGL() or resizeGL(), 00248 //and then once whenever the widget has been assigned a new QGLContext. 00249 // This function should set up any required OpenGL context rendering flags, defining display lists, etc. 00250 00251 //---------------------------------------------------------------------------------------------------------------------- 00252 void StatsVisualization::initializeGL() 00253 { 00254 00255 glClearColor(0.4f, 0.4f, 0.4f, 1.0f); // Grey Background 00256 // enable depth testing for drawing 00257 glEnable(GL_DEPTH_TEST); 00258 00259 glEnable(GL_MULTISAMPLE); 00260 00261 // Now we will create a basic Camera from the graphics library 00262 // This is a static camera so it only needs to be set once 00263 // First create Values for the camera position 00264 00265 ngl::Vec3 from(0,0.2,50); 00266 ngl::Vec3 to(0,0,0); 00267 ngl::Vec3 up(0,1,0); 00268 00269 m_cam= new ngl::Camera(from,to,up,ngl::PERSPECTIVE); 00270 // set the shape using FOV 45 Aspect Ratio based on Width and Height 00271 // The final two are near and far clipping planes of 0.5 and 10 00272 m_cam->setShape(45,(float)640/480,0.001,150,ngl::PERSPECTIVE); 00273 00274 00275 00276 00277 00278 ngl::NGLInit *Init = ngl::NGLInit::instance(); 00279 #ifdef WIN32 00280 glewInit(); 00281 #endif 00282 Init->initGlew(); 00283 00284 // we create 2 shaders, one for 3D rendering, another one for 2D quad pasting 00285 00286 //PER FRAGMENT ASD SHADER FOR 3D RENDER 00287 00288 // now to load the shader and set the values 00289 // grab an instance of shader manager 00290 00291 ngl::ShaderLib *shader = ngl::ShaderLib::instance(); 00292 //shader = ngl::ShaderLib::instance(); 00293 // we are creating a shader called PerFragADS 00294 shader->createShaderProgram("PerFragADS"); 00295 // now we are going to create empty shaders for Frag and Vert 00296 shader->attachShader("PerFragADSVertex",ngl::VERTEX); 00297 shader->attachShader("PerFragADSFragment",ngl::FRAGMENT); 00298 // attach the source 00299 shader->loadShaderSource("PerFragADSVertex","shaders/PerFragASDVert.glsl"); 00300 shader->loadShaderSource("PerFragADSFragment","shaders/PerFragASDFrag.glsl"); 00301 // compile the shaders 00302 shader->compileShader("PerFragADSVertex"); 00303 shader->compileShader("PerFragADSFragment"); 00304 // add them to the program 00305 shader->attachShaderToProgram("PerFragADS","PerFragADSVertex"); 00306 shader->attachShaderToProgram("PerFragADS","PerFragADSFragment"); 00307 00308 // now we have associated this data we can link the shader 00309 shader->linkProgramObject("PerFragADS"); 00310 // and make it active ready to load values 00311 (*shader)["PerFragADS"]->use(); 00312 // now we need to set the material and light values 00313 /* 00314 *struct MaterialInfo 00315 { 00316 // Ambient reflectivity 00317 vec3 Ka; 00318 // Diffuse reflectivity 00319 vec3 Kd; 00320 // Specular reflectivity 00321 vec3 Ks; 00322 // Specular shininess factor 00323 float shininess; 00324 };*/ 00325 shader->setShaderParam3f("material.Ka",0.1,0.1,0.1); 00326 // green diffuse 00327 shader->setShaderParam3f("material.Kd",0.0,0.8,0.0); 00328 // white spec 00329 shader->setShaderParam3f("material.Ks",1.0,1.0,1.0); 00330 shader->setShaderParam1f("material.shininess",100); 00331 // now for the lights values (all set to white) 00332 /*struct LightInfo 00333 { 00334 // Light position in eye coords. 00335 vec4 position; 00336 // Ambient light intensity 00337 vec3 La; 00338 // Diffuse light intensity 00339 vec3 Ld; 00340 // Specular light intensity 00341 vec3 Ls; 00342 };*/ 00343 shader->setUniform("light.position",m_lightPos); 00344 shader->setShaderParam3f("light.La",0.1,0.1,0.1); 00345 shader->setShaderParam3f("light.Ld",1.0,1.0,1.0); 00346 shader->setShaderParam3f("light.Ls",0.9,0.9,0.9); 00347 00348 00349 00350 // TEXTURE SHADER INSTANCE FOR 2D 00351 00352 // now shader for Texture Pasting used for 2D viz. 00353 shader = ngl::ShaderLib::instance(); 00354 shader->createShaderProgram("TextureShaderStats"); 00355 00356 shader->attachShader("TextureVertex",ngl::VERTEX); 00357 shader->attachShader("TextureFragment",ngl::FRAGMENT); 00358 shader->loadShaderSource("TextureVertex","shaders/TextureVert.glsl"); 00359 shader->loadShaderSource("TextureFragment","shaders/TextureFrag.glsl"); 00360 00361 shader->compileShader("TextureVertex"); 00362 shader->compileShader("TextureFragment"); 00363 shader->attachShaderToProgram("TextureShaderStats","TextureVertex"); 00364 shader->attachShaderToProgram("TextureShaderStats","TextureFragment"); 00365 00366 shader->linkProgramObject("TextureShaderStats"); 00367 (*shader)["TextureShaderStats"]->use(); 00368 shader->setShaderParam1i("tex",0); 00369 00370 m_2DScreen = new ScreenQuad(640,480,"TextureShaderStats"); 00371 00372 ngl::Texture crowdTexture("textures/crowd.png"); 00373 ngl::Texture tableTexture("textures/blue_ultramarine.png"); 00374 00375 ngl::Texture speedLegendTexture("textures/speedlegendbold.png"); 00376 ngl::Texture rpmLegendTexture("textures/rpslegend.png"); 00377 ngl::Texture trajectoryLegendTexture("textures/traj_map.png"); 00378 ngl::Texture htMapLegendTexture("textures/height_map.png"); 00379 ngl::Texture htGridMapLegendTexture("textures/grid.png"); 00380 00381 m_crowdTextureName = crowdTexture.setTextureGL(); 00382 m_tableTextureName = tableTexture.setTextureGL(); 00383 00384 m_speedLegend = speedLegendTexture.setTextureGL(); 00385 m_rpmLegend = rpmLegendTexture.setTextureGL(); 00386 m_trajectoryLegend = trajectoryLegendTexture.setTextureGL(); 00387 m_heightMapLegend = htMapLegendTexture.setTextureGL(); 00388 m_gridXYHtMap = htGridMapLegendTexture.setTextureGL(); 00389 00390 //frame rate GUNDU 00391 m_text=new ngl::Text(QFont("Arial",25)); 00392 m_text->setColour(1,1,1); 00393 //m_text->setScreenSize(640,480); 00394 00395 // m_text1=new ngl::Text(QFont("Arial",25)); 00396 // m_text1->setColour(1,1,1); 00397 // m_text1->setScreenSize(640,480); 00398 00399 m_updateTimer = startTimer(3); 00400 00401 } 00402 00403 //---------------------------------------------------------------------------------------------------------------------- 00404 //This virtual function is called whenever the widget has been resized. 00405 // The new size is passed in width and height. 00406 void StatsVisualization::resizeGL( 00407 int _w, 00408 int _h 00409 ) 00410 { 00411 //glViewport(0,0,_w,_h); 00412 00413 m_legendWidth = _w * (200/640.0); 00414 m_legendHeight = _h * (200/480.0); 00415 //m_cam->setShape(45,(float)_w/_h,0.001,150,ngl::PERSPECTIVE); 00416 } 00417 00418 // change this name to ads shader 00419 void StatsVisualization::loadMatricesToADSShader() 00420 { 00421 ngl::ShaderLib *shader=ngl::ShaderLib::instance(); 00422 //(*shader)["PerFragADS"]->use(); 00423 00424 ngl::Mat4 MV; 00425 ngl::Mat4 MVP; 00426 ngl::Mat3 normalMatrix; 00427 ngl::Mat4 M; 00428 M=m_transformStack.getCurrentTransform().getMatrix(); 00429 MV= m_transformStack.getCurrAndGlobal().getMatrix()*m_cam->getViewMatrix(); 00430 MVP=MV*m_cam->getProjectionMatrix() ; 00431 normalMatrix=MV; 00432 normalMatrix.inverse(); 00433 shader->setUniform("MVP",MVP); 00434 shader->setUniform("MV",MV); 00435 shader->setUniform("normalMatrix",normalMatrix); 00436 shader->setUniform("light.position",m_lightPos); 00437 00438 } 00439 00440 void StatsVisualization::loadMatricesToTextureShader() 00441 { 00442 ngl::ShaderLib *shader=ngl::ShaderLib::instance(); 00443 //(*shader)["TextureShaderStats"]->use(); 00444 00445 ngl::Mat4 MVP=m_transformStack.getCurrAndGlobal().getMatrix()*m_cam->getVPMatrix(); 00446 00447 shader->setShaderParamFromMat4("MVP",MVP); 00448 shader->setUniform("textureFlag",true); 00449 00450 00451 00452 } 00453 00454 //---------------------------------------------------------------------------------------------------------------------- 00455 //This virtual function is called whenever the widget needs to be painted. 00456 // this is our main drawing routine 00457 void StatsVisualization::paintGL() 00458 { 00459 00460 00461 //UPDATETIMER does not call PAINTGL 00462 //JUST CALLS ONCE finally WHEN FIELD VALUES ARE COMPUTED and kills the timer 00463 00464 // clear the screen and depth buffer 00465 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 00466 00467 //glViewport(0,0,640,480); 00468 00469 // only when 3D data is requested.. 00470 if(m_3dFlag) 00471 { 00472 // Rotation based on the mouse position for our global transform 00473 ngl::Transformation trans; 00474 ngl::Mat4 rotX; 00475 ngl::Mat4 rotY; 00476 // create the rotation matrices 00477 rotX.rotateX(m_spinXFace); 00478 rotY.rotateY(m_spinYFace); 00479 // multiply the rotations 00480 ngl::Mat4 final=rotY*rotX; 00481 // add the translations 00482 final.m_m[3][0] = m_modelPos.m_x; 00483 final.m_m[3][1] = m_modelPos.m_y; 00484 final.m_m[3][2] = m_modelPos.m_z; 00485 // set this in the TX stack 00486 trans.setMatrix(final); 00487 m_transformStack.setGlobal(trans); 00488 //loadMatricesToADSShader(); 00489 00490 // if we were previously seeing a 2D stats 00491 // window it would have been restricted to 640*480 00492 // so we need to resize our opengl window 00493 // to render to the current window size for 3D stats 00494 glViewport(0,0,this->size().width(),this->size().height()); 00495 // this resize is called to resize the ratio of the legend window 00496 // which will be displayed in 3d stats 00497 resizeGL(this->size().width(),this->size().height()); 00498 00499 } 00500 else 00501 { 00502 // for 2D stats the gl window can only be 640*480 00503 glViewport(0,0,640,480); 00504 m_text->setScreenSize(640,480); 00505 resizeGL(640,480); 00506 00507 } 00508 00509 00510 drawEntireScene(); 00511 00512 } 00513 00514 void StatsVisualization::drawEntireScene() 00515 { 00516 00517 cv::Mat drawing = cv::Mat::zeros(480,640,CV_8UC3 ); 00518 00519 if((m_width != 0) && (m_height != 0)) 00520 { 00521 00522 cv::rectangle(drawing,m_fieldOfPlay,cv::Scalar(92,163,69),-1); 00523 00524 cv::line(drawing,cv::Point(m_midTopX,m_midTopY),cv::Point(m_midBottomX,m_midBottomY),cv::Scalar(255,0,0),1); 00525 00526 cv::line(drawing,cv::Point(m_midLeftX,m_midLeftY),cv::Point(m_midRightX,m_midRightY),cv::Scalar(233,235,226),3); 00527 00528 00529 // Note for All following Switch cases and Statistics: 00530 00531 // if data has been processed by the processing utility 00532 // then call a local function which will call playerallrallies function 00533 // store in player specific array and draw it if not empty 00534 00535 // if impact pts have already been filled, then this will avoid 00536 // further calling of functions..saves time and calculations 00537 // same logic applies for all statistics 00538 00539 switch (m_whichStat) 00540 { 00541 case IMPACT_POINTS_VIEW: 00542 { 00543 //m_3dFlag = 0; 00544 00545 if(!(m_impactPtsFilled)) 00546 { 00547 if(m_playerA->checkDataProcessed() && m_playerB->checkDataProcessed()) 00548 { 00549 fillAllImpactPointsBothPlayers(); 00550 } 00551 } 00552 00553 switch(m_whichPlayer) 00554 { 00555 case PLAYERA: 00556 { 00557 if(m_playerAImpactData.size() != 0) 00558 { 00559 for(int i=0;i<m_playerAImpactData.size();i++) 00560 { 00561 cv::circle(drawing,m_playerAImpactData[i],8,cv::Scalar(255,255,255),-1); 00562 } 00563 } 00564 break; 00565 } 00566 00567 case PLAYERB: 00568 { 00569 if(m_playerBImpactData.size() != 0) 00570 { 00571 for(int i=0;i<m_playerBImpactData.size();i++) 00572 { 00573 cv::circle(drawing,m_playerBImpactData[i],8,cv::Scalar(255,0,0),-1); 00574 } 00575 } 00576 break; 00577 } 00578 case BOTH: 00579 { 00580 if(m_playerAImpactData.size() != 0) 00581 { 00582 for(int i=0;i<m_playerAImpactData.size();i++) 00583 { 00584 cv::circle(drawing,m_playerAImpactData[i],8,cv::Scalar(255,255,255),-1); 00585 } 00586 } 00587 00588 if(m_playerBImpactData.size() != 0) 00589 { 00590 for(int i=0;i<m_playerBImpactData.size();i++) 00591 { 00592 cv::circle(drawing,m_playerBImpactData[i],8,cv::Scalar(255,0,0),-1); 00593 } 00594 } 00595 00596 break; 00597 } 00598 00599 } 00600 break; 00601 } 00602 00603 case IMPACT_PERCENTAGE_DISTRIBUTION_VIEW: 00604 { 00605 // pecentage distrbn 00606 // to stop recalculating in every paintgl, we check against -1 00607 00608 // THESE SWITCH CASES MIGHT ONLY BE USEFUL WHEN IT IS RENDERED APO-APO 00609 // LIKE THE IMPACT DRAWING BUFFER...WE NEED TO FIND A WAY FOR THIS 00610 00611 //threeDFlag = 0; 00612 00613 if(!(m_impactPtsFilled)) 00614 { 00615 if(m_playerA->checkDataProcessed() && m_playerB->checkDataProcessed()) 00616 { 00617 fillAllImpactPointsBothPlayers(); 00618 } 00619 } 00620 00621 switch(m_whichPlayer) 00622 { 00623 case PLAYERA: 00624 { 00625 00626 if(!(m_quadMapBuilt) && (m_impactPtsFilled == true)) 00627 { 00628 buildQuadSpecificData(); 00629 } 00630 00631 switch(m_whichQuad) 00632 { 00633 case BOTTOM_LEFT: 00634 { 00635 00636 if(m_quadSpecABL.size() != 0) 00637 { 00638 for(int i=0;i<m_quadSpecABL.size();i++) 00639 { 00640 cv::circle(drawing,m_quadSpecABL[i],8,cv::Scalar(255,255,255),-1); 00641 } 00642 00643 00644 } 00645 break; 00646 } 00647 case TOP_LEFT: 00648 { 00649 00650 if(m_quadSpecATL.size() != 0) 00651 { 00652 for(int i=0;i<m_quadSpecATL.size();i++) 00653 { 00654 cv::circle(drawing,m_quadSpecATL[i],8,cv::Scalar(255,255,255),-1); 00655 } 00656 00657 } 00658 00659 break; 00660 } 00661 case TOP_RIGHT: 00662 { 00663 00664 00665 if(m_quadSpecATR.size() != 0) 00666 { 00667 for(int i=0;i<m_quadSpecATR.size();i++) 00668 { 00669 cv::circle(drawing,m_quadSpecATR[i],8,cv::Scalar(255,255,255),-1); 00670 } 00671 00672 } 00673 00674 break; 00675 } 00676 case BOTTOM_RIGHT: 00677 { 00678 00679 if(m_quadSpecABR.size() != 0) 00680 { 00681 for(int i=0;i<m_quadSpecABR.size();i++) 00682 { 00683 cv::circle(drawing,m_quadSpecABR[i],8,cv::Scalar(255,255,255),-1); 00684 } 00685 00686 } 00687 00688 break; 00689 } 00690 case ALL: // draw A pts 00691 { 00692 if(m_playerAImpactData.size() != 0) 00693 { 00694 for(int i=0;i<m_playerAImpactData.size();i++) 00695 { 00696 cv::circle(drawing,m_playerAImpactData[i],8,cv::Scalar(255,255,255),-1); 00697 } 00698 00699 } 00700 break; 00701 } 00702 } 00703 00704 break; 00705 } 00706 00707 case PLAYERB: 00708 { 00709 if(!(m_quadMapBuilt) && (m_impactPtsFilled == true)) 00710 { 00711 buildQuadSpecificData(); 00712 } 00713 00714 switch(m_whichQuad) 00715 { 00716 case BOTTOM_LEFT: 00717 { 00718 00719 if(m_quadSpecBBL.size() != 0) 00720 { 00721 for(int i=0;i<m_quadSpecBBL.size();i++) 00722 { 00723 cv::circle(drawing,m_quadSpecBBL[i],8,cv::Scalar(255,0,0),-1); 00724 } 00725 } 00726 00727 break; 00728 } 00729 case TOP_LEFT: 00730 { 00731 00732 if(m_quadSpecBTL.size() != 0) 00733 { 00734 for(int i=0;i<m_quadSpecBTL.size();i++) 00735 { 00736 cv::circle(drawing,m_quadSpecBTL[i],8,cv::Scalar(255,0,0),-1); 00737 } 00738 } 00739 00740 break; 00741 } 00742 case TOP_RIGHT: 00743 { 00744 00745 if(m_quadSpecBTR.size() != 0) 00746 { 00747 for(int i=0;i<m_quadSpecBTR.size();i++) 00748 { 00749 cv::circle(drawing,m_quadSpecBTR[i],8,cv::Scalar(255,0,0),-1); 00750 } 00751 } 00752 00753 break; 00754 } 00755 case BOTTOM_RIGHT: 00756 { 00757 00758 if(m_quadSpecBBR.size() != 0) 00759 { 00760 for(int i=0;i<m_quadSpecBBR.size();i++) 00761 { 00762 cv::circle(drawing,m_quadSpecBBR[i],8,cv::Scalar(255,0,0),-1); 00763 } 00764 } 00765 00766 break; 00767 } 00768 00769 case ALL: //tbd // draw B pts 00770 { 00771 if(m_playerBImpactData.size() != 0) 00772 { 00773 for(int i=0;i<m_playerBImpactData.size();i++) 00774 { 00775 cv::circle(drawing,m_playerBImpactData[i],8,cv::Scalar(255,0,0),-1); 00776 } 00777 } 00778 break; 00779 } 00780 } 00781 00782 break; 00783 } 00784 case BOTH: 00785 { 00786 if(!(m_quadMapBuilt) && (m_impactPtsFilled == true)) 00787 { 00788 buildQuadSpecificData(); 00789 } 00790 00791 switch(m_whichQuad) 00792 { 00793 case BOTTOM_LEFT: 00794 { 00795 00796 if(m_quadSpecABL.size() != 0) 00797 { 00798 for(int i=0;i<m_quadSpecABL.size();i++) 00799 { 00800 cv::circle(drawing,m_quadSpecABL[i],8,cv::Scalar(255,255,255),-1); 00801 } 00802 } 00803 00804 if(m_quadSpecBBL.size() != 0) 00805 { 00806 for(int i=0;i<m_quadSpecBBL.size();i++) 00807 { 00808 cv::circle(drawing,m_quadSpecBBL[i],8,cv::Scalar(255,0,0),-1); 00809 } 00810 } 00811 break; 00812 } 00813 case TOP_LEFT: 00814 { 00815 00816 if(m_quadSpecATL.size() != 0) 00817 { 00818 for(int i=0;i<m_quadSpecATL.size();i++) 00819 { 00820 cv::circle(drawing,m_quadSpecATL[i],8,cv::Scalar(255,255,255),-1); 00821 } 00822 } 00823 00824 if(m_quadSpecBTL.size() != 0) 00825 { 00826 for(int i=0;i<m_quadSpecBTL.size();i++) 00827 { 00828 cv::circle(drawing,m_quadSpecBTL[i],8,cv::Scalar(255,0,0),-1); 00829 } 00830 } 00831 00832 break; 00833 } 00834 case TOP_RIGHT: 00835 { 00836 00837 if(m_quadSpecATR.size() != 0) 00838 { 00839 for(int i=0;i<m_quadSpecATR.size();i++) 00840 { 00841 cv::circle(drawing,m_quadSpecATR[i],8,cv::Scalar(255,255,255),-1); 00842 } 00843 } 00844 00845 if(m_quadSpecBTR.size() != 0) 00846 { 00847 for(int i=0;i<m_quadSpecBTR.size();i++) 00848 { 00849 cv::circle(drawing,m_quadSpecBTR[i],8,cv::Scalar(255,0,0),-1); 00850 } 00851 } 00852 00853 break; 00854 } 00855 case BOTTOM_RIGHT: 00856 { 00857 00858 if(m_quadSpecABR.size() != 0) 00859 { 00860 for(int i=0;i<m_quadSpecABR.size();i++) 00861 { 00862 cv::circle(drawing,m_quadSpecABR[i],8,cv::Scalar(255,255,255),-1); 00863 } 00864 } 00865 00866 if(m_quadSpecBBR.size() != 0) 00867 { 00868 for(int i=0;i<m_quadSpecBBR.size();i++) 00869 { 00870 cv::circle(drawing,m_quadSpecBBR[i],8,cv::Scalar(255,0,0),-1); 00871 } 00872 } 00873 00874 break; 00875 } 00876 00877 case ALL: // TBD 00878 { 00879 // if ALL quads and BOTH players selected in % view, its the same as full impact points 00880 if(m_playerAImpactData.size() != 0) 00881 { 00882 for(int i=0;i<m_playerAImpactData.size();i++) 00883 { 00884 cv::circle(drawing,m_playerAImpactData[i],8,cv::Scalar(255,255,255),-1); 00885 } 00886 } 00887 00888 if(m_playerBImpactData.size() != 0) 00889 { 00890 for(int i=0;i<m_playerBImpactData.size();i++) 00891 { 00892 cv::circle(drawing,m_playerBImpactData[i],8,cv::Scalar(255,0,0),-1); 00893 } 00894 } 00895 break; 00896 } 00897 } 00898 break; 00899 } 00900 00901 } 00902 break; 00903 } 00904 case IMPACT_HEIGHT_MAP_VIEW: 00905 { 00906 00907 00908 //hegith map 00909 m_cam->setEye(ngl::Vec4(0,3.0,55,1)); 00910 00911 if(!(m_impactPtsFilled)) 00912 { 00913 if(m_playerA->checkDataProcessed() && m_playerB->checkDataProcessed()) 00914 { 00915 fillAllImpactPointsBothPlayers(); 00916 } 00917 } 00918 00919 if(!(m_vao) && (m_impactPtsFilled == true)) 00920 { 00921 buildPointGraphBars(); 00922 } 00923 00924 00925 ngl::ShaderLib *shader=ngl::ShaderLib::instance(); 00926 switch(m_whichPlayer) 00927 { 00928 00929 case PLAYERA: 00930 { 00931 // in this case we are going to set our data as the vertices above 00932 00933 if(m_vao) 00934 { 00935 00936 drawCrowd("heightMapPlane"); 00937 drawTable("heightMapPlane"); 00938 00939 // draw the bounding graph planes 00940 drawContainingGridScaleXY(); 00941 00942 (*shader)["PerFragADS"]->use(); 00943 shader->setShaderParam3f("material.Kd",0.5,0.5,0.5); 00944 00945 m_transformStack.pushTransform(); 00946 { 00947 // next we bind it so it's active for setting data 00948 m_vao->bind(); 00949 m_vao->setData(m_dataVertsA.size()*sizeof(VertData),m_dataVertsA[0].nx); 00950 00951 //sizeof(vertData) and the offset into the data structure for the first x component is 3 (nx,ny,nz)..x 00952 m_vao->setVertexAttributePointer(0,3,GL_FLOAT,sizeof(VertData),3); 00953 // uv same as above but starts at 0 and is attrib 1 and only u,v so 2 00954 // normal same as vertex only starts at position 0 00955 m_vao->setVertexAttributePointer(2,3,GL_FLOAT,sizeof(VertData),0); 00956 m_vao->setNumIndices(m_dataVertsA.size()); 00957 00958 loadMatricesToADSShader(); 00959 00960 m_vao->draw(); 00961 // finally we have finished for now so time to unbind the VAO 00962 m_vao->unbind(); 00963 } 00964 m_transformStack.popTransform(); 00965 } 00966 break; 00967 } 00968 00969 case PLAYERB: 00970 { 00971 // in this case we are going to set our data as the vertices above 00972 if(m_vao) 00973 { 00974 drawCrowd("heightMapPlane"); 00975 drawTable("heightMapPlane"); 00976 // draw the bounding graph planes 00977 drawContainingGridScaleXY(); 00978 00979 (*shader)["PerFragADS"]->use(); 00980 shader->setShaderParam3f("material.Kd",0.8,0.0,0.0); 00981 00982 m_transformStack.pushTransform(); 00983 { 00984 // next we bind it so it's active for setting data 00985 m_vao->bind(); 00986 00987 m_vao->setData(m_dataVertsB.size()*sizeof(VertData),m_dataVertsB[0].nx); 00988 m_vao->setVertexAttributePointer(0,3,GL_FLOAT,sizeof(VertData),3); 00989 // normal same as vertex only starts at position 0 00990 m_vao->setVertexAttributePointer(2,3,GL_FLOAT,sizeof(VertData),0); 00991 m_vao->setNumIndices(m_dataVertsB.size()); 00992 loadMatricesToADSShader(); 00993 m_vao->draw(); 00994 // finally we have finished for now so time to unbind the VAO 00995 m_vao->unbind(); 00996 } 00997 m_transformStack.popTransform(); 00998 } 00999 01000 break; 01001 } 01002 case BOTH: 01003 { 01004 // cannot view 3d stats for both players at a time 01005 break; 01006 } 01007 } 01008 break; 01009 } 01010 case TRAJECTORY_VIEW: 01011 { 01012 01013 m_cam->setEye(ngl::Vec4(0,0.2,1,1)); 01014 01015 01016 if(!(m_impactPtsFilled)) 01017 { 01018 if(m_playerA->checkDataProcessed() && m_playerB->checkDataProcessed()) 01019 { 01020 fillAllImpactPointsBothPlayers(); 01021 } 01022 } 01023 01024 if(!(m_trajectoryBuilt) && (m_impactPtsFilled == true)) 01025 { 01026 buildTrajectory(); 01027 } 01028 01029 // draw field in WORLD coordinates 01030 // as the trajectory view is in 01031 // METRES SCALE 01032 // SHOW THE SCALE SOMEWHERE---font rendering 01033 ngl::ShaderLib *shader=ngl::ShaderLib::instance(); 01034 ngl::VAOPrimitives *prim = ngl::VAOPrimitives::instance(); 01035 01036 if(m_trajectoryBuilt) 01037 { 01038 drawCrowd("trajectoryPlane"); 01039 drawTable("trajectoryPlane"); 01040 drawContainingGridScaleXY(); 01041 } 01042 01043 switch(m_whichPlayer) 01044 { 01045 case PLAYERA: 01046 { 01047 01048 (*shader)["PerFragADS"]->use(); 01049 shader->setShaderParam3f("material.Kd",0.8,0.8,0.8); 01050 01051 if(!(m_importFlag)) // live data 01052 { 01053 for(int i=0;i<m_playerAInterpPtsMappedToRallies.size();i++) 01054 { 01055 for(int j=0;j<m_playerAInterpPtsMappedToRallies[i].size();j++) 01056 { 01057 if(m_playerAInterpPtsMappedToRallies[i][j].y < 0.0) 01058 { 01059 continue; 01060 } 01061 m_transformStack.pushTransform(); 01062 { 01063 m_transformStack.setPosition(m_playerAInterpPtsMappedToRallies[i][j].x, 01064 m_playerAInterpPtsMappedToRallies[i][j].y, 01065 m_playerAInterpPtsMappedToRallies[i][j].z); 01066 01067 01068 01069 loadMatricesToADSShader(); 01070 prim->draw("trajectorySphere"); 01071 } 01072 m_transformStack.popTransform(); 01073 } 01074 01075 01076 } 01077 } 01078 else // imported data 01079 { 01080 for(int j=0;j<m_playerATrajectoryFromFile.size();j = j+3) 01081 { 01082 if(m_playerATrajectoryFromFile[j + 1] < 0.0) 01083 { 01084 continue; 01085 } 01086 m_transformStack.pushTransform(); 01087 { 01088 m_transformStack.setPosition(m_playerATrajectoryFromFile[j], 01089 m_playerATrajectoryFromFile[j+1], 01090 m_playerATrajectoryFromFile[j+2]); 01091 01092 01093 loadMatricesToADSShader(); 01094 01095 prim->draw("trajectorySphere"); 01096 } 01097 m_transformStack.popTransform(); 01098 } 01099 01100 01101 } 01102 break; 01103 } 01104 case PLAYERB: 01105 { 01106 01107 (*shader)["PerFragADS"]->use(); 01108 shader->setShaderParam3f("material.Kd",0.8,0.0,0.0); 01109 01110 if(!(m_importFlag)) // live data 01111 { 01112 // render the vao1 for playerb data 01113 for(int i=0;i<m_playerBInterpPtsMappedToRallies.size();i++) 01114 { 01115 01116 for(int j=0;j<m_playerBInterpPtsMappedToRallies[i].size();j++) 01117 { 01118 // continue if the depth data is -1 01119 // as that represents no impact point 01120 // so move to next rally 01121 if(m_playerBInterpPtsMappedToRallies[i][j].y < 0.0) 01122 { 01123 continue; 01124 } 01125 m_transformStack.pushTransform(); 01126 { 01127 m_transformStack.setPosition(m_playerBInterpPtsMappedToRallies[i][j].x, 01128 m_playerBInterpPtsMappedToRallies[i][j].y, 01129 m_playerBInterpPtsMappedToRallies[i][j].z); 01130 01131 01132 loadMatricesToADSShader(); 01133 01134 prim->draw("trajectorySphere"); 01135 } 01136 m_transformStack.popTransform(); 01137 } 01138 01139 } 01140 01141 01142 } 01143 else // imported data 01144 { 01145 for(int j=0;j<m_playerBTrajectoryFromFile.size();j = j+3) 01146 { 01147 // continue if the depth data is -1 01148 // as that represents no impact point 01149 // so move to next rally 01150 if(m_playerBTrajectoryFromFile[j + 1] < 0.0) 01151 { 01152 continue; 01153 } 01154 m_transformStack.pushTransform(); 01155 { 01156 m_transformStack.setPosition(m_playerBTrajectoryFromFile[j], 01157 m_playerBTrajectoryFromFile[j+1], 01158 m_playerBTrajectoryFromFile[j+2]); 01159 01160 01161 loadMatricesToADSShader(); 01162 01163 prim->draw("trajectorySphere"); 01164 } 01165 m_transformStack.popTransform(); 01166 } 01167 01168 } 01169 break; 01170 } 01171 01172 case BOTH: 01173 { 01174 // cannot view 3d stats for both players at a time 01175 break; 01176 } 01177 } 01178 //3d trajectory 01179 break; 01180 } 01181 case VELOCITY_VIEW: 01182 { 01183 //velocity graphics view 01184 m_cam->setEye(ngl::Vec4(0,3.0,5,1)); 01185 01186 01187 if(!(m_impactPtsFilled)) 01188 { 01189 if(m_playerA->checkDataProcessed() && m_playerB->checkDataProcessed()) 01190 { 01191 fillAllImpactPointsBothPlayers(); 01192 } 01193 } 01194 01195 if(!(m_speedMapBuilt) && (m_impactPtsFilled == true)) 01196 { 01197 buildSpeedMap(); 01198 } 01199 01200 //ngl::ShaderLib *shader=ngl::ShaderLib::instance(); 01201 ngl::VAOPrimitives *prim = ngl::VAOPrimitives::instance(); 01202 01203 if(m_speedMapBuilt) 01204 { 01205 drawCrowd("speedPlane"); 01206 drawTable("speedPlane"); 01207 } 01208 01209 switch(m_whichPlayer) 01210 { 01211 case PLAYERA: 01212 { 01213 if(m_speedAData.size() != 0) 01214 { 01215 for(int i=0;i<m_playerAImpactPtsAllRalliesIn3D.size();i++) 01216 { 01217 // put your colour condition as m_speedAData[i] is within a range 01218 // set the shader to different colors 01219 m_transformStack.pushTransform(); 01220 { 01221 m_transformStack.setPosition(m_playerAImpactPtsAllRalliesIn3D[i].x, 01222 m_playerAImpactPtsAllRalliesIn3D[i].y, 01223 m_playerAImpactPtsAllRalliesIn3D[i].z); 01224 01225 setColorBasedOnSpeedRange(m_speedAData[i]); 01226 //(*shader)["PerFragADS"]->use(); 01227 loadMatricesToADSShader(); 01228 01229 prim->draw("sphere"); 01230 } 01231 m_transformStack.popTransform(); 01232 01233 //std::cout<<"Speed data A:"<<m_speedAData[i]<<"\n"; 01234 } 01235 } 01236 break; 01237 } 01238 case PLAYERB: 01239 { 01240 if(m_speedBData.size() != 0) 01241 { 01242 for(int i=0;i<m_playerBImpactPtsAllRalliesIn3D.size();i++) 01243 { 01244 // put your colour condition as m_speedAData[i] is within a range 01245 // set the shader to different colors 01246 m_transformStack.pushTransform(); 01247 { 01248 m_transformStack.setPosition(m_playerBImpactPtsAllRalliesIn3D[i].x, 01249 m_playerBImpactPtsAllRalliesIn3D[i].y, 01250 m_playerBImpactPtsAllRalliesIn3D[i].z); 01251 01252 setColorBasedOnSpeedRange(m_speedBData[i]); 01253 loadMatricesToADSShader(); 01254 //(*shader)["PerFragADS"]->use(); 01255 01256 prim->draw("sphere"); 01257 } 01258 m_transformStack.popTransform(); 01259 01260 //std::cout<<"Speed data B:"<<m_speedBData[i]<<"\n"; 01261 } 01262 } 01263 break; 01264 } 01265 case BOTH: 01266 { 01267 // not allowed, just a placeholder 01268 break; 01269 } 01270 } 01271 break; 01272 } 01273 case RPM_VIEW: 01274 { 01275 //rpm graphic 01276 m_cam->setEye(ngl::Vec4(0,3.0,5,1)); 01277 01278 01279 if(!(m_impactPtsFilled)) 01280 { 01281 if(m_playerA->checkDataProcessed() && m_playerB->checkDataProcessed()) 01282 { 01283 fillAllImpactPointsBothPlayers(); 01284 } 01285 } 01286 01287 if(!(m_rpmDataBuilt) && (m_impactPtsFilled == true)) 01288 { 01289 buildRPMData(); 01290 } 01291 01292 //ngl::ShaderLib *shader=ngl::ShaderLib::instance(); 01293 ngl::VAOPrimitives *prim = ngl::VAOPrimitives::instance(); 01294 01295 if(m_rpmDataBuilt) 01296 { 01297 drawCrowd("rpmPlane"); 01298 drawTable("rpmPlane"); 01299 } 01300 01301 switch(m_whichPlayer) 01302 { 01303 case PLAYERA: 01304 { 01305 if(m_playerARPM.size() != 0) 01306 { 01307 for(int i=0;i<m_playerAImpactPtsAllRalliesIn3D.size();i++) 01308 { 01309 m_transformStack.pushTransform(); 01310 { 01311 m_transformStack.setPosition(m_playerAImpactPtsAllRalliesIn3D[i].x, 01312 m_playerAImpactPtsAllRalliesIn3D[i].y, 01313 m_playerAImpactPtsAllRalliesIn3D[i].z); 01314 01315 01316 01317 setColorBasedOnRPMRange(m_playerARPM[i]); 01318 loadMatricesToADSShader(); 01319 //(*shader)["PerFragADS"]->use(); 01320 01321 prim->draw("rpmSphere"); 01322 } 01323 m_transformStack.popTransform(); 01324 } 01325 } 01326 break; 01327 } 01328 case PLAYERB: 01329 { 01330 if(m_playerBRPM.size() != 0) 01331 { 01332 for(int i=0;i<m_playerBImpactPtsAllRalliesIn3D.size();i++) 01333 { 01334 m_transformStack.pushTransform(); 01335 { 01336 m_transformStack.setPosition(m_playerBImpactPtsAllRalliesIn3D[i].x, 01337 m_playerBImpactPtsAllRalliesIn3D[i].y, 01338 m_playerBImpactPtsAllRalliesIn3D[i].z); 01339 01340 01341 setColorBasedOnRPMRange(m_playerBRPM[i]); 01342 loadMatricesToADSShader(); 01343 //(*shader)["PerFragADS"]->use(); 01344 01345 prim->draw("rpmSphere"); 01346 } 01347 m_transformStack.popTransform(); 01348 01349 } 01350 } 01351 break; 01352 } 01353 case BOTH: 01354 { 01355 // not allowed, just a place holder 01356 break; 01357 } 01358 } 01359 break; 01360 } 01361 } 01362 // or disable start tracking once process stats is clicked--easier way 01363 } 01364 01365 01366 if(!(m_3dFlag)) 01367 { 01368 01369 m_transformStack.pushTransform(); 01370 { 01371 m_2DScreen->draw(&drawing); 01372 } 01373 m_transformStack.popTransform(); 01374 01375 // this ngl text rendering should 01376 // have been placed along with the multiple switch cases 01377 // above, but for some reason ngl text was not rendering 01378 // when placed there, probably because of opencv buffer 01379 // rendering and shader switch.... 01380 // so we first draw the texture shader buffer and then finally render the percentages 01381 // in a seperate module renderPercentages() 01382 if(m_whichStat == IMPACT_PERCENTAGE_DISTRIBUTION_VIEW) 01383 { 01384 renderPercentages(); 01385 } 01386 else 01387 { 01388 // other stats do not rely on text rendering,so 01389 // do nothing 01390 } 01391 } 01392 else 01393 { 01394 01395 01396 01397 // 3D drawing, taken care in multiple switch cases in place,so 01398 // do nothing other than drawing the appropriate net lines 01399 //loadMatricesToADSShader(); 01400 01401 01402 ngl::VertexArrayObject *vao= ngl::VertexArrayObject::createVOA(GL_LINES); 01403 ngl::Vec3 points[2]; 01404 01405 01406 m_transformStack.pushTransform(); 01407 { 01408 // middle net line representaion for ht map 01409 if(m_whichStat == IMPACT_HEIGHT_MAP_VIEW) 01410 { 01411 01412 //draw line 01413 vao->bind(); 01414 points[0].m_x=0; 01415 points[0].m_y=0.2; 01416 points[0].m_z=m_fieldOfPlay.height/20.0; 01417 points[1].m_x= 0; 01418 points[1].m_y= 0.2; 01419 points[1].m_z= -(m_fieldOfPlay.height/20.0); 01420 01421 vao->setData(2*sizeof(ngl::Vec3),points[0].m_x); 01422 vao->setVertexAttributePointer(0,3,GL_FLOAT,sizeof(ngl::Vec3),0); 01423 vao->setNumIndices(2); 01424 ngl::ShaderLib *shader = ngl::ShaderLib::instance(); 01425 (*shader)["PerFragADS"]->use(); 01426 shader->setShaderParam3f("material.Kd",0.0,0.0,0.0); 01427 loadMatricesToADSShader(); 01428 vao->draw(); 01429 vao->removeVOA(); 01430 01431 legendWindow(m_heightMapLegend); 01432 01433 } 01434 // middle net line representaion for trajectory 01435 else if(m_whichStat == TRAJECTORY_VIEW) 01436 { 01437 //draw line 01438 vao->bind(); 01439 points[0].m_x=0; 01440 points[0].m_y=0.005; 01441 points[0].m_z=m_finalCourtDepthWorld/2; 01442 points[1].m_x= 0; 01443 points[1].m_y= 0.005; 01444 points[1].m_z= -(m_finalCourtDepthWorld/2); 01445 01446 vao->setData(2*sizeof(ngl::Vec3),points[0].m_x); 01447 vao->setVertexAttributePointer(0,3,GL_FLOAT,sizeof(ngl::Vec3),0); 01448 vao->setNumIndices(2); 01449 ngl::ShaderLib *shader = ngl::ShaderLib::instance(); 01450 (*shader)["PerFragADS"]->use(); 01451 shader->setShaderParam3f("material.Kd",0.0,0.0,0.0); 01452 loadMatricesToADSShader(); 01453 vao->draw(); 01454 vao->removeVOA(); 01455 01456 legendWindow(m_trajectoryLegend); 01457 } 01458 // for speed and rpm stats same scale is maintained 01459 else if(m_whichStat == VELOCITY_VIEW) 01460 { 01461 01462 //draw line 01463 vao->bind(); 01464 points[0].m_x=0; 01465 points[0].m_y=0; 01466 points[0].m_z=(m_finalCourtDepthWorld*10)/2; 01467 points[1].m_x= 0; 01468 points[1].m_y= 0; 01469 points[1].m_z= -((m_finalCourtDepthWorld*10)/2); 01470 01471 vao->setData(2*sizeof(ngl::Vec3),points[0].m_x); 01472 vao->setVertexAttributePointer(0,3,GL_FLOAT,sizeof(ngl::Vec3),0); 01473 vao->setNumIndices(2); 01474 ngl::ShaderLib *shader = ngl::ShaderLib::instance(); 01475 (*shader)["PerFragADS"]->use(); 01476 shader->setShaderParam3f("material.Kd",0.0,0.0,0.0); 01477 loadMatricesToADSShader(); 01478 vao->draw(); 01479 vao->removeVOA(); 01480 01481 01482 legendWindow(m_speedLegend); 01483 01484 } 01485 01486 else if(m_whichStat == RPM_VIEW) 01487 { 01488 01489 //draw line 01490 vao->bind(); 01491 points[0].m_x=0; 01492 points[0].m_y=0; 01493 points[0].m_z=(m_finalCourtDepthWorld*10)/2; 01494 points[1].m_x= 0; 01495 points[1].m_y= 0; 01496 points[1].m_z= -((m_finalCourtDepthWorld*10)/2); 01497 01498 vao->setData(2*sizeof(ngl::Vec3),points[0].m_x); 01499 vao->setVertexAttributePointer(0,3,GL_FLOAT,sizeof(ngl::Vec3),0); 01500 vao->setNumIndices(2); 01501 ngl::ShaderLib *shader = ngl::ShaderLib::instance(); 01502 (*shader)["PerFragADS"]->use(); 01503 shader->setShaderParam3f("material.Kd",0.0,0.0,0.0); 01504 loadMatricesToADSShader(); 01505 vao->draw(); 01506 vao->removeVOA(); 01507 01508 legendWindow(m_rpmLegend); 01509 01510 } 01511 01512 } 01513 m_transformStack.popTransform(); 01514 } 01515 } 01516 01517 01518 void StatsVisualization::timerEvent( 01519 QTimerEvent *_event 01520 ) 01521 { 01522 if(_event->timerId() == m_updateTimer) 01523 { 01524 KinectInterface *kinect=KinectInterface::instance(); 01525 01526 if(m_importFlag == false) 01527 { 01528 01529 01530 // when stats window is not created with import flag, it is live window 01531 // so go ahead with computation, if not fieldOfPlay and width and height 01532 // would be filled up by the parser 01533 01534 if(kinect->getBounds()) 01535 { 01536 m_fieldOfPlay = kinect->getBoxObject(); 01537 01538 m_width = m_fieldOfPlay.width; 01539 m_height = m_fieldOfPlay.height; 01540 m_midTopX = m_fieldOfPlay.x + m_width/2; 01541 m_midTopY = m_fieldOfPlay.y; 01542 m_midBottomX = m_midTopX; 01543 m_midBottomY = m_midTopY + m_height; 01544 01545 m_midLeftX = m_fieldOfPlay.x; 01546 m_midLeftY = m_midTopY + m_height/2; 01547 m_midRightX = m_fieldOfPlay.x + m_width; 01548 m_midRightY = m_midLeftY; 01549 01550 // we kill the timer once the bounds are calculated finally 01551 // when rt click is done 01552 killTimer(m_updateTimer); 01553 } 01554 01555 01556 01557 } 01558 else if(m_importFlag) 01559 { 01560 killTimer(m_updateTimer); 01561 } 01562 01563 updateGL(); 01564 } 01565 01566 01567 } 01568 01569 void StatsVisualization::processKey( 01570 QKeyEvent *_event 01571 ) 01572 { 01573 // this method is called every time the main window recives a key event. 01574 // we then switch on the key value and set the camera in the StatsVisualization 01575 switch (_event->key()) 01576 { 01577 01578 default : break; 01579 } 01580 // finally update the StatsVisualization and re-draw 01581 updateGL(); 01582 } 01583 01584 01585 void StatsVisualization::updateDisplay() 01586 { 01587 // this is trigerred when process stats is clicked 01588 // if process stats is clicked, then tracking has been stopped 01589 // and its time to check if data is processed - this check is done 01590 // in paintgl, so we do not have to do anything here apart from calling paintgl 01591 updateGL(); 01592 } 01593 01594 01595 // Once ball pts processed thru ball pts processing, data will be available in the player instances 01596 // CALLS TO 2D AND 3D STATS FUNCTIONS WITH INPUTS BEING PLAYER SPECIFIC POINTS WILL BE SUFFICIENT 01597 void StatsVisualization::fillAllImpactPointsBothPlayers() 01598 { 01599 if(m_playerA->getPlayerBallPtsAll().size() != 0) 01600 { 01601 m_playerAImpactData = m_playerA->getPlayerImpactPtsAllRallies(); 01602 m_impactPtsFilled = true; 01603 } 01604 01605 if(m_playerB->getPlayerBallPtsAll().size() != 0) 01606 { 01607 m_playerBImpactData = m_playerB->getPlayerImpactPtsAllRallies(); 01608 m_impactPtsFilled = true; 01609 } 01610 01611 01612 01613 } 01614 01615 void StatsVisualization::buildQuadSpecificData() 01616 { 01617 m_percentageABL = m_playerA->getPercentageDistributionData(m_midTopX,m_midRightY,BOTTOM_LEFT); 01618 m_quadSpecABL = m_playerA->getQuadSpecificPoints(BOTTOM_LEFT); 01619 01620 m_percentageATL = m_playerA->getPercentageDistributionData(m_midTopX,m_midRightY,TOP_LEFT); 01621 m_quadSpecATL = m_playerA->getQuadSpecificPoints(TOP_LEFT); 01622 01623 m_percentageATR = m_playerA->getPercentageDistributionData(m_midTopX,m_midRightY,TOP_RIGHT); 01624 m_quadSpecATR = m_playerA->getQuadSpecificPoints(TOP_RIGHT); 01625 01626 m_percentageABR = m_playerA->getPercentageDistributionData(m_midTopX,m_midRightY,BOTTOM_RIGHT); 01627 m_quadSpecABR = m_playerA->getQuadSpecificPoints(BOTTOM_RIGHT); 01628 01629 m_percentageBBL = m_playerB->getPercentageDistributionData(m_midTopX,m_midRightY,BOTTOM_LEFT); 01630 m_quadSpecBBL = m_playerB->getQuadSpecificPoints(BOTTOM_LEFT); 01631 01632 m_percentageBTL = m_playerB->getPercentageDistributionData(m_midTopX,m_midRightY,TOP_LEFT); 01633 m_quadSpecBTL = m_playerB->getQuadSpecificPoints(TOP_LEFT); 01634 01635 m_percentageBTR = m_playerB->getPercentageDistributionData(m_midTopX,m_midRightY,TOP_RIGHT); 01636 m_quadSpecBTR = m_playerB->getQuadSpecificPoints(TOP_RIGHT); 01637 01638 m_percentageBBR = m_playerB->getPercentageDistributionData(m_midTopX,m_midRightY,BOTTOM_RIGHT); 01639 m_quadSpecBBR = m_playerB->getQuadSpecificPoints(BOTTOM_RIGHT); 01640 01641 m_quadMapBuilt = true; 01642 } 01643 01644 void StatsVisualization::setWhichStatToView(int _inputWhichStat) 01645 { 01646 m_whichStat = (WHICH_STAT)_inputWhichStat; 01647 01648 if((m_whichStat == IMPACT_HEIGHT_MAP_VIEW) || (m_whichStat == TRAJECTORY_VIEW) || 01649 (m_whichStat == VELOCITY_VIEW) || (m_whichStat == RPM_VIEW)) // add more later 01650 { 01651 m_3dFlag = true; 01652 } 01653 else 01654 { 01655 m_3dFlag = false; 01656 } 01657 updateGL(); 01658 } 01659 01660 void StatsVisualization::setWhoseStatToView(int _inputWhoseStat) 01661 { 01662 m_whichPlayer = (WHOSE_STATS)_inputWhoseStat; 01663 updateGL(); 01664 } 01665 01666 void StatsVisualization::setWhichQuadToView(int _inputWhichQuad) 01667 { 01668 m_whichQuad = (WHICH_QUADRANT)_inputWhichQuad; 01669 updateGL(); 01670 } 01671 01672 void StatsVisualization::setKinectToPlayAreaDistance(double _inputDistanceInMeters) 01673 { 01674 // if the user wishes to change this value from UI 01675 // it has to be done before starting the tracking 01676 // this is not a dynamic variable 01677 m_kinectToPlayAreaInMeters = _inputDistanceInMeters; 01678 } 01679 01680 void StatsVisualization::setDiameterOfBallInMeters(double _inputDiaInMeters) 01681 { 01682 // if the user wishes to change this value from UI 01683 // it has to be done before starting the tracking 01684 // this is not a dynamic variable 01685 m_diameterOfBAllInMeters = _inputDiaInMeters; 01686 } 01687 01688 void StatsVisualization::buildPointGraphBars() 01689 { 01690 // grid resol is set to 10 now... 01691 // make it dynamic later 01692 01693 std::vector<cv::Point3f> aBarGraphVertices,bBarGraphVertices; 01694 01695 aBarGraphVertices = m_playerA->getBarGraphVertices(cv::Point(m_fieldOfPlay.x,m_fieldOfPlay.y),m_fieldOfPlay.width, 01696 m_fieldOfPlay.height,10); 01697 01698 bBarGraphVertices = m_playerB->getBarGraphVertices(cv::Point(m_fieldOfPlay.x,m_fieldOfPlay.y),m_fieldOfPlay.width, 01699 m_fieldOfPlay.height,10); 01700 01701 01702 fillDataVertsWithNormals(aBarGraphVertices,m_dataVertsA); 01703 fillDataVertsWithNormals(bBarGraphVertices,m_dataVertsB); 01704 01705 01706 ngl::VAOPrimitives *prim = ngl::VAOPrimitives::instance(); 01707 01708 // we scale it down only by 10 and not by 20 as tri plane is drawn from 0,0,0 01709 // so it will stretch from 10 untis up to 10 units down 01710 // similarly for width as well from left to right 01711 01712 prim->createTrianglePlane("heightMapPlane",m_fieldOfPlay.width/10.0,m_fieldOfPlay.height/10.0,1,1,ngl::Vec3(0,1,0)); 01713 01714 // create a vao as a series of GL_TRIANGLES 01715 m_vao= ngl::VertexArrayObject::createVOA(GL_TRIANGLES); 01716 01717 01718 } 01719 01720 01721 void StatsVisualization::buildTrajectory() 01722 { 01723 m_playerAInterpPtsMappedToRallies = m_playerA->getPlayerInterpolatedBallPtsAll(m_kinectToPlayAreaInMeters); 01724 m_playerBInterpPtsMappedToRallies = m_playerB->getPlayerInterpolatedBallPtsAll(m_kinectToPlayAreaInMeters); 01725 01726 // conversion to world coords just to draw a static field of play 01727 // plane to be relative to the scale of the trajectories 01728 // i.e, both the field of play and the trajectories would be in Metres scale 01729 01730 // note to self: DISPLAY the METRES SCALE on the window 01731 01732 calculateFieldOfPlayInWorldCoords(); 01733 01734 ngl::VAOPrimitives *prim = ngl::VAOPrimitives::instance(); 01735 01736 // no scaling... 1 unit = 1 meter 01737 prim->createTrianglePlane("trajectoryPlane",m_finalCourtWidthWorld,m_finalCourtDepthWorld,1,1,ngl::Vec3(0,1,0)); 01738 01739 prim->createSphere("trajectorySphere",0.004,10.0); 01740 01741 m_trajectoryBuilt = true; 01742 01743 01744 01745 } 01746 01747 void StatsVisualization::buildSpeedMap() 01748 { 01749 m_speedAData = m_playerA->getPlayerSpeedData(m_kinectToPlayAreaInMeters); 01750 m_playerAImpactPtsAllRalliesIn3D = m_playerA->getPlayerImpactPtsIn3DAllRallies(); 01751 01752 m_speedBData = m_playerB->getPlayerSpeedData(m_kinectToPlayAreaInMeters); 01753 m_playerBImpactPtsAllRalliesIn3D = m_playerB->getPlayerImpactPtsIn3DAllRallies(); 01754 01755 std::cout<<"PlayerA speeddata size is:"<<m_speedAData.size()<<"\n"; 01756 std::cout<<"PlayerA impct point size is:"<<m_playerAImpactPtsAllRalliesIn3D.size()<<"\n"; 01757 01758 std::cout<<"PlayerB speeddata size is:"<<m_speedBData.size()<<"\n"; 01759 std::cout<<"PlayerB impct point size is:"<<m_playerBImpactPtsAllRalliesIn3D.size()<<"\n"; 01760 01761 calculateFieldOfPlayInWorldCoords(); 01762 01763 ngl::VAOPrimitives *prim = ngl::VAOPrimitives::instance(); 01764 01765 prim->createSphere("sphere",0.08,10.0); 01766 01767 // scaled by 10 as the speedmap view's scale is 01768 // 1 unit = 0.1 meter 01769 prim->createTrianglePlane("speedPlane",m_finalCourtWidthWorld*10.0,m_finalCourtDepthWorld*10.0,1,1,ngl::Vec3(0,1,0)); 01770 01771 m_speedMapBuilt = true; 01772 01773 01774 01775 } 01776 01777 void StatsVisualization::calculateFieldOfPlayInWorldCoords() 01778 { 01779 // have to set 0.70 to 1.0 and check if scaling issue gets resolved 01780 // and set it to depth paramter if something other than 1 01781 01782 float fieldOfPlayXWorld = (m_fieldOfPlay.x/640 - 0.5) * m_kinectToPlayAreaInMeters * 1.111467f; 01783 float fieldOfPlayYWorld = (0.5 - m_fieldOfPlay.y/480) * m_kinectToPlayAreaInMeters * 0.833599f; 01784 01785 float fieldOfPlayDownY = m_fieldOfPlay.y + m_fieldOfPlay.height; 01786 float fieldOfPlayDownYWorld = (0.5 - fieldOfPlayDownY/480) * m_kinectToPlayAreaInMeters * 0.833599f; 01787 01788 float fieldOfPlayExtremeLeftX = m_fieldOfPlay.x + m_fieldOfPlay.width; 01789 float fieldOfPlayExtremeLeftXWorld = (fieldOfPlayExtremeLeftX/640 - 0.5) * m_kinectToPlayAreaInMeters * 1.111467f; 01790 01791 m_finalCourtWidthWorld = fabs(fieldOfPlayExtremeLeftXWorld - fieldOfPlayXWorld); 01792 m_finalCourtDepthWorld = fabs(fieldOfPlayDownYWorld - fieldOfPlayYWorld); 01793 } 01794 01795 void StatsVisualization::setColorBasedOnSpeedRange(float _inputVelocity) 01796 { 01797 ngl::ShaderLib *shader=ngl::ShaderLib::instance(); 01798 (*shader)["PerFragADS"]->use(); 01799 01800 if(_inputVelocity >= 0.0 && _inputVelocity < 0.3) 01801 { 01802 shader->setShaderParam3f("material.Kd",0.0,0.8,1.0); 01803 } 01804 else if(_inputVelocity >= 0.3 && _inputVelocity < 0.6) 01805 { 01806 shader->setShaderParam3f("material.Kd",1.0,1.0,0.0); 01807 } 01808 else if(_inputVelocity >= 0.6) 01809 { 01810 shader->setShaderParam3f("material.Kd",1.0,0.5,0.0); 01811 } 01812 } 01813 01814 void StatsVisualization::buildRPMData() 01815 { 01816 m_playerARPM = m_playerA->getRevolutionsPerMinute(m_diameterOfBAllInMeters,m_kinectToPlayAreaInMeters); 01817 m_playerAImpactPtsAllRalliesIn3D = m_playerA->getPlayerImpactPtsIn3DAllRallies(); 01818 01819 m_playerBRPM = m_playerB->getRevolutionsPerMinute(m_diameterOfBAllInMeters,m_kinectToPlayAreaInMeters); 01820 m_playerBImpactPtsAllRalliesIn3D = m_playerB->getPlayerImpactPtsIn3DAllRallies(); 01821 01822 std::cout<<"PlayerA rpmdata size is:"<<m_playerARPM.size()<<"\n"; 01823 std::cout<<"PlayerA impct point size is:"<<m_playerAImpactPtsAllRalliesIn3D.size()<<"\n"; 01824 01825 std::cout<<"PlayerB rpmdata size is:"<<m_playerBRPM.size()<<"\n"; 01826 std::cout<<"PlayerB impct point size is:"<<m_playerBImpactPtsAllRalliesIn3D.size()<<"\n"; 01827 01828 calculateFieldOfPlayInWorldCoords(); 01829 01830 // currently creating balls again which will be rendered color coded 01831 // based on the rpm value 01832 01833 ngl::VAOPrimitives *prim = ngl::VAOPrimitives::instance(); 01834 01835 prim->createSphere("rpmSphere",0.08,10.0); 01836 01837 // scaled by 10 as the speedmap view's scale is 01838 // 1 unit = 0.1 meter 01839 prim->createTrianglePlane("rpmPlane",m_finalCourtWidthWorld*10.0,m_finalCourtDepthWorld*10.0,1,1,ngl::Vec3(0,1,0)); 01840 01841 m_rpmDataBuilt = true; 01842 01843 01844 } 01845 01846 void StatsVisualization::setColorBasedOnRPMRange(float _inputRPM) 01847 { 01848 ngl::ShaderLib *shader=ngl::ShaderLib::instance(); 01849 (*shader)["PerFragADS"]->use(); 01850 01851 if(_inputRPM >= 0 && _inputRPM < 100) 01852 { 01853 shader->setShaderParam3f("material.Kd",0.0,0.8,1.0); 01854 } 01855 else if(_inputRPM >= 100 && _inputRPM < 200) 01856 { 01857 shader->setShaderParam3f("material.Kd",1.0,1.0,0.0); 01858 } 01859 else if(_inputRPM >= 200) 01860 { 01861 shader->setShaderParam3f("material.Kd",1.0,0.5,0.0); 01862 } 01863 } 01864 01865 void StatsVisualization::fillDataVertsWithNormals(std::vector<cv::Point3f>& _inputVertList, 01866 std::vector<VertData>& o_normalFilledDataVerts) 01867 { 01868 // we scale it down only by 10 and not by 20 as tri plane is drawn from 0,0,0 01869 // so it will stretch from 10 untis up to 10 units down 01870 // similarly for width as well from left to right 01871 int cubeIndex = 0; 01872 VertData d; 01873 01874 // for every cube 01875 for(int i=0;i<_inputVertList.size();i=i+8) 01876 { 01877 //for every face in the cube - 6 vertices per face (2 triangle per face) 01878 for(int j=0;j<sizeof(indices)/sizeof(indices[0]);j=j+6)// size of indices = 36 01879 { 01880 // GUNDU FACE 01881 01882 //triangle 1, v1 01883 d.x = _inputVertList[indices[j]+i].x;// - _gapFactor*normals[j/6].m_x; 01884 d.y = _inputVertList[indices[j]+i].y;//- _gapFactor*normals[j/6].m_y; 01885 d.z = _inputVertList[indices[j]+i].z;// - _gapFactor*normals[j/6].m_z; 01886 01887 d.nx = normals[j/6].m_x; 01888 d.ny = normals[j/6].m_y; 01889 d.nz = normals[j/6].m_z; 01890 o_normalFilledDataVerts.push_back(d); 01891 01892 //triangle 1, v2 01893 d.x = _inputVertList[indices[j+1]+i].x;// - _gapFactor*normals[j/6].m_x; 01894 d.y = _inputVertList[indices[j+1]+i].y;// - _gapFactor*normals[j/6].m_y; 01895 d.z = _inputVertList[indices[j+1]+i].z;// - _gapFactor*normals[j/6].m_z; 01896 01897 d.nx = normals[j/6].m_x; 01898 d.ny = normals[j/6].m_y; 01899 d.nz = normals[j/6].m_z; 01900 o_normalFilledDataVerts.push_back(d); 01901 01902 //triangle 1, v3 01903 d.x = _inputVertList[indices[j+2]+i].x;// - _gapFactor*normals[j/6].m_x; 01904 d.y = _inputVertList[indices[j+2]+i].y;// - _gapFactor*normals[j/6].m_y; 01905 d.z = _inputVertList[indices[j+2]+i].z;// - _gapFactor*normals[j/6].m_z; 01906 01907 d.nx = normals[j/6].m_x; 01908 d.ny = normals[j/6].m_y; 01909 d.nz = normals[j/6].m_z; 01910 o_normalFilledDataVerts.push_back(d); 01911 01912 //triangle 2, v1 01913 d.x = _inputVertList[indices[j+3]+i].x;// - _gapFactor*normals[j/6].m_x; 01914 d.y = _inputVertList[indices[j+3]+i].y;// - _gapFactor*normals[j/6].m_y; 01915 d.z = _inputVertList[indices[j+3]+i].z;// - _gapFactor*normals[j/6].m_z; 01916 01917 d.nx = normals[j/6].m_x; 01918 d.ny = normals[j/6].m_y; 01919 d.nz = normals[j/6].m_z; 01920 o_normalFilledDataVerts.push_back(d); 01921 01922 //triangle 2, v2 01923 d.x = _inputVertList[indices[j+4]+i].x;// - _gapFactor*normals[j/6].m_x; 01924 d.y = _inputVertList[indices[j+4]+i].y;// - _gapFactor*normals[j/6].m_y; 01925 d.z = _inputVertList[indices[j+4]+i].z;// - _gapFactor*normals[j/6].m_z; 01926 01927 d.nx = normals[j/6].m_x; 01928 d.ny = normals[j/6].m_y; 01929 d.nz = normals[j/6].m_z; 01930 o_normalFilledDataVerts.push_back(d); 01931 01932 //triangle 2, v3 01933 d.x = _inputVertList[indices[j+5]+i].x;// - _gapFactor*normals[j/6].m_x; 01934 d.y = _inputVertList[indices[j+5]+i].y;// - _gapFactor*normals[j/6].m_y; 01935 d.z = _inputVertList[indices[j+5]+i].z;// - _gapFactor*normals[j/6].m_z; 01936 01937 d.nx = normals[j/6].m_x; 01938 d.ny = normals[j/6].m_y; 01939 d.nz = normals[j/6].m_z; 01940 01941 o_normalFilledDataVerts.push_back(d); 01942 } 01943 cubeIndex++; 01944 } 01945 } 01946 01947 void StatsVisualization::readFile(QString _inputFileName) 01948 { 01949 if(_inputFileName.isEmpty()) 01950 { 01951 std::cout<<"Filename empty. Returning. Read Aborted\n"; 01952 return; 01953 } 01954 //read 01955 std::cout <<"Reading: "<<"\n"; 01956 01957 cv::FileStorage fs; 01958 fs.open(_inputFileName.toStdString(), cv::FileStorage::READ); 01959 01960 01961 fillDataFromFileForBothPlayers(fs,PLAYERA); 01962 fillDataFromFileForBothPlayers(fs,PLAYERB); 01963 01964 cv::FileNode n8 = fs["FieldOfPlay"]; 01965 cv::FileNodeIterator it8 = n8.begin(); 01966 m_fieldOfPlay.x = (int)*it8; 01967 m_fieldOfPlay.y = (int)*(++it8); 01968 m_fieldOfPlay.width = (int)*(++it8); 01969 m_fieldOfPlay.height = (int)*(++it8); 01970 01971 m_finalCourtWidthWorld = (float)fs["CourtWidth"]; 01972 m_finalCourtDepthWorld = (float)fs["CourtDepth"]; 01973 m_width = (int)fs["Width"]; 01974 m_height = (int)fs["Height"]; 01975 m_midTopX = (int)fs["MidTopX"]; 01976 m_midTopY = (int)fs["MidTopY"]; 01977 m_midBottomX = (int)fs["MidBottomX"]; 01978 m_midBottomY = (int)fs["MidBottomY"]; 01979 m_midLeftX = (int)fs["MidLeftX"]; 01980 m_midLeftY = (int)fs["MidLeftY"]; 01981 m_midRightX = (int)fs["MidRightX"]; 01982 m_midRightY = (int)fs["MidRightY"]; 01983 01984 m_quadMapBuilt = true; 01985 m_speedMapBuilt = true; 01986 m_rpmDataBuilt = true; 01987 m_trajectoryBuilt = true; 01988 m_impactPtsFilled = true; 01989 01990 //Generating our rendering stuff 01991 01992 // create a vao as a series of GL_TRIANGLES 01993 m_vao= ngl::VertexArrayObject::createVOA(GL_TRIANGLES); 01994 01995 // we will create separate planes and spheres for various statistics instead of 01996 // trying to scale them each time as we have different units of scaling and 01997 // those scale factors are calculated at various times 01998 // and this is much easier than that even though it takes quite a bit of memory 01999 02000 ngl::VAOPrimitives *prim = ngl::VAOPrimitives::instance(); 02001 prim->createTrianglePlane("heightMapPlane",m_fieldOfPlay.width/10.0,m_fieldOfPlay.height/10.0,1,1,ngl::Vec3(0,1,0)); 02002 prim->createTrianglePlane("trajectoryPlane",m_finalCourtWidthWorld,m_finalCourtDepthWorld,1,1,ngl::Vec3(0,1,0)); 02003 prim->createSphere("trajectorySphere",0.004,10.0); 02004 prim->createSphere("sphere",0.08,10.0); 02005 prim->createTrianglePlane("speedPlane",m_finalCourtWidthWorld*10.0,m_finalCourtDepthWorld*10.0,1,1,ngl::Vec3(0,1,0)); 02006 prim->createSphere("rpmSphere",0.08,10.0); 02007 prim->createTrianglePlane("rpmPlane",m_finalCourtWidthWorld*10.0,m_finalCourtDepthWorld*10.0,1,1,ngl::Vec3(0,1,0)); 02008 02009 updateGL(); 02010 02011 } 02012 02013 // recieve file name input from UI 02014 void StatsVisualization::writeFile() 02015 { 02016 02017 QString fileName = QFileDialog::getSaveFileName(this, "Save File","archive"," Xml File (*.xml)"); 02018 02019 02020 // check if filename is valid, if so call read 02021 if(fileName.isEmpty()) 02022 { 02023 std::cout<<"File name empty. Write aborted.\n"; 02024 return; 02025 } 02026 02027 cv::FileStorage fs(fileName.toStdString(), cv::FileStorage::WRITE); 02028 02029 // we build all the data if not already present in the respective buffers 02030 // this might take quite a while as all data are captured in buffers 02031 // sequentially 02032 if(!(m_impactPtsFilled)) 02033 { 02034 fillAllImpactPointsBothPlayers(); 02035 } 02036 02037 if(!(m_quadMapBuilt)) 02038 { 02039 buildQuadSpecificData(); 02040 } 02041 02042 if(!(m_vao)) 02043 { 02044 buildPointGraphBars(); 02045 } 02046 02047 if(!(m_trajectoryBuilt)) 02048 { 02049 buildTrajectory(); 02050 } 02051 02052 if(!(m_speedMapBuilt)) 02053 { 02054 buildSpeedMap(); 02055 } 02056 02057 if(!(m_rpmDataBuilt)) 02058 { 02059 buildRPMData(); 02060 } 02061 02062 // Data corresponding to both the players written out to xml 02063 // Also, common data such as field of play width etc are written out to xml 02064 02065 // PLAYERA data 02066 02067 fs << "PLAYERA"; 02068 fs<< "{"; 02069 02070 fs<< "ImpactData"<<m_playerAImpactData; 02071 02072 fs<< "QuadSpecBL"<<m_quadSpecABL; 02073 02074 fs<< "QuadSpecTL"<<m_quadSpecATL; 02075 02076 fs<< "QuadSpecTR"<<m_quadSpecATR; 02077 02078 fs<< "QuadSpecBR"<<m_quadSpecABR; 02079 02080 fs<< "PercentageBL"<< m_percentageABL; 02081 02082 fs<< "PercentageTL"<< m_percentageATL; 02083 02084 fs<< "PercentageTR"<< m_percentageATR; 02085 02086 fs<< "PercentageBR"<< m_percentageABR; 02087 02088 fs<< "InterpPtsMappedToRallies"<< m_playerAInterpPtsMappedToRallies; 02089 02090 fs<< "CubeDataVertices"<<"["; 02091 for(int i=0;i<m_dataVertsA.size();i++) 02092 { 02093 fs<< m_dataVertsA[i].nx; 02094 fs<< m_dataVertsA[i].ny; 02095 fs<< m_dataVertsA[i].nz; 02096 fs<< m_dataVertsA[i].x; 02097 fs<< m_dataVertsA[i].y; 02098 fs<< m_dataVertsA[i].z; 02099 } 02100 fs<< "]"; 02101 02102 fs<< "SpeedData"<<m_speedAData; 02103 02104 fs<< "PlayerImpactPointsIn3D"<<m_playerAImpactPtsAllRalliesIn3D; 02105 02106 fs<< "RPMData"<<m_playerARPM; 02107 02108 fs<< "}"; 02109 02110 02111 //PLAYERB data 02112 02113 fs<< "PLAYERB"; 02114 fs<< "{"; 02115 02116 fs<< "ImpactData"<<m_playerBImpactData; 02117 02118 fs<< "QuadSpecBL"<<m_quadSpecBBL; 02119 02120 fs<< "QuadSpecTL"<<m_quadSpecBTL; 02121 02122 fs<< "QuadSpecTR"<<m_quadSpecBTR; 02123 02124 fs<< "QuadSpecBR"<<m_quadSpecBBR; 02125 02126 fs<< "PercentageBL"<< m_percentageBBL; 02127 02128 fs<< "PercentageTL"<< m_percentageBTL; 02129 02130 fs<< "PercentageTR"<< m_percentageBTR; 02131 02132 fs<< "PercentageBR"<< m_percentageBBR; 02133 02134 fs<< "InterpPtsMappedToRallies"<< m_playerBInterpPtsMappedToRallies; 02135 02136 fs<< "CubeDataVertices"<<"["; 02137 for(int i=0;i<m_dataVertsB.size();i++) 02138 { 02139 fs<< m_dataVertsB[i].nx; 02140 fs<< m_dataVertsB[i].ny; 02141 fs<< m_dataVertsB[i].nz; 02142 fs<< m_dataVertsB[i].x; 02143 fs<< m_dataVertsB[i].y; 02144 fs<< m_dataVertsB[i].z; 02145 } 02146 fs<< "]"; 02147 02148 fs<< "SpeedData"<<m_speedBData; 02149 02150 fs<< "PlayerImpactPointsIn3D"<<m_playerBImpactPtsAllRalliesIn3D; 02151 02152 fs<< "RPMData"<<m_playerBRPM; 02153 02154 fs<< "}"; 02155 02156 02157 fs<<"FieldOfPlay"<<"["<<m_fieldOfPlay.x<<m_fieldOfPlay.y<<m_fieldOfPlay.width<<m_fieldOfPlay.height<<"]"; 02158 fs<<"CourtWidth"<<m_finalCourtWidthWorld; 02159 fs<<"CourtDepth"<<m_finalCourtDepthWorld; 02160 fs<<"Width"<<m_width; 02161 fs<<"Height"<<m_height; 02162 fs<<"MidTopX"<<m_midTopX; 02163 fs<<"MidTopY"<<m_midTopY; 02164 fs<<"MidBottomX"<<m_midBottomX; 02165 fs<<"MidBottomY"<<m_midBottomY; 02166 fs<<"MidLeftX"<<m_midLeftX; 02167 fs<<"MidLeftY"<<m_midLeftY; 02168 fs<<"MidRightX"<<m_midRightX; 02169 fs<<"MidRightY"<<m_midRightY; 02170 02171 fs.release(); // explicit close 02172 02173 std::cout << "Write Done.\n"; 02174 02175 02176 } 02177 02178 02179 void StatsVisualization::fillDataFromFileForBothPlayers(cv::FileStorage& _fs,WHOSE_STATS _whichPlayer) 02180 { 02181 std::string whichPlayerString; 02182 02183 if(_whichPlayer == PLAYERA) 02184 { 02185 whichPlayerString = "PLAYERA"; 02186 } 02187 else 02188 { 02189 whichPlayerString = "PLAYERB"; 02190 } 02191 02192 cv::FileNode n1 = _fs[whichPlayerString]["ImpactData"]; // Read string sequence - Get node 02193 if (n1.type() != cv::FileNode::SEQ) 02194 { 02195 std::cout << "Impact pt is not a sequence\n"; 02196 } 02197 02198 cv::FileNodeIterator it1 = n1.begin(), it1_end = n1.end(); // Go through the node 02199 for (; it1 != it1_end; ++it1++) 02200 { 02201 if(whichPlayerString == "PLAYERA") 02202 { 02203 this->m_playerAImpactData.push_back(cv::Point2f((float)*it1,(float)*(++it1))); 02204 } 02205 else if(whichPlayerString == "PLAYERB") 02206 { 02207 this->m_playerBImpactData.push_back(cv::Point2f((float)*it1,(float)*(++it1))); 02208 } 02209 } 02210 02211 02212 02213 cv::FileNode n2 = _fs[whichPlayerString]["QuadSpecBL"]; // Read string sequence - Get node 02214 if (n2.type() != cv::FileNode::SEQ) 02215 { 02216 std::cout << "ABL is not a sequence\n"; 02217 } 02218 02219 cv::FileNodeIterator it2 = n2.begin(), it2_end = n2.end(); // Go through the node 02220 for (; it2 != it2_end; ++it2++) 02221 { 02222 if(whichPlayerString == "PLAYERA") 02223 { 02224 this->m_quadSpecABL.push_back(cv::Point2f((float)*it2,(float)*(++it2))); 02225 } 02226 else if(whichPlayerString == "PLAYERB") 02227 { 02228 this->m_quadSpecBBL.push_back(cv::Point2f((float)*it2,(float)*(++it2))); 02229 } 02230 } 02231 02232 02233 cv::FileNode n3 = _fs[whichPlayerString]["QuadSpecTL"]; // Read string sequence - Get node 02234 if (n3.type() != cv::FileNode::SEQ) 02235 { 02236 std::cout << "ATL is not a sequence\n"; 02237 } 02238 02239 cv::FileNodeIterator it3 = n3.begin(), it3_end = n3.end(); // Go through the node 02240 for (; it3 != it3_end; ++it3++) 02241 { 02242 if(whichPlayerString == "PLAYERA") 02243 { 02244 this->m_quadSpecATL.push_back(cv::Point2f((float)*it3,(float)*(++it3))); 02245 } 02246 else if(whichPlayerString == "PLAYERB") 02247 { 02248 this->m_quadSpecBTL.push_back(cv::Point2f((float)*it3,(float)*(++it3))); 02249 } 02250 } 02251 02252 02253 cv::FileNode n4 = _fs[whichPlayerString]["QuadSpecTR"]; // Read string sequence - Get node 02254 if (n4.type() != cv::FileNode::SEQ) 02255 { 02256 std::cout << "ATR is not a sequence!\n"; 02257 } 02258 02259 cv::FileNodeIterator it4 = n4.begin(), it4_end = n4.end(); // Go through the node 02260 for (; it4 != it4_end; ++it4++) 02261 { 02262 if(whichPlayerString == "PLAYERA") 02263 { 02264 this->m_quadSpecATR.push_back(cv::Point2f((float)*it4,(float)*(++it4))); 02265 } 02266 else if(whichPlayerString == "PLAYERB") 02267 { 02268 this->m_quadSpecBTR.push_back(cv::Point2f((float)*it4,(float)*(++it4))); 02269 } 02270 } 02271 02272 cv::FileNode n5 = _fs[whichPlayerString]["QuadSpecBR"]; // Read string sequence - Get node 02273 if (n5.type() != cv::FileNode::SEQ) 02274 { 02275 std::cout << "ABR not a sequence!\n"; 02276 } 02277 02278 cv::FileNodeIterator it5 = n5.begin(), it5_end = n5.end(); // Go through the node 02279 for (; it5 != it5_end; ++it5++) 02280 { 02281 if(whichPlayerString == "PLAYERA") 02282 { 02283 this->m_quadSpecABR.push_back(cv::Point2f((float)*it5,(float)*(++it5))); 02284 } 02285 else if(whichPlayerString == "PLAYERB") 02286 { 02287 this->m_quadSpecBBR.push_back(cv::Point2f((float)*it5,(float)*(++it5))); 02288 } 02289 } 02290 02291 02292 if(whichPlayerString == "PLAYERA") 02293 { 02294 this->m_percentageABL = (float)_fs[whichPlayerString]["PercentageBL"]; 02295 this->m_percentageATL = (float)_fs[whichPlayerString]["PercentageTL"]; 02296 this->m_percentageATR = (float)_fs[whichPlayerString]["PercentageTR"]; 02297 this->m_percentageABR = (float)_fs[whichPlayerString]["PercentageBR"]; 02298 } 02299 else if(whichPlayerString == "PLAYERB") 02300 { 02301 this->m_percentageBBL = (float)_fs[whichPlayerString]["PercentageBL"]; 02302 this->m_percentageBTL = (float)_fs[whichPlayerString]["PercentageTL"]; 02303 this->m_percentageBTR = (float)_fs[whichPlayerString]["PercentageTR"]; 02304 this->m_percentageBBR = (float)_fs[whichPlayerString]["PercentageBR"]; 02305 } 02306 02307 02308 02309 cv::FileNode trajectoryNode = _fs[whichPlayerString]["InterpPtsMappedToRallies"]; // Read string sequence - Get node 02310 if (trajectoryNode.type() != cv::FileNode::SEQ) 02311 { 02312 std::cout << "Trajectory node not a sequence!\n"; 02313 } 02314 02315 cv::FileNodeIterator trajectoryNodeit = trajectoryNode.begin(), trajectoryNodeit_end = trajectoryNode.end(); // Go through the node 02316 for (; trajectoryNodeit != trajectoryNodeit_end; ++trajectoryNodeit) 02317 { 02318 if(whichPlayerString == "PLAYERA") 02319 { 02320 this->m_playerATrajectoryFromFile.push_back((float)*trajectoryNodeit); 02321 } 02322 else if(whichPlayerString == "PLAYERB") 02323 { 02324 this->m_playerBTrajectoryFromFile.push_back((float)*trajectoryNodeit); 02325 } 02326 } 02327 02328 02329 cv::FileNode htMapNode = _fs[whichPlayerString]["CubeDataVertices"]; // Read string sequence - Get node 02330 if (htMapNode.type() != cv::FileNode::SEQ) 02331 { 02332 std::cout << "HtMap node not a sequence!\n"; 02333 } 02334 02335 cv::FileNodeIterator htMapNodeit = htMapNode.begin(), htMapNodeit_end = htMapNode.end(); // Go through the node 02336 for (; htMapNodeit != htMapNodeit_end; ++htMapNodeit) 02337 { 02338 VertData tempData; 02339 tempData.nx = (float)*(htMapNodeit); 02340 tempData.ny = (float)*(++htMapNodeit); 02341 tempData.nz = (float)*(++htMapNodeit); 02342 02343 tempData.x = (float)*(++htMapNodeit); 02344 tempData.y = (float)*(++htMapNodeit); 02345 tempData.z = (float)*(++htMapNodeit); 02346 02347 if(whichPlayerString == "PLAYERA") 02348 { 02349 this->m_dataVertsA.push_back(tempData); 02350 } 02351 else if(whichPlayerString == "PLAYERB") 02352 { 02353 this->m_dataVertsB.push_back(tempData); 02354 } 02355 } 02356 02357 02358 cv::FileNode n6 = _fs[whichPlayerString]["SpeedData"]; // Read string sequence - Get node 02359 if (n6.type() != cv::FileNode::SEQ) 02360 { 02361 std::cout << "SpeedData not a sequence!\n"; 02362 } 02363 02364 cv::FileNodeIterator it6 = n6.begin(), it6_end = n6.end(); // Go through the node 02365 for (; it6 != it6_end; ++it6) 02366 { 02367 if(whichPlayerString == "PLAYERA") 02368 { 02369 this->m_speedAData.push_back((float)*it6); 02370 } 02371 else if(whichPlayerString == "PLAYERB") 02372 { 02373 this->m_speedBData.push_back((float)*it6); 02374 } 02375 } 02376 02377 02378 cv::FileNode impactPt3DNode = _fs[whichPlayerString]["PlayerImpactPointsIn3D"]; // Read string sequence - Get node 02379 if (impactPt3DNode.type() != cv::FileNode::SEQ) 02380 { 02381 std::cout << "PlayerImpactPointsIn3D node not a sequence!\n"; 02382 } 02383 02384 cv::FileNodeIterator impactPt3DNodeit = impactPt3DNode.begin(), impactPt3DNodeit_end = impactPt3DNode.end(); // Go through the node 02385 for (; impactPt3DNodeit != impactPt3DNodeit_end; ++impactPt3DNodeit) 02386 { 02387 cv::Point3f tempPoint3D((float)*(impactPt3DNodeit), (float)*(++impactPt3DNodeit), (float)*(++impactPt3DNodeit)); 02388 02389 if(whichPlayerString == "PLAYERA") 02390 { 02391 this->m_playerAImpactPtsAllRalliesIn3D.push_back(tempPoint3D); 02392 } 02393 else if(whichPlayerString == "PLAYERB") 02394 { 02395 this->m_playerBImpactPtsAllRalliesIn3D.push_back(tempPoint3D); 02396 } 02397 } 02398 02399 02400 cv::FileNode n7 = _fs[whichPlayerString]["RPMData"]; // Read string sequence - Get node 02401 if (n7.type() != cv::FileNode::SEQ) 02402 { 02403 std::cout << "RPMData not a sequence!\n"; 02404 } 02405 02406 cv::FileNodeIterator it7 = n7.begin(), it7_end = n7.end(); // Go through the node 02407 for (; it7 != it7_end; ++it7) 02408 { 02409 if(whichPlayerString == "PLAYERA") 02410 { 02411 this->m_playerARPM.push_back((float)*it7); 02412 } 02413 else if(whichPlayerString == "PLAYERB") 02414 { 02415 this->m_playerBRPM.push_back((float)*it7); 02416 } 02417 02418 } 02419 } 02420 02421 void StatsVisualization::drawCrowd(const std::string& _inputPlaneName) 02422 { 02423 02424 ngl::ShaderLib *shader=ngl::ShaderLib::instance(); 02425 (*shader)["TextureShaderStats"]->use(); 02426 // need to bind the active texture before drawing 02427 glBindTexture(GL_TEXTURE_2D,m_crowdTextureName); 02428 //glPolygonMode(GL_FRONT_AND_BACK,GL_FILL); 02429 02430 ngl::VAOPrimitives *prim = ngl::VAOPrimitives::instance(); 02431 02432 ngl::Real positionX,positionZ; 02433 positionX = positionZ = 0.0; 02434 02435 if(_inputPlaneName == "heightMapPlane") 02436 { 02437 positionX = (m_fieldOfPlay.width/2);// + 300.0; 02438 positionZ = (m_fieldOfPlay.width/2) - 10; //285.0; 02439 } 02440 else if(_inputPlaneName == "trajectoryPlane") 02441 { 02442 positionX = m_finalCourtWidthWorld + 3.0; 02443 positionZ = m_finalCourtWidthWorld + 3.0; 02444 } 02445 else if((_inputPlaneName == "speedPlane") || (_inputPlaneName == "rpmPlane")) 02446 { 02447 positionX = (m_finalCourtWidthWorld * 10) + 30.0; 02448 positionZ = (m_finalCourtWidthWorld * 10) + 30.0; 02449 } 02450 // rt 02451 m_transformStack.pushTransform(); 02452 { 02453 m_transformStack.setScale(10,10,10); 02454 m_transformStack.setRotation(0,90,90); 02455 m_transformStack.setPosition(positionX,0,0); 02456 02457 loadMatricesToTextureShader(); 02458 prim->draw(_inputPlaneName); 02459 } 02460 m_transformStack.popTransform(); 02461 02462 02463 02464 // lt 02465 m_transformStack.pushTransform(); 02466 { 02467 m_transformStack.setScale(10,10,10); 02468 m_transformStack.setRotation(0,90,90); 02469 m_transformStack.setPosition(-(positionX),0,0); 02470 02471 02472 loadMatricesToTextureShader(); 02473 prim->draw(_inputPlaneName); 02474 } 02475 m_transformStack.popTransform(); 02476 02477 02478 02479 // far 02480 m_transformStack.pushTransform(); 02481 { 02482 m_transformStack.setScale(10,10,10); 02483 m_transformStack.setRotation(-90,0,0); 02484 m_transformStack.setPosition(0,0,positionZ); 02485 02486 02487 loadMatricesToTextureShader(); 02488 prim->draw(_inputPlaneName); 02489 } 02490 m_transformStack.popTransform(); 02491 02492 02493 02494 // back 02495 m_transformStack.pushTransform(); 02496 { 02497 m_transformStack.setScale(10,10,10); 02498 m_transformStack.setRotation(-90,0,0); 02499 m_transformStack.setPosition(0,0,-(positionZ)); 02500 02501 02502 loadMatricesToTextureShader(); 02503 prim->draw(_inputPlaneName); 02504 } 02505 m_transformStack.popTransform(); 02506 02507 02508 02509 } 02510 02511 void StatsVisualization::drawTable(const std::string& _inputTableName) 02512 { 02513 ngl::ShaderLib *shader=ngl::ShaderLib::instance(); 02514 (*shader)["TextureShaderStats"]->use(); 02515 ngl::VAOPrimitives *prim = ngl::VAOPrimitives::instance(); 02516 02517 ngl::Real positionY = 0.0; 02518 02519 if((_inputTableName == "speedPlane") || (_inputTableName == "rpmPlane")) 02520 { 02521 positionY = -0.08; 02522 } 02523 else 02524 { 02525 positionY = 0.0; 02526 } 02527 m_transformStack.pushTransform(); 02528 { 02529 m_transformStack.setPosition(0,positionY,0); 02530 glBindTexture(GL_TEXTURE_2D,m_tableTextureName); 02531 loadMatricesToTextureShader(); 02532 prim->draw(_inputTableName); 02533 } 02534 m_transformStack.popTransform(); 02535 02536 } 02537 02538 void StatsVisualization::drawContainingGridScaleXY() 02539 { 02540 ngl::ShaderLib *shader=ngl::ShaderLib::instance(); 02541 (*shader)["TextureShaderStats"]->use(); 02542 // need to bind the active texture before drawing 02543 glBindTexture(GL_TEXTURE_2D,m_gridXYHtMap); 02544 //glPolygonMode(GL_FRONT_AND_BACK,GL_FILL); 02545 02546 ngl::VAOPrimitives *prim = ngl::VAOPrimitives::instance(); 02547 ngl::Real positionX,positionZ,positionY; 02548 positionX = positionZ = positionY = 0; 02549 02550 // we will create separate planes and spheres for various statistics instead of 02551 // trying to scale them each time as we have different units of scaling and 02552 // those scale factors are calculated at various times 02553 // and this is much easier than that even though it takes quite a bit of memory 02554 if(m_whichStat == IMPACT_HEIGHT_MAP_VIEW) 02555 { 02556 prim->createTrianglePlane("xygridrtplane",m_fieldOfPlay.height/10.0,20,1,1,ngl::Vec3(0,1,0)); 02557 prim->createTrianglePlane("xygridfarplane",m_fieldOfPlay.width/10.0,20,1,1,ngl::Vec3(0,1,0)); 02558 positionX = -(m_fieldOfPlay.width/20.0); 02559 positionY = 10; 02560 positionZ = -(m_fieldOfPlay.height/20.0); 02561 } 02562 else if(m_whichStat == TRAJECTORY_VIEW) 02563 { 02564 prim->createTrianglePlane("xygridrtplane",m_finalCourtDepthWorld,0.5,1,1,ngl::Vec3(0,1,0)); 02565 prim->createTrianglePlane("xygridfarplane",m_finalCourtWidthWorld,0.5,1,1,ngl::Vec3(0,1,0)); 02566 positionX = -(m_finalCourtWidthWorld/2.0); 02567 positionY = 0.25; 02568 positionZ = -(m_finalCourtDepthWorld/2.0); 02569 } 02570 02571 02572 // rt 02573 m_transformStack.pushTransform(); 02574 { 02575 //m_transformStack.setScale(m_fieldOfPlay.width,20,0); 02576 m_transformStack.setRotation(0,90,-270); 02577 m_transformStack.setPosition(positionX,positionY,0); 02578 loadMatricesToTextureShader(); 02579 prim->draw("xygridrtplane"); 02580 02581 } 02582 m_transformStack.popTransform(); 02583 02584 02585 02586 // far 02587 m_transformStack.pushTransform(); 02588 { 02589 //m_transformStack.setScale(m_fieldOfPlay.width,20,0); 02590 m_transformStack.setRotation(-90,0,0); 02591 m_transformStack.setPosition(0,positionY,positionZ); 02592 loadMatricesToTextureShader(); 02593 prim->draw("xygridfarplane"); 02594 02595 } 02596 m_transformStack.popTransform(); 02597 02598 02599 } 02600 02601 void StatsVisualization::renderPercentages() 02602 { 02603 02604 QString text; 02605 02606 float bottomLeftPosX = m_midTopX - (m_fieldOfPlay.width/4); 02607 float bottomLeftPosY = m_midTopY + (m_fieldOfPlay.height/2); 02608 02609 float topLeftPosX = m_midTopX - (m_fieldOfPlay.width/4); 02610 float topLeftPosY = m_midTopY + (m_fieldOfPlay.height/4); 02611 02612 float topRightPosX = m_midTopX + (m_fieldOfPlay.width/8); 02613 float topRightPosY = m_midTopY + (m_fieldOfPlay.height/4); 02614 02615 float bottomRightPosX = m_midTopX + (m_fieldOfPlay.width/8); 02616 float bottomRightPosY = m_midTopY + (m_fieldOfPlay.height/2); 02617 02618 //m_text->setScreenSize(640,480); 02619 02620 switch(m_whichStat) 02621 { 02622 case IMPACT_PERCENTAGE_DISTRIBUTION_VIEW: 02623 { 02624 switch(m_whichPlayer) 02625 { 02626 case PLAYERA: 02627 { 02628 m_text->setColour(1,1,0); 02629 switch(m_whichQuad) 02630 { 02631 case BOTTOM_LEFT: 02632 { 02633 text.sprintf("%3.2f %%",m_percentageABL); 02634 m_text->renderText(bottomLeftPosX,bottomLeftPosY,text);//bl 02635 break; 02636 } 02637 case TOP_LEFT: 02638 { 02639 text.sprintf("%3.2f %%",m_percentageATL); 02640 m_text->renderText(topLeftPosX,topLeftPosY,text);//tl 02641 break; 02642 } 02643 case TOP_RIGHT: 02644 { 02645 text.sprintf("%3.2f %%",m_percentageATR); 02646 m_text->renderText(topRightPosX,topRightPosY,text);//tr 02647 break; 02648 } 02649 case BOTTOM_RIGHT: 02650 { 02651 text.sprintf("%3.2f %%",m_percentageABR); 02652 m_text->renderText(bottomRightPosX,bottomRightPosY,text);//br 02653 break; 02654 } 02655 case ALL: 02656 { 02657 text.sprintf("%3.2f %%",m_percentageABL); 02658 m_text->renderText(bottomLeftPosX,bottomLeftPosY,text);//bl 02659 02660 text.sprintf("%3.2f %%",m_percentageATL); 02661 m_text->renderText(topLeftPosX,topLeftPosY,text);//tl 02662 02663 text.sprintf("%3.2f %%",m_percentageATR); 02664 m_text->renderText(topRightPosX,topRightPosY,text);//tr 02665 02666 text.sprintf("%3.2f %%",m_percentageABR); 02667 m_text->renderText(bottomRightPosX,bottomRightPosY,text);//br 02668 02669 break; 02670 } 02671 02672 } 02673 break; 02674 } 02675 02676 case PLAYERB: 02677 { 02678 m_text->setColour(0,0,0); 02679 switch(m_whichQuad) 02680 { 02681 case BOTTOM_LEFT: 02682 { 02683 text.sprintf("%3.2f %%",m_percentageBBL); 02684 m_text->renderText(bottomLeftPosX,bottomLeftPosY,text);//bl 02685 break; 02686 } 02687 case TOP_LEFT: 02688 { 02689 text.sprintf("%3.2f %%",m_percentageBTL); 02690 m_text->renderText(topLeftPosX,topLeftPosY,text);//tl 02691 break; 02692 } 02693 case TOP_RIGHT: 02694 { 02695 text.sprintf("%3.2f %%",m_percentageBTR); 02696 m_text->renderText(topRightPosX,topRightPosY,text);//tr 02697 break; 02698 } 02699 case BOTTOM_RIGHT: 02700 { 02701 text.sprintf("%3.2f %%",m_percentageBBR); 02702 m_text->renderText(bottomRightPosX,bottomRightPosY,text);//br 02703 break; 02704 } 02705 case ALL: 02706 { 02707 text.sprintf("%3.2f %%",m_percentageBBL); 02708 m_text->renderText(bottomLeftPosX,bottomLeftPosY,text);//bl 02709 02710 text.sprintf("%3.2f %%",m_percentageBTL); 02711 m_text->renderText(topLeftPosX,topLeftPosY,text);//tl 02712 02713 text.sprintf("%3.2f %%",m_percentageBTR); 02714 m_text->renderText(topRightPosX,topRightPosY,text);//tr 02715 02716 text.sprintf("%3.2f %%",m_percentageBBR); 02717 m_text->renderText(bottomRightPosX,bottomRightPosY,text);//br 02718 break; 02719 } 02720 02721 } 02722 break; 02723 } 02724 case BOTH: 02725 { 02726 switch(m_whichQuad) 02727 { 02728 case BOTTOM_LEFT: 02729 { 02730 m_text->setColour(1,1,0); 02731 text.sprintf("(%3.0f / ",m_percentageABL); 02732 m_text->renderText(bottomLeftPosX - 80,bottomLeftPosY,text);//bl 02733 02734 m_text->setColour(0,0,0); 02735 text.sprintf("%3.0f)%%",m_percentageBBL); 02736 m_text->renderText(bottomLeftPosX + 10,bottomLeftPosY,text);//bl 02737 break; 02738 } 02739 case TOP_LEFT: 02740 { 02741 m_text->setColour(1,1,0); 02742 text.sprintf("(%3.0f / ",m_percentageATL); 02743 m_text->renderText(topLeftPosX - 80,topLeftPosY,text);//tl 02744 02745 m_text->setColour(0,0,0); 02746 text.sprintf("%3.0f)%%",m_percentageBTL); 02747 m_text->renderText(topLeftPosX + 10,topLeftPosY,text);//tl 02748 break; 02749 } 02750 case TOP_RIGHT: 02751 { 02752 m_text->setColour(1,1,0); 02753 text.sprintf("(%3.0f / ",m_percentageATR); 02754 m_text->renderText(topRightPosX - 60,topRightPosY,text);//tr 02755 02756 m_text->setColour(0,0,0); 02757 text.sprintf("%3.0f)%%",m_percentageBTR); 02758 m_text->renderText(topRightPosX + 30,topRightPosY,text);//tr 02759 02760 break; 02761 } 02762 case BOTTOM_RIGHT: 02763 { 02764 m_text->setColour(1,1,0); 02765 text.sprintf("(%3.0f / ",m_percentageABR); 02766 m_text->renderText(bottomRightPosX - 60,bottomRightPosY,text);//br 02767 02768 m_text->setColour(0,0,0); 02769 text.sprintf("%3.0f)%%",m_percentageBBR); 02770 m_text->renderText(bottomRightPosX + 30,bottomRightPosY,text);//br 02771 break; 02772 } 02773 case ALL: 02774 { 02775 m_text->setColour(1,1,0); 02776 text.sprintf("(%3.0f / ",m_percentageABL); 02777 m_text->renderText(bottomLeftPosX - 80,bottomLeftPosY,text);//bl 02778 m_text->setColour(0,0,0); 02779 text.sprintf("%3.0f)%%",m_percentageBBL); 02780 m_text->renderText(bottomLeftPosX + 10,bottomLeftPosY,text);//bl 02781 02782 m_text->setColour(1,1,0); 02783 text.sprintf("(%3.0f / ",m_percentageATL); 02784 m_text->renderText(topLeftPosX - 80,topLeftPosY,text);//tl 02785 m_text->setColour(0,0,0); 02786 text.sprintf("%3.0f)%%",m_percentageBTL); 02787 m_text->renderText(topLeftPosX + 10,topLeftPosY,text);//tl 02788 02789 m_text->setColour(1,1,0); 02790 text.sprintf("(%3.0f / ",m_percentageATR); 02791 m_text->renderText(topRightPosX - 60,topRightPosY,text);//tr 02792 m_text->setColour(0,0,0); 02793 text.sprintf("%3.0f)%%",m_percentageBTR); 02794 m_text->renderText(topRightPosX + 30,topRightPosY,text);//tr 02795 02796 m_text->setColour(1,1,0); 02797 text.sprintf("(%3.0f / ",m_percentageABR); 02798 m_text->renderText(bottomRightPosX - 60,bottomRightPosY,text);//br 02799 m_text->setColour(0,0,0); 02800 text.sprintf("%3.0f)%%",m_percentageBBR); 02801 m_text->renderText(bottomRightPosX + 30,bottomRightPosY,text);//br 02802 02803 break; 02804 } 02805 02806 } 02807 break; 02808 } 02809 02810 } 02811 break; 02812 } 02813 02814 default: 02815 break; 02816 } 02817 02818 // this has to be done at the end to avoid 3d stats rendering in black 02819 // ngl text has something which makes other shaders work only when ngl 02820 // text color is set to white before using other shaders 02821 m_text->setColour(1,1,1); 02822 } 02823 02824 //-------------------------------------------------- 02825 /* ALL MOUSE EVENTS SHOULD ONLY WORK IN 3D....so place the parentvar check before processing any mouse events*/ 02826 //-------------------------------------------------- 02827 02828 02829 //---------------------------------------------------------------------------------------------------------------------- 02830 void StatsVisualization::mouseMoveEvent ( 02831 QMouseEvent * _event 02832 ) 02833 { 02834 // note the method buttons() is the button state when event was called 02835 // this is different from button() which is used to check which button was 02836 // pressed when the mousePress/Release event is generated 02837 if(m_rotate && _event->buttons() == Qt::LeftButton) 02838 { 02839 int diffx=_event->x()-m_origX; 02840 int diffy=_event->y()-m_origY; 02841 m_spinXFace += (float) 0.5f * diffy; 02842 m_spinYFace += (float) 0.5f * diffx; 02843 m_origX = _event->x(); 02844 m_origY = _event->y(); 02845 updateGL(); 02846 02847 } 02848 // right mouse translate code 02849 else if(m_translate && _event->buttons() == Qt::RightButton) 02850 { 02851 int diffX = (int)(_event->x() - m_origXPos); 02852 int diffY = (int)(_event->y() - m_origYPos); 02853 m_origXPos=_event->x(); 02854 m_origYPos=_event->y(); 02855 m_modelPos.m_x += INCREMENT * diffX; 02856 m_modelPos.m_y -= INCREMENT * diffY; 02857 updateGL(); 02858 02859 } 02860 02861 } 02862 02863 02864 //---------------------------------------------------------------------------------------------------------------------- 02865 void StatsVisualization::mousePressEvent ( 02866 QMouseEvent * _event 02867 ) 02868 { 02869 // this method is called when the mouse button is pressed in this case we 02870 // store the value where the maouse was clicked (x,y) and set the Rotate flag to true 02871 if(_event->button() == Qt::LeftButton) 02872 { 02873 m_origX = _event->x(); 02874 m_origY = _event->y(); 02875 m_rotate =true; 02876 } 02877 // right mouse translate mode 02878 else if(_event->button() == Qt::RightButton) 02879 { 02880 m_origXPos = _event->x(); 02881 m_origYPos = _event->y(); 02882 m_translate=true; 02883 } 02884 02885 } 02886 02887 //---------------------------------------------------------------------------------------------------------------------- 02888 void StatsVisualization::mouseReleaseEvent ( 02889 QMouseEvent * _event 02890 ) 02891 { 02892 // this event is called when the mouse button is released 02893 // we then set Rotate to false 02894 if (_event->button() == Qt::LeftButton) 02895 { 02896 m_rotate=false; 02897 } 02898 // right mouse translate mode 02899 if (_event->button() == Qt::RightButton) 02900 { 02901 m_translate=false; 02902 } 02903 } 02904 02905 //---------------------------------------------------------------------------------------------------------------------- 02906 void StatsVisualization::wheelEvent(QWheelEvent *_event) 02907 { 02908 02909 // check the diff of the wheel position (0 means no change) 02910 if(_event->delta() > 0) 02911 { 02912 m_modelPos.m_z+=ZOOM; 02913 } 02914 else if(_event->delta() <0 ) 02915 { 02916 m_modelPos.m_z-=ZOOM; 02917 } 02918 updateGL(); 02919 } 02920 02921 02922 void StatsVisualization::legendWindow(GLuint _inputLegendName) 02923 { 02924 ngl::ShaderLib *shader=ngl::ShaderLib::instance(); 02925 (*shader)["TextureShaderStats"]->use(); 02926 // need to bind the active texture before drawing 02927 glBindTexture(GL_TEXTURE_2D,_inputLegendName); 02928 02929 ngl::Transformation trans; 02930 02931 // get the VBO instance and draw the built in teapot 02932 ngl::VAOPrimitives *prim=ngl::VAOPrimitives::instance(); 02933 02934 // we will create separate planes and spheres for various statistics instead of 02935 // trying to scale them each time as we have different units of scaling and 02936 // those scale factors are calculated at various times 02937 // and this is much easier than that even though it takes quite a bit of memory 02938 prim->createTrianglePlane("legendplane",0.8,0.8,1,1,ngl::Vec3(0,1,0)); 02939 02940 // first draw a top persp // front //side 02941 ngl::Vec3 from(0,2,0); 02942 ngl::Vec3 to(0,0,0); 02943 ngl::Vec3 up(0,0,-1); 02945 m_transformStack.pushTransform(); 02946 { 02947 from.set(0,0,2); 02948 up.set(0,1,0); 02949 m_view=ngl::lookAt(from,to,up); 02950 m_projection=ngl::ortho(-1,1,-1,1, 0.01f, 200.0f); 02951 02952 glViewport(10,10,m_legendWidth,m_legendHeight); 02953 //m_2DScreen->draw(); 02954 02955 m_transformStack.setGlobal(trans); 02956 m_transformStack.setRotation(90,180,180); 02957 m_transformStack.setPosition(0,0,0); 02958 //m_transformStack.setScale(m_legendWidth,m_legendHeight,0); 02959 //loadMatricesToTextureShader(); 02960 loadMatricesToLegendShader(); 02961 prim->draw("legendplane"); 02962 02963 } 02964 m_transformStack.popTransform(); 02965 02966 } 02967 02968 void StatsVisualization::loadMatricesToLegendShader() 02969 { 02970 ngl::ShaderLib *shader=ngl::ShaderLib::instance(); 02971 ngl::Mat4 MVP; 02972 ngl::Mat4 MV; 02973 ngl::Mat4 M; 02974 M=m_transformStack.getCurrAndGlobal().getMatrix(); 02975 MV= m_transformStack.getCurrAndGlobal().getMatrix()*m_view; 02976 MVP= M*m_view*m_projection; 02977 shader->setShaderParamFromMat4("MVP",MVP); 02978 shader->setUniform("textureFlag",true); 02979 02980 } 02981