~duyi001/gephi/DSNI

« back to all changes in this revision

Viewing changes to PreviewPlugin/src/org/gephi/preview/plugin/renderers/EdgeRenderer.java

  • Committer: sunsnowad
  • Author(s): Yi Du
  • Date: 2011-09-08 16:36:59 UTC
  • mfrom: (1435.1.968 gephi)
  • Revision ID: sunsnowad@www-691ed046717-20110908163659-aorx14ylp8f9qwdx
1.merge with main branch
2.update twitter4j to version 2.2.4
3.fix an existing bug on "twitter user import"

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
Copyright 2008-2011 Gephi
 
3
Authors : Yudi Xue <yudi.xue@usask.ca>, Mathieu Bastian
 
4
Website : http://www.gephi.org
 
5
 
 
6
This file is part of Gephi.
 
7
 
 
8
Gephi is free software: you can redistribute it and/or modify
 
9
it under the terms of the GNU Affero General Public License as
 
10
published by the Free Software Foundation, either version 3 of the
 
11
License, or (at your option) any later version.
 
12
 
 
13
Gephi 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.  See the
 
16
GNU Affero General Public License for more details.
 
17
 
 
18
You should have received a copy of the GNU Affero General Public License
 
19
along with Gephi.  If not, see <http://www.gnu.org/licenses/>.
 
20
 */
 
21
package org.gephi.preview.plugin.renderers;
 
22
 
 
23
import java.awt.Color;
 
24
import java.util.Locale;
 
25
import org.gephi.graph.api.Edge;
 
26
import org.gephi.graph.api.Node;
 
27
import org.gephi.preview.api.Item;
 
28
import org.gephi.preview.api.PreviewModel;
 
29
import org.gephi.preview.api.PreviewProperties;
 
30
import org.gephi.preview.api.PreviewProperty;
 
31
import org.gephi.preview.api.ProcessingTarget;
 
32
import org.gephi.preview.api.RenderTarget;
 
33
import org.gephi.preview.api.SVGTarget;
 
34
import org.gephi.preview.plugin.items.EdgeItem;
 
35
import org.gephi.preview.plugin.items.NodeItem;
 
36
import org.gephi.preview.spi.Renderer;
 
37
import org.gephi.preview.types.EdgeColor;
 
38
import org.openide.util.NbBundle;
 
39
import org.openide.util.lookup.ServiceProvider;
 
40
import org.w3c.dom.Element;
 
41
import processing.core.PGraphics;
 
42
import processing.core.PVector;
 
43
 
 
44
/**
 
45
 *
 
46
 * @author Yudi Xue, Mathieu Bastian
 
47
 */
 
48
@ServiceProvider(service = Renderer.class, position = 100)
 
