6 * $Date: 2012-07-04 23:09:19 +0200 (Mi, 04. Jul 2012) $
7 ***************************************************************/
10 * \brief Implements classes GridLayout and GridLayoutMapped
12 * \author Carsten Gutwenger
15 * This file is part of the Open Graph Drawing Framework (OGDF).
19 * See README.txt in the root directory of the OGDF installation for details.
22 * This program is free software; you can redistribute it and/or
23 * modify it under the terms of the GNU General Public License
24 * Version 2 or 3 as published by the Free Software Foundation;
25 * see the file LICENSE.txt included in the packaging of this file
29 * This program is distributed in the hope that it will be useful,
30 * but WITHOUT ANY WARRANTY; without even the implied warranty of
31 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
32 * GNU General Public License for more details.
35 * You should have received a copy of the GNU General Public
36 * License along with this program; if not, write to the Free
37 * Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
38 * Boston, MA 02110-1301, USA.
40 * \see http://www.gnu.org/copyleft/gpl.html
41 ***************************************************************/
44 #include <ogdf/basic/GridLayoutMapped.h>
45 #include <ogdf/planarity/PlanRepUML.h>
46 #include <ogdf/orthogonal/OrthoRep.h>
47 #include <ogdf/basic/Layout.h>
48 #include <ogdf/basic/HashArray.h>
54 //---------------------------------------------------------
56 //---------------------------------------------------------
58 IPolyline
GridLayout::polyline(edge e
) const
60 IPolyline ipl
= m_bends
[e
];
61 IPoint ipStart
= IPoint(m_x
[e
->source()],m_y
[e
->source()]);
62 IPoint ipEnd
= IPoint(m_x
[e
->target()],m_y
[e
->target()]);
64 if(ipl
.empty() || ipStart
!= ipl
.front())
65 ipl
.pushFront(ipStart
);
67 if(ipEnd
!= ipl
.back() || ipl
.size() < 2)
73 struct OGDF_EXPORT GridPointInfo
75 GridPointInfo() : m_v(0), m_e(0) { }
76 GridPointInfo(node v
) : m_v(v
), m_e(0) { }
77 GridPointInfo(edge e
) : m_v(0), m_e(e
) { }
79 bool operator==(const GridPointInfo
&i
) const {
80 return (m_v
== i
.m_v
&& m_e
== i
.m_e
);
83 bool operator!=(const GridPointInfo
&i
) const {
84 return !operator==(i
);
91 ostream
&operator<<(ostream
&os
, const GridPointInfo
&i
)
93 if(i
.m_v
== 0 && i
.m_e
== 0)
96 os
<< "{node " << i
.m_v
<< "}";
98 os
<< "{edge " << i
.m_e
<< "}";
104 class IPointHashFunc
{
106 int hash(const IPoint
&ip
) {
107 return 7*ip
.m_x
+ 23*ip
.m_y
;
112 bool GridLayout::checkLayout()
114 const Graph
&G
= *m_x
.graphOf();
115 HashArray
<IPoint
,GridPointInfo
> H
;
120 IPoint ip
= IPoint(m_x
[v
],m_y
[v
]);
121 GridPointInfo i
= H
[ip
];
122 if(i
!= GridPointInfo()) {
123 cout
<< "conflict of " << v
<< " with " << H
[ip
] << endl
;
127 H
[ip
] = GridPointInfo(v
);
133 const IPolyline
&bends
= m_bends
[e
];
135 ListConstIterator
<IPoint
> it
;
136 for(it
= bends
.begin(); it
.valid(); ++it
) {
137 GridPointInfo i
= H
[*it
];
138 if(i
!= GridPointInfo()) {
139 cout
<< "conflict of bend point " << (*it
) << " of edge " << e
<< " with " << H
[*it
] << endl
;
143 H
[*it
] = GridPointInfo(e
);
151 bool GridLayout::isRedundant(IPoint
&p1
, IPoint
&p2
, IPoint
&p3
)
153 int dzy1
= p3
.m_x
- p2
.m_x
;
154 int dzy2
= p3
.m_y
- p2
.m_y
;
155 int dyx1
= p2
.m_x
- p1
.m_x
;
157 if (dzy1
== 0) return (dyx1
== 0 || dzy2
== 0);
161 return (f
% dzy1
== 0 && (p2
.m_y
- p1
.m_y
) == f
/ dzy1
);
164 void GridLayout::compact(IPolyline
&ip
)
166 if (ip
.size() < 3) return;
168 ListIterator
<IPoint
> it
= ip
.begin();
169 IPoint p
= *it
; ++it
;
170 for (it
= it
.succ(); it
.valid(); ++it
) {
171 ListIterator
<IPoint
> itPred
= it
.pred();
172 if(p
== *itPred
|| isRedundant(p
,*itPred
,*it
)) {
180 IPolyline
GridLayout::getCompactBends(edge e
) const
182 IPolyline ipl
= m_bends
[e
];
184 if (ipl
.size() == 0) return ipl
;
187 IPoint ip_first
= ipl
.front();
188 IPoint ip_last
= ipl
.back();
191 IPoint
ip_src(m_x
[e
->source()],m_y
[e
->source()]);
192 IPoint
ip_tgt(m_x
[e
->target()],m_y
[e
->target()]);
194 ipl
.pushFront(ip_src
);
195 ipl
.pushBack (ip_tgt
);
203 if (ip_first
!= ip_src
&& (ipl
.empty() || ip_first
!= ipl
.front()))
204 ipl
.pushFront(ip_first
);
205 if (ip_last
!= ip_tgt
&& (ipl
.empty() || ip_last
!= ipl
.back()))
206 ipl
.pushBack(ip_last
);
213 void GridLayout::compactAllBends()
215 const Graph
&G
= *m_x
.graphOf();
219 m_bends
[e
] = getCompactBends(e
);
222 void GridLayout::remap(Layout
&drawing
)
224 const Graph
&G
= *m_x
.graphOf();
228 drawing
.x(v
) = m_x
[v
];
229 drawing
.y(v
) = m_y
[v
];
235 void GridLayout::computeBoundingBox(int &xmin
, int &xmax
, int &ymin
, int &ymax
)
237 const Graph
*pG
= m_x
.graphOf();
239 if(pG
== 0 || pG
->empty()) {
240 xmin
= xmax
= ymin
= ymax
= 0;
244 xmin
= ymin
= INT_MAX
;
245 xmax
= ymax
= INT_MIN
;
248 forall_nodes(v
,*pG
) {
250 if(x
< xmin
) xmin
= x
;
251 if(x
> xmax
) xmax
= x
;
254 if(y
< ymin
) ymin
= y
;
255 if(y
> ymax
) ymax
= y
;
259 forall_edges(e
,*pG
) {
260 ListConstIterator
<IPoint
> it
;
261 for(it
= m_bends
[e
].begin(); it
.valid(); ++it
) {
263 if(x
< xmin
) xmin
= x
;
264 if(x
> xmax
) xmax
= x
;
267 if(y
< ymin
) ymin
= y
;
268 if(y
> ymax
) ymax
= y
;
274 int GridLayout::manhattanDistance(const IPoint
&ip1
, const IPoint
&ip2
)
276 return abs(ip2
.m_x
-ip1
.m_x
) + abs(ip2
.m_y
-ip1
.m_y
);
279 double GridLayout::euclideanDistance(const IPoint
&ip1
, const IPoint
&ip2
)
281 double dx
= ip2
.m_x
-ip1
.m_x
;
282 double dy
= ip2
.m_y
-ip1
.m_y
;
284 return sqrt(dx
*dx
+ dy
*dy
);
288 int GridLayout::totalManhattanEdgeLength() const
290 const Graph
*pG
= m_x
.graphOf();
295 length
+= manhattanEdgeLength(e
);
297 // IPoint ip1 = IPoint(m_x[e->source()],m_y[e->source()]);
298 // ListConstIterator<IPoint> it = m_bends[e].begin();
299 // for(; it.valid(); ++it) {
300 // length += manhattanDistance(ip1,*it);
303 // length += manhattanDistance(ip1,IPoint(m_x[e->target()],m_y[e->target()]));
310 int GridLayout::maxManhattanEdgeLength() const
312 const Graph
*pG
= m_x
.graphOf();
317 length
= max( length
, manhattanEdgeLength(e
) );
323 int GridLayout::manhattanEdgeLength(edge e
) const
327 IPoint ip1
= IPoint(m_x
[e
->source()],m_y
[e
->source()]);
328 ListConstIterator
<IPoint
> it
= m_bends
[e
].begin();
329 for(; it
.valid(); ++it
) {
330 length
+= manhattanDistance(ip1
,*it
);
333 length
+= manhattanDistance(ip1
,IPoint(m_x
[e
->target()],m_y
[e
->target()]));
339 double GridLayout::totalEdgeLength() const
341 const Graph
*pG
= m_x
.graphOf();
345 forall_edges(e
,*pG
) {
346 IPoint ip1
= IPoint(m_x
[e
->source()],m_y
[e
->source()]);
347 ListConstIterator
<IPoint
> it
= m_bends
[e
].begin();
348 for(; it
.valid(); ++it
) {
349 length
+= euclideanDistance(ip1
,*it
);
352 length
+= euclideanDistance(ip1
,IPoint(m_x
[e
->target()],m_y
[e
->target()]));
359 int GridLayout::numberOfBends() const
361 const Graph
*pG
= m_x
.graphOf();
366 num
+= m_bends
[e
].size();
372 //---------------------------------------------------------
374 //---------------------------------------------------------
376 GridLayoutMapped::GridLayoutMapped(
382 GridLayout(PG
), m_gridWidth(PG
,0), m_gridHeight(PG
,0), m_pPG(&PG
)
384 // determine grid mapping factor
385 double minDelta
= separation
;
390 node vOrig
= PG
.original(v
);
391 if(vOrig
== 0) continue;
393 const OrthoRep::VertexInfoUML
*pInfo
= OR
.cageInfo(v
);
395 for(int s
= 0; s
<= 3; ++s
) {
396 const OrthoRep::SideInfoUML
&si
= pInfo
->m_side
[s
];
397 double size
= (s
& 1) ? PG
.widthOrig(vOrig
) : PG
.heightOrig(vOrig
);
398 if (size
== 0) continue;
401 int k
= max(si
.m_nAttached
[0],si
.m_nAttached
[1]);
403 minDelta
= min(minDelta
, size
/2);
405 minDelta
= min(minDelta
, size
/ (2*(k
+ cOverhang
)));
408 if (si
.m_nAttached
[0] == 0)
409 minDelta
= min(minDelta
, size
);
411 else if ( !((si
.m_nAttached
[0] == 1) && (cOverhang
== 0.0)) ) //hier cov= 0 abfangen
412 minDelta
= min(minDelta
,
413 size
/ (si
.m_nAttached
[0] - 1 + 2*cOverhang
));
415 minDelta
= min(minDelta
, size
/2);
422 if(0 < cOverhang
&& cOverhang
< 1) {
423 /*double tryMinDelta = max(cOverhang * minDelta, separation/10000.0);
424 double tryMinDelta = max(cOverhang * minDelta, separation/10000.0);
425 if(tryMinDelta < minDelta)
426 minDelta = tryMinDelta;*/
427 minDelta
*= cOverhang
;
430 m_fMapping
= fineness
/ minDelta
;
433 // initialize grid sizes of vertices
436 node vOrig
= PG
.original(v
);
439 m_gridWidth
[v
] = toGrid(PG
.widthOrig (vOrig
));
440 m_gridHeight
[v
] = toGrid(PG
.heightOrig(vOrig
));
446 void GridLayoutMapped::remap(Layout
&drawing
)
449 forall_nodes(v
,*m_pPG
) {
450 //should use toDouble here
451 drawing
.x(v
) = (m_x
[v
]/cGridScale
) / m_fMapping
;
452 drawing
.y(v
) = (m_y
[v
]/cGridScale
) / m_fMapping
;
457 } // end namespace ogdf