CrossHair Tracing In JFreeChart - java

I was able to implement real-time mouse tracing as follow :
The source code is as follow :
http://jstock.cvs.sourceforge.net/viewvc/jstock/jstock/src/org/yccheok/jstock/charting/CrossHairUI.java?revision=1.5&view=markup
http://jstock.cvs.sourceforge.net/viewvc/jstock/jstock/src/org/yccheok/jstock/gui/ChartJDialog.java?revision=1.9&view=markup
However, I unable to obtained the correct y screen coordinate, when an subplot being added.
(broken image)
I suspect I didn't get the correct screen data area.
When there is only one plot in the screen, I get a screen data area with height 300++
When a sub plot added to the bottom, I expect screen data area height will be reduced, due to the height occupied by the newly added subplot.
However, I have no idea how to obtain the correct screen data area for the first plot.
final XYPlot plot = (XYPlot) cplot.getSubplots().get(0);
// Shall I get _plotArea represents screen for getSubplots().get(0)?
// How?
// I try
//
// chartPanel.getScreenDataArea(0, 0);
// chartPanel.getScreenDataArea(0, 1);
// chartPanel.getScreenDataArea(1, 0);
// chartPanel.getScreenDataArea(1, 1);
//
// All returned null
// OK. I suspect this is causing me unable to get the correct screen y coordinate
// I always get the same _plotArea, although a new sub plot had been added.
final Rectangle2D _plotArea = chartPanel.getScreenDataArea();
final RectangleEdge rangeAxisEdge = plot.getRangeAxisEdge();
final double yJava2D = rangeAxis.valueToJava2D(yValue, _plotArea, rangeAxisEdge);

Here is the code snippet to obtained the correct rectangle after dive into JFreeChart source code.
/* Try to get correct main chart area. */
final Rectangle2D _plotArea = chartPanel.getChartRenderingInfo().getPlotInfo().getSubplotInfo(0).getDataArea();

Related

Custom actor for BitmapFont (libgdx)

