void VisibilityLayout::layout(GraphAttributes &GA, const UpwardPlanRep &UPROrig) { UpwardPlanRep UPR = UPROrig; //clear some data for(edge e : GA.constGraph().edges) { GA.bends(e).clear(); } int minGridDist = 1; for(node v : GA.constGraph().nodes) { if (minGridDist < max(GA.height(v), GA.width(v))) minGridDist = (int) max(GA.height(v), GA.width(v)); } minGridDist = max(minGridDist*2+1, m_grid_dist); CombinatorialEmbedding &gamma = UPR.getEmbedding(); //add edge (s,t) adjEntry adjSrc = nullptr; for(adjEntry adj : UPR.getSuperSource()->adjEntries) { if (gamma.rightFace(adj) == gamma.externalFace()) adjSrc = adj; break; } OGDF_ASSERT(adjSrc != nullptr); edge e_st = UPR.newEdge(adjSrc, UPR.getSuperSink()); // on the right gamma.computeFaces(); gamma.setExternalFace(gamma.rightFace(e_st->adjSource())); constructVisibilityRepresentation(UPR); // the preliminary postion NodeArray<int> xPos(UPR); NodeArray<int> yPos(UPR); // node Position for(node v : UPR.nodes) { NodeSegment vVis = nodeToVis[v]; int x = (int) (vVis.x_l + vVis.x_r)/2 ; // median positioning xPos[v] = x; yPos[v] = vVis.y; if (UPR.original(v) != nullptr) { node vOrig = UPR.original(v); //final position GA.x(vOrig) = x * minGridDist; GA.y(vOrig) = vVis.y * minGridDist; } } //compute bendpoints for(edge e : GA.constGraph().edges) { const List<edge> &chain = UPR.chain(e); for(edge eUPR : chain) { EdgeSegment eVis = edgeToVis[eUPR]; if (chain.size() == 1) { if ((yPos[eUPR->target()] - yPos[eUPR->source()]) > 1) { DPoint p1(eVis.x*minGridDist, (yPos[eUPR->source()]+1)*minGridDist); DPoint p2(eVis.x*minGridDist, (yPos[eUPR->target()]-1)*minGridDist); GA.bends(e).pushBack(p1); if (yPos[eUPR->source()]+1 != yPos[eUPR->target()]-1) GA.bends(e).pushBack(p2); } } else { //short edge if ((yPos[eUPR->target()] - yPos[eUPR->source()]) == 1) { if (UPR.original(eUPR->target()) == nullptr) { node tgtUPR = eUPR->target(); DPoint p(xPos[tgtUPR]*minGridDist, yPos[tgtUPR]*minGridDist); GA.bends(e).pushBack(p); } } //long edge else { DPoint p1(eVis.x*minGridDist, (yPos[eUPR->source()]+1)*minGridDist); DPoint p2(eVis.x*minGridDist, (yPos[eUPR->target()]-1)*minGridDist); GA.bends(e).pushBack(p1); if (yPos[eUPR->source()]+1 != yPos[eUPR->target()]-1) GA.bends(e).pushBack(p2); if (UPR.original(eUPR->target()) == nullptr) { node tgtUPR = eUPR->target(); DPoint p(xPos[tgtUPR]*minGridDist, yPos[tgtUPR]*minGridDist); GA.bends(e).pushBack(p); } } } } DPolyline &poly = GA.bends(e); DPoint pSrc(GA.x(e->source()), GA.y(e->source())); DPoint pTgt(GA.x(e->target()), GA.y(e->target())); poly.normalize(pSrc, pTgt); } }
void GEMLayout::call(GraphAttributes &AG) { const Graph &G = AG.constGraph(); if(G.empty()) return; OGDF_ASSERT(m_numberOfRounds >= 0); OGDF_ASSERT(DIsGreaterEqual(m_minimalTemperature,0)); OGDF_ASSERT(DIsGreaterEqual(m_initialTemperature,m_minimalTemperature)); OGDF_ASSERT(DIsGreaterEqual(m_gravitationalConstant,0)); OGDF_ASSERT(DIsGreaterEqual(m_desiredLength,0)); OGDF_ASSERT(DIsGreaterEqual(m_maximalDisturbance,0)); OGDF_ASSERT(DIsGreaterEqual(m_rotationAngle,0)); OGDF_ASSERT(DIsLessEqual(m_rotationAngle,pi / 2)); OGDF_ASSERT(DIsGreaterEqual(m_oscillationAngle,0)); OGDF_ASSERT(DIsLessEqual(m_oscillationAngle,pi / 2)); OGDF_ASSERT(DIsGreaterEqual(m_rotationSensitivity,0)); OGDF_ASSERT(DIsLessEqual(m_rotationSensitivity,1)); OGDF_ASSERT(DIsGreaterEqual(m_oscillationSensitivity,0)); OGDF_ASSERT(DIsLessEqual(m_oscillationSensitivity,1)); OGDF_ASSERT(m_attractionFormula == 1 || m_attractionFormula == 2); // all edges straight-line AG.clearAllBends(); GraphCopy GC; GC.createEmpty(G); // compute connected component of G NodeArray<int> component(G); int numCC = connectedComponents(G,component); // intialize the array of lists of nodes contained in a CC Array<List<node> > nodesInCC(numCC); node v; forall_nodes(v,G) nodesInCC[component[v]].pushBack(v); EdgeArray<edge> auxCopy(G); Array<DPoint> boundingBox(numCC); int i; for(i = 0; i < numCC; ++i) { GC.initByNodes(nodesInCC[i],auxCopy); GraphCopyAttributes AGC(GC,AG); node vCopy; forall_nodes(vCopy, GC) { node vOrig = GC.original(vCopy); AGC.x(vCopy) = AG.x(vOrig); AGC.y(vCopy) = AG.y(vOrig); } SList<node> permutation; node v; // initialize node data m_impulseX.init(GC,0); m_impulseY.init(GC,0); m_skewGauge.init(GC,0); m_localTemperature.init(GC,m_initialTemperature); // initialize other data m_globalTemperature = m_initialTemperature; m_barycenterX = 0; m_barycenterY = 0; forall_nodes(v,GC) { m_barycenterX += weight(v) * AGC.x(v); m_barycenterY += weight(v) * AGC.y(v); }
static inline void writeAttributes( std::ostream &out, int depth, const GraphAttributes &GA, node v) { const long attrs = GA.attributes(); if(attrs & GraphAttributes::nodeGraphics) { const double z = (attrs & GraphAttributes::threeD) ? GA.z(v) : 0.0; GraphIO::indent(out, depth) << "<viz:position " << "x=\"" << GA.x(v) << "\" " << "y=\"" << GA.y(v) << "\" " << "z=\"" << z << "\" " << "/>\n"; // TODO: size is a scale here, so we have to know average size first. // const double size = std::max(GA.width(v), GA.height(v)); // GraphIO::indent(out, depth) << "<viz:size " // << "value=\"" << size << "\" " // << "/>\n"; const Shape shape = GA.shape(v); GraphIO::indent(out, depth) << "<viz:shape " << "value=\"" << toString(shape) << "\" " << "/>\n"; } if(attrs & GraphAttributes::nodeStyle) { const Color &color = GA.fillColor(v); const int red = color.red(); const int green = color.green(); const int blue = color.blue(); const int alpha = color.alpha(); GraphIO::indent(out, depth) << "<viz:color " << "red=\"" << red << "\" " << "green=\"" << green << "\" " << "blue=\"" << blue << "\" " << "alpha=\"" << alpha << "\" " << "/>\n"; } /* * Node type, template and weight are not supported by VIZ module. So, they * need to be written using <attvalues> tag (for estetic reasons, we write * them only if either of them is present). For convenience reasons, we use * the same names and values as in GraphML format. */ if(!(attrs & (GraphAttributes::nodeType | GraphAttributes::nodeTemplate | GraphAttributes::nodeWeight))) { return; } GraphIO::indent(out, depth) << "<attvalues>\n"; if(attrs & GraphAttributes::nodeType) { writeAttValue( out, depth + 1, graphml::a_nodeType, graphml::toString(GA.type(v))); } if(attrs & GraphAttributes::nodeTemplate) { writeAttValue(out, depth + 1, graphml::a_template, GA.templateNode(v)); } if(attrs & GraphAttributes::nodeWeight) { writeAttValue(out, depth + 1, graphml::a_nodeWeight, GA.weight(v)); } GraphIO::indent(out, depth) << "</attvalues>\n"; }
void DominanceLayout::layout(GraphAttributes &GA, const UpwardPlanRep &UPROrig) { UpwardPlanRep UPR = UPROrig; //clear some data for(edge e : GA.constGraph().edges) { GA.bends(e).clear(); } //compute and splite transitiv edges List<edge> splitMe; findTransitiveEdges(UPR, splitMe); for(edge eSplit : splitMe) { UPR.getEmbedding().split(eSplit); } // set up first-/lastout, first-/lastin firstout.init(UPR, nullptr); lastout.init(UPR, nullptr); firstin.init(UPR, nullptr); lastin.init(UPR, nullptr); node s = UPR.getSuperSource(); node t = UPR.getSuperSink(); firstout[t] = lastout[t] = nullptr; firstin[s] = lastin[s] = nullptr; firstin[t] = lastin[t] =t->firstAdj()->theEdge(); adjEntry adjRun = s->firstAdj(); while (UPR.getEmbedding().rightFace(adjRun) != UPR.getEmbedding().externalFace()) { adjRun = adjRun->cyclicSucc(); } lastout[s] = adjRun->theEdge(); firstout[s] = adjRun->cyclicSucc()->theEdge(); for(node v : UPR.nodes) { if (v == t || v == s) continue; adjEntry adj = UPR.leftInEdge(v); firstin[v] = adj->theEdge(); firstout[v] = adj->cyclicSucc()->theEdge(); adjEntry adjRightIn = adj; while (adjRightIn->cyclicPred()->theEdge()->source() != v) adjRightIn = adjRightIn->cyclicPred(); lastin[v] = adjRightIn->theEdge(); lastout[v] = adjRightIn->cyclicPred()->theEdge(); } //compute m_L and m_R for min. area drawing m_L = 0; m_R = 0; for(edge e : UPR.edges) { node src = e->source(); node tgt = e->target(); if (lastin[tgt] == e && firstout[src] == e) m_L++; if (firstin[tgt] == e && lastout[src] == e) m_R++; } // compute preleminary coordinate xPreCoord.init(UPR); yPreCoord.init(UPR); int count = 0; labelX(UPR, s, count); count = 0; labelY(UPR, s, count); // compaction compact(UPR, GA); // map coordinate to GA for(node v : GA.constGraph().nodes) { node vUPR = UPR.copy(v); GA.x(v) = xCoord[vUPR]; GA.y(v) = yCoord[vUPR]; } // add bends to original edges for(edge e : GA.constGraph().edges) { const List<edge> &chain = UPR.chain(e); for(edge eChain : chain) { node tgtUPR = eChain->target(); if (tgtUPR != chain.back()->target()) { DPoint p(xCoord[tgtUPR], yCoord[tgtUPR]); GA.bends(e).pushBack(p); } } } //rotate the drawing for(node v : GA.constGraph().nodes) { double r = sqrt(GA.x(v)*GA.x(v) + GA.y(v)*GA.y(v)); if (r == 0) continue; double alpha = asin(GA.y(v)/r); double yNew = sin(alpha + m_angle)*r; double xNew = cos(alpha + m_angle)*r; GA.x(v) = xNew; GA.y(v) = yNew; } for(edge e : GA.constGraph().edges) { DPolyline &poly = GA.bends(e); DPoint pSrc(GA.x(e->source()), GA.y(e->source())); DPoint pTgt(GA.x(e->target()), GA.y(e->target())); poly.normalize(pSrc, pTgt); for(DPoint &p : poly) { double r = p.distance(DPoint(0,0)); if (r == 0) continue; double alpha = asin( p.m_y/r); double yNew = sin(alpha + m_angle)*r; double xNew = cos(alpha + m_angle)*r; p.m_x = xNew; p.m_y = yNew; } } }
static void compute_bounding_box(const GraphAttributes &A, double &xmin, double &ymin, double &xmax, double &ymax) { const Graph &G = A.constGraph(); if(G.numberOfNodes() == 0) { xmin = xmax = ymin = ymax = 0; return; } node v = G.firstNode(); xmin = xmax = A.x(v), ymin = ymax = A.y(v); forall_nodes(v, G) { double lw = (A.attributes() & GraphAttributes::nodeStyle) ? 0.5*A.strokeWidth(v) : 0.5; xmax = max(xmax, A.x(v) + A.width (v)/2 + lw); ymax = max(ymax, A.y(v) + A.height(v)/2 + lw); xmin = min(xmin, A.x(v) - A.width (v)/2 - lw); ymin = min(ymin, A.y(v) - A.height(v)/2 - lw); }
void PlanarizationLayoutUML::doSimpleCall(GraphAttributes &GA) { m_nCrossings = 0; if(GA.constGraph().empty()) return; PlanRepUML pr = PlanRepUML(GA); const int numCC = pr.numberOfCCs(); // (width,height) of the layout of each connected component Array<DPoint> boundingBox(numCC); //------------------------------------------ //now planarize CCs and apply drawing module for(int i = 0; i < numCC; ++i) { //--------------------------------------- // 1. crossing minimization //--------------------------------------- int cr; m_crossMin.get().call(pr, i, cr); m_nCrossings += cr; //--------------------------------------- // 2. embed resulting planar graph //--------------------------------------- adjEntry adjExternal = 0; m_embedder.get().call(pr, adjExternal); //--------------------------------------------------------- // 3. compute layout of planarized representation //--------------------------------------------------------- Layout drawing(pr); //call the Layouter for the CC's UMLGraph m_planarLayouter.get().call(pr,adjExternal,drawing); // copy layout into umlGraph // Later, we move nodes and edges in each connected component, such // that no two overlap. for(int j = pr.startNode(); j < pr.stopNode(); ++j) { node vG = pr.v(j); GA.x(vG) = drawing.x(pr.copy(vG)); GA.y(vG) = drawing.y(pr.copy(vG)); adjEntry adj; forall_adj(adj,vG) { if ((adj->index() & 1) == 0) continue; edge eG = adj->theEdge(); drawing.computePolylineClear(pr, eG, GA.bends(eG)); } } // the width/height of the layout has been computed by the planar // layout algorithm; required as input to packing algorithm boundingBox[i] = m_planarLayouter.get().getBoundingBox(); } //---------------------------------------- // 4. arrange layouts of connected components //---------------------------------------- arrangeCCs(pr, GA, boundingBox); }
bool GraphIO::writeDL(const GraphAttributes &GA, std::ostream &os) { writeGraph(os, GA.constGraph(), &GA); return true; }
bool GmlParser::read(Graph &G, GraphAttributes &AG) { OGDF_ASSERT(&G == &(AG.constGraph())) G.clear(); int minId = m_mapToNode.low(); int maxId = m_mapToNode.high(); int notDefined = minId-1; //indicates not defined id key HashArray<string,Shape> strToShape(shRect); strToShape["rectangle"] = shRect; strToShape["rect"] = shRect; strToShape["roundedRect"] = shRoundedRect; strToShape["oval"] = shEllipse; strToShape["ellipse"] = shEllipse; strToShape["triangle"] = shTriangle; strToShape["pentagon"] = shPentagon; strToShape["hexagon"] = shHexagon; strToShape["octagon"] = shOctagon; strToShape["rhomb"] = shRhomb; strToShape["trapeze"] = shTrapeze; strToShape["parallelogram"] = shParallelogram; strToShape["invTriangle"] = shInvTriangle; strToShape["invTrapeze"] = shInvTrapeze; strToShape["invParallelogram"] = shInvParallelogram; strToShape["image"] = shImage; DPolyline bends; GmlObject *son = m_graphObject->m_pFirstSon; for(; son; son = son->m_pBrother) { switch(id(son)) { case nodePredefKey: { if (son->m_valueType != gmlListBegin) break; // set attributes to default values int vId = notDefined; double x = 0, y = 0, w = 0, h = 0; string label; string templ; string fill; // the fill color attribute string line; // the line color attribute string shape; //the shape type float lineWidth = 1.0f; //node line width int pattern = 1; //node brush pattern int stipple = 1; //line style pattern int weight = 0; // node weight // read all relevant attributes GmlObject *nodeSon = son->m_pFirstSon; for(; nodeSon; nodeSon = nodeSon->m_pBrother) { switch(id(nodeSon)) { case idPredefKey: if(nodeSon->m_valueType != gmlIntValue) break; vId = nodeSon->m_intValue; break; case graphicsPredefKey: { if (nodeSon->m_valueType != gmlListBegin) break; GmlObject *graphicsObject = nodeSon->m_pFirstSon; for(; graphicsObject; graphicsObject = graphicsObject->m_pBrother) { switch(id(graphicsObject)) { case xPredefKey: if(graphicsObject->m_valueType != gmlDoubleValue) break; x = graphicsObject->m_doubleValue; break; case yPredefKey: if(graphicsObject->m_valueType != gmlDoubleValue) break; y = graphicsObject->m_doubleValue; break; case wPredefKey: if(graphicsObject->m_valueType != gmlDoubleValue) break; w = graphicsObject->m_doubleValue; break; case hPredefKey: if(graphicsObject->m_valueType != gmlDoubleValue) break; h = graphicsObject->m_doubleValue; break; case fillPredefKey: if(graphicsObject->m_valueType != gmlStringValue) break; fill = graphicsObject->m_stringValue; break; case linePredefKey: if(graphicsObject->m_valueType != gmlStringValue) break; line = graphicsObject->m_stringValue; break; case lineWidthPredefKey: if(graphicsObject->m_valueType != gmlDoubleValue) break; lineWidth = (float)graphicsObject->m_doubleValue; break; case typePredefKey: if(graphicsObject->m_valueType != gmlStringValue) break; shape = graphicsObject->m_stringValue; break; case patternPredefKey: //fill style if(graphicsObject->m_valueType != gmlIntValue) break; pattern = graphicsObject->m_intValue; case stipplePredefKey: //line style if(graphicsObject->m_valueType != gmlIntValue) break; stipple = graphicsObject->m_intValue; } } break; } case templatePredefKey: if (nodeSon->m_valueType != gmlStringValue) break; templ = nodeSon->m_stringValue; break; case labelPredefKey: if (nodeSon->m_valueType != gmlStringValue) break; label = nodeSon->m_stringValue; break; case edgeWeightPredefKey: //sic! if (nodeSon->m_valueType != gmlIntValue) break; weight = nodeSon->m_intValue; break; } } // check if everything required is defined correctly if (vId == notDefined) { setError("node id not defined"); return false; } // create new node if necessary and assign attributes if (m_mapToNode[vId] == nullptr) m_mapToNode[vId] = G.newNode(); node v = m_mapToNode[vId]; if (AG.has(GraphAttributes::nodeGraphics)) { AG.x(v) = x; AG.y(v) = y; AG.width (v) = w; AG.height(v) = h; AG.shape(v) = strToShape[shape]; } if (AG.has(GraphAttributes::nodeLabel)) AG.label(m_mapToNode[vId]) = label; if (AG.has(GraphAttributes::nodeTemplate)) AG.templateNode(m_mapToNode[vId]) = templ; if (AG.has(GraphAttributes::nodeId)) AG.idNode(m_mapToNode[vId]) = vId; if (AG.has(GraphAttributes::nodeWeight)) AG.weight(m_mapToNode[vId]) = weight; if (AG.has(GraphAttributes::nodeStyle)) { AG.fillColor(m_mapToNode[vId]) = fill; AG.strokeColor(m_mapToNode[vId]) = line; AG.setFillPattern(m_mapToNode[vId], intToFillPattern(pattern)); AG.setStrokeType(m_mapToNode[vId], intToStrokeType(stipple)); AG.strokeWidth(m_mapToNode[vId]) = lineWidth; } }//node //Todo: line style set stipple value break; case edgePredefKey: { string arrow; // the arrow type attribute string fill; //the color fill attribute int stipple = 1; //the line style float lineWidth = 1.0f; double edgeWeight = 1.0; int subGraph = 0; //edgeSubGraphs attribute string label; // label attribute if (son->m_valueType != gmlListBegin) break; // set attributes to default values int sourceId = notDefined, targetId = notDefined; Graph::EdgeType umlType = Graph::association; // read all relevant attributes GmlObject *edgeSon = son->m_pFirstSon; for(; edgeSon; edgeSon = edgeSon->m_pBrother) { switch(id(edgeSon)) { case sourcePredefKey: if (edgeSon->m_valueType != gmlIntValue) break; sourceId = edgeSon->m_intValue; break; case targetPredefKey: if (edgeSon->m_valueType != gmlIntValue) break; targetId = edgeSon->m_intValue; break; case subGraphPredefKey: if (edgeSon->m_valueType != gmlIntValue) break; subGraph = edgeSon->m_intValue; break; case labelPredefKey: if (edgeSon->m_valueType != gmlStringValue) break; label = edgeSon->m_stringValue; break; case graphicsPredefKey: { if (edgeSon->m_valueType != gmlListBegin) break; GmlObject *graphicsObject = edgeSon->m_pFirstSon; for(; graphicsObject; graphicsObject = graphicsObject->m_pBrother) { if(id(graphicsObject) == LinePredefKey && graphicsObject->m_valueType == gmlListBegin) { readLineAttribute(graphicsObject->m_pFirstSon,bends); } if(id(graphicsObject) == arrowPredefKey && graphicsObject->m_valueType == gmlStringValue) arrow = graphicsObject->m_stringValue; if(id(graphicsObject) == fillPredefKey && graphicsObject->m_valueType == gmlStringValue) fill = graphicsObject->m_stringValue; if (id(graphicsObject) == stipplePredefKey && //line style graphicsObject->m_valueType == gmlIntValue) stipple = graphicsObject->m_intValue; if (id(graphicsObject) == lineWidthPredefKey && //line width graphicsObject->m_valueType == gmlDoubleValue) lineWidth = (float)graphicsObject->m_doubleValue; if (id(graphicsObject) == edgeWeightPredefKey && graphicsObject->m_valueType == gmlDoubleValue) edgeWeight = graphicsObject->m_doubleValue; }//for graphics } case generalizationPredefKey: if (edgeSon->m_valueType != gmlIntValue) break; umlType = (edgeSon->m_intValue == 0) ? Graph::association : Graph::generalization; break; } } // check if everything required is defined correctly if (sourceId == notDefined || targetId == notDefined) { setError("source or target id not defined"); return false; } else if (sourceId < minId || maxId < sourceId || targetId < minId || maxId < targetId) { setError("source or target id out of range"); return false; } // create adjacent nodes if necessary and new edge if (m_mapToNode[sourceId] == nullptr) m_mapToNode[sourceId] = G.newNode(); if (m_mapToNode[targetId] == nullptr) m_mapToNode[targetId] = G.newNode(); edge e = G.newEdge(m_mapToNode[sourceId],m_mapToNode[targetId]); if (AG.has(GraphAttributes::edgeGraphics)) AG.bends(e).conc(bends); if (AG.has(GraphAttributes::edgeType)) AG.type(e) = umlType; if(AG.has(GraphAttributes::edgeSubGraphs)) AG.subGraphBits(e) = subGraph; if (AG.has(GraphAttributes::edgeLabel)) AG.label(e) = label; if (AG.has(GraphAttributes::edgeArrow)) { if (arrow == "none") AG.arrowType(e) = eaNone; else if (arrow == "last") AG.arrowType(e) = eaLast; else if (arrow == "first") AG.arrowType(e) = eaFirst; else if (arrow == "both") AG.arrowType(e) = eaBoth; else AG.arrowType(e) = eaUndefined; } if (AG.has(GraphAttributes::edgeStyle)) { AG.strokeColor(e) = fill; AG.setStrokeType(e, intToStrokeType(stipple)); AG.strokeWidth(e) = lineWidth; } if (AG.has(GraphAttributes::edgeDoubleWeight)) AG.doubleWeight(e) = edgeWeight; break; } case directedPredefKey: { if(son->m_valueType != gmlIntValue) break; AG.setDirected(son->m_intValue > 0); break; } } } return true; }//read
void ELabelPosSimple::call(GraphAttributes &ug, ELabelInterface<double> &eli) { //ug.addNodeCenter2Bends(); for(edge e : ug.constGraph().edges) { EdgeLabel<double> &el = eli.getLabel(e); DPolyline bends = ug.bends(e); bends.normalize(); if (bends.size() < 2) OGDF_THROW_PARAM(AlgorithmFailureException, afcLabel); double frac; if (m_absolut) { double len = bends.length(); if (len == 0.0) frac = 0.0; else frac = m_marginDistance / len; } else { frac = m_marginDistance; } if (frac < 0.0) frac = 0.0; if (frac > 0.4) frac = 0.4; double midFrac = 0.5; double startFrac = frac; double endFrac = 1.0 -frac; // hole Positionen auf der Kante DPoint midPoint = bends.position(midFrac); DPoint startPoint = bends.position(startFrac); DPoint endPoint = bends.position(endFrac); // hole die beteiligten Segmente DLine midLine = segment(bends, midFrac); DLine startLine = segment(bends, startFrac); DLine endLine = segment(bends, endFrac); // berechne die Labelpositionen if (el.usedLabel(elEnd1)) { DPoint np = leftOfSegment(startLine, startPoint, m_edgeDistance, true); el.setX(elEnd1, np.m_x); el.setY(elEnd1, np.m_y); } if (el.usedLabel(elMult1)) { DPoint np = leftOfSegment(startLine, startPoint, m_edgeDistance, false); el.setX(elMult1, np.m_x); el.setY(elMult1, np.m_y); } if (el.usedLabel(elName)) { DPoint np = m_midOnEdge ? midPoint : leftOfSegment(midLine, midPoint, m_edgeDistance, true); el.setX(elName, np.m_x); el.setY(elName, np.m_y); } if (el.usedLabel(elEnd2)) { DPoint np = leftOfSegment(endLine, endPoint, m_edgeDistance, true); el.setX(elEnd2, np.m_x); el.setY(elEnd2, np.m_y); } if (el.usedLabel(elMult2)) { DPoint np = leftOfSegment(endLine, endPoint, m_edgeDistance, false); el.setX(elMult2, np.m_x); el.setY(elMult2, np.m_y); } } }
void EdgeLengthCompacter::assignCoordinates(const Graph& g, NodeArray<int>& nodeColumns, EdgeArray<int>& edgeColumns, NodeArray<NodeCoordinates>& nodeCoordinates, EdgeArray<EdgeCoordinates>& edgeCoordinates, GraphAttributes& retVal){ assignXCoordinates(nodeColumns, retVal); node n; forall_nodes(n, g){ retVal.y(n) = (nodeCoordinates[n].y_top + nodeCoordinates[n].y_bottom) / 2; } edge e; forall_edges(e, g){ EdgeCoordinates& ec = edgeCoordinates[e]; // cout << "Edge "<< e->source() << " -> " << e->target() << endl; // cout << "\ty1\t"<< ec.y_1<< endl; // cout << "\ty2\t"<< ec.y_2<< endl; // cout << "\tt off\t"<< ec.x_offset_target<< endl; // cout << "\ts_off\t"<< ec.x_offset_source<< endl; node source = e->source(); node target = e->target(); double sourceColumn = nodeColumns[source]; double edgeColumn = edgeColumns[e]; double targetColumn = nodeColumns[target]; double sourceX = sourceColumn * (boxWidth + boxBoxSpacing) + ec.x_offset_source; double targetX = targetColumn * (boxWidth + boxBoxSpacing) + ec.x_offset_target; double edgeX = edgeColumns[e] * (boxWidth + boxBoxSpacing); retVal.bends(e).clear(); DPoint p0(sourceX, nodeCoordinates[source].y_bottom + 0.001); retVal.bends(e).pushBack(p0); DPoint p1(sourceX, ec.y_1); retVal.bends(e).pushBack(p1); if (sourceColumn == edgeColumns[e]){ DPoint p2(sourceX, ec.y_1); retVal.bends(e).pushBack(p2); DPoint p3(sourceX, ec.y_2); retVal.bends(e).pushBack(p3); } else if (targetColumn == edgeColumns[e]){ DPoint p2(targetX, ec.y_1); retVal.bends(e).pushBack(p2); DPoint p3(targetX, ec.y_2); retVal.bends(e).pushBack(p3); } else { DPoint p2(edgeX, ec.y_1); retVal.bends(e).pushBack(p2); DPoint p3(edgeX, ec.y_2); retVal.bends(e).pushBack(p3); } DPoint p4(targetX, ec.y_2); retVal.bends(e).pushBack(p4); DPoint p5(targetX, nodeCoordinates[target].y_top - 0.001); retVal.bends(e).pushBack(p5); }
bool GmlParser::read(Graph &G, GraphAttributes &AG) { OGDF_ASSERT(&G == &(AG.constGraph())) G.clear(); int minId = m_mapToNode.low(); int maxId = m_mapToNode.high(); int notDefined = minId-1; //indicates not defined id key DPolyline bends; GmlObject *son = m_graphObject->m_pFirstSon; for(; son; son = son->m_pBrother) { switch(id(son)) { case nodePredefKey: { if (son->m_valueType != gmlListBegin) break; // set attributes to default values int vId = notDefined; double x = 0, y = 0, w = 0, h = 0; String label; String templ; String fill; // the fill color attribute String line; // the line color attribute String shape; //the shape type double lineWidth = 1.0; //node line width int pattern = 1; //node brush pattern int stipple = 1; //line style pattern // read all relevant attributes GmlObject *nodeSon = son->m_pFirstSon; for(; nodeSon; nodeSon = nodeSon->m_pBrother) { switch(id(nodeSon)) { case idPredefKey: if(nodeSon->m_valueType != gmlIntValue) break; vId = nodeSon->m_intValue; break; case graphicsPredefKey: { if (nodeSon->m_valueType != gmlListBegin) break; GmlObject *graphicsObject = nodeSon->m_pFirstSon; for(; graphicsObject; graphicsObject = graphicsObject->m_pBrother) { switch(id(graphicsObject)) { case xPredefKey: if(graphicsObject->m_valueType != gmlDoubleValue) break; x = graphicsObject->m_doubleValue; break; case yPredefKey: if(graphicsObject->m_valueType != gmlDoubleValue) break; y = graphicsObject->m_doubleValue; break; case wPredefKey: if(graphicsObject->m_valueType != gmlDoubleValue) break; w = graphicsObject->m_doubleValue; break; case hPredefKey: if(graphicsObject->m_valueType != gmlDoubleValue) break; h = graphicsObject->m_doubleValue; break; case fillPredefKey: if(graphicsObject->m_valueType != gmlStringValue) break; fill = graphicsObject->m_stringValue; break; case linePredefKey: if(graphicsObject->m_valueType != gmlStringValue) break; line = graphicsObject->m_stringValue; break; case lineWidthPredefKey: if(graphicsObject->m_valueType != gmlDoubleValue) break; lineWidth = graphicsObject->m_doubleValue; break; case typePredefKey: if(graphicsObject->m_valueType != gmlStringValue) break; shape = graphicsObject->m_stringValue; break; case patternPredefKey: //fill style if(graphicsObject->m_valueType != gmlIntValue) break; pattern = graphicsObject->m_intValue; case stipplePredefKey: //line style if(graphicsObject->m_valueType != gmlIntValue) break; stipple = graphicsObject->m_intValue; } } break; } case templatePredefKey: if (nodeSon->m_valueType != gmlStringValue) break; templ = nodeSon->m_stringValue; break; case labelPredefKey: if (nodeSon->m_valueType != gmlStringValue) break; label = nodeSon->m_stringValue; break; } } // check if everything required is defined correctly if (vId == notDefined) { setError("node id not defined"); return false; } // create new node if necessary and assign attributes if (m_mapToNode[vId] == 0) m_mapToNode[vId] = G.newNode(); if (AG.attributes() & GraphAttributes::nodeGraphics) { AG.x(m_mapToNode[vId]) = x; AG.y(m_mapToNode[vId]) = y; AG.width (m_mapToNode[vId]) = w; AG.height(m_mapToNode[vId]) = h; if (shape == "oval") AG.shapeNode(m_mapToNode[vId]) = GraphAttributes::oval; else AG.shapeNode(m_mapToNode[vId]) = GraphAttributes::rectangle; } if ( (AG.attributes() & GraphAttributes::nodeColor) && (AG.attributes() & GraphAttributes::nodeGraphics) ) { AG.colorNode(m_mapToNode[vId]) = fill; AG.nodeLine(m_mapToNode[vId]) = line; } if (AG.attributes() & GraphAttributes::nodeLabel) AG.labelNode(m_mapToNode[vId]) = label; if (AG.attributes() & GraphAttributes::nodeTemplate) AG.templateNode(m_mapToNode[vId]) = templ; if (AG.attributes() & GraphAttributes::nodeId) AG.idNode(m_mapToNode[vId]) = vId; if (AG.attributes() & GraphAttributes::nodeStyle) { AG.nodePattern(m_mapToNode[vId]) = GraphAttributes::intToPattern(pattern); AG.styleNode(m_mapToNode[vId]) = GraphAttributes::intToStyle(stipple); AG.lineWidthNode(m_mapToNode[vId]) = lineWidth; } }//node //Todo: line style set stipple value break; case edgePredefKey: { String arrow; // the arrow type attribute String fill; //the color fill attribute int stipple = 1; //the line style double lineWidth = 1.0; double edgeWeight = 1.0; int subGraph = 0; //edgeSubGraph attribute String label; // label attribute if (son->m_valueType != gmlListBegin) break; // set attributes to default values int sourceId = notDefined, targetId = notDefined; Graph::EdgeType umlType = Graph::association; // read all relevant attributes GmlObject *edgeSon = son->m_pFirstSon; for(; edgeSon; edgeSon = edgeSon->m_pBrother) { switch(id(edgeSon)) { case sourcePredefKey: if (edgeSon->m_valueType != gmlIntValue) break; sourceId = edgeSon->m_intValue; break; case targetPredefKey: if (edgeSon->m_valueType != gmlIntValue) break; targetId = edgeSon->m_intValue; break; case subGraphPredefKey: if (edgeSon->m_valueType != gmlIntValue) break; subGraph = edgeSon->m_intValue; break; case labelPredefKey: if (edgeSon->m_valueType != gmlStringValue) break; label = edgeSon->m_stringValue; break; case graphicsPredefKey: { if (edgeSon->m_valueType != gmlListBegin) break; GmlObject *graphicsObject = edgeSon->m_pFirstSon; for(; graphicsObject; graphicsObject = graphicsObject->m_pBrother) { if(id(graphicsObject) == LinePredefKey && graphicsObject->m_valueType == gmlListBegin) { readLineAttribute(graphicsObject->m_pFirstSon,bends); } if(id(graphicsObject) == arrowPredefKey && graphicsObject->m_valueType == gmlStringValue) arrow = graphicsObject->m_stringValue; if(id(graphicsObject) == fillPredefKey && graphicsObject->m_valueType == gmlStringValue) fill = graphicsObject->m_stringValue; if (id(graphicsObject) == stipplePredefKey && //line style graphicsObject->m_valueType == gmlIntValue) stipple = graphicsObject->m_intValue; if (id(graphicsObject) == lineWidthPredefKey && //line width graphicsObject->m_valueType == gmlDoubleValue) lineWidth = graphicsObject->m_doubleValue; if (id(graphicsObject) == edgeWeightPredefKey && graphicsObject->m_valueType == gmlDoubleValue) edgeWeight = graphicsObject->m_doubleValue; }//for graphics } case generalizationPredefKey: if (edgeSon->m_valueType != gmlIntValue) break; umlType = (edgeSon->m_intValue == 0) ? Graph::association : Graph::generalization; break; } } // check if everything required is defined correctly if (sourceId == notDefined || targetId == notDefined) { setError("source or target id not defined"); return false; } else if (sourceId < minId || maxId < sourceId || targetId < minId || maxId < targetId) { setError("source or target id out of range"); return false; } // create adjacent nodes if necessary and new edge if (m_mapToNode[sourceId] == 0) m_mapToNode[sourceId] = G.newNode(); if (m_mapToNode[targetId] == 0) m_mapToNode[targetId] = G.newNode(); edge e = G.newEdge(m_mapToNode[sourceId],m_mapToNode[targetId]); if (AG.attributes() & GraphAttributes::edgeGraphics) AG.bends(e).conc(bends); if (AG.attributes() & GraphAttributes::edgeType) AG.type(e) = umlType; if(AG.attributes() & GraphAttributes::edgeSubGraph) AG.subGraphBits(e) = subGraph; if (AG.attributes() & GraphAttributes::edgeLabel) AG.labelEdge(e) = label; if (AG.attributes() & GraphAttributes::edgeArrow) if (arrow == "none") AG.arrowEdge(e) = GraphAttributes::none; else if (arrow == "last") AG.arrowEdge(e) = GraphAttributes::last; else if (arrow == "first") AG.arrowEdge(e) = GraphAttributes::first; else if (arrow == "both") AG.arrowEdge(e) = GraphAttributes::both; else AG.arrowEdge(e) = GraphAttributes::undefined; if (AG.attributes() & GraphAttributes::edgeColor) AG.colorEdge(e) = fill; if (AG.attributes() & GraphAttributes::edgeStyle) { AG.styleEdge(e) = AG.intToStyle(stipple); AG.edgeWidth(e) = lineWidth; } if (AG.attributes() & GraphAttributes::edgeDoubleWeight) AG.doubleWeight(e) = edgeWeight; break; } case directedPredefKey: { if(son->m_valueType != gmlIntValue) break; AG.directed(son->m_intValue > 0); break; } } } return true; }//read
void SpringEmbedderFRExact::call(GraphAttributes &AG) { const Graph &G = AG.constGraph(); if(G.empty()) return; // all edges straight-line AG.clearAllBends(); ArrayGraph component(AG); component.m_useNodeWeight = m_useNodeWeight; EdgeArray<edge> auxCopy(G); Array<DPoint> boundingBox(component.numberOfCCs()); int i; for(i = 0; i < component.numberOfCCs(); ++i) { component.initCC(i); if (component.numberOfNodes() >= 2) { initialize(component); #ifdef OGDF_SSE3_EXTENSIONS if(System::cpuSupports(cpufSSE3)) mainStep_sse3(component); else #endif mainStep(component); } double minX, maxX, minY, maxY; minX = maxX = component.m_x[0]; minY = maxY = component.m_y[0]; for(int vCopy = 0; vCopy < component.numberOfNodes(); ++vCopy) { node v = component.original(vCopy); AG.x(v) = component.m_x[vCopy]; AG.y(v) = component.m_y[vCopy]; if(AG.x(v)-AG.width (v)/2 < minX) minX = AG.x(v)-AG.width(v) /2; if(AG.x(v)+AG.width (v)/2 > maxX) maxX = AG.x(v)+AG.width(v) /2; if(AG.y(v)-AG.height(v)/2 < minY) minY = AG.y(v)-AG.height(v)/2; if(AG.y(v)+AG.height(v)/2 > maxY) maxY = AG.y(v)+AG.height(v)/2; } minX -= m_minDistCC; minY -= m_minDistCC; for(int vCopy = 0; vCopy < component.numberOfNodes(); ++vCopy) { node v = component.original(vCopy); AG.x(v) -= minX; AG.y(v) -= minY; } boundingBox[i] = DPoint(maxX - minX, maxY - minY); } Array<DPoint> offset(component.numberOfCCs()); TileToRowsCCPacker packer; packer.call(boundingBox,offset,m_pageRatio); // The arrangement is given by offset to the origin of the coordinate // system. We still have to shift each node and edge by the offset // of its connected component. for(i = 0; i < component.numberOfCCs(); ++i) { const SList<node> &nodes = component.nodesInCC(i); const double dx = offset[i].m_x; const double dy = offset[i].m_y; // iterate over all nodes in ith CC for(node v : nodes) { AG.x(v) += dx; AG.y(v) += dy; } } }
double LayoutStatistics::angularResolution( const GraphAttributes &ga, double *pMaxAngle, double *pAvgAngle, double *pStdDeviation, bool considerBends) { const Graph &G = ga.constGraph(); double minAngle = 2*Math::pi, maxAngle = 0, sumAngles = 0; int numAngles = 0; ListPure<double> allAngles; for (node v : G.nodes) { double vx = ga.x(v), vy = ga.y(v); List<double> angles; for (adjEntry adj : v->adjEntries) { const DPolyline &dpl = ga.bends(adj->theEdge()); double ex, ey; if (dpl.empty()) { ex = ga.x(adj->twinNode()); ey = ga.y(adj->twinNode()); } else { ex = dpl.front().m_x; ey = dpl.front().m_y; } angles.pushBack(atan2(ex-vx, ey-vy)); } if (angles.size() < 2) continue; numAngles += angles.size(); angles.quicksort(); double lastAngle = angles.back(); for (double psi : angles) { double alpha = psi - lastAngle; if (pStdDeviation) allAngles.pushBack(alpha); sumAngles += alpha; minAngle = min(minAngle, alpha); maxAngle = max(maxAngle, alpha); lastAngle = psi; } } if (considerBends) { for (edge e : G.edges) { DPolyline dpl = ga.bends(e); dpl.pushFront( DPoint(ga.x(e->source()), ga.y(e->source())) ); dpl.pushBack ( DPoint(ga.x(e->target()), ga.y(e->target())) ); dpl.normalize(); if (dpl.size() < 3) continue; for (ListConstIterator<DPoint> it = dpl.begin().succ(); it != dpl.rbegin(); ++it) { double bx = (*it).m_x, by = (*it).m_y; const DPoint &p1 = *it.pred(); double psi1 = atan2(p1.m_x-bx, p1.m_y-by); const DPoint &p2 = *it.succ(); double psi2 = atan2(p2.m_x - bx, p2.m_y - by); double alpha = fabs(psi1 - psi2); if (alpha > Math::pi) alpha -= Math::pi; sumAngles += 2 * Math::pi; minAngle = min(minAngle, alpha); maxAngle = max(maxAngle, alpha + Math::pi); if (pStdDeviation) { numAngles += 2; allAngles.pushBack(alpha); allAngles.pushBack(alpha*Math::pi); } } } } double avgAngle = sumAngles / numAngles; if (pAvgAngle) *pAvgAngle = avgAngle; if (pMaxAngle) *pMaxAngle = maxAngle; if (pStdDeviation) { double sum = 0; for (double alpha : allAngles) { double d = alpha - avgAngle; sum += d*d; } *pStdDeviation = sqrt(sum / numAngles); } return minAngle; }
void GEMLayout::call(GraphAttributes &AG) { const Graph &G = AG.constGraph(); if(G.empty()) return; // all edges straight-line AG.clearAllBends(); GraphCopy GC; GC.createEmpty(G); // compute connected component of G NodeArray<int> component(G); int numCC = connectedComponents(G,component); // intialize the array of lists of nodes contained in a CC Array<List<node> > nodesInCC(numCC); for(node v : G.nodes) nodesInCC[component[v]].pushBack(v); EdgeArray<edge> auxCopy(G); Array<DPoint> boundingBox(numCC); int i; for(i = 0; i < numCC; ++i) { GC.initByNodes(nodesInCC[i],auxCopy); GraphCopyAttributes AGC(GC,AG); for(node vCopy : GC.nodes) { node vOrig = GC.original(vCopy); AGC.x(vCopy) = AG.x(vOrig); AGC.y(vCopy) = AG.y(vOrig); } SList<node> permutation; // initialize node data m_impulseX.init(GC,0); m_impulseY.init(GC,0); m_skewGauge.init(GC,0); m_localTemperature.init(GC,m_initialTemperature); // initialize other data m_globalTemperature = m_initialTemperature; m_barycenterX = 0; m_barycenterY = 0; for(node v : GC.nodes) { m_barycenterX += weight(v) * AGC.x(v); m_barycenterY += weight(v) * AGC.y(v); } m_cos = cos(m_oscillationAngle / 2.0); m_sin = sin(Math::pi / 2 + m_rotationAngle / 2.0); // main loop int counter = m_numberOfRounds; while(OGDF_GEOM_ET.greater(m_globalTemperature,m_minimalTemperature) && counter--) { // choose nodes by random permutations if(permutation.empty()) { for(node v : GC.nodes) permutation.pushBack(v); permutation.permute(m_rng); } node v = permutation.popFrontRet(); // compute the impulse of node v computeImpulse(GC,AGC,v); // update node v updateNode(GC,AGC,v); } node vFirst = GC.firstNode(); double minX = AGC.x(vFirst), maxX = AGC.x(vFirst), minY = AGC.y(vFirst), maxY = AGC.y(vFirst); for(node vCopy : GC.nodes) { node v = GC.original(vCopy); AG.x(v) = AGC.x(vCopy); AG.y(v) = AGC.y(vCopy); if(AG.x(v)-AG.width (v)/2 < minX) minX = AG.x(v)-AG.width(v) /2; if(AG.x(v)+AG.width (v)/2 > maxX) maxX = AG.x(v)+AG.width(v) /2; if(AG.y(v)-AG.height(v)/2 < minY) minY = AG.y(v)-AG.height(v)/2; if(AG.y(v)+AG.height(v)/2 > maxY) maxY = AG.y(v)+AG.height(v)/2; } minX -= m_minDistCC; minY -= m_minDistCC; for(node vCopy : GC.nodes) { node v = GC.original(vCopy); AG.x(v) -= minX; AG.y(v) -= minY; } boundingBox[i] = DPoint(maxX - minX, maxY - minY); } Array<DPoint> offset(numCC); TileToRowsCCPacker packer; packer.call(boundingBox,offset,m_pageRatio); // The arrangement is given by offset to the origin of the coordinate // system. We still have to shift each node and edge by the offset // of its connected component. for(i = 0; i < numCC; ++i) { const List<node> &nodes = nodesInCC[i]; const double dx = offset[i].m_x; const double dy = offset[i].m_y; // iterate over all nodes in ith CC ListConstIterator<node> it; for(node v : nodes) { AG.x(v) += dx; AG.y(v) += dy; } } // free node data m_impulseX.init(); m_impulseY.init(); m_skewGauge.init(); m_localTemperature.init(); }
//this sets the parameters of the class DavidsonHarel, adds the energy functions and //starts the optimization process void DavidsonHarelLayout::call(GraphAttributes &AG) { // all edges straight-line AG.clearAllBends(); DavidsonHarel dh; Repulsion rep(AG); Attraction atr(AG); Overlap over(AG); Planarity plan(AG); //PlanarityGrid plan(AG); //PlanarityGrid2 plan(AG); //NodeIntersection ni(AG); // Either use a fixed value... if (DIsGreater(m_prefEdgeLength, 0.0)) { atr.setPreferredEdgelength(m_prefEdgeLength); } // ...or set it depending on vertex sizes else atr.reinitializeEdgeLength(m_multiplier); dh.addEnergyFunction(&rep,m_repulsionWeight); dh.addEnergyFunction(&atr,m_attractionWeight); dh.addEnergyFunction(&over,m_nodeOverlapWeight); if (m_crossings) dh.addEnergyFunction(&plan,m_planarityWeight); //dh.addEnergyFunction(&ni,2000.0); //dh.setNumberOfIterations(m_numberOfIterations); //dh.setStartTemperature(m_startTemperature); const Graph& G = AG.constGraph(); //TODO: Immer Anzahl Iterationen abhängig von Größe if (m_numberOfIterations == 0) { switch (m_speed) //todo: function setSpeedParameters { case sppFast: { m_numberOfIterations = max(75, 3*G.numberOfNodes()); m_startTemperature = 400; } break; case sppMedium: { m_numberOfIterations = 10*G.numberOfNodes(); m_startTemperature = 1500; } break; case sppHQ: { m_numberOfIterations = 2500*G.numberOfNodes(); //should be: isolate m_startTemperature = 2000; } break; default: OGDF_THROW_PARAM(AlgorithmFailureException, afcIllegalParameter); break; }//switch }//if else { if (m_itAsFactor) dh.setNumberOfIterations(200+m_numberOfIterations*G.numberOfNodes()); else dh.setNumberOfIterations(m_numberOfIterations); } dh.setStartTemperature(m_startTemperature); dh.call(AG); }
void BertaultLayout::call(GraphAttributes &AG) { const Graph &G = AG.constGraph(); if(G.numberOfNodes() == 0) return; if( (AG.attributes() & GraphAttributes::nodeGraphics) == 0 ) return; if( (AG.attributes() & GraphAttributes::edgeGraphics) != 0 ) AG.clearAllBends(); if(iter_no==0) iter_no=G.numberOfNodes()*10; if(req_length==0) { edge e; forall_edges(e,G) { node a=e->source(); node b=e->target(); req_length+=sqrt((AG.x(a)-AG.x(b))*(AG.x(a)-AG.x(b))+(AG.y(a)-AG.y(b))*(AG.y(a)-AG.y(b))); }