void CGraphTouchgraphLayoutImpl::moveNodes() { lastMaxMotion = maxMotion; float maxMotionA; maxMotionA=0; PointF pos; for(CComPtr<IGraphItemIterator> itr = m_graph->GetChildren(new MetaVisibleSkipper(m_meta)); itr->IsValidItem(); itr->NextItem()) { IGraphItem* item=itr->Get(); float dx = m_dv[item->GetID()].x; float dy = m_dv[item->GetID()].y; dx*=damper; //The damper slows things down. It cuts down jiggling at the last moment, and optimizes dy*=damper; //layout. As an experiment, get rid of the damper in these lines, and make a //long straight line of nodes. It wiggles too much and doesn't straighten out. m_dv[item->GetID()].x = dx/2; //Slow down, but don't stop. Nodes in motion store momentum. This helps when the force m_dv[item->GetID()].y = dy/2; //on a node is very low, but you still want to get optimal layout. float distMoved = sqrt(dx*dx+dy*dy); //how far did the node actually move? //ATLTRACE(_T("Node Moved %f\n"), distMoved); CComQIPtr<ILegacyRenderer> lr = m_canvas->GetRenderer(item); if(lr && !lr->GetPinned() && !lr->GetDragging()) { lr->GetPosition(pos); pos.x += std::max<float>(-30, std::min<float>(30, dx)); //don't move faster then 30 units at a time. pos.y += std::max<float>(-30, std::min<float>(30, dy)); //I forget when this is important. Stopping severed nodes from flying away? lr->SetPosition(pos); } else { CComQIPtr<ILegacySubgraphRenderer> lsgr = m_canvas->GetRenderer(item); if(lsgr && !lsgr->GetPinned()) { lsgr->GetPosition(pos); pos.x += std::max<float>(-30, std::min<float>(30, dx)); //don't move faster then 30 units at a time. pos.y += std::max<float>(-30, std::min<float>(30, dy)); //I forget when this is important. Stopping severed nodes from flying away? lsgr->SetPosition(pos); } } maxMotionA=std::max<float>(distMoved, maxMotionA); } maxMotion = maxMotionA; if (maxMotion>0) motionRatio = lastMaxMotion/maxMotion-1; //subtract 1 to make a m_positive value mean that else motionRatio = 0; //things are moving faster }