Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
jadex.micro.mandelbrot.display.DisplayPanel Maven / Gradle / Ivy
package jadex.micro.mandelbrot.display;
import java.awt.Color;
import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Insets;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Shape;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseWheelEvent;
import java.awt.geom.Rectangle2D;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.UUID;
import javax.swing.JComponent;
import javax.swing.JProgressBar;
import javax.swing.JViewport;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
import jadex.core.IExternalAccess;
import jadex.future.ISubscriptionIntermediateFuture;
import jadex.future.IntermediateEmptyResultListener;
import jadex.micro.mandelbrot.generate.IGenerateService;
import jadex.micro.mandelbrot.model.AbstractFractalAlgorithm;
import jadex.micro.mandelbrot.model.AreaData;
import jadex.micro.mandelbrot.model.IFractalAlgorithm;
import jadex.micro.mandelbrot.model.PartDataChunk;
import jadex.micro.mandelbrot.model.ProgressData;
import jadex.providedservice.impl.search.ServiceQuery;
import jadex.requiredservice.IRequiredServiceFeature;
/**
* Panel for displaying calculated results.
*/
public class DisplayPanel extends JComponent
{
//-------- constants --------
/** The help text. */
public static final String HELPTEXT =
"Use mouse to navigate:\n" +
"[wheel] zoom in/out\n" +
"[left button] choose and click into area\n" +
"[rigth button] drag to move, click for original area.\n";
//-------- attributes --------
/** The service provider. */
protected IExternalAccess agent;
/** The colors for drawing. */
protected Color[] colors;
/** The latest area data used for determining original coordinates of painted regions. */
protected AreaData data;
/** The current image derived from the results. */
protected Image image;
/** The current selection start point (if any). */
protected Point point;
/** The current selection range (if any). */
protected Rectangle range;
/** Flag indicating that a calculation is in progress. */
protected boolean calculating;
/** Progress data objects, available only when calculating (progress data -> percent finished). */
protected Set progressdata;
/** Start point for dragging (if any). */
protected Point startdrag;
/** End point for dragging (if any). */
protected Point enddrag;
/** The display id. */
protected String displayid;
/** The generate service. */
protected IGenerateService genservice;
protected boolean dirty;
protected List algos;
//-------- constructors --------
/**
* Create a new display panel.
*/
public DisplayPanel(final IExternalAccess agent)
{
this.agent = agent;
this.displayid = ""+UUID.randomUUID();
boolean[] init = new boolean[2];
agent.scheduleStep(ag ->
{
ag.getFeature(IRequiredServiceFeature.class).addQuery(new ServiceQuery(IDisplayService.class)).next(ds ->
{
init[0] = true;
displayServiceAvailable(ds);
//if(init[0] && init[1])
// calcDefaultImage();
});
ag.getFeature(IRequiredServiceFeature.class).addQuery(new ServiceQuery(IGenerateService.class)).next(gs ->
{
init[1] = true;
this.genservice = gs;
//if(init[0] && init[1])
// calcDefaultImage();
});
});
Timer timer = new Timer(10, a ->
{
if(dirty)
{
getParent().invalidate();
getParent().doLayout();
getParent().repaint();
}
dirty = false;
});
timer.start();
}
//-------- methods --------
/**
* Subscribe for updates when display service is available.
* @param ds The display service.
*/
// Annotation only possible on agent
//@OnService(requiredservice = @RequiredService(min = 1, max = 1))
public void displayServiceAvailable(IDisplayService ds)
{
List> algos = ds.getAlgorithms().get();
this.algos = AbstractFractalAlgorithm.createAlgorithms(algos);
ISubscriptionIntermediateFuture sub = ds.subscribeToDisplayUpdates(displayid);
sub.addResultListener(new IntermediateEmptyResultListener()
{
public void resultAvailable(Collection result)
{
}
public void intermediateResultAvailable(Object result)
{
//System.out.println("rec: "+result.getClass());
if(result instanceof AreaData)
{
setResults((AreaData)result);
}
else if(result instanceof ProgressData)
{
addProgress(((ProgressData)result));
}
else if(result instanceof PartDataChunk)
{
PartDataChunk chunk = (PartDataChunk)result;
//System.out.println("received: "+result);
addProgress(new ProgressData(chunk.getWorker(), null, chunk.getArea(), chunk.getProgress(), chunk.getImageWidth(), chunk.getImageHeight(), chunk.getDisplayId()));
addDataChunk((PartDataChunk)result);
}
}
public void finished()
{
// todo: close
}
public void exceptionOccurred(Exception exception)
{
exception.printStackTrace();
}
});
setColorScheme(new Color[]{new Color(50, 100, 0), Color.red}, true);
// Dragging with right mouse button.
MouseAdapter draghandler = new MouseAdapter()
{
public void mousePressed(MouseEvent e)
{
if(!calculating && e.getButton()==MouseEvent.BUTTON3 && e.getClickCount()==1 && image!=null)
{
startdrag = new Point(e.getX(), e.getY());
range = null;
point = null;
}
else
{
startdrag = null;
}
}
public void mouseDragged(MouseEvent e)
{
if(startdrag!=null)
{
enddrag = new Point(e.getX(), e.getY());
repaint();
}
}
public void mouseReleased(MouseEvent e)
{
if(startdrag!=null && enddrag!=null)
{
// System.out.println("dragged: "+startdrag+" "+enddrag);
agent.scheduleStep(() -> dragImage());
}
}
};
addMouseMotionListener(draghandler);
addMouseListener(draghandler);
// Zooming with mouse wheel.
addMouseWheelListener(new MouseAdapter()
{
public void mouseWheelMoved(MouseWheelEvent e)
{
if(!calculating)
{
int sa = e.getScrollAmount();
double dir = Math.signum(e.getWheelRotation());
double percent = 10*sa;
double factor;
if(dir>0)
{
factor = (100+percent)/100;
}
else
{
factor = 100/(100+percent);
}
agent.scheduleStep(() -> zoomImage(e.getX(), e.getY(), factor));
}
}
});
// Selecting range and default area.
addMouseListener(new MouseAdapter()
{
public void mouseClicked(MouseEvent e)
{
if(SwingUtilities.isRightMouseButton(e))
{
agent.scheduleStep(() -> calcDefaultImage());
}
else if(!calculating && range!=null)
{
if(e.getX()>=range.x && e.getX()<=range.x+range.width
&& e.getY()>=range.y && e.getY()<=range.y+range.height)
{
agent.scheduleStep(() -> zoomIntoRange());
}
}
}
public void mousePressed(MouseEvent e)
{
if(!calculating)
{
if(SwingUtilities.isRightMouseButton(e))
{
DisplayPanel.this.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
}
else
{
point = e.getPoint();
DisplayPanel.this.setCursor(Cursor.getPredefinedCursor(Cursor.CROSSHAIR_CURSOR));
}
}
}
public void mouseReleased(MouseEvent e)
{
if(!calculating)
{
DisplayPanel.this.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
}
}
});
addMouseMotionListener(new MouseAdapter()
{
public void mouseMoved(MouseEvent e)
{
if(!calculating && range!=null)
{
if(e.getX()>=range.x && e.getX()<=range.x+range.width
&& e.getY()>=range.y && e.getY()<=range.y+range.height)
{
DisplayPanel.this.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
}
else
{
DisplayPanel.this.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
}
}
}
public void mouseDragged(MouseEvent e)
{
if(!calculating && point!=null)
{
range = new Rectangle(
point.x();
progressdata.remove(part);
if(!part.isFinished())
progressdata.add(part);
if(progressdata.size()==1)
range = null;
if(progressdata.size()==0)
calculating = false;
dirty = true;
//System.out.println("progressdata: "+progressdata.size());
}
};
if(SwingUtilities.isEventDispatchThread())
{
r.run();
}
else
{
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
r.run();
}
});
}
}
/**
* Set new results.
*/
public void addDataChunk(final PartDataChunk data)
{
// first chunk is empty and only delivers name of worker
if(data.getData()==null)
return;
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
short[] chunk = data.getData();
short[][] results;
results = DisplayPanel.this.data.fetchData();
int xi = ((int)data.getArea().getX())+data.getXStart();
int yi = ((int)data.getArea().getY())+data.getYStart();
int xmax = (int)(data.getArea().getX()+data.getArea().getWidth());
//System.out.println("received: "+xi+" "+yi);
//for(int i=0; i=xmax)
{
xi=((int)data.getArea().getX());
yi++;
}
}
}
catch(Exception e)
{
e.printStackTrace();
}
/*if(DisplayPanel.this.image==null)
DisplayPanel.this.image = createImage(results.length, results[0].length);
Graphics g = image.getGraphics();
for(int x=0; x it=progressdata.iterator(); it.hasNext(); )
{
ProgressData progress = (ProgressData)it.next();
//System.out.println("progress is: "+progress);
double xf = drawarea.getWidth()/progress.getImageWidth();
double yf = drawarea.getHeight()/progress.getImageHeight();
int corx = (int)(progress.getArea().x*xf);
int cory = (int)(progress.getArea().y*yf);
int corw = (int)(progress.getArea().width*xf);
int corh = (int)(progress.getArea().height*yf);
//System.out.println("progress info: "+corx+" "+cory+" "+corw+" "+corh);
if(!progress.isFinished())
{
g.setColor(new Color(32,32,32,160));
g.fillRect(bounds.x+drawarea.x+corx+1, bounds.y+drawarea.y+cory+1, corw-1, corh-1);
}
g.setColor(Color.white);
g.drawRect(bounds.x+drawarea.x+corx, bounds.y+drawarea.y+cory, corw, corh);
// Print provider name.
String name = progress.getProviderId()!=null? progress.getProviderId().toString(): "";
String provider = "";
int index = name.indexOf('@');
if(index!=-1)
{
provider = name.substring(index+1);
name = name.substring(0, index);
}
// provider = progress.getTaskId().toString();
int width;
int height;
while(true)
{
FontMetrics fm = g.getFontMetrics();
Rectangle2D sb1 = fm.getStringBounds(name, g);
Rectangle2D sb2 = fm.getStringBounds(provider, g);
width = (int)Math.max(sb1.getWidth(), sb2.getWidth());
height = fm.getHeight()*2 + barsize.height + 2;
Font f = g.getFont();
if(width8 && corh>8)
{
//System.out.println("b: "+width+" "+height+" "+corw+" "+corh);
bar.setStringPainted(false);
int x = bounds.x+drawarea.x+corx + 2;
int y = bounds.y+drawarea.y+cory + Math.max((corh-barsize.height)/2, 2);
bar.setValue(progress.getProgress());
bar.setBounds(0, 0, corw-4, Math.min(barsize.height, corh-4));
Graphics g2 = g.create();
g2.translate(x, y);
bar.paint(g2);
}
}
}
}
// Draw range area.
if(!calculating && range!=null)
{
Rectangle bounds = getInnerBounds(false);
double rratio = (double)range.width/range.height;
double bratio = (double)bounds.width/bounds.height;
// Draw left and right boxes to show unused space
if(rratiobratio)
{
int drawheight = range.width*bounds.height/bounds.width;
int offset = (range.height-drawheight)/2;
g.setColor(new Color(128,128,128,64));
g.fillRect(range.x, range.y+offset, range.width+1, -offset);
g.fillRect(range.x, range.y+range.height, range.width+1, -offset);
}
g.setColor(Color.white);
g.drawRect(range.x, range.y, range.width, range.height);
}
}
/**
* Calculate draw area for image.
*/
protected Rectangle scaleToFit(Rectangle bounds, int iwidth, int iheight)
{
double iratio = (double)iwidth/iheight;
double bratio = (double)bounds.width/bounds.height;
Rectangle drawarea = new Rectangle(0, 0, bounds.width, bounds.height);
// Scale to fit height
if(iratiobratio)
{
double wratio = (double)bounds.width/iwidth;
drawarea.height = (int)(iheight*wratio);
drawarea.y = (bounds.height-drawarea.height)/2;
}
return drawarea;
}
/**
* Get the bounds with respect to insets (if any).
* @param scrollarea True when inner bounds of scroll area instead of visible window space should be considered.
*/
protected Rectangle getInnerBounds(boolean scrollarea)
{
Rectangle bounds = getBounds();
if(!scrollarea && getParent() instanceof JViewport)
{
// Get bounds of outer scroll panel
Rectangle pbounds = getParent().getParent().getBounds();
if(bounds.width>pbounds.width || bounds.height>pbounds.height)
{
bounds = pbounds;
}
}
Insets insets = getInsets();
if(insets!=null)
{
bounds.x = insets.left;
bounds.y = insets.top;
bounds.width -= insets.left + insets.right;
bounds.height -= insets.top + insets.bottom;
}
else
{
bounds.x = 0;
bounds.y = 0;
}
return bounds;
}
/**
* Get the desired size of the panel.
*/
public Dimension getMinimumSize()
{
Insets ins = getInsets();
Dimension ret = new Dimension(ins!=null ? ins.left+ins.right : 0, ins!=null ? ins.top+ins.bottom : 0);
if(image!=null)
{
ret.width += image.getWidth(this);
ret.height += image.getHeight(this);
}
return ret;
}
/**
* Get the desired size of the panel.
*/
public Dimension getPreferredSize()
{
return getMinimumSize();
}
/**
* Set the color scheme.
*/
public void setColorScheme(Color[] scheme, boolean cycle)
{
if(scheme==null || scheme.length==0)
{
colors = new Color[]{Color.white};
}
else if(scheme.length==1)
{
colors = scheme;
}
else if(cycle)
{
colors = new Color[scheme.length*16];
for(int i=0; ibratio)
{
int height = (int)(bounds.width/rratio);
bounds.height = height;
}
// Clear image for painting only background.
image = createImage(bounds.width, bounds.height);
calcArea(settings.getXStart(), settings.getXEnd(), settings.getYStart(), settings.getYEnd(), bounds.width, bounds.height);
}
/**
* Zoom into the selected range.
*/
protected void zoomIntoRange()
{
// Calculate bounds relative to original image.
Rectangle bounds = getInnerBounds(true);
Rectangle drawarea = scaleToFit(bounds, image.getWidth(DisplayPanel.this), image.getHeight(DisplayPanel.this));
final double x = (double)(range.x-bounds.x-drawarea.x)/drawarea.width;
final double y = (double)(range.y-bounds.y-drawarea.y)/drawarea.height;
final double x2 = x + (double)range.width/drawarea.width;
final double y2 = y + (double)range.height/drawarea.height;
// Original bounds
final double ox = data.getXStart();
final double oy = data.getYStart();
final double owidth = data.getXEnd()-data.getXStart();
final double oheight = data.getYEnd()-data.getYStart();
// Calculate pixel width/height of visible area.
bounds = getInnerBounds(false);
double rratio = (double)range.width/range.height;
double bratio = (double)bounds.width/bounds.height;
if(rratiobratio)
{
bounds.height = (int)(bounds.width/rratio);
}
final Rectangle area = bounds;
calcArea(ox+owidth*x, ox+owidth*x2, oy+oheight*y, oy+oheight*y2, area.width, area.height);
}
/**
* Calculate the given area.
*/
protected void calcArea(double x1, double x2, double y1, double y2, int sizex, int sizey)
{
AreaData settings;
if(data==null)
settings = AbstractFractalAlgorithm.getDefaultAlgorithm(algos).getDefaultSettings();
else
settings = data;
//final AreaData ad = new AreaData(x1, x2, y1, y2, sizex, sizey,
// settings.getMax(), settings.getTaskSize(), settings.getAlgorithmClass(), displayid, settings.getChunkCount());
final AreaData ad = new AreaData(x1,x2,y1,y2,sizex,sizey)
.setMax(settings.getMax()).setTaskSize(settings.getTaskSize()).setAlgorithmClass(settings.getAlgorithmClass())
.setDisplayId(displayid).setChunkCount(settings.getChunkCount());
//settings.getMax(), settings.getParallel(), settings.getTaskSize(), settings.getAlgorithm(), displayid);
DisplayPanel.this.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
calculating = true;
repaint();
if(genservice!=null)
{
/*genservice.generateArea(ad).addResultListener(new SwingDefaultResultListener()
{
public void customResultAvailable(Void result)
{
// already done with partials
//DisplayPanel.this.setResults(result);
}
public void customExceptionOccurred(Exception exception)
{
calculating = false;
DisplayPanel.this.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
super.customExceptionOccurred(exception);
}
});*/
genservice.generateArea(ad).catchEx(ex ->
{
SwingUtilities.invokeLater(() ->
{
calculating = false;
DisplayPanel.this.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
});
});
}
else
{
System.out.println("No generate service found");
}
}
public static void main(String[] args)
{
int x = 461;
int y = 235;
double factor = 1.2;
final Rectangle drawarea = new Rectangle(0,0,500,500);
int mx = Math.min(drawarea.x+drawarea.width, Math.max(drawarea.x, x));
int my = Math.min(drawarea.y+drawarea.height, Math.max(drawarea.y, y));
double xrel = ((double)mx-(drawarea.x))/drawarea.width;
double yrel = ((double)my-(drawarea.y))/drawarea.height;
double wold = 2.08;
double hold = 2.08;
double wnew = wold*factor;
double hnew = hold*factor;
double wd = wold-wnew;
double hd = hold-hnew;
final double xs = -2.272226080246914+wd*xrel;
final double xe = xs+wnew;
final double ys = -0.9846365740740745+hd*yrel;
final double ye = ys+hnew;
// Set range for drawing preview of zoom area.
double xdiff = drawarea.width - drawarea.width*factor;
double ydiff = drawarea.height - drawarea.height*factor;
Rectangle range = new Rectangle(drawarea.x+(int)Math.round(xdiff*xrel), drawarea.y+(int)Math.round(ydiff*yrel),
(int)Math.round(drawarea.width*factor), (int)Math.round(drawarea.height*factor));
// zoomIntoRange();
System.out.println("zoom: "+x+" "+y+" "+factor+" "+xs+" "+xe+" "+ys+" "+ye+" "+500+" "+500);
//calcArea(xs, xe, ys, ye, data.getSizeX(), data.getSizeY());
}
}