Tulip 5.7.1
Large graphs analysis and drawing
Loading...
Searching...
No Matches
minmaxproperty.cxx
1/*
2 *
3 * This file is part of Tulip (https://tulip.labri.fr)
4 *
5 * Authors: David Auber and the Tulip development Team
6 * from LaBRI, University of Bordeaux
7 *
8 * Tulip is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU Lesser General Public License
10 * as published by the Free Software Foundation, either version 3
11 * of the License, or (at your option) any later version.
12 *
13 * Tulip is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
16 * See the GNU General Public License for more details.
17 *
18 */
19#include <tulip/Graph.h>
20#include <tulip/Coord.h>
21
22template <typename nodeType, typename edgeType, typename propType>
24 tlp::Graph *graph, const std::string &name, NODE_VALUE NodeMin, NODE_VALUE NodeMax,
25 EDGE_VALUE EdgeMin, EDGE_VALUE EdgeMax)
26 : AbstractProperty<nodeType, edgeType, propType>(graph, name), _nodeMin(NodeMin),
27 _nodeMax(NodeMax), _edgeMin(EdgeMin), _edgeMax(EdgeMax), needGraphListener(false) {}
28
29template <typename nodeType, typename edgeType, typename propType>
31 const tlp::Graph *graph) {
32 if (!graph) {
33 graph = this->propType::graph;
34 }
35
36 unsigned int graphID = graph->getId();
37 auto it = minMaxNode.find(graphID);
38
39 return (it == minMaxNode.end()) ? computeMinMaxNode(graph) : it->second;
40}
41
42template <typename nodeType, typename edgeType, typename propType>
44 const tlp::Graph *graph) {
45 if (!graph) {
46 graph = this->propType::graph;
47 }
48
49 unsigned int graphID = graph->getId();
50 auto it = minMaxEdge.find(graphID);
51
52 return (it == minMaxEdge.end()) ? computeMinMaxEdge(graph) : it->second;
53}
54
55template <typename nodeType, typename edgeType, typename propType>
56 const MINMAX_PAIR(nodeType) &
58 if (!graph) {
59 graph = this->propType::graph;
60 }
61
62 NODE_VALUE maxN2 = _nodeMin, minN2 = _nodeMax;
63
65 for (auto n : graph->nodes()) {
66 CONST_NODE_VALUE tmp = this->getNodeValue(n);
67
68 if (tmp > maxN2)
69 maxN2 = tmp;
70 if (tmp < minN2)
71 minN2 = tmp;
72 }
73 }
74
75 if (maxN2 < minN2)
76 maxN2 = minN2 = AbstractProperty<nodeType, edgeType, propType>::nodeDefaultValue;
77
78 unsigned int sgi = graph->getId();
79
80 // graph observation is now delayed
81 // until we need to do some minmax computation
82 // this will minimize the graph loading
83 if (minMaxNode.find(sgi) == minMaxNode.end() && minMaxEdge.find(sgi) == minMaxEdge.end()) {
84 // launch graph hierarchy observation
85 graph->addListener(this);
86 }
87
88 return minMaxNode[sgi] = {minN2, maxN2};
89}
90
91template <typename nodeType, typename edgeType, typename propType>
92 const MINMAX_PAIR(edgeType) &
94 EDGE_VALUE maxE2 = _edgeMin, minE2 = _edgeMax;
95
97 for (auto ite : graph->edges()) {
98 CONST_EDGE_VALUE tmp = this->getEdgeValue(ite);
99
100 if (tmp > maxE2)
101 maxE2 = tmp;
102 if (tmp < minE2)
103 minE2 = tmp;
104 }
105 }
106
107 if (maxE2 < minE2)
108 maxE2 = minE2 = AbstractProperty<nodeType, edgeType, propType>::edgeDefaultValue;
109
110 unsigned int sgi = graph->getId();
111
112 // graph observation is now delayed
113 // until we need to do some minmax computation
114 // this will minimize the graph loading time
115 if (minMaxNode.find(sgi) == minMaxNode.end() && minMaxEdge.find(sgi) == minMaxEdge.end()) {
116 // launch graph hierarchy observation
117 graph->addListener(this);
118 }
119
120 return minMaxEdge[sgi] = {minE2, maxE2};
121}
122
123template <typename nodeType, typename edgeType, typename propType>
125 // we need to clear one of our map
126 // this will invalidate some minmax computations
127 // so the graphs corresponding to these cleared minmax computations
128 // may not have to be longer observed if they have no validated
129 // minmax computation in the other map
130
131 // loop to remove unneeded graph observation
132 // it is the case if minmax computation
133 //
134 auto it = minMaxNode.begin();
135 auto ite = minMaxNode.end();
136
137 for (; it != ite; ++it) {
138 unsigned int gi = it->first;
139 auto itg = minMaxEdge.find(gi);
140
141 if (itg == minMaxEdge.end()) {
142 // no computation in the other map
143 // we can stop observing the current graph
144 Graph *g = (propType::graph->getId() == gi) ? (needGraphListener ? nullptr : propType::graph)
145 : propType::graph->getDescendantGraph(gi);
146
147 if (g)
148 g->removeListener(this);
149 }
150 }
151
152 // finally clear the map
153 minMaxNode.clear();
154}
155
156template <typename nodeType, typename edgeType, typename propType>
158 // we need to clear one of our map
159 // this will invalidate some minmax computations
160 // so the graphs corresponding to these cleared minmax computations
161 // may not have to be longer observed if they have no validated
162 // minmax computation in the other map
163
164 // loop to remove unneeded graph observation
165 // it is the case if minmax computation
166 //
167 auto it = minMaxEdge.begin();
168 auto ite = minMaxEdge.end();
169
170 for (; it != ite; ++it) {
171 unsigned int gi = it->first;
172 auto itg = minMaxNode.find(gi);
173
174 if (itg == minMaxNode.end()) {
175 // no computation in the other map
176 // we can stop observing the current graph
177 Graph *g = (propType::graph->getId() == gi) ? (needGraphListener ? nullptr : propType::graph)
178 : propType::graph->getDescendantGraph(gi);
179
180 if (g)
181 g->removeListener(this);
182 }
183 }
184
185 // finally clear the map
186 minMaxEdge.clear();
187}
188
189template <typename nodeType, typename edgeType, typename propType>
191 CONST_NODE_VALUE newValue) {
192 auto it = minMaxNode.begin();
193
194 if (it != minMaxNode.end()) {
195 CONST_NODE_VALUE oldV = this->getNodeValue(n);
196
197 if (newValue != oldV) {
198 // loop on subgraph min/max
199 for (; it != minMaxNode.end(); ++it) {
200 auto sid = it->first;
201 if (sid) {
202 // check if n belongs to current subgraph
203 auto sg = this->graph->getDescendantGraph(sid);
204 // sg might be null in undo/redo context
205 if (sg && !sg->isElement(n))
206 continue;
207 }
208 // if min/max is ok for the current subgraph
209 // check if min or max has to be updated
210 CONST_NODE_VALUE minV = it->second.first;
211 CONST_NODE_VALUE maxV = it->second.second;
212
213 // check if min or max has to be updated
214 if ((newValue < minV) || (newValue > maxV) || (oldV == minV) || (oldV == maxV)) {
215 removeListenersAndClearNodeMap();
216 break;
217 }
218 }
219 }
220 }
221}
222
223template <typename nodeType, typename edgeType, typename propType>
225 CONST_EDGE_VALUE newValue) {
226 auto it = minMaxEdge.begin();
227
228 if (it != minMaxEdge.end()) {
229 CONST_EDGE_VALUE oldV = this->getEdgeValue(e);
230
231 if (newValue != oldV) {
232 // loop on subgraph min/max
233 for (; it != minMaxEdge.end(); ++it) {
234 auto sid = it->first;
235 if (sid) {
236 // check if e belongs to current subgraph
237 // sg might be null in undo/redo context
238 auto sg = this->graph->getDescendantGraph(sid);
239 if (sg && !sg->isElement(e))
240 continue;
241 }
242 // if min/max is ok for the current subgraph
243 // check if min or max has to be updated
244 CONST_EDGE_VALUE minV = it->second.first;
245 CONST_EDGE_VALUE maxV = it->second.second;
246
247 // check if min or max has to be updated
248 if ((newValue < minV) || (newValue > maxV) || (oldV == minV) || (oldV == maxV)) {
249 removeListenersAndClearEdgeMap();
250 break;
251 }
252 }
253 }
254 }
255}
256
257template <typename nodeType, typename edgeType, typename propType>
259 CONST_NODE_VALUE newValue) {
260 auto it = minMaxNode.begin();
261 // loop on subgraph min/max
262 MINMAX_PAIR(nodeType) minmax(newValue, newValue);
263
264 for (; it != minMaxNode.end(); ++it) {
265 unsigned int gid = it->first;
266 minMaxNode[gid] = minmax;
267 }
268}
269
270template <typename nodeType, typename edgeType, typename propType>
272 CONST_EDGE_VALUE newValue) {
273 auto it = minMaxEdge.begin();
274 // loop on subgraph min/max
275 MINMAX_PAIR(edgeType) minmax(newValue, newValue);
276
277 for (; it != minMaxEdge.end(); ++it) {
278 unsigned int gid = it->first;
279 minMaxEdge[gid] = minmax;
280 }
281}
282
283template <typename nodeType, typename edgeType, typename propType>
285 const GraphEvent *graphEvent = dynamic_cast<const tlp::GraphEvent *>(&ev);
286
287 if (graphEvent) {
288 tlp::Graph *graph = graphEvent->getGraph();
289
290 switch (graphEvent->getType()) {
291 case GraphEvent::TLP_ADD_NODE:
292 removeListenersAndClearNodeMap();
293 break;
294
295 case GraphEvent::TLP_DEL_NODE: {
296 unsigned int sgi = graph->getId();
297 auto it = minMaxNode.find(sgi);
298
299 if (it != minMaxNode.end()) {
300 CONST_NODE_VALUE oldV = this->getNodeValue(graphEvent->getNode());
301
302 // check if min or max has to be updated
303 if ((oldV == it->second.first) || (oldV == it->second.second)) {
304 minMaxNode.erase(it);
305
306 if ((minMaxEdge.find(sgi) == minMaxEdge.end()) &&
307 (!needGraphListener || (graph != propType::graph)))
308 // graph observation is no longer needed
309 graph->removeListener(this);
310 }
311 }
312
313 break;
314 }
315
316 case GraphEvent::TLP_ADD_EDGE:
317 removeListenersAndClearEdgeMap();
318 break;
319
320 case GraphEvent::TLP_DEL_EDGE: {
321 unsigned int sgi = graph->getId();
322 auto it = minMaxEdge.find(sgi);
323
324 if (it != minMaxEdge.end()) {
325 EDGE_VALUE oldV = this->getEdgeValue(graphEvent->getEdge());
326
327 // check if min or max has to be updated
328 if ((oldV == it->second.first) || (oldV == it->second.second)) {
329 minMaxEdge.erase(it);
330
331 if ((minMaxNode.find(sgi) == minMaxNode.end()) &&
332 (!needGraphListener || (graph != propType::graph)))
333 // graph observation is no longer needed
334 graph->removeListener(this);
335 }
336 }
337
338 break;
339 }
340
341 default:
342 // we don't care about the rest
343 break;
344 }
345 }
346}
This class extends upon PropertyInterface, and adds type-safe methods to get and set the node and edg...
bool hasNonDefaultValuatedEdges(const Graph *g=nullptr) const override
Returns whether the property has edges with a non default value. When given a Graph as parameter,...
bool hasNonDefaultValuatedNodes(const Graph *g=nullptr) const override
Returns whether the property has nodes with a non default value. When given a Graph as parameter,...
Event is the base class for all events used in the Observation mechanism.
Definition: Observable.h:52
unsigned int getId() const
Gets the unique identifier of the graph.
Definition: Graph.h:1067
Abstracts the computation of minimal and maximal values on node and edge values of properties.
void updateNodeValue(tlp::node n, CONST_NODE_VALUE newValue)
Updates the value on a node, and updates the minimal/maximal cached values if necessary....
MinMaxProperty(tlp::Graph *graph, const std::string &name, NODE_VALUE NodeMin, NODE_VALUE NodeMax, EDGE_VALUE EdgeMin, EDGE_VALUE EdgeMax)
Constructs a MinMaxProperty.
void updateEdgeValue(tlp::edge e, CONST_EDGE_VALUE newValue)
Updates the value on an edge, and updates the minimal/maximal cached values if necessary....
void updateAllEdgesValues(CONST_EDGE_VALUE newValue)
Updates the value of all edges, setting the maximum and minimum values to this. Should be called by s...
void treatEvent(const tlp::Event &ev) override
This function is called when events are sent to the Listeners, and Listeners only.
void updateAllNodesValues(CONST_NODE_VALUE newValue)
Updates the value of all nodes, setting the maximum and minimum values to this. Should be called by s...
void removeListener(Observable *const listener) const
Removes a listener from this object.
The edge struct represents an edge in a Graph object.
Definition: Edge.h:40
The node struct represents a node in a Graph object.
Definition: Node.h:40