/* Copyright 2008-2010 Gephi Authors : Mathieu Bastian <mathieu.bastian@gephi.org> Website : http://www.gephi.org This file is part of Gephi. Gephi is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Gephi is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with Gephi. If not, see <http://www.gnu.org/licenses/>. */ package org.gephi.visualization.opengl.compatibility.objects; import javax.media.opengl.GL; import javax.media.opengl.glu.GLU; import org.gephi.graph.api.EdgeData; import org.gephi.graph.api.MetaEdge; import org.gephi.graph.api.Model; import org.gephi.graph.api.NodeData; import org.gephi.visualization.VizModel; import org.gephi.visualization.apiimpl.ModelImpl; import org.gephi.lib.gleem.linalg.Vecf; import org.gephi.visualization.GraphLimits; import org.gephi.visualization.opengl.octree.Octant; /** * * @author Mathieu Bastian */ public class Edge2dModel extends ModelImpl<EdgeData> { protected static final float WEIGHT_MINIMUM = 0.4f; protected static final float WEIGHT_MAXIMUM = 8f; //An edge is set in both source node and target node octant. Hence edges are not drawn when none of //these octants are visible. protected Arrow2dModel arrow; protected float weight; public Edge2dModel() { octants = new Octant[2]; } @Override public int[] octreePosition(float centerX, float centerY, float centerZ, float size) { //Not used, because getOctants() already returns right octant to add the edge NodeData nodeFrom = obj.getSource(); NodeData nodeTo = obj.getTarget(); int index1 = -1, index2 = -1; size /= 2; //True if the point is in the big cube. if (!(Math.abs(nodeFrom.x() - centerX) > size || Math.abs(nodeFrom.y() - centerY) > size || Math.abs(nodeFrom.z() - centerZ) > size)) { index1 = 0; //Point1 if (nodeFrom.y() < centerY) { index1 += 4; } if (nodeFrom.z() > centerZ) { index1 += 2; } if (nodeFrom.x() < centerX) { index1 += 1; } } if (!(Math.abs(nodeTo.x() - centerX) > size || Math.abs(nodeTo.y() - centerY) > size || Math.abs(nodeTo.z() - centerZ) > size)) { index2 = 0; //Point2 if (nodeTo.y() < centerY) { index2 += 4; } if (nodeTo.z() > centerZ) { index2 += 2; } if (nodeTo.x() < centerX) { index2 += 1; } } if (index1 >= 0 && index2 >= 0) { if (index1 != index2) { return new int[]{index1, index2}; } else { return new int[]{index1}; } } else if (index1 >= 0) { return new int[]{index1}; } else if (index2 >= 0) { return new int[]{index2}; } else { return new int[]{}; } } @Override public boolean isInOctreeLeaf(Octant leaf) { NodeData nodeFrom = obj.getSource(); NodeData nodeTo = obj.getTarget(); if (nodeFrom.getModel() == null || nodeTo.getModel() == null) { return false; } boolean res = true; if (octants[0] == leaf) { if (octants[0] != ((ModelImpl) nodeFrom.getModel()).getOctants()[0]) //0 = nodeFrom { res = false; } } if (octants[1] == leaf) { if (octants[1] != ((ModelImpl) nodeTo.getModel()).getOctants()[0]) //1 = nodeTo { res = false; } } if (octants[0] != leaf && octants[1] != leaf) { res = false; } return res; } @Override public void display(GL gl, GLU glu, VizModel vizModel) { if (this.arrow != null) { this.arrow.setSelected(selected); } if (!selected && vizModel.isHideNonSelectedEdges()) { return; } if (selected && vizModel.isAutoSelectNeighbor()) { ModelImpl m1 = (ModelImpl) obj.getSource().getModel(); ModelImpl m2 = (ModelImpl) obj.getTarget().getModel(); m1.mark = true; m2.mark = true; } //Edge weight GraphLimits limits = vizModel.getLimits(); float w; if (obj.getEdge() instanceof MetaEdge) { float weightRatio; if (limits.getMinMetaWeight() == limits.getMaxMetaWeight()) { weightRatio = WEIGHT_MINIMUM / limits.getMinMetaWeight(); } else { weightRatio = Math.abs((WEIGHT_MAXIMUM - WEIGHT_MINIMUM) / (limits.getMaxMetaWeight() - limits.getMinMetaWeight())); } float edgeScale = vizModel.getEdgeScale() * vizModel.getMetaEdgeScale(); w = weight; w = ((w - limits.getMinMetaWeight()) * weightRatio + WEIGHT_MINIMUM) * edgeScale; } else { float weightRatio; if (limits.getMinWeight() == limits.getMaxWeight()) { weightRatio = WEIGHT_MINIMUM / limits.getMinWeight(); } else { weightRatio = Math.abs((WEIGHT_MAXIMUM - WEIGHT_MINIMUM) / (limits.getMaxWeight() - limits.getMinWeight())); } float edgeScale = vizModel.getEdgeScale(); w = weight; w = ((w - limits.getMinWeight()) * weightRatio + WEIGHT_MINIMUM) * edgeScale; } // float x1 = obj.getSource().x(); float x2 = obj.getTarget().x(); float y1 = obj.getSource().y(); float y2 = obj.getTarget().y(); float t1 = w; float t2 = w; float sideVectorX = y1 - y2; float sideVectorY = x2 - x1; float norm = (float) Math.sqrt(sideVectorX * sideVectorX + sideVectorY * sideVectorY); sideVectorX /= norm; sideVectorY /= norm; float x1Thick = sideVectorX / 2f * t1; float x2Thick = sideVectorX / 2f * t2; float y1Thick = sideVectorY / 2f * t1; float y2Thick = sideVectorY / 2f * t2; if (!selected) { float r; float g; float b; float a; r = obj.r(); if (r == -1f) { if (vizModel.isEdgeHasUniColor()) { float[] uni = vizModel.getEdgeUniColor(); r = uni[0]; g = uni[1]; b = uni[2]; a = uni[3]; } else { NodeData source = obj.getSource(); r = 0.498f * source.r(); g = 0.498f * source.g(); b = 0.498f * source.b(); a = obj.alpha(); } } else { g = 0.498f * obj.g(); b = 0.498f * obj.b(); r *= 0.498f; a = obj.alpha(); } if (vizModel.getConfig().isLightenNonSelected()) { float lightColorFactor = vizModel.getConfig().getLightenNonSelectedFactor(); a = a - (a - 0.01f) * lightColorFactor; gl.glColor4f(r, g, b, a); } else { gl.glColor4f(r, g, b, a); } } else { float r = 0f; float g = 0f; float b = 0f; if (vizModel.isEdgeSelectionColor()) { ModelImpl m1 = (ModelImpl) obj.getSource().getModel(); ModelImpl m2 = (ModelImpl) obj.getTarget().getModel(); if (m1.isSelected() && m2.isSelected()) { float[] both = vizModel.getEdgeBothSelectionColor(); r = both[0]; g = both[1]; b = both[2]; } else if (m1.isSelected()) { float[] out = vizModel.getEdgeOutSelectionColor(); r = out[0]; g = out[1]; b = out[2]; } else if (m2.isSelected()) { float[] in = vizModel.getEdgeInSelectionColor(); r = in[0]; g = in[1]; b = in[2]; } } else { r = obj.r(); if (r == -1f) { NodeData source = obj.getSource(); r = source.r(); g = source.g(); b = source.b(); } else { g = obj.g(); b = obj.b(); } } gl.glColor4f(r, g, b, 1f); } gl.glVertex2f(x1 + x1Thick, y1 + y1Thick); gl.glVertex2f(x1 - x1Thick, y1 - y1Thick); gl.glVertex2f(x2 - x2Thick, y2 - y2Thick); gl.glVertex2f(x2 - x2Thick, y2 - y2Thick); gl.glVertex2f(x2 + x2Thick, y2 + y2Thick); gl.glVertex2f(x1 + x1Thick, y1 + y1Thick); } @Override public boolean selectionTest(Vecf distanceFromMouse, float selectionSize) { // TODO Auto-generated method stub return false; } @Override public float getCollisionDistance(double angle) { // TODO Auto-generated method stub return 0; } @Override public float getCameraDistance() { return (obj.getSource().getModel().getCameraDistance() + obj.getTarget().getModel().getCameraDistance()) / 2f; } @Override public boolean isAutoSelected() { Model nSource = obj.getSource().getModel(); Model nTarget = obj.getTarget().getModel(); if (nSource != null && nTarget != null) { return obj.getSource().getModel().isSelected() || obj.getTarget().getModel().isSelected(); } return false; } @Override public boolean onlyAutoSelect() { return true; } @Override public boolean isSelected() { return selected; } @Override public String toSVG() { // TODO Auto-generated method stub return null; } @Override public void setOctant(Octant octant) { if (((ModelImpl) obj.getSource().getModel()).getOctants()[0] == octant) { octants[0] = octant; } if (((ModelImpl) obj.getTarget().getModel()).getOctants()[0] == octant) { octants[1] = octant; } } @Override public void resetOctant() { octants[0] = null; octants[1] = null; } @Override public Octant[] getOctants() { if (this.octants[0] == null && this.octants[1] == null) { Octant sourceOctant = ((ModelImpl) obj.getSource().getModel()).getOctants()[0]; Octant targetOctant = ((ModelImpl) obj.getTarget().getModel()).getOctants()[0]; if (sourceOctant == targetOctant) { return new Octant[]{sourceOctant}; } else { return new Octant[]{sourceOctant, targetOctant}; } } else { return this.octants; } } @Override public boolean isValid() { return octants[0] != null || octants[1] != null; } public Arrow2dModel getArrow() { return arrow; } public void setArrow(Arrow2dModel arrow) { this.arrow = arrow; } @Override public float getViewportX() { return (obj.getSource().getModel().getViewportX() + 2 * obj.getTarget().getModel().getViewportX()) / 3f; } @Override public float getViewportY() { return (obj.getSource().getModel().getViewportY() + 2 * obj.getTarget().getModel().getViewportY()) / 3f; } public void setWeight(float weight) { this.weight = weight; } }