- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
所以我正在使用 JUNG,这对我来说是新事物。我已经实现了一个简单的 GUI,它显示顶点和边,并且通过使用 Transformer 我可以更改形状等。但是我该如何沿着边缘制作图像动画呢?
如果边缘是直线,那就很容易了,因为我知道起点和终点 X 和 Y 坐标,但边缘也可以是 BentLines、CubicCurves 或 QuadCurves。比如说,我如何让汽车沿着绘制的线移动?
我已经查看了 PathIterator 的文档,但说实话,我不知道它实际上是做什么的以及它是否适合我想要的。
任何正确方向的指针将不胜感激!
最佳答案
事实上,这有点棘手。
首先,为了获得屏幕上绘制的真实边缘形状,需要进行一些扭曲。幸运的是,相关代码已包含在 JUNG 的 ShapePickSupport.java
类中。
然后,必须计算该形状上的一个点(因此隐式假定为一条线)。这涉及到使用 PathIterator 来计算总长度以及线路上的当前位置。
我尝试实现这个(以非常基本且简单的形式)并将其封装在 ImageAtEdgePainter
类中:它接收 VisualizationViewer
用于边缘形状计算,以及应绘制的边缘和图像。它有一个 setImageLocation
方法,接受 0.0 到 1.0 之间的值,其中 0.0 表示图像应位于边缘的开始处,1.0 表示图像位于边缘的末端,分别。
使用虚拟图表和虚拟图像,结果如下所示:
图像在边缘端点之间振荡。这是代码,如 MCVE :
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Shape;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.geom.AffineTransform;
import java.awt.geom.PathIterator;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
import edu.uci.ics.jung.algorithms.layout.FRLayout;
import edu.uci.ics.jung.algorithms.layout.Layout;
import edu.uci.ics.jung.graph.DirectedSparseGraph;
import edu.uci.ics.jung.graph.Graph;
import edu.uci.ics.jung.graph.util.Context;
import edu.uci.ics.jung.graph.util.Pair;
import edu.uci.ics.jung.visualization.Layer;
import edu.uci.ics.jung.visualization.MultiLayerTransformer;
import edu.uci.ics.jung.visualization.RenderContext;
import edu.uci.ics.jung.visualization.VisualizationViewer;
public class JUNGEdgePathTest
{
public static void main(String[] args)
{
SwingUtilities.invokeLater(new Runnable()
{
@Override
public void run()
{
createAndShowGUI();
}
});
}
private static BufferedImage createDummyImage()
{
int w = 100;
int h = 30;
BufferedImage image =
new BufferedImage(w,h, BufferedImage.TYPE_INT_ARGB);
Graphics2D g = image.createGraphics();
g.setColor(Color.BLACK);
g.fillRect(0,0,w,h);
g.setColor(Color.WHITE);
g.drawString("Image", 10, 20);
g.dispose();
return image;
}
private static void createAndShowGUI()
{
JFrame f = new JFrame();
final Graph<String, String> graph = getGraph();
final VisualizationViewer<String, String> vv =
new VisualizationViewer<String, String>(
new FRLayout<String, String>(graph));
final BufferedImage image = createDummyImage();
String edge = graph.getEdges().iterator().next();
final ImageAtEdgePainter<String, String> imageAtEdgePainter =
new ImageAtEdgePainter<String, String>(vv, edge, image);
Timer t = new Timer(20, new ActionListener()
{
long prevMillis = 0;
@Override
public void actionPerformed(ActionEvent e)
{
if (prevMillis == 0)
{
prevMillis = System.currentTimeMillis();
}
long dtMs = System.currentTimeMillis() - prevMillis;
double dt = dtMs / 1000.0;
double phase = 0.5 + Math.sin(dt) * 0.5;
imageAtEdgePainter.setImageLocation(phase);
vv.repaint();
}
});
t.start();
vv.addPostRenderPaintable(imageAtEdgePainter);
f.getContentPane().add(vv);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.pack();
f.setVisible(true);
}
static class ImageAtEdgePainter<V, E> implements VisualizationViewer.Paintable
{
private final VisualizationViewer<V, E> vv;
private final E edge;
private final BufferedImage image;
private double imageLocation;
ImageAtEdgePainter(
VisualizationViewer<V, E> vv,
E edge,
BufferedImage image)
{
this.vv = vv;
this.edge = edge;
this.image = image;
}
public void setImageLocation(double imageLocation)
{
this.imageLocation = imageLocation;
}
@Override
public void paint(Graphics gr)
{
Graphics2D g = (Graphics2D)gr;
Shape shape = getTransformedEdgeShape(vv, vv.getGraphLayout(), edge);
Point2D p = computePointAt(shape, 0.2, imageLocation);
//g.setColor(Color.BLUE);
//g.draw(shape);
//System.out.println(p);
gr.drawImage(image, (int)p.getX(), (int)p.getY(), null);
}
@Override
public boolean useTransform()
{
return true;
}
}
private static double computeLength(Shape shape, double flatness)
{
double length = 0;
PathIterator pi = shape.getPathIterator(null, flatness);
double[] coords = new double[6];
double previous[] = new double[2];
while (!pi.isDone())
{
int segment = pi.currentSegment(coords);
switch (segment)
{
case PathIterator.SEG_MOVETO:
previous[0] = coords[0];
previous[1] = coords[1];
break;
case PathIterator.SEG_LINETO:
double dx = previous[0]-coords[0];
double dy = previous[1]-coords[1];
length += Math.sqrt(dx*dx+dy*dy);
previous[0] = coords[0];
previous[1] = coords[1];
break;
}
pi.next();
}
return length;
}
public static Point2D computePointAt(
Shape shape, double flatness, double alpha)
{
alpha = Math.min(1.0, Math.max(0.0, alpha));
double totalLength = computeLength(shape, flatness);
double targetLength = alpha * totalLength;
double currentLength = 0;
PathIterator pi = shape.getPathIterator(null, flatness);
double[] coords = new double[6];
double previous[] = new double[2];
while (!pi.isDone())
{
int segment = pi.currentSegment(coords);
switch (segment)
{
case PathIterator.SEG_MOVETO:
previous[0] = coords[0];
previous[1] = coords[1];
break;
case PathIterator.SEG_LINETO:
double dx = previous[0]-coords[0];
double dy = previous[1]-coords[1];
double segmentLength = Math.sqrt(dx*dx+dy*dy);
double nextLength = currentLength + segmentLength;
if (nextLength >= targetLength)
{
double localAlpha =
(currentLength - targetLength) / segmentLength;
//System.out.println("current "+currentLength+" target "+targetLength+" seg "+segmentLength);
double x = previous[0] + localAlpha * dx;
double y = previous[1] + localAlpha * dy;
return new Point2D.Double(x,y);
}
previous[0] = coords[0];
previous[1] = coords[1];
currentLength = nextLength;
break;
}
pi.next();
}
return null;
}
// This method is take from JUNG ShapePickSupport.java
private static <V, E> Shape getTransformedEdgeShape(
VisualizationViewer<V, E> vv, Layout<V, E> layout, E e) {
Pair<V> pair = layout.getGraph().getEndpoints(e);
V v1 = pair.getFirst();
V v2 = pair.getSecond();
boolean isLoop = v1.equals(v2);
RenderContext<V, E> rc = vv.getRenderContext();
MultiLayerTransformer multiLayerTransformer =
rc.getMultiLayerTransformer();
Point2D p1 = multiLayerTransformer.transform(
Layer.LAYOUT, layout.transform(v1));
Point2D p2 = multiLayerTransformer.transform(
Layer.LAYOUT, layout.transform(v2));
if(p1 == null || p2 == null)
return null;
float x1 = (float) p1.getX();
float y1 = (float) p1.getY();
float x2 = (float) p2.getX();
float y2 = (float) p2.getY();
AffineTransform xform = AffineTransform.getTranslateInstance(x1, y1);
Shape edgeShape =
rc.getEdgeShapeTransformer().transform(
Context.<Graph<V,E>,E>getInstance(
vv.getGraphLayout().getGraph(),e));
if(isLoop) {
Shape s2 = rc.getVertexShapeTransformer().transform(v2);
Rectangle2D s2Bounds = s2.getBounds2D();
xform.scale(s2Bounds.getWidth(),s2Bounds.getHeight());
xform.translate(0, -edgeShape.getBounds2D().getHeight()/2);
} else {
float dx = x2 - x1;
float dy = y2 - y1;
double theta = Math.atan2(dy,dx);
xform.rotate(theta);
float dist = (float) Math.sqrt(dx*dx + dy*dy);
xform.scale(dist, 1.0f);
}
edgeShape = xform.createTransformedShape(edgeShape);
return edgeShape;
}
public static Graph<String, String> getGraph()
{
Graph<String, String> g = new DirectedSparseGraph<String, String>();
g.addVertex("v0");
g.addVertex("v1");
g.addVertex("v2");
g.addVertex("v3");
g.addVertex("v4");
g.addEdge("e0", "v0", "v1");
g.addEdge("e1", "v1", "v2");
g.addEdge("e2", "v2", "v3");
g.addEdge("e3", "v3", "v4");
g.addEdge("e4", "v4", "v0");
g.addEdge("e5", "v1", "v3");
g.addEdge("e6", "v2", "v4");
return g;
}
}
当您说要沿线移动汽车时,我可以想象您还希望将汽车的图像与边缘对齐 - 即旋转 图像,使汽车始终指向边缘的末端。这不会太困难。但如果这是一个问题,您可能应该首先看看其他问题(例如 Java: Rotate image towards mouse position? ),看看那里的答案是否可以......“启发”您,或者将其作为一个单独的(非 JUNG 特定的)提出) 问题。
关于java - JUNG 沿边缘的动画图像,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26977847/
我有一串数字。我需要检查边缘上的数字是否对称,这意味着它们以 2 为模时具有相同的余数。 我已经编写了一个有效的代码,但我对此感到不安,在一些失败之后我想出了这个代码: int PaliPair(ch
我要删除黑色蒙版和人体图像之间的白色边框 图像输入示例: 厚度为1的图像输出: 厚度为2的图像输出: 我尝试了一些在这里找到的具有模糊和阈值的游戏 我还使用此代码查找和绘制轮廓 thickne
这应该是一个在用户悬停时打开的飞出菜单。 这在 Chrome 中工作得很好,我已经尝试了多种方法(使用 CSS :hover,(mousenter)和(mouseleave ) 问题是 - 使用 Ed
我有一个 Apache 服务器 v2.4.43 为我的网站提供服务,我使用一个简单的 .htpasswd,我使用指令“AuthUserFile ”在 .htaccess 中调用它来进行身份验证。 现在
如何仅使用剪辑路径创建波浪边缘? 波浪应该是这样的图像: 最佳答案 您应该通过波函数及其频率生成此剪辑路径。 我用过 cos()在 PHP 中。您可以找到如下链接: https://repl.it/@
我有这张图: digraph G { 1 [label="car"]; 2 [label="x"]; 3 [label="car"]; 4 [label="y"]; 5 [label="cdr"];
我想强制点仅显示节点之间的垂直或水平边缘。 我在帖子 Family tree layout with Dot/GraphViz 中发现了类似的请求,但我不处理树,所以我希望有一个解决方案,无需插入额外
我已经设法让两个直方图重叠,但如果你仔细观察,条形开始倾斜并且没有完全重叠。 我已经调整了线宽和宽度,并没有改善。 我的目标是让所有的条形排列在彼此的顶部,黑边没有歪斜。 有什么办法解决这个问题 这是
我已经设法让两个直方图重叠,但如果你仔细观察,条形开始倾斜并且没有完全重叠。 我已经调整了线宽和宽度,并没有改善。 我的目标是让所有的条形排列在彼此的顶部,黑边没有歪斜。 有什么办法解决这个问题 这是
我一直在与 latex table 搏斗太久了。我需要一个具有居中标题的表格,以及包含可能环绕的文本的正文单元格。由于环绕要求,我使用 p{xxx} 而不是 l 来指定单元格宽度。这导致的问题是单元格
有没有办法平滑转换(平移和旋转)的 BufferedImage 的锯齿状边缘? 测试图像的放大 View : (请注意,这不是将要使用的实际 BufferedImage,仅用于此处演示)。 已使用双线
我在 my page 有一个旋转木马.我的父元素和子元素的边缘都是 flex 的,但是当您按“下一个”或“上一个”并滑动旋转木马时,子元素在移动时不会保持 flex 。我怎样才能避免这种情况? .ho
我在 .boxwrap 和 .lsmlbox + .rsmlbox 之间的嵌套 div 中添加了不必要的空格,这使得无法将 .smlbox + .rsmlbox 与 .box 对齐我相信这是一个比预期
我正在使用 Apple 的 ARKit 制作 AR 应用程序,我想制作盒子的线框轮廓。代码中描述并显示在图片中的那个在盒子的每个面上绘制斜边。它还隐藏了盒子另一侧的角。 Scene Kit 中有没有办
下图仅包含阈值处理后的黑色和白色像素。我在此图像的顶部绘制了一个灰色的旋转矩形。现在我想计算这个旋转矩形内的黑色像素数,但不包括白色矩形矩形外的黑色像素(即白色矩形内的像素数)。 做到这一点的最佳方法
你们如何处理边际 CSS?我所说的边缘是指需要斜体或粗体的单个单词或短语。只用 声明一个“大胆”的类似乎很愚蠢 Bold { font-weight: bold; } 或者斜体,要么! Italic
好的。我知道有几十个类似的线程。我几乎检查了每一个,但找不到可行的解决方案。我试过负边距、最小高度、最大高度、绝对页脚、正文背景颜色,甚至将溢出:隐藏到页面中的所有主要容器。然后将 clearfix
我网站的一部分使用代码使用倾斜边缘: -webkit-clip-path: 多边形(0% 0%, 100% 0%, 81% 100%, 0% 100%) 这在 Chrome 中运行良好,但不适用于任何
我一直在创建这个网站,并且进展顺利。然后我试着给它添加一个模态,但一切都有点走下坡路。问题是在添加模式后,Chrome 中的图像对齐方式发生了变化。它在 Edge 中运行良好。现在我知道这可能是因为
如果我在 Matlab 中使用 image() 命令制作一个 4 x 4 像素的图像,它会将刻度线居中放置在像素的中间。我希望刻度线以像素的左下角为中心。有什么方法可以做到这一点吗? 最佳答案 您可以
我是一名优秀的程序员,十分优秀!