Trying to draw grid ends up in drawing long rectangle - android

I'd like to draw a grid. Therefore I've got
private int GRID_WIDTH = 6; <----Amount of columns
private int GRID_HEIGHT = 6; <----Amount of rows
private int GRID_SIZE; = 50 <----Width and height of a cell
Now I am trying to draw them:
for(int i = 0; i < GRID_WIDTH; i++) {
for(int j = 0; j < GRID_HEIGHT; j++) {
canvas.drawRect(new Rect(i*GRID_SIZE + 5, j*GRID_SIZE + 5, GRID_SIZE, GRID_SIZE), paint);
}
}
The "5" after each coordinate should make a gap between two rectangles.
This should end up in some nice grid, but as result I see multiple rectangles pushed together, without these 5px padding between them. No matter what I choose as padding, It resuls in following image: (Here the padding is set to 20 instead of 5...)
What am i doing wrong?
Thanks in advance!

Consider that the Rect constructor signature is:
Rect(int left, int top, int right, int bottom)
and you're doing like:
Rect(int left, int top, int width, int height)
Notice the difference in the last two arguments. You must do like this:
int left = i * (GRID_SIZE + 5);
int top = j * (GRID_SIZE + 5);
int right = left + GRID_SIZE;
int bottom = top + GRID_SIZE;
canvas.drawRect(new Rect(left, top, right, bottom), paint);

Related

How to get X and Y of detected circles?

I want to extract circles in and Image, So I extract them with below code:
Mat circles = new Mat();
Imgproc.HoughCircles(adaptiveThresh, circles, Imgproc.HOUGH_GRADIENT, 1.0, (double) adaptiveThresh.rows() / 40, 100.0, 30.0, 20, 30);
And then I iterate through them with below code:
for (int x = 0; x < circles.cols(); x++) {
double[] c = circles.get(0, x);
Point center = new Point(Math.round(c[0]), Math.round(c[1]));
int radius = (int) Math.round(c[2]);
Imgproc.circle(source, center, radius, new Scalar(0, 0, 255), 3);
}
But I want to sort them from topleft to bottom right, And the problem is I can not access the x and y of the circles!
How may I sort them based on row from top left to bottom right?
Your question is can be confusing. As it can be (1) sort distance to the circle to the top left of the image. (2)sort the distance from top left of each circle to top left of the image corner?
I assume you want to find the circle which is most close to top left case (1).
Here is my response.
From the C++ sample( i guess you are using android, not very familiar). You can convert using my sample code below.
for( size_t i = 0; i < circles.size(); i++ )
{
Point center(cvRound(circles[i][0]), cvRound(circles[i][1]));
int radius = cvRound(circles[i][2]);
// circle center
circle( src, center, 3, Scalar(0,255,0), -1, 8, 0 );
// circle outline
circle( src, center, radius, Scalar(0,0,255), 3, 8, 0 );
}
the center should be the point you want.
To sort them from top left to bottom right using city block distance you just have to
void sort_points (std::vector<Vec3f> &array)
{
std::cout<<"Elements in the array: "<<array.size()<<std::endl;
//comparisons will be done n times
for (int i = 0; i < array.size(); i++)
{
//compare elemet to the next element, and swap if condition is true
for(int j = 0; j < array.size() - 1; j++)
{
if ((array[j][0]+array[j][1]) > (array[j+1][0]+ array[j+1][1])
Swap(&array[j], &array[j+1]);
}
}
}
int main(argc,argv)
// ...................//do your stuff
vector<Vec3f> circles; //detected circle
// ... //do the detection
sort_points(circles);
//circles here is fully sorted from city block distance
std::cout<<circles<<std::endl; // print out all sorted circile
// ...................//do your stuff
}
if it is 2nd case just change if by
if ((array[j][0]+array[j][1]-2*array[j][2]) > (array[j+1][0]+ array[j+1][1]-2*array[j+1][2])
Here is what you need to do:
First, declare a Circle class (for encapsulation the circle properties for sorting purpose)
class Circle {
int cX;
int cY;
int radius;
double distance;
}
Now iterate over the HoughCircles result, and create a Circle instance and then add it to the List
List<Circle> circleList = new ArrayList<>();
//start point, it is used to calculate the distance
Point p1 = new Point(0, 0);
for (int x = 0; x < circles.cols(); x++) {
double[] c = circles.get(0, x);
Point center = new Point(Math.round(c[0]), Math.round(c[1]));
int radius = (int) Math.round(c[2]);
Imgproc.circle(source, center, radius, new Scalar(0, 0, 255), 3);
// here create the Circle instance
Circle circle = new Circle();
cricle.cX = center.x;
circle.cY = center.y;
circle.radius= radius;
double D = Math.sqrt(Math.pow(abs(p1.x - circles.x), 2) + Math.pow(abs(p1.y - circles.y), 2));
circle.distance = D;
// add the circle instance to the list
circleList.add(circle);
}
Now sort the circles in the list, use distance from small to bigger
circleList.sort(new Comparator<File>() {
#Override
public int compare(Circle c1, Circle c2) {
return Double.compare(c1.distance, c2.distance);
}
});
Now you can do what you want with circles list.
Hope it helps!!

drawing in canvas using canvas width and height

I'm trying to draw 3 rows of barrels with 4 barrels each row. In order for it to fit all screens I'm using canvas' height and width. this is my code:
int width = canvas.getWidth();
int height=canvas.getHeight();
int x = 20, y = 20, count = 0;
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 4; j++) {
canvas.drawBitmap(BarrelSprite, width*(x/100), height*(y/100), null);
rect[count] = new Rect( width*(x/100), height*(y/100), width*(x/100) + BarrelSprite.getWidth(), height*(y/100) + BarrelSprite.getHeight());
count++;
x += 20;
}
y += 20;
x = 20;
when I run it all the barrels seems to stack at the top left corner for some reason. I wanted to draw every barrel's X in the first 20% of the screen, 40%,60% etc. same for Y value.
found the mistake, height was int variable and dividing it by 100 making it 0 so I multiply by 0 all the the time hence making all the barrels fit the 0,0 coordinates

