I've been trying to include the ability to show routes in an android app, and was working this solution into my app:
J2ME/Android/BlackBerry - driving directions, route between two locations
I've got basically all of the code in place, but in the drawPath method I get the error "The method toPixels(GeoPoint, Point) in the type Projection is not applicable for the arguments (GeoPoint, Point)" on the starred code below. Here's the code:
public void drawPath(MapView mMapView, Canvas canvas)
{
int x1 = -1, y1 = -1, x2 = -1, y2 = -1;
Paint paint = new Paint();
paint.setColor(Color.GREEN);
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeWidth(3);
for (int i = 0; i < mPoints.size(); i++)
{
Point point = new Point();
mMapView.getProjection().*****toPixels*****(mPoints.get(i), point);
x2 = point.*****x*****;
y2 = point.*****y*****;
if (i > 0)
{
canvas.drawLine(x1, y1, x2, y2, paint);
}
x1 = x2;
y1 = y2;
}
}
I've not been able to test it at all yet because I've been unable to sort this error, so I don't know if there are other problems elsewhere. However in the meantime, if anybody knows why this error pops up it would be really appreciated. Thanks in advance! Oh and if anybody needs to see any of my other code or classes please let me know.
here is a good example i have posted you can try out this
I had tried this source code.
Copy the file from source code, don't change anything before that.
DON'T press Ctrl + Shift + O to load library class automatically.
Sometimes, eclipse import a wrong library. Why? That's another topic on eclipse.
Edit all these lines manually
import org.ci.geo.route.Road;
import org.ci.geo.route.RoadProvider;
Change import to your package library name.
Then edit this line that suit to your layout:
setContentView(R.layout.main);
mapView = (MapView) findViewById(R.id.mapview);
and this for sweet flavour
TextView textView = (TextView) findViewById(R.id.description);
Hope this will help you
Related
https://boofcv.org/index.php?title=Example_Fit_Polygon
This link above gives does some image detection, and provides good example but it is not for android which is what I need. What I'm really stuck on right now is there any equivalent for this
VisualizeShapes.drawPolygon(vertexes,true,g2);
in Andriod. If there is can someone help me how to draw it like on the method with those paramters. For example, the drawPolygon takes vertexes as these
List<PointIndex_I32> vertexes = ShapeFittingOps.fitPolygon(c.external,true, minSide,cornerPenalty);
and the true boolean is loop, and g2 is java.awt.Graphics2D. The documentation for VisualizeShapes are provided here:
http://boofcv.org/javadoc/boofcv/gui/feature/VisualizeShapes.html
The issue is that VisualizeShapes is giving me an error because it not a supported library for android development and I need some way to find equivalent to polygonFitting detection on android.
The Android demonstration app is a good place to start when looking for stuff like that. MiscUtil.java has something similar to what you're looking for.
public static void renderPolygon(Polygon2D_F64 s, Path path , Canvas canvas , Paint paint ) {
path.reset();
for (int j = 0; j < s.size(); j++) {
Point2D_F64 p = s.get(j);
if (j == 0)
path.moveTo((float) p.x, (float) p.y);
else
path.lineTo((float) p.x, (float) p.y);
}
Point2D_F64 p = s.get(0);
path.lineTo((float) p.x, (float) p.y);
path.close();
canvas.drawPath(path, paint);
}
So basically, I'm creating an android app (using tesseract and OpenCV) which when given a word after pre-processing and scan steps, draws a rectangle around that word - basically "finds" the word and marks it. However I'm wondering how to get coordinates of a character ? or atleast a word ? I have coordinates of each line, but the coordinates are not relative to the "main-picture", but only coordinates of "text-blocks" that I have. Maybe someone has/knows either explanation/tutorial or some kind of info on how to go about finding coordinates of a word/character. Would highly appreciate.
This sample code, taken from the API Examples Wiki page from tesseract should help:
APIExamples
Focus on those 2 lines:
int x1, y1, x2, y2;
ri->BoundingBox(level, &x1, &y1, &x2, &y2);
Pix *image = pixRead("/usr/src/tesseract/testing/phototest.tif");
tesseract::TessBaseAPI *api = new tesseract::TessBaseAPI();
api->Init(NULL, "eng");
api->SetImage(image);
api->SetVariable("save_blob_choices", "T");
api->SetRectangle(37, 228, 548, 31);
api->Recognize(NULL);
tesseract::ResultIterator* ri = api->GetIterator();
tesseract::PageIteratorLevel level = tesseract::RIL_SYMBOL;
if(ri != 0) {
do {
const char* symbol = ri->GetUTF8Text(level);
float conf = ri->Confidence(level);
int x1, y1, x2, y2;
ri->BoundingBox(level, &x1, &y1, &x2, &y2);
if(symbol != 0) {
printf("symbol %s, conf: %f", symbol, conf);
bool indent = false;
tesseract::ChoiceIterator ci(*ri);
do {
if (indent) printf("\t\t ");
printf("\t- ");
const char* choice = ci.GetUTF8Text();
printf("%s conf: %f\n", choice, ci.Confidence());
indent = true;
} while(ci.Next());
}
printf("---------------------------------------------\n");
delete[] symbol;
} while((ri->Next(level)));
}
I have a small problem with ploting my graph. On a picture below is what I have already done.
The graph should represent the actual signal strength of available Wi-Fi network(s). It's a simple XYPlot here data are represented with SimpleXYSeries (values are dynamically created).
Here is a little snippet of code (only for example):
plot = (XYPlot) findViewById(R.id.simplexyPlot);
series1 = new SimpleXYSeries(Arrays.asList(series1Numbers),
SimpleXYSeries.ArrayFormat.Y_VALS_ONLY, "Link 1");
f1 = new LineAndPointFormatter(color.getColor(), null,
Color.argb(60, color.getRed(), color.getGreen(), color.getBlue()), null);
plot.addSeries(series1, f1);
The example in the picture is a dynamic simulation of dB changes. Everything works, I guess, correctly, but what I want to achieve is to have line with "rounded" corners (see the picture to see what I mean).
I already tried to customize LineFormatter:
f1.getFillPaint().setStrokeJoin(Join.ROUND);
f1.getFillPaint().setStrokeWidth(8);
But this didn't work as expected.
Note: The Wifi Analyzer application has a similar graph and its graph has the rounded corners I want. It looks like this:
You can use Path.cubicTo() method. It draws a line using cubic spline algorithm which results in the smoothing effect you want.
Checkout the answer to a similar question here, where a guy is talking about cubic splines. There is a short algorithm showing how to calculate input parameters for Path.cubicTo() method. You can play with divider values to achieve required smoothness. For example, in the picture below I divided by 5 instead of 3. Hope this helps.
I have spent some time and implemented a SplineLineAndPointFormatter class, which does the stuff you need in androidplot library. It uses same technics. Here is how androidplot example applications looks like. You just need to use it instead of LineAndPointFormatter.
Here is code example and the class I wrote.
f1 = new SplineLineAndPointFormatter(color.getColor(), null,
Color.argb(60, color.getRed(), color.getGreen(), color.getBlue()), null);
plot.addSeries(series1, f1);
Here is the class doing the magic. It is based on version 0.6.1 of androidplot library.
package com.androidplot.xy;
import android.graphics.Canvas;
import android.graphics.Path;
import android.graphics.PointF;
import android.graphics.RectF;
import com.androidplot.ui.SeriesRenderer;
import com.androidplot.util.ValPixConverter;
public class SplineLineAndPointFormatter extends LineAndPointFormatter {
public SplineLineAndPointFormatter() { }
public SplineLineAndPointFormatter(Integer lineColor, Integer vertexColor, Integer fillColor) {
super(lineColor, vertexColor, fillColor, null);
}
public SplineLineAndPointFormatter(Integer lineColor, Integer vertexColor, Integer fillColor, FillDirection fillDir) {
super(lineColor, vertexColor, fillColor, null, fillDir);
}
#Override
public Class<? extends SeriesRenderer> getRendererClass() {
return SplineLineAndPointRenderer.class;
}
#Override
public SeriesRenderer getRendererInstance(XYPlot plot) {
return new SplineLineAndPointRenderer(plot);
}
public static class SplineLineAndPointRenderer extends LineAndPointRenderer<BezierLineAndPointFormatter> {
static class Point {
public float x, y, dx, dy;
public Point(PointF pf) { x = pf.x; y = pf.y; }
}
private Point prev, point, next;
private int pointsCounter;
public SplineLineAndPointRenderer(XYPlot plot) {
super(plot);
}
#Override
protected void appendToPath(Path path, final PointF thisPoint, PointF lastPoint) {
pointsCounter--;
if (point == null) {
point = new Point(thisPoint);
point.dx = ((point.x - prev.x) / 5);
point.dy = ((point.y - prev.y) / 5);
return;
} else if (next == null) {
next = new Point(thisPoint);
} else {
prev = point;
point = next;
next = new Point(thisPoint);
}
point.dx = ((next.x - prev.x) / 5);
point.dy = ((next.y - prev.y) / 5);
path.cubicTo(prev.x + prev.dx, prev.y + prev.dy, point.x - point.dx, point.y - point.dy, point.x, point.y);
if (pointsCounter == 1) { // last point
next.dx = ((next.x - point.x) / 5);
next.dy = ((next.y - point.y) / 5);
path.cubicTo(point.x + point.dx, point.y + point.dy, next.x - next.dx, next.y - next.dy, next.x, next.y);
}
}
#Override
protected void drawSeries(Canvas canvas, RectF plotArea, XYSeries series, LineAndPointFormatter formatter) {
Number y = series.getY(0);
Number x = series.getX(0);
if (x == null || y == null) throw new IllegalArgumentException("no null values in xyseries permitted");
XYPlot p = getPlot();
PointF thisPoint = ValPixConverter.valToPix(x, y, plotArea,
p.getCalculatedMinX(), p.getCalculatedMaxX(), p.getCalculatedMinY(), p.getCalculatedMaxY());
prev = new Point(thisPoint);
point = next = null;
pointsCounter = series.size();
super.drawSeries(canvas, plotArea, series, formatter);
}
}
}
1- I guess that you only use a few points to draw graphs of signals. All graph/chart applications try to connect points with direct lines and then your chart will be shown. So if you only use three points, your graph will looks like a triangle! If you want your graph to be curved, you have to add more points. Then it comes out like a curve.
2- Or you can find any library that can draw sin graph, for example GraphView Library. Then try to draw this function:
So it looks like to this:
Then translate it to (a,0), so result seems like what you want.
3- And another way, you can use built in Math.sin in Java:
Chose for example 1000 point in range a to b and compute value of above function for each point and finally create a path and show them in a canvas.
You can use quadTo (float x1, float y1, float x2, float y2) that simplify drawing quad curves for you. The documentation says:
Add a quadratic bezier from the last point, approaching control point
(x1,y1), and ending at (x2,y2). If no moveTo() call has been made for
this contour, the first point is automatically set to (0,0).
Parameters
x1 The x-coordinate of the control point on a quadratic curve
y1 The y-coordinate of the control point on a quadratic curve
x2 The x-coordinate of the end point on a quadratic curve
y2 The y-coordinate of the end point on a quadratic curve
Finally, I add a simple class that extends View and can draw a curve that looks like what you want:
public class SinWave extends View {
private float first_X = 50;
private float first_Y = 230;
private float end_X = 100;
private float end_Y = 230;
private float Max = 50;
public SinWave(Context context, AttributeSet attrs) {
super(context, attrs);
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
Paint paint = new Paint() {
{
setStyle(Paint.Style.STROKE);
setStrokeCap(Paint.Cap.ROUND);
setStrokeWidth(0.7f);
setAntiAlias(true);
setColor(0xFFFF00FF);
}
};
final Path path = new Path();
path.moveTo(first_X, first_Y);
path.quadTo((first_X + end_X)/2, Max, end_X, end_Y);
canvas.drawPath(path, paint);
}
}
The result must look like this:
You can add more methods to the class and change it to increase performance!
There's always been a smooth line renderer in Androidplot: BezierLineAndPointRenderer, which like the implementations above uses Android's built in Bezier drawing routines cubicTo(...) & quadTo(...). The problem is that using Beziers to draw smooth lines in this way creates a false line that overshoots the actual control points by varying amounts, which you can see happening if you look closely at the image above.
The solution is to use the Catmull-Rom spline interpolation, which is now finally supported by Androidplot. Details here: http://androidplot.com/smooth-curves-and-androidplot/
Just use ChartFactory.getCubeLineChartView instead of ChartFactory.getLineChartView using achart engine
In some simple cases, this could help:
mPaint.pathEffect = CornerPathEffect(radius)
even in combination with
path.lineTo(x,y)
try this:
symbol = new Path();
paint = new Paint();
paint.setAntiAlias(true);
paint.setStrokeWidth(2);
paint.setColor(-7829368);
paint.setStrokeJoin(Paint.Join.ROUND); // set the join to round you want
paint.setStrokeCap(Paint.Cap.ROUND); // set the paint cap to round too
paint.setPathEffect(new CornerPathEffect(10) );
paint.setStyle(Paint.Style.STROKE);
symbol.moveTo(50.0F, 230.0F);
symbol.lineTo(75.0F, 100.0F);
symbol.lineTo(100.0F, 230.0F);
most of the info found here
I have a problem, I have tried resolve the problem but I haven't found a solution.
I have two columns of images. I want to join them through the midpoint of each image. The problem I have is that the attachment point moves down, like the image
I have a "main" class and I have the internal class: public class DrawView extends LinearLayout
with the atribute:
private Paint paint = new Paint();
and I set the next values:
paint.setColor(Color.BLACK);
paint.setStrokeWidth(6);
I use the next code for draw the lines:
public void onDraw(Canvas canvas) {
}
#SuppressLint("UseValueOf")
#Override
public void dispatchDraw(Canvas canvas) {
super.dispatchDraw(canvas);
if (activateDraw) {
for (int i = 0; i < 5; i++) {
//I not include the color selection.
x1= Image[i].x + Image[i].width;
y1=Image[i].y+ (new Double(Image[i].height / 2).intValue()));
x2=ImagePr[i].x;
y2=ImagePr[i].y + (new Double((ImagePr[i].height) / 2).intValue()));
canvas.drawLine(x1, y1, x2, y2, paint);
}
activateDraw = false;
}
}
To set the x and y values I use the method:
public void setData(ImageView img) {
image = img;
int[] values = new int[2];
image.getLocationInWindow(values);
x = values[0];
y = values[1];
width = image.getWidth();
height = image.getHeight();
}
In the main class I have the atribute:
Canvas auxCanvas = new Canvas();
and I execute the onDraw(auxCanvas) method when I want draw the lines. Why the lines don't draw joining the "midpoints"?
Anyone can help me?Thanks!!
#Shaunak Sorry, it was a fail. I've removed it and it doesn't affect, the problem continues. Thank you!
#anthropomo I tried your change but the problem continues.
I don't understand why in the emulator seems to work fine, but not on the device.
SOLUTION:
(I thought I had written the answer, sorry)
The solution was very simple. The app is destinated to students that have 6-8 years, so I decided to hide the status bar and the above code works perfect without do changes!
Hide the status bar:
Hide Notification bar
How to hide the title bar for an Activity in XML with existing custom theme
If other people want to show the status bar, I suppose you need to subtract the status bar height.
reference: http://developer.android.com/reference/android/util/DisplayMetrics.html#density
does something like this work for you?:
float d = getResources().getDisplayMetrics().density;
canvas.drawLine(x1*d, y1*d, x2*d, y2*d, paint);
note: if the multiplication doesn't work try dividing by d... i can never remember what to do.
I'm working on a simple Android app for plotting routes on a map. All is going well, but I have an issue when zooming in on my Samsung Galaxy S2. It works fine on a Galaxy S3, so I'm wondering whether it's related to memory management on the lower specced device. It also works fine on the emulator.
Here is equivalent code located in the overlays onDraw method, just condensed for posting here:
Point current = new Point();
Path path = new Path();
Projection projection = mapView.getProjection();
Iterator<GeoPoint> iterator = pointList.iterator();
if (iterator.hasNext()) {
projection.toPixels(iterator.next(), current);
path.moveTo((float) current.x, (float) current.y);
} else return path;
while(iterator.hasNext()) {
projection.toPixels(iterator.next(), current);
path.lineTo((float) current.x, (float) current.y);
}
Paint roadPaint = new Paint();
roadPaint.setAntiAlias(true);
roadPaint.setStrokeWidth(8.0f);
roadPaint.setColor(Color.BLACK);
roadPaint.setStyle(Paint.Style.STROKE);
canvas.drawPath(path, roadPaint);
It's not too dissimilar to most of the sample code floating around for doing this. I'm just wondering if anyone can confirm my suspicions and advise if there is anything I can do in terms of configuration or tweaks that I can do to force drawing at all zoom levels?
Thanks in advance.
Cheers,
Nathan
The problem is that you are painting the overlay yourself for a very specific state of the mapview. You should use OverlayItem instead.
The OverlayItem is added to the MapView overlays collection, and the MapView handles all the re-drawing depending on it's own state ( zoom, location, etc )
#Override
public void draw( Canvas canvas, MapView mapView, boolean shadow )
{
super.draw( canvas, mapView, shadow );
int x1 = -1;
int y1 = -1;
int x2 = -1;
int y2 = -1;
Paint paint = new Paint();
paint.setStyle( Paint.Style.STROKE );
paint.setColor( GeoLocation.ROUTE_COLOR );
paint.setStrokeWidth( STROKE_WIDTH );
for ( int i = 0; i < mRouteGeoPoints.size(); i++ )
{
Point point = new Point();
mapView.getProjection().toPixels( geoPoints.get( i ), point );
x2 = point.x;
y2 = point.y;
if ( i > 0 )
{
canvas.drawLine( x1, y1, x2, y2, paint );
}
x1 = x2;
y1 = y2;
}
}
You said that code above was an equivalent (not the real code you are running) and that's clear because you are returning a Path object in a onDraw() which you couldn't.
The "compressed form" of code you show should work as well as using the drawLine(). So the problem should come from something else (may the original code).
Anyway, I'll give you a couple of hints:
When the top and bottom of object you are drawing to a canvas are both out of screen, the object is ignored and not drawn. Check if this is not whats happening with your path. See my answer in this post Android Map Overlay Disappears on Zoom
You don't need to rebuild the path object every time. You are probably already doing it, and that's why you made the short version above. See my answer in this post with some suggestions to improve path drawing: Overlay behavior when zooming
If for some reason you really want to use the slower approach of drawLine(), you can use the follwing to make the line look better:
paint = new Paint();
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeJoin(Paint.Join.ROUND);
paint.setStrokeCap(Paint.Cap.ROUND);
paint.setColor(...);
paint.setAlpha(...);
paint.setStrokeWidth(...);
Finally, if the issue remains, update your question with more relevant code and let me know. Maybe I can help further.
Regards.