void PaintMethods::paintEllipse(const DebugDrawing::Ellipse& element, QPainter& painter) { setBrush(element.fillStyle, element.fillColor, painter); setPen(element, painter); if(element.rotation != 0.0f) { QTransform trans(painter.transform()); QTransform transBack(painter.transform()); trans.translate(qreal(element.x), qreal(element.y)); trans.rotateRadians(qreal(element.rotation)); painter.setTransform(trans); painter.drawEllipse(-element.radiusX, -element.radiusY, 2 * element.radiusX, 2 * element.radiusY); painter.setTransform(transBack); } else { painter.drawEllipse(element.x - element.radiusX, element.y - element.radiusY, 2 * element.radiusX, 2 * element.radiusY); } }
void PaintMethods::paintRectangle(const DebugDrawing::Rectangle& element, QPainter& painter) { setBrush(element.fillStyle, element.fillColor, painter); setPen(element, painter); const QRect dRect(element.topLX, element.topLY, element.w, element.h); if(element.rotation != 0.0f) { const QPoint center = dRect.center(); QTransform trans(painter.transform()); QTransform transBack(painter.transform()); trans.translate(center.x(), center.y()); trans.rotateRadians(qreal(element.rotation)); painter.setTransform(trans); painter.drawRect(element.topLX - center.x(), element.topLY - center.y(), dRect.width(), dRect.height()); painter.setTransform(transBack); } else { painter.drawRect(dRect); } }
void PaintMethods::paintDebugDrawing(QPainter& painter, const DebugDrawing& debugDrawing, const QTransform& baseTrans) { static QBrush brush(Qt::SolidPattern); static QBrush noBrush(Qt::NoBrush); static QPen pen; static QPen noPen(Qt::NoPen); for(const DebugDrawing::Element* e = debugDrawing.getFirst(); e; e = debugDrawing.getNext(e)) switch(e->type) { case DebugDrawing::Element::POLYGON: { const DebugDrawing::Polygon& element = *(const DebugDrawing::Polygon*) e; // select brush if(element.fillStyle == Drawings::bs_solid) { brush.setColor(QColor(element.fillColor.r, element.fillColor.g, element.fillColor.b, element.fillColor.a)); painter.setBrush(brush); } else painter.setBrush(noBrush); // select pen if(element.penStyle != Drawings::ps_null) { pen.setColor(QColor(element.penColor.r, element.penColor.g, element.penColor.b, element.penColor.a)); // A line width of zero indicates a cosmetic pen. This means that the pen width is always drawn one pixel wide, independent of the transformation set on the painter. pen.setWidth(element.width); switch(element.penStyle) { case Drawings::ps_dash: pen.setStyle(Qt::DashLine); break; case Drawings::ps_dot: pen.setStyle(Qt::DotLine); break; case Drawings::ps_solid: default: pen.setStyle(Qt::SolidLine); } painter.setPen(pen); } else painter.setPen(noPen); // copy vector2 to QPoints static QPoint points[16]; for(int n = element.nCount - 1; n >= 0 ; --n) points[n] = QPoint(element.points[n].x, element.points[n].y); painter.drawPolygon(points, element.nCount); break; } case DebugDrawing::Element::GRID_RGBA: { const DebugDrawing::GridRGBA& element = *(const DebugDrawing::GridRGBA*) e; const int totalWidth(element.cellsX * element.cellSize); const int totalHeight(element.cellsY * element.cellSize); for(int y = 0; y < element.cellsY; ++y) { for(int x = 0; x < element.cellsX; ++x) { int startX(x * element.cellSize - totalWidth / 2); int startY(y * element.cellSize - totalHeight / 2); int c(y * element.cellsX + x); brush.setColor(QColor(element.cells[c].r, element.cells[c].g, element.cells[c].b, element.cells[c].a)); pen.setColor(QColor(element.cells[c].r, element.cells[c].g, element.cells[c].b, element.cells[c].a)); pen.setWidth(1); painter.setBrush(brush); painter.setPen(pen); painter.drawRect(startX, startY, element.cellSize - 1, element.cellSize - 1); } } break; } case DebugDrawing::Element::GRID_MONO: { const DebugDrawing::GridMono& element = *(const DebugDrawing::GridMono*) e; const int totalWidth(element.cellsX * element.cellSize); const int totalHeight(element.cellsY * element.cellSize); for(int y = 0; y < element.cellsY; ++y) { for(int x = 0; x < element.cellsX; ++x) { int startX(x * element.cellSize - totalWidth / 2); int startY(y * element.cellSize - totalHeight / 2); int c(y * element.cellsX + x); ColorRGBA col(element.baseColor * (1.0f - (static_cast<float>(element.cells[c]) / 255.0))); brush.setColor(QColor(col.r, col.g, col.b, element.baseColor.a)); pen.setColor(QColor(col.r, col.g, col.b, element.baseColor.a)); pen.setWidth(1); painter.setBrush(brush); painter.setPen(pen); painter.drawRect(startX, startY, element.cellSize - 1, element.cellSize - 1); } } break; } case DebugDrawing::Element::ELLIPSE: { const DebugDrawing::Ellipse& element = *(const DebugDrawing::Ellipse*) e; // select brush if(element.fillStyle == Drawings::bs_solid) { brush.setColor(QColor(element.fillColor.r, element.fillColor.g, element.fillColor.b, element.fillColor.a)); painter.setBrush(brush); } else painter.setBrush(noBrush); // select pen if(element.penStyle != Drawings::ps_null) { pen.setColor(QColor(element.penColor.r, element.penColor.g, element.penColor.b, element.penColor.a)); // A line width of zero indicates a cosmetic pen. This means that the pen width is always drawn one pixel wide, independent of the transformation set on the painter. pen.setWidth(element.width); switch(element.penStyle) { case Drawings::ps_dash: pen.setStyle(Qt::DashLine); break; case Drawings::ps_dot: pen.setStyle(Qt::DotLine); break; case Drawings::ps_solid: default: pen.setStyle(Qt::SolidLine); } painter.setPen(pen); } else painter.setPen(noPen); if(element.rotation != 0.0f) { QTransform trans(painter.transform()); QTransform transBack(painter.transform()); trans.translate(qreal(element.x), qreal(element.y)); trans.rotateRadians(qreal(element.rotation)); painter.setTransform(trans); painter.drawEllipse(-element.radiusX, -element.radiusY, 2 * element.radiusX, 2 * element.radiusY); painter.setTransform(transBack); } else { painter.drawEllipse(element.x - element.radiusX, element.y - element.radiusY, 2 * element.radiusX, 2 * element.radiusY); } break; } case DebugDrawing::Element::LINE: { const DebugDrawing::Line& element = *(const DebugDrawing::Line*) e; if(element.penStyle != Drawings::ps_null) { pen.setColor(QColor(element.penColor.r, element.penColor.g, element.penColor.b, element.penColor.a)); // A line width of zero indicates a cosmetic pen. This means that the pen width is always drawn one pixel wide, independent of the transformation set on the painter. pen.setWidth(element.width); switch(element.penStyle) { case Drawings::ps_dash: pen.setStyle(Qt::DashLine); break; case Drawings::ps_dot: pen.setStyle(Qt::DotLine); break; case Drawings::ps_solid: default: pen.setStyle(Qt::SolidLine); } painter.setPen(pen); painter.drawLine(element.xStart, element.yStart, element.xEnd, element.yEnd); } break; } case DebugDrawing::Element::ORIGIN: { const DebugDrawing::Origin& element = *(const DebugDrawing::Origin*) e; QTransform trans(baseTrans); trans.translate(qreal(element.x), qreal(element.y)); trans.rotateRadians(qreal(element.angle)); painter.setTransform(trans); break; } case DebugDrawing::Element::TEXT: { const DebugDrawing::Text& element = *(const DebugDrawing::Text*) e; pen.setColor(QColor(element.penColor.r, element.penColor.g, element.penColor.b, element.penColor.a)); painter.setPen(pen); QTransform trans(painter.transform()); const QPoint& pos(trans.map(QPoint(element.x, element.y))); painter.resetTransform(); painter.drawText(pos, (const char*)(&element + 1)); painter.setTransform(trans); break; } default: break; } }
void NewXZRotExperimentHCI::update(const std::vector<MinVR::EventRef> &events){ //later to be pass into closestTouchPair function glm::dvec3 pos1; glm::dvec3 pos2; double minDistance = DBL_MAX; MinVR::TimeStamp timestamp; //boolean flags bool xzTrans = false; glm::dmat4 xzTransMat = dmat4(0.0); bool yTrans = false; glm::dmat4 yTransMat = dmat4(0.0); bool yRotScale = false; numTouchForHand1 = 0; numTouchForHand2 = 0; //only update the map and other variables first for(int p = 0; p < events.size(); p++) { timestamp = events[p]->getTimestamp(); std::string name = events[p]->getName(); int id = events[p]->getId(); if (boost::algorithm::starts_with(name, "TUIO_Cursor_up")) { //delete the cursor down associated with this up event std::map<int, TouchDataRef>::iterator it = registeredTouchData.find(id); if (it != registeredTouchData.end()) { // if id is found registeredTouchData.erase(it); //erase value associate with that it //std::cout << "UP" <<std::endl; } else { std::cout<<"ERROR: Received touch up for a cursor not in the registered touch data!"<<std::endl; std::cout << events[p]->toString() << std::endl; for (auto iter = registeredTouchData.begin(); iter != registeredTouchData.end(); iter++) { std::cout << "\t" << iter->second->toString() << std::endl; } } } else if (boost::algorithm::starts_with(name, "TUIO_Cursor_down")) { // always add a new one on DOWN glm::dvec3 roomCoord = convertScreenToRoomCoordinates(events[p]->get2DData()); TouchDataRef datum(new TouchData(events[p], roomCoord)); registeredTouchData.insert(std::pair<int, TouchDataRef>(id, datum)); //std::cout << "DOWN " << glm::to_string(events[p]->get2DData()) <<std::endl; } else if (boost::algorithm::starts_with(name, "TUIO_CursorMove")) { //update the map with the move event // if the corresponding id was down, make it a move event std::map<int, TouchDataRef>::iterator it = registeredTouchData.find(id); //std::cout << "Move " << events[p]->getId() <<std::endl; if (it != registeredTouchData.end()) { // if id is found glm::dvec2 screenCoord (events[p]->get4DData()); glm::dvec3 roomCoord = convertScreenToRoomCoordinates(glm::dvec2(events[p]->get4DData())); // update map it->second->setCurrentEvent(events[p]); it->second->setCurrRoomPos(roomCoord); } } // end of TUIO events // Update hand positions if (name == "Hand_Tracker1") { //std::cout << "Inside hand tracking 1 event (xz) " << std::endl; //only enter one time to init prevHandPos1 if (prevHandPos1.y == -1.0) { glm::dvec3 currHandPos1 (events[p]->getCoordinateFrameData()[3]); prevHandPos1 = currHandPos1; initRoomPos = true; } else { //std::cout << "updating hand 1 curr and prev position " << std::endl; prevHandPos1 = currHandPos1; currHandPos1 = glm::dvec3(events[p]->getCoordinateFrameData()[3]); } } //std::cout<<"currHandPos1: "<<glm::to_string(currHandPos1)<<std::endl; //std::cout<<"prevHandPos1: "<<glm::to_string(prevHandPos1)<<std::endl; if(name == "Hand_Tracker2") { //std::cout << "Inside hand tracking 2 event (xz) " << std::endl; if (prevHandPos2.y == -1.0) { glm::dvec3 currHandPos2 (events[p]->getCoordinateFrameData()[3]); prevHandPos2 = currHandPos2; } else { //std::cout << "updating hand 2 curr and prev position " << std::endl; prevHandPos2 = currHandPos2; currHandPos2 = glm::dvec3(events[p]->getCoordinateFrameData()[3]); } } } // end of data-updating for loop // give feedback object the touch data so //it can draw touch positions feedback->registeredTouchData = registeredTouchData; // At this point, the touch data should be updated, and hand positions std::map<int, TouchDataRef>::iterator iter; for (iter = registeredTouchData.begin(); iter != registeredTouchData.end(); iter++) { glm::dvec3 currRoomPos (iter->second->getCurrRoomPos()); bool belongsToHand1 = (glm::length(currHandPos1 - currRoomPos) < glm::length(currHandPos2 - currRoomPos)); if (belongsToHand1) { numTouchForHand1++; if(iter->second->getBelongTo() == -1){ iter->second->setBelongTo(1); } } else { // belongs to hand 2 numTouchForHand2++; if(iter->second->getBelongTo() == -1){ iter->second->setBelongTo(2); } } } // end touch enumeration //from TUIO move //std::cout << "Touch size: " << registeredTouchData.size() << std::endl; //find closest pair of TouchPoints if (registeredTouchData.size() > 1) { closestTouchPair(registeredTouchData , pos1, pos2, minDistance); //std::cout << "Min distance: " << minDistance << std::endl; } if (minDistance < 0.06 && currHandPos1 != prevHandPos1) { xzRotFlag = true; //std::cout << "Inside XZRot Mode" << std::endl; } if (xzRotFlag && liftedFingers) { // might have to be xzRotFlag and not any other flag feedback->displayText = "rotating"; if(initRoomPos){ // pos1 and pos2 are where you put your fingers down. We're finding the centroid //to calculate the box boundary for xzRotMode initRoomTouchCentre = 0.5*(pos1 + pos2); initRoomPos = false; } // try to change around center of origin glm::dvec3 centOfRot (glm::dvec3((glm::column(cFrameMgr->getVirtualToRoomSpaceFrame(), 3)))); //calculate the current handToTouch vector if(registeredTouchData.size() > 1 && !centerRotMode) { roomTouchCentre = 0.5*(pos1 + pos2); } //std::cout << "Touch Center: " << glm::to_string(roomTouchCentre) << std::endl; //Should not be equal in XZRotMode but just in case. //for choosing the hand that rotates /*std::cout<<"currHandPos1: "<<glm::to_string(currHandPos1)<<std::endl;*/ if (numTouchForHand1 >= numTouchForHand2) { //std::cout << "Using right hand: " << std::endl; if (roomTouchCentre - currHandPos1 != glm::dvec3(0.0)) {//zero guard currHandToTouch = roomTouchCentre - currHandPos1; } if (roomTouchCentre - prevHandPos1 != glm::dvec3(0.0)) {//zero guard prevHandToTouch = roomTouchCentre - prevHandPos1; } } else { //std::cout << "Using Left hand: " << std::endl; if (roomTouchCentre - currHandPos2 != glm::dvec3(0.0)) { //zero guard currHandToTouch = roomTouchCentre - currHandPos2; } if (roomTouchCentre - prevHandPos2 != glm::dvec3(0.0)) { //zero guard prevHandToTouch = roomTouchCentre - prevHandPos2; } } //set up the 2 vertices for a square boundry for the gesture glm::dvec3 upRight = glm::dvec3(initRoomTouchCentre.x+0.2, 0.0, initRoomTouchCentre.z+0.2); glm::dvec3 lowLeft = glm::dvec3(initRoomTouchCentre.x-0.2, 0.0, initRoomTouchCentre.z-0.2); //this if-else block for setting xzRotFlag, //also for grabbing xzCentOfRot if(registeredTouchData.size() == 0) { //if no touch on screen then automatically exit the xzrot mode xzRotFlag = false; initRoomPos = true; liftedFingers = true; feedback->displayText = ""; feedback->centOfRot.x = DBL_MAX; //std::cout<<"no touchyyy so I quit"<<std::endl; } else { //if there are touch(s) then check if the touch is in bound of the rectangle bool setxzRotFlag = true; std::map<int, TouchDataRef>::iterator iter; int countFingers = 0; for (iter = registeredTouchData.begin(); iter != registeredTouchData.end(); iter++) { // not exactly sure why roomPos. > upRight.z , I think it should be <. but that doesn't work if(!(iter->second->getCurrRoomPos().x > upRight.x || iter->second->getCurrRoomPos().z > upRight.z ||iter->second->getCurrRoomPos().x < lowLeft.x ||iter->second->getCurrRoomPos().z < lowLeft.z)){ //you are in the box //std::cout << "fingers in bound so STILL IN XZRot Mode" << std::endl; setxzRotFlag = false; countFingers += 1; } //else{ // touch point not in box, assume as center of rotation // centOfRot = iter->second->getCurrRoomPos(); // centerRotMode = true; // //std::cout << "Cent of Rot set" << std::endl; // feedback->centOfRot = centOfRot; //} // only tries to change the xzRotFlag at the end of the data in the map if(iter == std::prev(registeredTouchData.end(),1) && setxzRotFlag) { xzRotFlag = false; initRoomPos = true; feedback->displayText = ""; feedback->centOfRot.x = DBL_MAX; //std::cout << "all fingers went out of bound so Out of XZRot Mode" << std::endl; // found bug where person just drags their fingers across the table, and it reinitiates xzRotMode liftedFingers = false; } } // end for loop over registeredTouchData if(countFingers == registeredTouchData.size()){//all fingers in bound centerRotMode = false; feedback->centOfRot.x = DBL_MAX; } } // end if/else block //std::cout<<"currHandToTouch: "<<glm::to_string(currHandToTouch)<<std::endl; //std::cout<<"prevHandToTouch: "<<glm::to_string(prevHandToTouch)<<std::endl; //std::cout<<"dot product of them: "<< glm::to_string(glm::dot(glm::normalize(currHandToTouch), glm::normalize(prevHandToTouch))) << std::endl; //std::cout<<"what we clamping: "<<glm::clamp(glm::dot(currHandToTouch, prevHandToTouch),-1.0,1.0)<<std::endl; double alpha = glm::acos(glm::clamp(glm::dot(glm::normalize(currHandToTouch), glm::normalize(prevHandToTouch)),-1.0,1.0)); // from 0 to pi //std::cout<<"alpha: " << alpha << std::endl; // get cross prod glm::dvec3 cross = glm::normalize(glm::cross(currHandToTouch, prevHandToTouch)); //std::cout<<"cross: "<<glm::to_string(cross)<<std::endl; glm::dvec3 projCross = glm::normalize(glm::dvec3(cross.x, 0.0, cross.z)); // projection //std::cout<<"projcross: "<<glm::to_string(projCross)<<std::endl; // project cross prod onto the screen, get a length double lengthOfProjection = glm::dot(cross, projCross); //std::cout<<"lengthOfProjection: "<<glm::to_string(lengthOfProjection)<<std::endl; // projected cross prod //glm::dvec3 projectedCrossProd = lengthOfProjection * normProjCross; //std::cout<<"lengthOfProjection: "<<lengthOfProjection<<std::endl; //std::cout<<"alpha in degree before times lengthofprojection: "<<glm::degrees(alpha)<<std::endl; alpha = alpha * lengthOfProjection; //std::cout<<"alpha in degree after: "<<glm::degrees(alpha)<<std::endl; //std::cout<<"normProjCross: "<<glm::to_string(normProjCross)<<std::endl; glm::dmat4 XZRotMat = glm::rotate(glm::dmat4(1.0), glm::degrees(alpha) /* * 2.0 */, glm::normalize(projCross)); // have translations when we have a touch point not in the bounding box // translate to origin glm::dmat4 transMat(glm::translate(glm::dmat4(1.0), -1.0*centOfRot)); //translate back glm::dmat4 transBack(glm::translate(glm::dmat4(1.0), centOfRot)); //put it into the matrix stack //std::cout<<"XZRotMat: "<<glm::to_string(XZRotMat) <<std::endl; cFrameMgr->setRoomToVirtualSpaceFrame(cFrameMgr->getRoomToVirtualSpaceFrame() * transBack * XZRotMat * transMat); } // end xzRot Gesture if(registeredTouchData.size() == 0) { feedback->displayText = ""; liftedFingers = true; } //this is bret's commented out line //updateHandPos(events); }
void NewAnchoredExperimentHCI::yRotationAndScale(TouchDataRef centOfRotData, TouchDataRef roomCoordData) { // have to do calculations, switching between both touch points // translate to origin glm::dmat4 transMat(glm::translate(glm::dmat4(1.0), -1.0*centOfRotData->getCurrRoomPos())); glm::dmat4 rotMat = glm::dmat4(1.0); glm::dmat4 scaleMat = glm::dmat4(1.0); // movement of touch point is above threshold if(glm::abs(glm::length(roomCoordData->getPrevRoomPos()) - glm::length(roomCoordData->getCurrRoomPos())) > THRESH) { //std::cout<<"using the filtered pos in rotate and scale"<<std::endl; // rotate //// 0 vector guard glm::dvec3 prevDiffBetweenTwoPoints; if (glm::length(roomCoordData->getPrevRoomPos() - centOfRotData->getCurrRoomPos()) > 0.0) { prevDiffBetweenTwoPoints = glm::normalize(roomCoordData->getPrevRoomPos() - centOfRotData->getCurrRoomPos()); // "it" is the current thing through the for loop below } //// 0 vector guard glm::dvec3 currDiffBetweenTwoPoints; if (glm::length(roomCoordData->getCurrRoomPos() - centOfRotData->getCurrRoomPos()) > 0.0) { currDiffBetweenTwoPoints = glm::normalize(roomCoordData->getCurrRoomPos() - centOfRotData->getCurrRoomPos()); } // both distances are normalized glm::dvec3 crossProd = glm::cross(prevDiffBetweenTwoPoints,currDiffBetweenTwoPoints); double theta = glm::acos(glm::dot(prevDiffBetweenTwoPoints,currDiffBetweenTwoPoints)); if(crossProd.y < 0){ theta = -theta; } //std::cout << "Rotation Angle Theta: " << theta << std::endl; // glm::rotate takes degrees! Madness. rotMat = glm::rotate(glm::dmat4(1.0) , glm::degrees(-theta), glm::dvec3(0.0, 1.0, 0.0)); // scale double prevDistanceDiff = glm::length(roomCoordData->getPrevRoomPos() - centOfRotData->getCurrRoomPos()); double currDistanceDiff = glm::length(roomCoordData->getCurrRoomPos() - centOfRotData->getCurrRoomPos()); //std::cout << prevDistanceDiff/currDistanceDiff << std::endl; // might move this into a more general function // to test for crazy input /*if (glm::dvec3(prevDistanceDiff/currDistanceDiff)) { }*/ glm::dvec3 scaleBy = glm::dvec3(prevDistanceDiff/currDistanceDiff); scaleMat = glm::scale( glm::dmat4(1.0), scaleBy); } // translate back glm::dmat4 transBack(glm::translate(glm::dmat4(1.0), centOfRotData->getCurrRoomPos())); // combine transforms glm::dmat4 yRotScaleMat = cFrameMgr->getRoomToVirtualSpaceFrame() * transBack * scaleMat *rotMat * transMat; cFrameMgr->setRoomToVirtualSpaceFrame(yRotScaleMat); }