PDA

View Full Version : diagram scene example - intersection test



sajis997
23rd August 2011, 20:26
Hello forum,

I believe almost everyone in the forum have gone through the diagramscene example that comes along with in the Qt Demo.

I have included a new shape - ellipse in the editor. And i need some hint on how to do the intersection test while rendering the arrow head in the paint(....) function in arrow.cpp



Any hint would be very helpful .


Regards
Sajjad

sajis997
24th August 2011, 09:08
Hello,

Sorry forum, i believe that my previous post was very confusing. Let me elaborate again. I would like to draw the arrow between two nodes. The diagram scene example already is drawing the arrow between two QGraphicsPolygonItem. I included a new shape in the editor of type QGraphicsItem and i want to be able to draw arrow and arrow-heads between two nodes.


From the source i see that while drawing the arrow between the two QGraphicsPolygonItem, intersection test has been performed. How i do the intersection test if the want to draw the arrow between the two nodes. I think those intersection functions are ony avialable for the polygon types.


Any suggestion will be very helpful.



Regards
Sajjad

Rachol
24th August 2011, 09:46
If I were you, I would write my own function to check the interception point by reffering to following page:
http://mathworld.wolfram.com/Ellipse-LineIntersection.html

sajis997
26th August 2011, 13:48
Thanks for the suggestion,

In that case i think i have to over-ride the function the bool QGraphicsItem::collidesWithItem(...).

I need some example where this function has been over-ridden.


Could you please refer me to any examples ?



Regards
Sajjad

norobro
26th August 2011, 21:35
I think those intersection functions are ony avialable for the polygon types.Looks to me like you could use QGraphicsEllipseItem::shape().toFillPolygon() without changing the intersection code.

sajis997
28th August 2011, 12:19
Hi

I have created the node as a subclass of the QGraphicsItem as follows:



class Node : public QGraphicsItem
{

}




And inside this class i have implemented the shape() function. So in that case i do not have to over-ride the collission detection function, right?

Now if you take a look at the diagramscene example where the line and arrow head is added to the polygon items based on the intersection test.


I want to do the same thing on the customized item i have created. I would like to have some hint on doing it.

norobro
28th August 2011, 12:55
No need to subclass. For an ellipse try this:

diagramitem.h

enum DiagramType { Step, Conditional, StartEnd, Io, Ellipse };
diagramitem.cpp

case Ellipse:
{
QGraphicsEllipseItem item(-100,-50,200,100);
myPolygon = item.shape().toFillPolygon();
break;
}
mainwindow::createToolBox()

layout->addWidget(createCellWidget(tr("Ellipse"),DiagramItem::Ellipse), 2, 0);

sajis997
13th September 2011, 01:14
Hello forum,

Thanks for the useful hints.

Now in the example diagramscene example the arrow between the diagramitems is only drawn when the the line tool button is enabled.


If i want to draw the arrow only when the mouse is moved while Ctrl key is pressed down, what are the issues i have to look into.?

1. I am confused about tracking the mouse event position in side the mouseMoveEvent() function. To draw the line i need to different position. The mouse move event with the Ctrl modifier i get the starting position of the line. and the line ends when the Ctrl modifer is released. Do i have to consider the keyReleaseEvent() as well?


Please provide me with some suggestion here as well.


Regards
Sajjad

norobro
13th September 2011, 04:02
Try using QGraphicsSceneMouseEvent::modifiers() in DiagramScene::mousePressEvent() and modify "myMode"

sajis997
13th September 2011, 11:38
Hello norobro,

I have tried with the following code snippet inside the mouseMoveEvent() of diagramscne. I have appended another else if as follows:




else if(mouseEvent->modifiers() == Qt::CTRL /* && line == 0 */)
{

std::cout << "Insert line mode to insert the line and moving mode" << std::endl;

//create a new line item with the mouse event
line = new QGraphicsLineItem(QLineF(mouseEvent->scenePos(),
mouseEvent->scenePos()));

//set the line color
line->setPen(QPen(myLineColor, 2));

//add the line item
addItem(line);
}




I am having the following output:

1. When i hold down the Ctrl button while the mouse is moving, , i do get inside the condition but no line is drawn.



Any more hint?


Regards
Sajjad

norobro
13th September 2011, 14:07
Hi Sajjad,

