void balazs::TransverseCurve::initIntervalsInOrder() { std::vector<Mod1NumberIntExchange> collectionEndPoints = getEndpoints(m_sepSegmentCollection); std::size_t disjointIntervalIndex = m_disjointIntervals.wrapsAroundEnds() ? m_disjointIntervals.endpoints().size() - 1 : 0; Mod1NumberIntExchange currentPoint; m_intervalsInOrder.reserve(m_sepSegmentCollection.size()); for(std::size_t i = 0; i < m_sepSegmentCollection.size(); i++) { currentPoint = m_disjointIntervals.endpoints()[disjointIntervalIndex]; m_intervalsInOrder.push_back(currentPoint); if(i % 2 == 0) { disjointIntervalIndex = (disjointIntervalIndex + 1) % m_disjointIntervals.endpoints().size(); } else { auto it = std::find(collectionEndPoints.begin(), collectionEndPoints.end(), currentPoint); std::size_t index = it - collectionEndPoints.begin(); assert(index < collectionEndPoints.size()); index = (index % 2 == 0) ? index + 1 : index - 1; auto it2 = std::lower_bound(m_disjointIntervals.endpoints().begin(), m_disjointIntervals.endpoints().end(), collectionEndPoints[index]); disjointIntervalIndex = it2 - m_disjointIntervals.endpoints().begin(); assert(disjointIntervalIndex < m_disjointIntervals.endpoints().size()); } } }
balazs::TransverseCurve::TransverseCurve(const SepSegmentCollection &segments, bool wrapsAroundEnds, SepSegmentDatabase &ssDatabase) : m_sepSegmentCollection(segments), m_disjointIntervals(getEndpoints(m_sepSegmentCollection), wrapsAroundEnds), m_sepSegmentDatabase(ssDatabase) { assert(&m_sepSegmentDatabase == &m_sepSegmentCollection.sepSegmentDatabase()); initIntervalsInOrder(); initTouchingSegments(); // might throw if touching segments cannot be initialized because of saddle connection m_topIntersections.reserve(foliation().numIntervals()); for(std::size_t i = 0; i < foliation().numIntervals(); i++) { m_topIntersections.push_back(touchingSepSegment({HDirection::Right, VDirection::Down, i}, SepSegmentDatabase::Centered).endpoint().shiftedTo(HDirection::Center)); } m_bottomRightIntersections.reserve(foliation().numIntervals()); for(std::size_t i = 0; i < foliation().numIntervals(); i++) { m_bottomRightIntersections.push_back(touchingSepSegment({HDirection::Right, VDirection::Up, i}, SepSegmentDatabase::Centered).endpoint().shiftedTo(HDirection::Center)); } m_bottomLeftIntersections.reserve(foliation().numIntervals()); for(std::size_t i = 0; i < foliation().numIntervals(); i++) { m_bottomLeftIntersections.push_back(touchingSepSegment({HDirection::Left, VDirection::Up, i}, SepSegmentDatabase::Centered).endpoint().shiftedTo(HDirection::Center)); } }
void SPConnEndPair::reroutePath(void) { if (!isAutoRoutingConn()) { // Do nothing return; } SPCurve *curve = _path->curve; Geom::Point endPt[2]; getEndpoints(endPt); Avoid::Point src(endPt[0][Geom::X], endPt[0][Geom::Y]); Avoid::Point dst(endPt[1][Geom::X], endPt[1][Geom::Y]); _connRef->updateEndPoint(Avoid::VertID::src, src); _connRef->updateEndPoint(Avoid::VertID::tar, dst); _connRef->generatePath(src, dst); Avoid::PolyLine route = _connRef->route(); _connRef->calcRouteDist(); curve->reset(); curve->moveto(endPt[0]); for (int i = 1; i < route.pn; ++i) { Geom::Point p(route.ps[i].x, route.ps[i].y); curve->lineto(p); } }
uint Board::scoreAxis(const Cell* cell, AXIS::Axis axis, string prefix) { uint score = 0; uint wf = 1; uint incr = getIncrement(axis); Cell *from, *to; if (getEndpoints(cell, axis, from, to) && from != to) { //cout << "\n\n"; for (const Cell* c = from; c <= to; c += incr) { uint lf = c->letterFactor; uint lwf = c->wordFactor; uint va = c->value; wf *= lwf; score += lf * va; } score *= wf; } return score; }
// Called from sp_path_update to initialise the endpoints. void SPConnEndPair::update(void) { if (_connType != SP_CONNECTOR_NOAVOID) { g_assert(_connRef != NULL); if (!(_connRef->isInitialised())) { Geom::Point endPt[2]; getEndpoints(endPt); Avoid::Point src(endPt[0][Geom::X], endPt[0][Geom::Y]); Avoid::Point dst(endPt[1][Geom::X], endPt[1][Geom::Y]); _connRef->setEndpoints(src, dst); _connRef->setCallback(&redrawConnectorCallback, _path); } // Store the ID of the objects attached to the connector. storeIds(); } }
uint Board::scoreMove(const Cell* cell, AXIS::Axis axis) { uint primaryScore = scoreAxis(cell, axis); uint dualScores = 0; uint numChanged = 0; Cell *from, *to; uint incr = getIncrement(axis); AXIS::Axis dual = getDual(axis); if (getEndpoints(cell, axis, from, to)) { for (const Cell* c = from; c <= to; c += incr) { if (changed(c)) { numChanged++; uint sec = scoreAxis(c, dual, " "); dualScores += sec; } } } uint totalScore = primaryScore + dualScores; if(numChanged == Common::rackSize) totalScore+=Common::bingoValue; return totalScore; }
void SPConnEndPair::tellLibavoidNewEndpoints(const bool processTransaction) { if (!isAutoRoutingConn()) { // Do nothing return; } makePathInvalid(); Geom::Point endPt[2]; getEndpoints(endPt); Avoid::Point src(endPt[0][Geom::X], endPt[0][Geom::Y]); Avoid::Point dst(endPt[1][Geom::X], endPt[1][Geom::Y]); _connRef->setEndpoints(src, dst); if (processTransaction) { _connRef->router()->processTransaction(); } return; }
//--------------------------------------------------------------------------------- void NiceGraph::selfOrganize(float force, float min, float max) { // this function only self organizes 1 step, must be called multiple times for continous updating // the force value ranges from [0,1] and is the fraction of the final step to take // min and max values are protected distances for the various edges if (force > 1) force = 1; else if (force <=0) force = 0.001; // iterate over edges, attract and check bounds, rearrange as necessary for (map<int,Edge*>::iterator iter = edgeList.begin(); iter != edgeList.end(); iter++) { int e = iter->first; vector<float> v1 (3), v2 (3); float attraction = 0, dx = 0, dy = 0, dz = 0; int id1 = edgeList[e]->from->vID; int id2 = edgeList[e]->to->vID; getEndpoints (e, v1, v2); float vx = v2[0] - v1[0]; float vy = v2[1] - v1[1]; float vz = v2[2] - v1[2]; float dr = sqrt ( vx*vx + vy*vy + vz*vz ); attraction = -1.0 * (max - dr) / (100 * (max - min)/2); dx += 0.5 * attraction * vx; dy += 0.5 * attraction * vy; dz += 0.5 * attraction * vz; float scale = 1.0; setXYZPos (id1, v1[0] + scale * dx, v1[1] + scale * dy, v1[2] + scale * dz); setXYZPos (id2, v2[0] - scale * dx, v2[1] - scale * dy, v2[2] - scale * dz); } for (map<int,Vertex*>::iterator iter = vertexList.begin(); iter != vertexList.end(); iter++) { int self = iter->first; float dx = 0, dy = 0, dz = 0, repulsion = 0; float px = vertexList[self]->posX; float py = vertexList[self]->posY; float pz = vertexList[self]->posZ; // sum repulsion from other vertices for (map<int,Vertex*>::iterator iter2 = vertexList.begin(); iter2 != vertexList.end(); iter2++) { int other = iter2->first; if (self == other) // don't need to repel self, too! continue; float vx = vertexList[other]->posX - px; float vy = vertexList[other]->posY - py; float vz = vertexList[other]->posZ - pz; float dr = sqrt (vx * vx + vy * vy + vz * vz); // let the repulsion go as 1/r^2, like the electrostatic force repulsion = -0.01 * force*force / (sqrt(dr) * dr); dx += repulsion * vx; dy += repulsion * vy; dz += repulsion * vz; } // update position setXYZPos (self, px + dx, py + dy, pz + dz); } }
// NB STILL GETS CAUGHT IN LOCAL MINIMA AND NODES OVERLAP! void NiceGraph::fruchtermanReingoldLayout(float xmin, float xmax, float ymin, float ymax, float zmin, float zmax) { float volume = (xmax - xmin) * (ymax - ymin) * (zmax - zmin); float k = 1000 * pow( ( volume / getNumVertices()),1.0f/3.0f ); if ((zmin == 0) && (zmax ==0)) k = pow (k,3.0f/2.0f); // for a two dimensional constant int iterations = 100; // this value is arbitrary // use FR "quadrant variation" on 1/5 largest axes in zone // ie only calculate repulsion within the zone float zone = max(xmax - xmin, ymax - ymin); zone = max(zone, zmax - zmin); zone = zone; float t = zone; // arbitrary initial temperature // do some arbitrary number of iterations for (int i = 0; i < iterations; i++) { map<int,float> dx,dy,dz; // store displacements by vertex ID until the end //calculate repulsive forces for (map<int,Vertex*>::iterator pU = vertexList.begin(); pU != vertexList.end(); pU++) { // initialize values int u_id = pU->first; vector<float> u_pos(3); getXYZPos (u_id, u_pos); for (map<int,Vertex*>::iterator pV = vertexList.begin(); pV != vertexList.end(); pV++) { vector<float> v_pos(3); getXYZPos(pV->first, v_pos); float diffx = v_pos[0]-u_pos[0]; float diffy = v_pos[1]-u_pos[1]; float diffz = v_pos[2]-u_pos[2]; float dr = sqrt (diffx*diffx+diffy*diffy+diffz*diffz); if (dr < zone) // only do the calculations if U is within the zone of V { float force_r = 0; float scale = 0; if (dr == 0) { force_r = -100; scale = 1; } else { force_r = -1.0*(k * k)/dr; scale = dr; } dx[u_id] += force_r * diffx/scale ; dy[u_id] += force_r * diffy/scale ; dz[u_id] += force_r * diffz/scale ; } } } // calculate attractive forces for (map<int,Edge*>::iterator pE = edgeList.begin(); pE != edgeList.end(); pE++) { vector<float> u_pos(3), v_pos(3); getEndpoints(pE->first, u_pos, v_pos); float diffx = v_pos[0]-u_pos[0]; float diffy = v_pos[1]-u_pos[1]; float diffz = v_pos[2]-u_pos[2]; float dr = sqrt (diffx*diffx + diffy*diffy + diffz*diffz); float force_a = (dr*dr)/k; float scale = dr; if (dr ==0) scale = -1.0; dx[pE->second->from->vID] += force_a * diffx/scale ; dy[pE->second->from->vID] += force_a * diffy/scale ; dz[pE->second->from->vID] += force_a * diffz/scale ; dx[pE->second->to->vID] += -1.0 * force_a * diffx/scale ; dy[pE->second->to->vID] += -1.0 * force_a * diffy/scale ; dz[pE->second->to->vID] += -1.0 * force_a * diffz/scale ; } // now do bounds checking and update all the positions for (map<int,Vertex*>::iterator V = vertexList.begin(); V != vertexList.end(); V++) { int id = V->first; vector<float> p(3); getXYZPos(id,p); p[0] += min (dx[id],t); p[1] += min (dy[id],t); p[2] += min (dz[id],t); // also do bounds checking on frame?? p[0] = min(xmax,max(xmin,p[0])); p[1] = min(ymax,max(ymin,p[1])); p[2] = min(zmax,max(zmin,p[2])); setXYZPos(id, p[0], p[1], p[2]); } // now cool the temperature a bit t*=.98; } }