linkablemapobj.cpp
author insilmaril
Fri, 11 Sep 2009 12:56:15 +0000
changeset 794 d922fb6ea482
parent 791 f1006de05c54
child 798 d251c7b2de54
permissions -rw-r--r--
more fixes for collisions
     1 #include <iostream>
     2 #include <math.h>
     3 
     4 #include "linkablemapobj.h"
     5 #include "branchobj.h"
     6 #include "vymmodel.h"
     7 
     8 using namespace std;
     9 
    10 /////////////////////////////////////////////////////////////////
    11 // LinkableMapObj
    12 /////////////////////////////////////////////////////////////////
    13 
    14 /* FIXME-3
    15 LinkableMapObj::LinkableMapObj():MapObj()
    16 {
    17   //  cout << "Const LinkableMapObj ()\n";
    18     init ();
    19 }
    20 */
    21 
    22 LinkableMapObj::LinkableMapObj(QGraphicsScene* s, TreeItem *ti) :MapObj(s,ti)
    23 {
    24 //    cout << "Const LinkableMapObj s="<<s<<"  ti="<<ti<<"  treeItem="<<treeItem<<endl;
    25     init ();
    26 }
    27 
    28 LinkableMapObj::LinkableMapObj (LinkableMapObj* lmo) : MapObj (lmo->scene)
    29 {
    30     copy (lmo);
    31 }
    32 
    33 LinkableMapObj::~LinkableMapObj()
    34 {
    35 	//cout << "Destructor LMO\n";
    36     delete (bottomline);
    37 	delLink();
    38 }
    39 
    40 void LinkableMapObj::delLink()
    41 {
    42 	switch (style)
    43 	{
    44 		case Line:
    45 			delete (l);
    46 			break;
    47 		case Parabel:
    48 			while (!segment.isEmpty()) delete segment.takeFirst();
    49 			break;
    50 		case PolyLine:
    51 			delete (p);
    52 			break;
    53 		case PolyParabel:
    54 			delete (p);
    55 			break;
    56 		default:
    57 			break;
    58 	}		
    59 }
    60 
    61 void LinkableMapObj::init ()
    62 {
    63     parObj=NULL;
    64     parObjTmpBuf=NULL;
    65     parPos=QPointF(0,0);
    66     childPos=QPointF(0,0);
    67 	link2ParPos=false;
    68     l=NULL;
    69 	p=NULL;
    70     orientation=UndefinedOrientation;
    71     linkwidth=20;		
    72 	thickness_start=8;
    73     style=UndefinedStyle;
    74 	linkpos=Bottom;
    75     arcsegs=13;
    76     
    77 // TODO instead of linkcolor pen.color() could be used	all around
    78 	pen.setWidth (1);
    79 	pen.setColor (linkcolor);
    80 	pen.setCapStyle ( Qt::RoundCap );
    81 	bottomline=scene->addLine(QLineF(1,1,1,1),pen);
    82     bottomline->setZValue(Z_LINK);
    83     bottomline->show();
    84 
    85 	topPad=botPad=leftPad=rightPad=0;
    86 
    87 	repositionRequest=false;
    88 
    89 	// Rel Positions
    90 	relPos=QPointF(0,0);
    91 	useRelPos=false;
    92 }
    93 
    94 void LinkableMapObj::copy (LinkableMapObj* other)
    95 {
    96     MapObj::copy(other);
    97 	bboxTotal=other->bboxTotal;
    98     setLinkStyle(other->style);
    99     setLinkColor (other->linkcolor);
   100 	relPos=other->relPos;
   101 	treeItem=other->treeItem;
   102 }
   103 
   104 void LinkableMapObj::setParObj(LinkableMapObj* o)
   105 {
   106     parObj=o;
   107 }
   108 
   109 void LinkableMapObj::setParObjTmp(LinkableMapObj*,QPointF,int)	// FIXME-3 make pure virtual
   110 {
   111 }
   112 
   113 void LinkableMapObj::unsetParObjTmp()	// FIXME-3 make pure virtual
   114 {
   115 }
   116 
   117 bool LinkableMapObj::hasParObjTmp()
   118 {
   119 	if (parObjTmpBuf) return true;
   120 	return false;
   121 }
   122 
   123 void LinkableMapObj::setUseRelPos (const bool &b)
   124 {
   125 	useRelPos=b;
   126 }
   127 
   128 void LinkableMapObj::setRelPos()
   129 {
   130 	if (parObj)
   131 	{	
   132 		relPos.setX (absPos.x() - parObj->getChildPos().x() );
   133 		relPos.setY (absPos.y() - parObj->getChildPos().y() );
   134 		parObj->calcBBoxSize();
   135 	}	
   136 }
   137 
   138 void LinkableMapObj::setRelPos(const QPointF &p)
   139 {
   140 	relPos=p;
   141 	if (parObj)
   142 	{		
   143 		parObj->calcBBoxSize();
   144 		requestReposition();
   145 	}
   146 }
   147 
   148 QPointF LinkableMapObj::getRelPos()
   149 {
   150 	if (!parObj) return QPointF();
   151 	return relPos;
   152 }
   153 
   154 qreal LinkableMapObj::getTopPad()
   155 {
   156 	return topPad;
   157 }
   158 
   159 qreal LinkableMapObj::getLeftPad()
   160 {
   161 	return leftPad;
   162 }
   163 
   164 qreal LinkableMapObj::getRightPad()
   165 {
   166 	return rightPad;
   167 }
   168 
   169 LinkableMapObj::Style LinkableMapObj::getDefLinkStyle (TreeItem *parent)
   170 {
   171 	VymModel *model=treeItem->getModel();
   172 	if (!model)
   173 	{
   174 		qWarning ("LMO::getDefLinkStyle   model=NULL");
   175 		//return UndefinedStyle;
   176 	}
   177 	Style ls=model->getMapLinkStyle();
   178 	int depth=1+parent->depth();
   179 	if (depth==0) return UndefinedStyle;
   180 	switch (ls)
   181 	{
   182 		case Line: 
   183 			return ls;
   184 			break;
   185 		case Parabel:
   186 			return ls;
   187 			break;
   188 		case PolyLine:	
   189 			if (depth>1)
   190 				return Line;
   191 			else	
   192 				return ls;
   193 			break;
   194 		case PolyParabel:	
   195 			if (depth>1)
   196 				return Parabel;
   197 			else	
   198 				return ls;
   199 			break;
   200 		default: 
   201 			break;	
   202 	}	
   203 	return UndefinedStyle;
   204 }
   205 
   206 void LinkableMapObj::setLinkStyle(Style newstyle)
   207 {
   208 	//if (newstyle==style) return; FIXME-3
   209 	delLink();
   210 		
   211 	style=newstyle;
   212 
   213     if (parObj != NULL)
   214     {
   215 		QGraphicsLineItem *cl;
   216 		switch (style)
   217 		{
   218 			case UndefinedStyle:
   219 				bottomline->hide();
   220 				break;
   221 			case Line: 
   222 				l = scene->addLine(QLineF(1,1,1,1),pen);
   223 				l->setZValue(Z_LINK);
   224 				if (visible)
   225 					l->show();
   226 				else
   227 					l->hide();
   228 				break;
   229 			case Parabel:
   230 				for (int i=0;i<arcsegs;i++)
   231 				{
   232 					cl = scene->addLine(QLineF(i*5,0,i*10,100),pen);
   233 					cl->setZValue(Z_LINK);
   234 					if (visible)
   235 						cl->show();
   236 					else
   237 						cl->hide();
   238 					segment.append(cl);
   239 				}
   240 				pa0.resize (arcsegs+1);
   241 				break;
   242 			case PolyLine:	
   243 				p =scene->addPolygon(QPolygonF(),pen,linkcolor);
   244 				p->setZValue(Z_LINK);
   245 				if (visible)
   246 					p->show();
   247 				else
   248 					p->hide();
   249 				pa0.resize (3);
   250 				break;
   251 			case PolyParabel:	
   252 				p = scene->addPolygon(QPolygonF(),pen,linkcolor);
   253 				p->setZValue(Z_LINK);
   254 				if (visible)
   255 					p->show();
   256 				else
   257 					p->hide();
   258 				pa0.resize (arcsegs*2+2);
   259 				pa1.resize (arcsegs+1);
   260 				pa2.resize (arcsegs+1);
   261 				break;
   262 			default: 
   263 				break;	
   264 		}	
   265 	} 
   266 }
   267 
   268 LinkableMapObj::Style LinkableMapObj::getLinkStyle()
   269 {
   270 	return style;
   271 }
   272 
   273 void LinkableMapObj::setHideLinkUnselected()
   274 {
   275 	setVisibility (visible);
   276 	updateLinkGeometry();
   277 }
   278 
   279 void LinkableMapObj::setLinkPos(Position lp)
   280 {
   281 	linkpos=lp;
   282 }
   283 
   284 LinkableMapObj::Position LinkableMapObj::getLinkPos()
   285 {
   286 	return linkpos;
   287 }
   288 
   289 void LinkableMapObj::setLinkColor()
   290 {
   291 	// Overloaded in BranchObj and children
   292 	// here only set default color
   293 	VymModel *model=treeItem->getModel();
   294 	if (model)
   295 		setLinkColor (model->getMapDefLinkColor());
   296 }
   297 
   298 void LinkableMapObj::setLinkColor(QColor col)
   299 {
   300 	linkcolor=col;
   301 	pen.setColor(col);
   302     bottomline->setPen( pen );
   303 	switch (style)
   304 	{
   305 		case Line:
   306 			l->setPen( pen);
   307 			break;	
   308 		case Parabel:	
   309 			for (int i=0; i<segment.size(); ++i)
   310 				segment.at(i)->setPen( pen);
   311 			break;
   312 		case PolyLine:
   313 			p->setBrush( QBrush(col));
   314 			p->setPen( pen);
   315 			break;
   316 		case PolyParabel:	
   317 			p->setBrush( QBrush(col));
   318 			p->setPen( pen);
   319 			break;
   320 		default:
   321 			break;
   322 	} 
   323 }
   324 
   325 QColor LinkableMapObj::getLinkColor()
   326 {
   327 	return linkcolor;
   328 }
   329 
   330 void LinkableMapObj::setVisibility (bool v)
   331 {
   332 	MapObj::setVisibility (v);
   333 	updateVisibility();
   334 }
   335 
   336 void LinkableMapObj::setOrientation()
   337 {
   338 	Orientation orientOld=orientation;
   339 
   340 	if (!parObj) 
   341 	{
   342 		orientation=UndefinedOrientation;
   343 		return;
   344 	}
   345 		
   346     // Set orientation, first look for orientation of parent
   347     if (parObj->getOrientation() != UndefinedOrientation ) 
   348 		// use the orientation of the parent:
   349 		orientation=parObj->getOrientation();
   350     else
   351     {
   352 		// calc orientation depending on position rel to parent
   353 		if (absPos.x() < QPointF(parObj->getChildPos() ).x() )
   354 			orientation=LeftOfCenter; 
   355 		else
   356 			orientation=RightOfCenter;
   357     }
   358 	if (orientOld!=orientation) requestReposition();
   359 }
   360 
   361 void LinkableMapObj::updateVisibility()
   362 {
   363 	bool visnow=visible;
   364 
   365 	if (((MapItem*)treeItem)->getHideLinkUnselected()
   366 		&& treeItem->getModel()->getSelectedLMO() !=this)
   367 		visnow=false;
   368 
   369 	if (visnow) 
   370 	{
   371 		bottomline->show();
   372 		switch (style)
   373 		{
   374 			case Line:
   375 				if (l) l->show();
   376 				break;
   377 			case Parabel:	
   378 				for (int i=0; i<segment.size(); ++i)
   379 					segment.at(i)->show();
   380 				break;	
   381 			case PolyLine:
   382 				if (!p) cout << "LMO::updateVis p==0 (PolyLine)\n"; //FIXME-3
   383 				if (p) p->show();
   384 				break;
   385 			case PolyParabel:	
   386 				if (!p) cout << "LMO::updateVis p==0 (PolyParabel) "<<treeItem->getHeading().toStdString()<<endl; //FIXME-3
   387 				if (p) p->show();
   388 				break;
   389 			default:
   390 				break;
   391 		}
   392 	} else 
   393 	{
   394 		bottomline->hide();
   395 		switch (style)
   396 		{
   397 			case Line:
   398 				if (l) l->hide();
   399 				break;
   400 			case Parabel:	
   401 				for (int i=0; i<segment.size(); ++i)
   402 					segment.at(i)->hide();
   403 				break;	
   404 			case PolyLine:
   405 				if (p) p->hide();
   406 				break;
   407 			case PolyParabel:	
   408 				if (p) p->hide();
   409 				break;
   410 			default:
   411 				break;
   412 		}
   413 	}	
   414 }
   415 
   416 void LinkableMapObj::updateLinkGeometry()
   417 {
   418     // needs:
   419     //	childPos of parent
   420     //	orient   of parent
   421     //	style
   422     // 
   423     // sets:
   424     //	orientation
   425     //	childPos	(by calling setDockPos())
   426     //	parPos		(by calling setDockPos())
   427 	//  bottomlineY
   428     //	drawing of the link itself
   429 
   430 	// updateLinkGeometry is called from move, but called from constructor we don't
   431 	// have parents yet...
   432 
   433 //cout <<"LMO::updateLinkGeometry: "<<treeItem->getHeadingStd()<<"  "<<parObj<<endl;
   434 	if (!parObj)	
   435 	{
   436 		// If I am a mapcenter, set childPos to middle of MapCenterObj
   437 		childPos.setX( clickBox.topLeft().x() + clickBox.width()/2 );
   438 		childPos.setY( clickBox.topLeft().y() + clickBox.height()/2 );
   439 		parPos=childPos;		
   440 		// Redraw links to children
   441 		for (int i=0; i<treeItem->branchCount(); ++i)
   442 			treeItem->getBranchObjNum(i)->updateLinkGeometry();
   443 		return;	
   444 	}
   445 
   446 	if (style==UndefinedStyle) return;	
   447 
   448 	switch (linkpos)
   449 	{
   450 		case Middle:
   451 			bottomlineY=bbox.top() + bbox.height()/2;	// draw link to middle (of frame)
   452 			break;
   453 		case Bottom:
   454 			//bottomlineY=bbox.bottom()-1;	// draw link to bottom of box
   455 			bottomlineY=bbox.bottom()-botPad;
   456 			break;
   457 	}
   458 	
   459     double p2x,p2y;								// Set P2 Before setting
   460 	if (!link2ParPos)
   461 	{
   462 		p2x=QPointF( parObj->getChildPos() ).x();	// P1, we have to look at
   463 		p2y=QPointF( parObj->getChildPos() ).y();	// orientation
   464 	} else	
   465 	{
   466 		p2x=QPointF( parObj->getParPos() ).x();	
   467 		p2y=QPointF( parObj->getParPos() ).y();
   468 	} 
   469 
   470 	setDockPos(); // Call overloaded method
   471 	setOrientation();
   472 
   473 	double p1x=parPos.x();	// Link is drawn from P1 to P2
   474 	double p1y=parPos.y();
   475 
   476 	double vx=p2x - p1x;	// V=P2-P1
   477 	double vy=p2y - p1y;
   478 
   479 	// Draw the horizontal line below heading (from ChildPos to ParPos)
   480 	//bottomline->prepareGeometryChange();
   481 	bottomline->setLine (QLine (qRound(childPos.x()),
   482 		qRound(childPos.y()),
   483 		qRound(p1x),
   484 		qRound(p1y) ));
   485 
   486 	double a;	// angle
   487 	if (vx > -0.000001 && vx < 0.000001)
   488 		a=M_PI_2;
   489 	else
   490 		a=atan( vy / vx );
   491 	// "turning point" for drawing polygonal links
   492 	QPointF tp (-qRound(sin (a)*thickness_start), qRound(cos (a)*thickness_start));	
   493 	
   494     // Draw the link
   495 	switch (style)
   496 	{
   497 		case Line:
   498 			l->setLine( QLine(qRound (parPos.x()),
   499 				qRound(parPos.y()),
   500 				qRound(p2x),
   501 				qRound(p2y) ));
   502 			break;	
   503 		case Parabel:	
   504 			parabel (pa0, p1x,p1y,p2x,p2y);
   505 			for (int i=0; i<segment.size(); ++i)
   506 				segment.at(i)->setLine(QLineF( pa0.at(i).x(), pa0.at(i).y(),pa0.at(i+1).x(),pa0.at(i+1).y()));
   507 			break;
   508 		case PolyLine:
   509 			pa0.clear();
   510 			pa0<<QPointF (qRound(p2x+tp.x()), qRound(p2y+tp.y()));
   511 			pa0<<QPointF (qRound(p2x-tp.x()), qRound(p2y-tp.y()));
   512 			pa0<<QPointF (qRound (parPos.x()), qRound(parPos.y()) );
   513 			p->setPolygon(QPolygonF (pa0));
   514 			break;
   515 		case PolyParabel:	
   516 			parabel (pa1, p1x,p1y,p2x+tp.x(),p2y+tp.y());
   517 			parabel (pa2, p1x,p1y,p2x-tp.x(),p2y-tp.y());
   518 			pa0.clear();
   519 			for (int i=0;i<=arcsegs;i++)
   520 				pa0 << QPointF (pa1.at(i));
   521 			for (int i=0;i<=arcsegs;i++)
   522 				pa0 << QPointF (pa2.at(arcsegs-i));
   523 			p->setPolygon(QPolygonF (pa0));
   524 			break;
   525 		default:
   526 			break;
   527 	} 
   528 }
   529 	
   530 LinkableMapObj* LinkableMapObj::getParObj()
   531 {
   532     return parObj;
   533 }
   534 
   535 QPointF LinkableMapObj::getChildPos()
   536 {
   537     return childPos;
   538 }
   539 
   540 QPointF LinkableMapObj::getParPos()
   541 {
   542     return parPos;
   543 }
   544 
   545 LinkableMapObj::Orientation LinkableMapObj::getOrientation()
   546 {
   547     return orientation;
   548 }
   549 
   550 QPointF LinkableMapObj::getRandPos()
   551 {
   552 	// Choose a random position with given distance to parent:
   553 	double a=rand()%360 * 2 * M_PI / 360;
   554     return QPointF ( (int)( + 150*cos (a)),
   555                     (int)( + 150*sin (a)));
   556 }
   557 
   558 void LinkableMapObj::reposition()
   559 {
   560 }
   561 
   562 void LinkableMapObj::requestReposition()	//FIXME-3 needed?
   563 {
   564 	if (!repositionRequest)
   565 	{
   566 		// Pass on the request to parental objects, if this hasn't
   567 		// been done yet
   568 		repositionRequest=true;
   569 		if (parObj) parObj->requestReposition();
   570 	}
   571 }
   572 
   573 void LinkableMapObj::forceReposition()
   574 {
   575 	// Sometimes a reposition has to be done immediatly: For example
   576 	// if the note editor flag changes, there is no user event in mapeditor
   577 	// which could collect requests for a reposition.
   578 	// Then we have to call forceReposition()
   579 	// But no rule without exception: While loading a map or undoing it,
   580 	// we want to block expensive repositioning, but just do it once at
   581 	// the end, thus check first:
   582 
   583 	VymModel *model=treeItem->getModel();
   584 	if (model->isRepositionBlocked()) return;	
   585 	
   586 	// Pass on the request to parent objects, if this hasn't been done yet
   587 	if (parObj) 
   588 		parObj->forceReposition(); 
   589 	else 
   590 		reposition(); 
   591 }
   592 
   593 bool LinkableMapObj::repositionRequested()
   594 {
   595 	return repositionRequest;
   596 }
   597 
   598 void LinkableMapObj::parabel (QPolygonF &ya, double p1x, double p1y, double p2x, double p2y)
   599 
   600 {
   601 	double vx=p2x - p1x;	// V=P2-P1
   602 	double vy=p2y - p1y;
   603 
   604 	double dx;				// delta x during calculation of parabel
   605 	
   606 	double pnx;				// next point
   607 	double pny;
   608 	double m;
   609 
   610 	if (vx > -0.0001 && vx < 0.0001)
   611 		m=0;
   612 	else	
   613 		m=(vy / (vx*vx));
   614 	dx=vx/(arcsegs);
   615 	ya.clear();
   616 	ya<<QPointF (p1x,p1y);
   617 	for (int i=1;i<=arcsegs;i++)
   618 	{	
   619 		pnx=p1x+dx;
   620 		pny=m*(pnx-parPos.x())*(pnx-parPos.x())+parPos.y();
   621 		ya<<QPointF (pnx,pny);
   622 		p1x=pnx;
   623 		p1y=pny;
   624 	}	
   625 }
   626