49
public class EdgeRenderer implements Renderer {
 
50
 
 
51
    //Custom properties
 
52
    public static final String EDGE_MIN_WEIGHT = "edge.min-weight";
 
53
    public static final String EDGE_MAX_WEIGHT = "edge.max-weight";
 
54
    public static final String BEZIER_CURVENESS = "edge.bezier-curveness";
 
55
    public static final String SOURCE = "edge.source";
 
56
    public static final String TARGET = "edge.target";
 
57
    public static final String TARGET_RADIUS = "edge.target.radius";
 
58
    //Default values
 
59
    private boolean defaultShowEdges = true;
 
60
    private float defaultThickness = 1;
 
61
    private boolean defaultRescaleWeight = true;
 
62
    private EdgeColor defaultColor = new EdgeColor(EdgeColor.Mode.MIXED);
 
63
    private boolean defaultEdgeCurved = true;
 
64
    private float defaultBezierCurviness = 0.2f;
 
65
    private int defaultOpacity = 100;
 
66
 
 
67
    public void preProcess(PreviewModel previewModel) {
 
68
        PreviewProperties properties = previewModel.getProperties();
 
69
        Item[] edgeItems = previewModel.getItems(Item.EDGE);
 
70
 
 
71
        //Put nodes in edge item
 
72
        for (Item item : edgeItems) {
 
73
            Edge edge = (Edge) item.getSource();
 
74
            Node source = edge.getSource().getNodeData().getRootNode();
 
75
            Node target = edge.getTarget().getNodeData().getRootNode();
 
76
            Item nodeSource = previewModel.getItem(Item.NODE, source);
 
77
            Item nodeTarget = previewModel.getItem(Item.NODE, target);
 
78
            item.setData(SOURCE, nodeSource);
 
79
            item.setData(TARGET, nodeTarget);
 
80
        }
 
81
 
 
82
        //Calculate max and min weight
 
83
        float minWeight = Float.POSITIVE_INFINITY;
 
84
        float maxWeight = Float.NEGATIVE_INFINITY;
 
85
 
 
86
        for (Item edge : edgeItems) {
 
87
            minWeight = Math.min(minWeight, (Float) edge.getData(EdgeItem.WEIGHT));
 
88
            maxWeight = Math.max(maxWeight, (Float) edge.getData(EdgeItem.WEIGHT));
 
89
        }
 
90
        properties.putValue(EDGE_MIN_WEIGHT, minWeight);
 
91
        properties.putValue(EDGE_MAX_WEIGHT, maxWeight);
 
92
 
 
93
        //Put bezier curveness in properties
 
94
        if (!properties.hasProperty(BEZIER_CURVENESS)) {
 
95
            properties.putValue(BEZIER_CURVENESS, defaultBezierCurviness);
 
96
        }
 
97
 
 
98
        //Rescale weight if necessary - and avoid negative weights
 
99
        boolean rescaleWeight = properties.getBooleanValue(PreviewProperty.EDGE_RESCALE_WEIGHT);
 
100
        for (Item item : edgeItems) {
 
101
            float weight = (Float) item.getData(EdgeItem.WEIGHT);
 
102
 
 
103
            //Rescale weight
 
104
            if (rescaleWeight) {
 
105
                if (!Double.isInfinite(minWeight) && !Double.isInfinite(maxWeight) && maxWeight != minWeight) {
 
106
                    float ratio = 1f / (maxWeight - minWeight);
 
107
                    weight = (weight - minWeight) * ratio;
 
108
                }
 
109
            } else if (minWeight <= 0) {
 
110
                //Avoid negative weight
 
111
                weight += Math.abs(minWeight) + 1;
 
112
            }
 
113
            //Multiply by thickness
 
114
            weight *= properties.getFloatValue(PreviewProperty.EDGE_THICKNESS);
 
115
            item.setData(EdgeItem.WEIGHT, weight);
 
116
        }
 
117
 
 
118
        //Target radius
 
119
        for (Item item : edgeItems) {
 
120
            if ((Boolean) item.getData(EdgeItem.DIRECTED) && !(Boolean) item.getData(EdgeItem.SELF_LOOP)) {
 
121
                Item targetItem = (Item) item.getData(TARGET);
 
122
                Float weight = item.getData(EdgeItem.WEIGHT);
 
123
                float radius = properties.getFloatValue(PreviewProperty.ARROW_RADIUS);
 
124
                float size = properties.getFloatValue(PreviewProperty.ARROW_SIZE) * weight;
 
125
                radius = -(radius + (Float) targetItem.getData(NodeItem.SIZE) / 2f + properties.getFloatValue(PreviewProperty.NODE_BORDER_WIDTH));
 
126
                item.setData(TARGET_RADIUS, radius - size);
 
127
            }
 
128
        }
 
129
    }
 
130
 
 
131
    public void render(Item item, RenderTarget target, PreviewProperties properties) {
 
132
        //Get nodes
 
133
        Item sourceItem = item.getData(SOURCE);
 
134
        Item targetItem = item.getData(TARGET);
 
135
 
 
136
        //Weight and color
 
137
        Float weight = item.getData(EdgeItem.WEIGHT);
 
138
        EdgeColor edgeColor = (EdgeColor) properties.getValue(PreviewProperty.EDGE_COLOR);
 
139
        Color color = edgeColor.getColor((Color) item.getData(EdgeItem.COLOR),
 
140
                (Color) sourceItem.getData(NodeItem.COLOR),
 
141
                (Color) targetItem.getData(NodeItem.COLOR));
 
142
        int alpha = (int) ((properties.getIntValue(PreviewProperty.EDGE_OPACITY) / 100f) * 255f);
 
143
        color = new Color(color.getRed(), color.getGreen(), color.getBlue(), alpha);
 
144
 
 
145
        if (sourceItem == targetItem) {
 
146
            renderSelfLoop(sourceItem, weight, color, properties, target);
 
147
        } else if (properties.getBooleanValue(PreviewProperty.EDGE_CURVED)) {
 
148
            renderCurvedEdge(item, sourceItem, targetItem, weight, color, properties, target);
 
149
        } else {
 
150
            renderStraightEdge(item, sourceItem, targetItem, weight, color, properties, target);
 
151
        }
 
152
    }
 
153
 
 
154
    public void renderSelfLoop(Item nodeItem, float thickness, Color color, PreviewProperties properties, RenderTarget renderTarget) {
 
155
        Float x = nodeItem.getData(NodeItem.X);
 
156
        Float y = nodeItem.getData(NodeItem.Y);
 
157
        Float size = nodeItem.getData(NodeItem.SIZE);
 
158
        Node node = (Node) nodeItem.getSource();
 
159
 
 
160
        PVector v1 = new PVector(x, y);
 
161
        v1.add(size, -size, 0);
 
162
 
 
163
        PVector v2 = new PVector(x, y);
 
164
        v2.add(size, size, 0);
 
165
 
 
166
        if (renderTarget instanceof ProcessingTarget) {
 
167
            PGraphics graphics = ((ProcessingTarget) renderTarget).getGraphics();
 
168
            graphics.strokeWeight(thickness);
 
169
            graphics.stroke(color.getRed(), color.getGreen(), color.getBlue(), color.getAlpha());
 
170
            graphics.noFill();
 
171
            graphics.bezier(x, y, v1.x, v1.y, v1.x, v2.y, x, y);
 
172
        } else if (renderTarget instanceof SVGTarget) {
 
173
            SVGTarget svgTarget = (SVGTarget) renderTarget;
 
174
 
 
175
            Element selfLoopElem = svgTarget.createElement("path");
 
176
            selfLoopElem.setAttribute("d", String.format(Locale.ENGLISH, "M %f,%f C %f,%f %f,%f %f,%f",
 
177
                    x, y, v1.x, v1.y, v2.x, v2.y, x, y));
 
178
            selfLoopElem.setAttribute("class", node.getNodeData().getId());
 
179
            selfLoopElem.setAttribute("stroke", svgTarget.toHexString(color));
 
180
            selfLoopElem.setAttribute("stroke-opacity", (color.getAlpha() / 255f) + "");
 
181
            selfLoopElem.setAttribute("stroke-width", Float.toString(thickness * svgTarget.getScaleRatio()));
 
182
            selfLoopElem.setAttribute("fill", "none");
 
183
            svgTarget.getTopElement(SVGTarget.TOP_EDGES).appendChild(selfLoopElem);
 
184
        }
 
185
    }
 
186
 
 
187
    public void renderCurvedEdge(Item edgeItem, Item sourceItem, Item targetItem, float thickness, Color color, PreviewProperties properties, RenderTarget renderTarget) {
 
188
        Edge edge = (Edge) edgeItem.getSource();
 
189
        Float x1 = sourceItem.getData(NodeItem.X);
 
190
        Float x2 = targetItem.getData(NodeItem.X);
 
191
        Float y1 = sourceItem.getData(NodeItem.Y);
 
192
        Float y2 = targetItem.getData(NodeItem.Y);
 
193
 
 
194
        //Curved edgs
 
195
        PVector direction = new PVector(x2, y2);
 
196
        direction.sub(new PVector(x1, y1));
 
197
        float length = direction.mag();
 
198
        direction.normalize();
 
199
 
 
200
        float factor = properties.getFloatValue(BEZIER_CURVENESS) * length;
 
201
 
 
202
        // normal vector to the edge
 
203
        PVector n = new PVector(direction.y, -direction.x);
 
204
        n.mult(factor);
 
205
 
 
206
        // first control point
 
207
        PVector v1 = new PVector(direction.x, direction.y);
 
208
        v1.mult(factor);
 
209
        v1.add(new PVector(x1, y1));
 
210
        v1.add(n);
 
211
 
 
212
        // second control point
 
213
        PVector v2 = new PVector(direction.x, direction.y);
 
214
        v2.mult(-factor);
 
215
        v2.add(new PVector(x2, y2));
 
216
        v2.add(n);
 
217
 
 
218
        if (renderTarget instanceof ProcessingTarget) {
 
219
            PGraphics graphics = ((ProcessingTarget) renderTarget).getGraphics();
 
220
            graphics.strokeWeight(thickness);
 
221
            graphics.stroke(color.getRed(), color.getGreen(), color.getBlue(), color.getAlpha());
 
222
            graphics.noFill();
 
223
            graphics.bezier(x1, y1, v1.x, v1.y, v2.x, v2.y, x2, y2);
 
224
        } else if (renderTarget instanceof SVGTarget) {
 
225
            SVGTarget svgTarget = (SVGTarget) renderTarget;
 
226
            Element edgeElem = svgTarget.createElement("path");
 
227
            edgeElem.setAttribute("class", edge.getSource().getNodeData().getId() + " " + edge.getTarget().getNodeData().getId());
 
228
            edgeElem.setAttribute("d", String.format(Locale.ENGLISH, "M %f,%f C %f,%f %f,%f %f,%f",
 
229
                    x1, y1, v1.x, v1.y, v2.x, v2.y, x2, y2));
 
230
            edgeElem.setAttribute("stroke", svgTarget.toHexString(color));
 
231
            edgeElem.setAttribute("stroke-width", Float.toString(thickness * svgTarget.getScaleRatio()));
 
232
            edgeElem.setAttribute("stroke-opacity", (color.getAlpha() / 255f) + "");
 
233
            edgeElem.setAttribute("fill", "none");
 
234
            svgTarget.getTopElement(SVGTarget.TOP_EDGES).appendChild(edgeElem);
 
235
        }
 
236
    }
 
237
 
 
238
    public void renderStraightEdge(Item edgeItem, Item sourceItem, Item targetItem, float thickness, Color color, PreviewProperties properties, RenderTarget renderTarget) {
 
239
        Edge edge = (Edge) edgeItem.getSource();
 
240
        Float x1 = sourceItem.getData(NodeItem.X);
 
241
        Float x2 = targetItem.getData(NodeItem.X);
 
242
        Float y1 = sourceItem.getData(NodeItem.Y);
 
243
        Float y2 = targetItem.getData(NodeItem.Y);
 
244
 
 
245
        //Target radius - to start at the base of the arrow
 
246
        Float targetRadius = edgeItem.getData(TARGET_RADIUS);
 
247
        if (targetRadius != 0) {
 
248
            PVector direction = new PVector(x2, y2);
 
249
            direction.sub(new PVector(x1, y1));
 
250
            direction.normalize();
 
251
            direction = new PVector(direction.x, direction.y);
 
252
            direction.mult(targetRadius);
 
253
            direction.add(new PVector(x2, y2));
 
254
            x2 = direction.x;
 
255
            y2 = direction.y;
 
256
        }
 
257
 
 
258
        if (renderTarget instanceof ProcessingTarget) {
 
259
            PGraphics graphics = ((ProcessingTarget) renderTarget).getGraphics();
 
260
            graphics.strokeWeight(thickness);
 
261
            graphics.strokeCap(PGraphics.SQUARE);
 
262
            graphics.stroke(color.getRed(), color.getGreen(), color.getBlue(), color.getAlpha());
 
263
            graphics.noFill();
 
264
            graphics.line(x1, y1, x2, y2);
 
265
        } else if (renderTarget instanceof SVGTarget) {
 
266
            SVGTarget svgTarget = (SVGTarget) renderTarget;
 
267
            Element edgeElem = svgTarget.createElement("path");
 
268
            edgeElem.setAttribute("class", edge.getSource().getNodeData().getId() + " " + edge.getTarget().getNodeData().getId());
 
269
            edgeElem.setAttribute("d", String.format(Locale.ENGLISH, "M %f,%f L %f,%f",
 
270
                    x1, y1, x2, y2));
 
271
            edgeElem.setAttribute("stroke", svgTarget.toHexString(color));
 
272
            edgeElem.setAttribute("stroke-width", Float.toString(thickness * svgTarget.getScaleRatio()));
 
273
            edgeElem.setAttribute("stroke-opacity", (color.getAlpha() / 255f) + "");
 
274
            edgeElem.setAttribute("fill", "none");
 
275
            svgTarget.getTopElement(SVGTarget.TOP_EDGES).appendChild(edgeElem);
 
276
        }
 
277
    }
 
278
 
 
279
    public PreviewProperty[] getProperties() {
 
280
        return new PreviewProperty[]{
 
281
                    PreviewProperty.createProperty(this, PreviewProperty.SHOW_EDGES, Boolean.class,
 
282
                    NbBundle.getMessage(EdgeRenderer.class, "EdgeRenderer.property.display.displayName"),
 
283
                    NbBundle.getMessage(EdgeRenderer.class, "EdgeRenderer.property.display.description"),
 
284
                    NbBundle.getMessage(EdgeRenderer.class, "EdgeRenderer.category")).setValue(defaultShowEdges),
 
285
                    PreviewProperty.createProperty(this, PreviewProperty.EDGE_THICKNESS, Float.class,
 
286
                    NbBundle.getMessage(EdgeRenderer.class, "EdgeRenderer.property.thickness.displayName"),
 
287
                    NbBundle.getMessage(EdgeRenderer.class, "EdgeRenderer.property.thickness.description"),
 
288
                    NbBundle.getMessage(EdgeRenderer.class, "EdgeRenderer.category"), PreviewProperty.SHOW_EDGES).setValue(defaultThickness),
 
289
                    PreviewProperty.createProperty(this, PreviewProperty.EDGE_RESCALE_WEIGHT, Boolean.class,
 
290
                    NbBundle.getMessage(EdgeRenderer.class, "EdgeRenderer.property.rescaleWeight.displayName"),
 
291
                    NbBundle.getMessage(EdgeRenderer.class, "EdgeRenderer.property.rescaleWeight.description"),
 
292
                    NbBundle.getMessage(EdgeRenderer.class, "EdgeRenderer.category"), PreviewProperty.SHOW_EDGES).setValue(defaultRescaleWeight),
 
293
                    PreviewProperty.createProperty(this, PreviewProperty.EDGE_COLOR, EdgeColor.class,
 
294
                    NbBundle.getMessage(EdgeRenderer.class, "EdgeRenderer.property.color.displayName"),
 
295
                    NbBundle.getMessage(EdgeRenderer.class, "EdgeRenderer.property.color.description"),
 
296
                    NbBundle.getMessage(EdgeRenderer.class, "EdgeRenderer.category"), PreviewProperty.SHOW_EDGES).setValue(defaultColor),
 
297
                    PreviewProperty.createProperty(this, PreviewProperty.EDGE_OPACITY, Float.class,
 
298
                    NbBundle.getMessage(EdgeRenderer.class, "EdgeRenderer.property.opacity.displayName"),
 
299
                    NbBundle.getMessage(EdgeRenderer.class, "EdgeRenderer.property.opacity.description"),
 
300
                    NbBundle.getMessage(EdgeRenderer.class, "EdgeRenderer.category"), PreviewProperty.SHOW_EDGES).setValue(defaultOpacity),
 
301
                    PreviewProperty.createProperty(this, PreviewProperty.EDGE_CURVED, Boolean.class,
 
302
                    NbBundle.getMessage(EdgeRenderer.class, "EdgeRenderer.property.curvedEdges.displayName"),
 
303
                    NbBundle.getMessage(EdgeRenderer.class, "EdgeRenderer.property.curvedEdges.description"),
 
304
                    NbBundle.getMessage(EdgeRenderer.class, "EdgeRenderer.category"), PreviewProperty.SHOW_EDGES).setValue(defaultEdgeCurved)};
 
305
    }
 
306
 
 
307
    public boolean isRendererForitem(Item item, PreviewProperties properties) {
 
308
        if (item instanceof EdgeItem && properties.getBooleanValue(PreviewProperty.SHOW_EDGES)
 
309
                && !properties.getBooleanValue(PreviewProperty.MOVING)) {
 
310
            return true;
 
311
        }
 
312
        return false;
 
313
    }
 
314
}