Try this:
void DiagramScene::mousePressEvent(QGraphicsSceneMouseE vent *mouseEvent)
{
if (mouseEvent->button() != Qt::LeftButton)
return;

if(mouseEvent->modifiers()==Qt::ControlModifier ) myMode = InsertLine; // add this line
You might want to save the original mode and reset "myMode" in mouseReleaseEvent(). Don't know if there are any side effects.

HTH

sajis997
14th September 2011, 12:16
Hello

1. Does the following function setMouseTracking(true) has any effect on the mouseMoveEvent() to sub-class of the QGraphicsScene. I think you cannot even call this function inside the definition of the constructor. So in this case mouseMoveEvent() should only be captured only when the mouse button(left) is down while the mouse is moving. I have overriden the mouseMoveEvent(..) for the customized QGraphicsScene class and i do not need to press the left mouse button down while moving the mouse. I think it is strange. The code snippet is as follows:






void DiagramScene::mouseMoveEvent(QGraphicsSceneMouseEv ent *mouseEvent)
{

//std::cout << "Mouse with the ctrl modifiers in the scene " << std::endl;

if (myMode == InsertLine && line != 0)
{
std::cout << "Insert line mode to insert the line in the move event" << std::endl;

QLineF newLine(line->line().p1(), mouseEvent->scenePos());
line->setLine(newLine);
}
else if(mouseEvent->modifiers() == Qt::ControlModifier /* && line == 0 */)
{
myMode = InsertLine;
// std::cout << "Insert line mode to insert the line and moving mode" << std::endl;

//create a new line item with the mouse event
line = new QGraphicsLineItem(QLineF(mouseEvent->scenePos(),
mouseEvent->scenePos()));

//set the line color
line->setPen(QPen(myLineColor, 2));

//add the line item
addItem(line);

std::cout << "Line addead while the Ctrl is down" << std::endl;
}
else if (myMode == MoveItem)
{
//std::cout << "Mouse with the ctrl modifiers in the scene " << std::endl;
QGraphicsScene::mouseMoveEvent(mouseEvent);
}
}

sajis997
14th September 2011, 17:48
Hello forum,

I think i am close to what i wanted with the existing diagramscene example. Let me explain it briefly again:

1. With the existing diagramscene example we can connect two diagram item with an arrow only when the InsertLine mode is enabled and with the mouse press event.

I wanted to add something more to it.

1. I should be able to do this with mouse move event with the Ctrl modifier. And to get it done i have made the following changes:

1.1. Inside the mouseMoveEvent of diagramscene i have added the following condition:





else if(mouseEvent->modifiers() == Qt::ControlModifier && line == 0 )
{
myMode = InsertLine;


//create a new line item with the mouse event
line = new QGraphicsLineItem(QLineF(mouseEvent->scenePos(),
mouseEvent->scenePos()));

//set the line color
line->setPen(QPen(myLineColor, 2));

//add the line item
addItem(line);



1.2. I have added a keyReleaseEvent() as follows:




void DiagramScene::keyReleaseEvent(QKeyEvent *event)
{
if(event->key() == Qt::Key_Control)
{

if(myMode == InsertLine)
{
QList<QGraphicsItem *> startItems = items(line->line().p1());

if (startItems.count() && startItems.first() == line)
startItems.removeFirst();

QList<QGraphicsItem *> endItems = items(line->line().p2());
if (endItems.count() && endItems.first() == line)
endItems.removeFirst();

removeItem(line);
delete line;


if (startItems.count() > 0 && endItems.count() > 0 &&
startItems.first()->type() == DiagramItem::Type &&
endItems.first()->type() == DiagramItem::Type &&
startItems.first() != endItems.first())
{
DiagramItem *startItem =
qgraphicsitem_cast<DiagramItem *>(startItems.first());
DiagramItem *endItem =
qgraphicsitem_cast<DiagramItem *>(endItems.first());
Arrow *arrow = new Arrow(startItem, endItem);
arrow->setColor(myLineColor);
startItem->addArrow(arrow);
endItem->addArrow(arrow);
arrow->setZValue(-1000.0);
addItem(arrow);
arrow->updatePosition();
}

myMode = MoveItem;
}
}

line = 0;
QGraphicsScene::keyReleaseEvent(event);
}




I get it almost right , except the following behavior.

When i run the application, i take the mouse cursor over the scene and move the mouse while the Ctrl button is down.Then i get the line drawn. Since there is no items beneath the mouse positions, the line should be deleted from the scene and no arrow will be drawn when the Ctrl button is released. This is how is should behave. BUT i am having the line drawn even after the Ctrl is released. It seems that Ctrl release is not captured. Please see the attached image.6853

The behavior that i have just described does not show up if just do a mouse press initially when the application is started. Then the Ctrl release is also captured.


I would request someone in the forum to make the above changes in the code and see if you are getting same behavior and suggest me to debug this scenario.

Please let me know if there is anything missing in the post.



Regards
Sajjad