How to avoid object creation inside the onDraw method

I know that creating objects inside the onDraw method is very costly. I want to draw a matrix of rounded rectangles, which coordinates are dynamic, and I can't cache all that rectangles, because I use a scroll view and there may be a lot of rectangles, there's no other overload for drawRoundRect method, which has primitive arguments, and I forced to create a Rectangle object in every iteration. Who can suggest an effective solution for that?
#Override
protected void onDraw(Canvas canvas) {
int h = getMeasuredHeight();
int tileSize = h / rows;
for(int i = 0; i < rows; ++i) {
for(int j = 0; j < columns; ++j) {
int x = j * tileSize;
int y = i * tileSize;
canvas.drawRoundRect(new RectF(x, y, x + tileSize, y + tileSize), 10, 10, tilePaint);
}
}
}
This is a just an example, rectangles can have arbitrary coordinates.
RectF has the set(left, top, right, bottom) method. You could allocate it on the constructor and it this method to change the Rectf's bounds.
mRect.set(x, y, x + tileSize, y + tileSize);
where mRect is RectF mRect = new RectF();

How to add ImageView instead Labels on Axis in AChartEngine?

I want to add Image instead of Labels on XAxis, so does anyone know how to do that ?
Thanks in advance.
Update
I want to do something like the below image.
For this you have to edit source code of Achartengine because there is not any direct method for this.
Draw circles instead of small lines . For different colors of the circles , you may have to change few other things .
Change drawXLabels() method in XYChart.java .
protected void drawXLabels(List<Double> xLabels, Double[] xTextLabelLocations, Canvas canvas,
Paint paint, int left, int top, int bottom, double xPixelsPerUnit, double minX, double maxX) {
int length = xLabels.size();
boolean showLabels = mRenderer.isShowLabels();
boolean showGridY = mRenderer.isShowGridY();
boolean showTickMarks = mRenderer.isShowTickMarks();
for (int i = 0; i < length; i++) {
double label = xLabels.get(i);
float xLabel = (float) (left + xPixelsPerUnit * (label - minX));
if (showLabels) {
paint.setColor(mRenderer.getXLabelsColor());
if (showTickMarks) {
// canvas.drawLine(xLabel, bottom, xLabel, bottom + mRenderer.getLabelsTextSize() / 3, paint);
canvas.drawCircle(xLabel, bottom + mRenderer.getLabelsTextSize() / 3,3, paint);
}
drawText(canvas, getLabel(mRenderer.getLabelFormat(), label), xLabel,
bottom + mRenderer.getLabelsTextSize() * 4 / 3 + mRenderer.getXLabelsPadding(), paint,
mRenderer.getXLabelsAngle());
}
if (showGridY) {
paint.setColor(mRenderer.getGridColor(0));
// canvas.drawLine(xLabel, bottom, xLabel, top, paint);
canvas.drawCircle(xLabel, top,3, paint);
}
}
drawXTextLabels(xTextLabelLocations, canvas, paint, showLabels, left, top, bottom,
xPixelsPerUnit, minX, maxX);
}

Use special date format for x axis in achartengine

I'm using achartengine to visualize some data in time. The use of a TimeChart and TimeSeries is perfect but I would like following result which doesn't seem possible at the moment.
Currently I'm using this:
GraphicalView view = ChartFactory.getTimeChartView(this, dataset, renderer, "MMM");
This results in following output on x axis:
nov. apr. aug.
But I would like a marker for each month and only the first character of each month, like this:
N D J F M A M J J A S O
Ideas on how to accomplish this? Thanks!
I've found the solution myself where I override the drawXLabels method in a custom TimeChart class.
private class CustomTimeChart extends TimeChart {
public CustomTimeChart(XYMultipleSeriesDataset dataset,
XYMultipleSeriesRenderer renderer) {
super(dataset, renderer);
}
#Override
protected void drawXLabels(List<Double> xLabels,
Double[] xTextLabelLocations, Canvas canvas, Paint paint,
int left, int top, int bottom, double xPixelsPerUnit,
double minX, double maxX) {
int length = xLabels.size();
if (length > 0) {
boolean showLabels = mRenderer.isShowLabels();
boolean showGridY = mRenderer.isShowGridY();
DateFormat format = new SimpleDateFormat("MMMM");
for (int i = 0; i < length; i++) {
long label = Math.round(xLabels.get(i));
float xLabel = (float) (left + xPixelsPerUnit
* (label - minX));
if (showLabels) {
paint.setColor(mRenderer.getXLabelsColor());
canvas.drawLine(xLabel, bottom, xLabel, bottom
+ mRenderer.getLabelsTextSize() / 3, paint);
drawText(canvas, format.format(new Date(label)).substring(0, 1).toUpperCase(Locale.getDefault()),
xLabel, bottom + mRenderer.getLabelsTextSize()
* 4 / 3, paint,
mRenderer.getXLabelsAngle());
}
if (showGridY) {
paint.setColor(mRenderer.getGridColor());
canvas.drawLine(xLabel, bottom, xLabel, top, paint);
}
}
}
drawXTextLabels(xTextLabelLocations, canvas, paint, true, left,
top, bottom, xPixelsPerUnit, minX, maxX);
}
Also make sure to use the setXLabels(int i) on the XYMultipleSeriesRenderer instance to set how many months you want to show on x axis.

Categories

Resources