I've spent several frustrating hours trying to implement (what I thought would be) a simple FontActor class.
The idea is to just draw text at a specific position using a provided BitmapFont. That much, I've managed to accomplish. However, I'm struggling to compute my actor's width/height based on the rendered text.
(Using a FitViewport for testing)
open class FontActor<T : BitmapFont>(val font: T, var text: CharSequence = "") : GameActor() {
val layout = Pools.obtain(GlyphLayout::class.java)!!
companion object {
val identity4 = Matrix4().idt()
val distanceFieldShader: ShaderProgram = DistanceFieldFont.createDistanceFieldShader()
}
override fun draw(batch: Batch?, parentAlpha: Float) {
if (batch == null) return
batch.end()
// grab ui camera and backup current projection
val uiCamera = Game.context.inject<OrthographicCamera>()
val prevTransform = batch.transformMatrix
val prevProjection = batch.projectionMatrix
batch.transformMatrix = identity4
batch.projectionMatrix = uiCamera.combined
if (font is DistanceFieldFont) batch.shader = distanceFieldShader
// the actor has pos = x,y in local coords, but we need UI coords
// start by getting group -> stage coords (world)
val coords = Vector3(localToStageCoordinates(Vector2(0f, 0f)), 0f)
// world coordinate destination -> screen coords
stage.viewport.project(coords)
// screen coords -> font camera world coords
uiCamera.unproject(coords,
stage.viewport.screenX.toFloat(),
stage.viewport.screenY.toFloat(),
stage.viewport.screenWidth.toFloat(),
stage.viewport.screenHeight.toFloat())
// adjust position by cap height so that bottom left of text aligns with x, y
coords.y = uiCamera.viewportHeight - coords.y + font.capHeight
/// TODO: use BitmapFontCache to prevent this call on every frame and allow for offline bounds calculation
batch.begin()
layout.setText(font, text)
font.draw(batch, layout, coords.x, coords.y)
batch.end()
// viewport screen coordinates -> world coordinates
setSize((layout.width / stage.viewport.screenWidth) * stage.width,
(layout.height / stage.viewport.screenHeight) * stage.height)
// restore camera
if (font is DistanceFieldFont) batch.shader = null
batch.projectionMatrix = prevProjection
batch.transformMatrix = prevTransform
batch.begin()
}
}
And in my parent Screen class implementation, I rescale my fonts on every window resize so that they don't become "smooshed" or stretched:
override fun resize(width: Int, height: Int) {
stage.viewport.update(width, height)
context.inject<OrthographicCamera>().setToOrtho(false, width.toFloat(), height.toFloat())
// rescale fonts
scaleX = width.toFloat() / Config.screenWidth
scaleY = height.toFloat() / Config.screenHeight
val scale = minOf(scaleX, scaleY)
gdxArrayOf<BitmapFont>().apply {
Game.assets.getAll(BitmapFont::class.java, this)
forEach { it.data.setScale(scale) }
}
gdxArrayOf<DistanceFieldFont>().apply {
Game.assets.getAll(DistanceFieldFont::class.java, this)
forEach { it.data.setScale(scale) }
}
}
This works and looks great until you resize your window.
After a resize, the fonts look fine and automatically adjust with the relative size of the window, but the FontActor has the wrong size, because my call to setSize is wrong.
Initial window:
After making window horizontally larger:
For example, if I then scale my window horizontally (which has no effect on the world size, because I'm using a FitViewport), the font looks correct, just as intended. However, the layout.width value coming back from the draw() changes, even though the text size hasn't changed on-screen. After investigation, I realized this is due to my use of setScale, but simply dividing the width by the x-scaling factor doesn't correct the error. And again, if I remove my setScale calls, the numbers make sense, but the font is now squished!
Another strategy I tried was converting the width/height into screen coordinates, then using the relevant project/unproject methods to get the width and height in world coordinates. This suffers from the same issue shown in the images.
How can I fix my math?
Or, is there a smarter/easier way to implement all of this? (No, I don't want Label, I just want a text actor.)
One problem was my scaling code.
The fix was to change the camera update as follows:
context.inject<OrthographicCamera>().setToOrtho(false, stage.viewport.screenWidth.toFloat(), stage.viewport.screenHeight.toFloat())
Which causes my text camera to match the world viewport camera. I was using the entire screen for my calculations, hence the stretching.
My scaleX/Y calculations were wrong for the same reason. After correcting both of those miscalculations, I have a nicely scaling FontActor with correct bounds in world coordinates.

PDFClown: Creating a TextMarkup leads to an inaccurate Box of the TextMarkup

Im working with PDFClown to analyze and work with PDFDocuments. My aim is to highlight all numbers within a table. For all numbers which belong together (For example: All numbers in one column of a table) I will create one TextMarkup with a List of Quads. First of all it looks like everythink work well: All highlights on the left belong to one TextMarkup and all Highlights on the right belong to another TextMarkup.
But when analyzing the size of the TextMarkup the size is bigger than it looks at the picture. So when drawing for example a rectangle arround the left TextMarkup box the rectangle intersects the other column despite no highlight of the left TextMarkup intersects the other column. Is there a way to optimize the Box of the TextMarkup? I think there is a bulbous ending of the box so that the box is intersecting the other TextMarkup
This is the code which creates the TextMarkup:
List<Quad> highlightQuads = new ArrayList<Quad>();
for (TextMarkup textMarkup : textMarkupsForOneAnnotation) {
Rectangle2D textBox = textMarkup.getBox();
Rectangle2D.Double rectangle = new Rectangle2D.Double(textBox.getX(), textBox.getY(), textBox.getWidth(), textBox.getHeight());
highlightQuads.add(Quad.get(rectangle));
}
if (highlightQuads.size() > 0) {
TextMarkup _textMarkup = new TextMarkup(pagesOfNewFile.get(lastFoundNewFilePage).getPage(), highlightQuads,"", MarkupTypeEnum.Highlight);
_textMarkup.setColor(DeviceRGBColor.get(Color.GREEN));
_textMarkup.setVisible(true);
allTextMarkUps.add(_textMarkup);
}
Here is an example file Example
Thank You !!
Your code is not really self contained (I cannot run it as it in particular misses the input data), so I could only do a bit of PDF Clown code analysis. That code analysis, though, did indeed turn up a PDF Clown implementation detail that would explain your observation.
How does PDF Clown calculate the dimensions of the markup annotation?
The markup annotation rectangle must be big enough to include all quads plus start and end decorations (rounded left and right caps on markup rectangle).
PDF Clown calculates this rectangle as follows in TextMarkup:
public void setMarkupBoxes(
List<Quad> value
)
{
PdfArray quadPointsObject = new PdfArray();
double pageHeight = getPage().getBox().getHeight();
Rectangle2D box = null;
for(Quad markupBox : value)
{
/*
NOTE: Despite the spec prescription, Point 3 and Point 4 MUST be inverted.
*/
Point2D[] markupBoxPoints = markupBox.getPoints();
quadPointsObject.add(PdfReal.get(markupBoxPoints[0].getX())); // x1.
quadPointsObject.add(PdfReal.get(pageHeight - markupBoxPoints[0].getY())); // y1.
quadPointsObject.add(PdfReal.get(markupBoxPoints[1].getX())); // x2.
quadPointsObject.add(PdfReal.get(pageHeight - markupBoxPoints[1].getY())); // y2.
quadPointsObject.add(PdfReal.get(markupBoxPoints[3].getX())); // x4.
quadPointsObject.add(PdfReal.get(pageHeight - markupBoxPoints[3].getY())); // y4.
quadPointsObject.add(PdfReal.get(markupBoxPoints[2].getX())); // x3.
quadPointsObject.add(PdfReal.get(pageHeight - markupBoxPoints[2].getY())); // y3.
if(box == null)
{box = markupBox.getBounds2D();}
else
{box.add(markupBox.getBounds2D());}
}
getBaseDataObject().put(PdfName.QuadPoints, quadPointsObject);
/*
NOTE: Box width is expanded to make room for end decorations (e.g. rounded highlight caps).
*/
double markupBoxMargin = getMarkupBoxMargin(box.getHeight());
box.setRect(box.getX() - markupBoxMargin, box.getY(), box.getWidth() + markupBoxMargin * 2, box.getHeight());
setBox(box);
refreshAppearance();
}
private static double getMarkupBoxMargin(
double boxHeight
)
{return boxHeight * .25;}
So it takes the bounding box of all the quads and adds left and right margins each as wide as a quarter of the height of this whole bounding box.
What is the result in your case?
While this added margin width is sensible if there is only a single quad, in case of your markup annotation which includes many quads on top of one another, this results in a giant, unnecessary margin.
How to improve the code?
As the added caps depend on the individual caps and not their combined bounding box, one can improve the code by using the maximum height of the individual quads instead of the height of the bounding box of all quads, e.g. like this:
Rectangle2D box = null;
double maxQuadHeight = 0;
for(Quad markupBox : value)
{
double quadHeight = markupBox.getBounds2D().getHeight();
if (quadHeight > maxQuadHeight)
maxQuadHeight = quadHeight;
...
}
...
double markupBoxMargin = getMarkupBoxMargin(maxQuadHeight);
box.setRect(box.getX() - markupBoxMargin, box.getY(), box.getWidth() + markupBoxMargin * 2, box.getHeight());
setBox(box);
If you don't want to patch PDF Clown for this, you can also execute this code (with minor adaptations) after constructing the TextMarkup _textMarkup to correct the precalculated annotation rectangle.
Is this fixing a PDF Clown error?
It is not an error as there is no need for the text markup annotation rectangle to be minimal; PDF Clown could also always use the whole crop box for each such annotation.
I would assume, though, that the author of the code wanted to calculate a somewhat minimal rectangle but only optimized for single line and so in a way did not live up to his own expectations...
Are there other problems in this code?
Yes. The text a markup annotation marks needs not be horizontal, it may be there at an angle, it could even be vertical. In such a case some margin would also be needed at the top and the bottom of the annotation rectangle, not (only) at the left and the right.

How CombinedDomainXYPlot and CombinedRangeXYPlot share Axis information with subplots

Related to: How can I share DomainAxis/RangeAxis across subplots without drawing them on each plot?
Note - I originally wrote this up as a question, and then realize my mistake, so I decided to just share the knowledge since I already had this all typed out.
In JFreeChart, there are two plot types that share an axis range and draw only one axis, while sharing that information with their subplots. These are CombinedDomainXYPlot and CombinedRangeXYPlot. I will focus on CombinedDomainXyPlot, but the other should be identical for the purposes of this question. Looking at the draw code we see:
...
setFixedRangeAxisSpaceForSubplots(null);
AxisSpace space = calculateAxisSpace(g2, area);
Rectangle2D dataArea = space.shrink(area, null);
// set the width and height of non-shared axis of all sub-plots
setFixedRangeAxisSpaceForSubplots(space);
// draw the shared axis
ValueAxis axis = getDomainAxis();
RectangleEdge edge = getDomainAxisEdge();
double cursor = RectangleEdge.coordinate(dataArea, edge);
AxisState axisState = axis.draw(g2, cursor, area, dataArea, edge, info); // <- draw the share axis
if (parentState == null) {
parentState = new PlotState();
}
parentState.getSharedAxisStates().put(axis, axisState); // <- put the state of the shared axis in a shared object
// draw all the subplots
for (int i = 0; i < this.subplots.size(); i++) {
XYPlot plot = (XYPlot) this.subplots.get(i);
PlotRenderingInfo subplotInfo = null;
if (info != null) {
subplotInfo = new PlotRenderingInfo(info.getOwner());
info.addSubplotInfo(subplotInfo);
}
plot.draw(g2, this.subplotAreas[i], anchor, parentState, subplotInfo); // <- pass this shared object to the subplot draw function.
}
...
in the subplot (XYPlot) draw method, we see:
domainAxisState = (AxisState) parentState.getSharedAxisStates().get(getDomainAxis());
The getDomainAxis() method is calls getDomainAxis(0), which is:
public ValueAxis getDomainAxis(int index) {
ValueAxis result = null;
if (index < this.domainAxes.size()) {
result = (ValueAxis) this.domainAxes.get(index); //<- try to find this domain axis in self
}
if (result == null) { //<- if not found in self ...
Plot parent = getParent();
if (parent instanceof XYPlot) {
XYPlot xy = (XYPlot) parent;
result = xy.getDomainAxis(index); //<- ...try to get from parent
}
}
return result;
}
Here, parent is the CombinedDomainXYPlot. This will return a reference to the domainAxis from CombinedDomainXYPlot, to be used for retrieving the axisState from the parentState object. It seems the getDomainAxis() method is not used for getting an axis to draw, only for getting a reference to it for other purposes.
I was looking into this because I was trying to use the same technique to pass multiple shared axes to multiple different groups of plots, but only draw them once. This technique seems to work, but there are glitches right now in that zooming the plots that only get state information does not update the main plot that has the axis... Working on it, but hopefully this information is useful to someone down the line.
Thanks,
Igor
Answered in question post.
As state above, the getDomainAxis() method in XYPlot is apparently not used for getting an axis to draw, only for getting a reference to it for other purposes. So if you override this method to link to another axis and put it's state information into a shared object, this state info will be shared between plots.

Route trace using java

i want to trace the trajectory between differents points
for the test i creat points and try to link between these points
this is my code
OpenStreetMapLayer osm = new OpenStreetMapLayer();
map.addLayer(vectorLayer);
List<Point>points= new ArrayList<Point>();
Point point = new Point(44.272872,4.27826);
Point point2 = new Point(-55.272873,5.3873837);
Point point3 = new Point(5.272873,54.3873837);
points.add(point);
points.add(point2);
points.add(point3);
Point[] coord=new Point[points.size()];
points.toArray(coord);
polyline.setPoints(coord);
vectorLayer.addComponent(polyline);
Style defaultstyle = new Style();
/* Set stroke color to green, otherwise like default style */
defaultstyle.extendCoreStyle("default");
defaultstyle.setStrokeColor("#0000ff");
defaultstyle.setStrokeWidth(3);
defaultstyle.setFillColor("#adfffc");
defaultstyle.setFillOpacity(0.4);
// Make borders of selected graphs bigger
Style selectStyle = new Style();
selectStyle.setStrokeWidth(5);
StyleMap stylemap = new StyleMap(defaultstyle, defaultstyle, null);
// make selectStyle inherit attributes not explicitly set
stylemap.setExtendDefault(true);
vectorLayer.setStyleMap(stylemap);
but when i execute my code i get just a point i've asked they told me this point is the point of cordinate(0,0)
this is the screen catch of the set of points without ZOOM (the blue point)
http://img4.hostingpics.net/pics/810776sss.png
and this is the MAX ZOOM
http://img4.hostingpics.net/pics/122823ert.png
i want to know if it is a probleme of scale or what?
thanks in advance
You are using https://en.wikipedia.org/wiki/EPSG:4326 coords but OSM is using https://wiki.openstreetmap.org/wiki/EPSG:3857. The first one is in abs(180,90) where the second one is in in abs(6356752,6378137). so your points are basically at the center in spherical mercator and zooming very close will give your result. you have to convert your data e.g. using geotools

jFreeChart: How to draw the y-axis in a line chart

With Java, is there any way of drawing the y-axis in a line chart with JFreeChart?
I need to show both the x-axis and the y-axis, and I already draw the x-axis with the flowing code:
LineFunction2D x_axis = new LineFunction2D(0, 0);
XYDataset xdataset = DatasetUtilities.sampleFunction2D(
x_axis, min_x-min_x/15, max_x+max_x/15, 100, "X-Axis");
xyplot.setDataset(1, xdataset);
I think it's impossible to draw the line x = 0 with LineFunction2D, which take the value of a and b of the equation y = ax + b.
Maybe there is a function to call to show the axis because I have seen a demo showing this.
There is a method in the XYPlot class:
public void setDomainZeroBaselineVisible(boolean visible);
...that will show a line at the zero value on the domain (x) axis.
Y=aX+b can be displayed using ChartFactory.createLineChart. This way, you get your series, the X and Y axis in one go.

Categories