How to draw a filled triangle in android canvas? - java

So I'm drawing this triangle in android maps using the code below in my draw method:
paint.setARGB(255, 153, 29, 29);
paint.setStyle(Paint.Style.FILL_AND_STROKE);
paint.setAntiAlias(true);
Path path = new Path();
path.moveTo(point1_returned.x, point1_returned.y);
path.lineTo(point2_returned.x, point2_returned.y);
path.moveTo(point2_returned.x, point2_returned.y);
path.lineTo(point3_returned.x, point3_returned.y);
path.moveTo(point3_returned.x, point3_returned.y);
path.lineTo(point1_returned.x, point1_returned.y);
path.close();
canvas.drawPath(path, paint);
The pointX_returned are the coordinates which I'm getting from the fields. They are basically latitudes and longitudes.
The result is a nice triangle but the insider is empty and therefore I can see the map. Is there a way to fill it up somehow?

Ok I've done it. I'm sharing this code in case someone else will need it:
super.draw(canvas, mapView, true);
Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
paint.setStrokeWidth(2);
paint.setColor(android.graphics.Color.RED);
paint.setStyle(Paint.Style.FILL_AND_STROKE);
paint.setAntiAlias(true);
Point point1_draw = new Point();
Point point2_draw = new Point();
Point point3_draw = new Point();
mapView.getProjection().toPixels(point1, point1_draw);
mapView.getProjection().toPixels(point2, point2_draw);
mapView.getProjection().toPixels(point3, point3_draw);
Path path = new Path();
path.setFillType(Path.FillType.EVEN_ODD);
path.moveTo(point1_draw.x,point1_draw.y);
path.lineTo(point2_draw.x,point2_draw.y);
path.lineTo(point3_draw.x,point3_draw.y);
path.lineTo(point1_draw.x,point1_draw.y);
path.close();
canvas.drawPath(path, paint);
//canvas.drawLine(point1_draw.x,point1_draw.y,point2_draw.x,point2_draw.y, paint);
return true;
Thanks for the hint Nicolas!

You probably need to do something like :
Paint red = new Paint();
red.setColor(android.graphics.Color.RED);
red.setStyle(Paint.Style.FILL);
And use this color for your path, instead of your ARGB. Make sure the last point of your path ends on the first one, it makes sense also.
Tell me if it works please !

you can also use vertice :
private static final int verticesColors[] = {
Color.LTGRAY, Color.LTGRAY, Color.LTGRAY, 0xFF000000, 0xFF000000, 0xFF000000
};
float verts[] = {
point1.x, point1.y, point2.x, point2.y, point3.x, point3.y
};
canvas.drawVertices(Canvas.VertexMode.TRIANGLES, verts.length, verts, 0, null, 0, verticesColors, 0, null, 0, 0, new Paint());

Using #Pavel's answer as guide, here's a helper method if you don't have the points but have start x,y and height and width. Also can draw inverted/upside down - which is useful for me as it was used as end of vertical barchart.
private void drawTriangle(int x, int y, int width, int height, boolean inverted, Paint paint, Canvas canvas){
Point p1 = new Point(x,y);
int pointX = x + width/2;
int pointY = inverted? y + height : y - height;
Point p2 = new Point(pointX,pointY);
Point p3 = new Point(x+width,y);
Path path = new Path();
path.setFillType(Path.FillType.EVEN_ODD);
path.moveTo(p1.x,p1.y);
path.lineTo(p2.x,p2.y);
path.lineTo(p3.x,p3.y);
path.close();
canvas.drawPath(path, paint);
}

this function shows how to create a triangle from bitmap. That is, create triangular shaped cropped image. Try the code below or download demo example
public static Bitmap getTriangleBitmap(Bitmap bitmap, int radius) {
Bitmap finalBitmap;
if (bitmap.getWidth() != radius || bitmap.getHeight() != radius)
finalBitmap = Bitmap.createScaledBitmap(bitmap, radius, radius,
false);
else
finalBitmap = bitmap;
Bitmap output = Bitmap.createBitmap(finalBitmap.getWidth(),
finalBitmap.getHeight(), Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(output);
Paint paint = new Paint();
final Rect rect = new Rect(0, 0, finalBitmap.getWidth(),
finalBitmap.getHeight());
Point point1_draw = new Point(75, 0);
Point point2_draw = new Point(0, 180);
Point point3_draw = new Point(180, 180);
Path path = new Path();
path.moveTo(point1_draw.x, point1_draw.y);
path.lineTo(point2_draw.x, point2_draw.y);
path.lineTo(point3_draw.x, point3_draw.y);
path.lineTo(point1_draw.x, point1_draw.y);
path.close();
canvas.drawARGB(0, 0, 0, 0);
paint.setColor(Color.parseColor("#BAB399"));
canvas.drawPath(path, paint);
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
canvas.drawBitmap(finalBitmap, rect, rect, paint);
return output;
}
The function above returns an triangular image drawn on canvas. Read more

private void drawArrows(Point[] point, Canvas canvas, Paint paint) {
float [] points = new float[8];
points[0] = point[0].x;
points[1] = point[0].y;
points[2] = point[1].x;
points[3] = point[1].y;
points[4] = point[2].x;
points[5] = point[2].y;
points[6] = point[0].x;
points[7] = point[0].y;
canvas.drawVertices(VertexMode.TRIANGLES, 8, points, 0, null, 0, null, 0, null, 0, 0, paint);
Path path = new Path();
path.moveTo(point[0].x , point[0].y);
path.lineTo(point[1].x,point[1].y);
path.lineTo(point[2].x,point[2].y);
canvas.drawPath(path,paint);
}

Don't moveTo() after each lineTo()
In other words, remove every moveTo() except the first one.
Seriously, if I just copy-paste OP's code and remove the unnecessary moveTo() calls, it works.
Nothing else needs to be done.
EDIT: I know the OP already posted his "final working solution", but he didn't state why it works. The actual reason was quite surprising to me, so I felt the need to add an answer.

You need remove path.moveTo after first initial.
Path path = new Path();
path.moveTo(point1_returned.x, point1_returned.y);
path.lineTo(point2_returned.x, point2_returned.y);
path.lineTo(point3_returned.x, point3_returned.y);
path.lineTo(point1_returned.x, point1_returned.y);
path.close();

Related

fill color inside triangle by three co-ordinates

I am using Point Cloud. I have 3D points with me .
Let's say : Point P(x,y,z), Point Q(x,y,z), Point R(x,y,z) assuming this points as Triangle PQR we proceed further .
Triangle Like this :
.
How can it be possible to fill the area inside this points plotted , so that the triangle will be filled with colour.
Like this :
.
My study that might have helped :
Convex hull
Java how to draw and fill a Polygon which has holes
Edit :
Some way to success :
public void make_polygon(float[] points_x,float[] points_y,float[] points_z)
{
Material mSphereMaterial_z = new Material();
//mSphereMaterial_z.setColor(Color.BLUE);
Bitmap p_z_bitty = getTriangleBitmap(BitmapFactory.decodeResource(mContext.getResources(),R.drawable.label_bg_sm),5,points_x,points_y,points_z);
Texture t = new Texture("text",p_z_bitty);
try {
mSphereMaterial_z.addTexture(t);
}
catch(Exception e)
{
e.printStackTrace();
}
Object3D p_z = new Plane();
p_z.setPosition(points_x[0],points_y[1],points_z[2]);
p_z.setMaterial(mSphereMaterial_z);
p_z.setDoubleSided(true);
getCurrentScene().addChild(p_z);
}
public static Bitmap getTriangleBitmap(Bitmap bitmap, int radius,float[] a,float[] b,float[] c) {
Bitmap finalBitmap;
if (bitmap.getWidth() != radius || bitmap.getHeight() != radius)
finalBitmap = Bitmap.createScaledBitmap(bitmap, radius, radius,
false);
else
finalBitmap = bitmap;
Bitmap output = Bitmap.createBitmap(finalBitmap.getWidth(),
finalBitmap.getHeight(), Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(output);
Paint paint = new Paint();
final Rect rect = new Rect(0, 0, finalBitmap.getWidth(),
finalBitmap.getHeight());
// Point point1_draw = new Point(75, 0);
// Point point2_draw = new Point(0, 180);
// Point point3_draw = new Point(180, 180);
PointF point1_draw = new PointF(a[0],a[1]);
PointF point2_draw = new PointF(b[0], b[1]);
PointF point3_draw = new PointF(c[0],c[1] );
Path path = new Path();
path.moveTo(point1_draw.x, point1_draw.y);
path.lineTo(point2_draw.x, point2_draw.y);
path.lineTo(point3_draw.x, point3_draw.y);
path.lineTo(point1_draw.x, point1_draw.y);
path.close();
canvas.drawARGB(0, 0, 0, 0);
paint.setColor(Color.parseColor("#BAB399"));
canvas.drawPath(path, paint);
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
canvas.drawBitmap(finalBitmap, rect, rect, paint);
return output;
}
Now result is :
Can some one guide me or suggest some article about it for Android java ?
If any more information / code needed , it shall be provided.
You should be able to do this by simply passing the vertices from the triangle to Rajawali in order to draw the triangle as a primitive. That way you can avoid using Canvas or drawing a bitmap and simplify the rendering.
// p, q, and r are triangle vertices and are of the form {x, y, z}.
public void make_triangle(float[] p, float[] q, float[] r)
{
Object3D triangle = new Object3D();
// Copy three points into a flat array as our vertices.
float[] vertices = new float[3 * 3];
for (int i = 0; i < 3; i++) {
vertices[i] = p[i];
vertices[3 + i] = q[i];
vertices[6 + i] = r[i];
}
// Set up index buffer to point at our three vertices and thus draw one triangle.
int[] indices = new int[3];
for (int i = 0; i < 3; i++) {
indices[i] = i;
}
// Set up the rendering data.
triangle.setData(vertices, null, null, null, indices, true);
// Render the triangle double sided.
triangle.setDoubleSided(true);
// Use a blue material.
Material material = new Material();
material.setColor(Color.BLUE);
triangle.setMaterial(material);
// Add the triangle to the current scene.
getCurrentScene().addChild(triangle);
}

Kaleidoscope Effect in Android

I'm trying to create a Kaleidoscope with an ImageView in Android. I'm struggling to get the rotation and mirroring for each 'segment' correct. I'm new to image manipulation and I'm trying to adapt the code example from here for android.
I have the following code:
private void drawKaleidoscope() {
Bitmap bm = BitmapFactory.decodeResource(getResources(), R.drawable.cropped_landscape);
Bitmap imageview_bitmap = Bitmap.createBitmap(bm.getWidth(), bm.getHeight(), Bitmap.Config.ARGB_8888);
Bitmap matrix_bitmap;
BitmapShader fillShader;
Path triangle_mask = new Path();
RectF r = new RectF(0, 0, bm.getWidth(), bm.getHeight()); // create new rectangle to match the dimensions of our image
this.radius = (int)r.height() / 2;
Canvas c = new Canvas(imageview_bitmap);
c.drawColor(Color.BLACK);
float start_angle = 0;
for (int i = 0; i < this.segments; i++) {
// Create pie-slice shape mask
triangle_mask.reset();
triangle_mask.moveTo(r.centerX(), r.centerY());
triangle_mask.arcTo(r, start_angle, angle);
triangle_mask.close();
// Use odd even check to decide when to mirror the image or not
if (i % 2 == 0) {
Matrix mat = new Matrix();
mat.preTranslate(-radius, -radius);
mat.postRotate(i * angle);
mat.postTranslate(radius, radius);
matrix_bitmap = Bitmap.createBitmap(bm, 0, 0, (int)r.width(), (int)r.height(), mat, true);
}
else {
Matrix mat = new Matrix();
// mirror on x axis
mat.postScale(-1, 1);
mat.postTranslate(-radius, radius);
mat.postRotate((float)-Math.PI);
mat.postRotate(i * angle);
mat.postTranslate(radius, -radius);
matrix_bitmap = Bitmap.createBitmap(bm, 0, 0, (int)r.width(), (int)r.height(), mat, true);
}
fillShader = new BitmapShader(matrix_bitmap, Shader.TileMode.MIRROR, Shader.TileMode.MIRROR);
// Fill the triangle masked area with our image now
Paint fill = new Paint();
fill.setColor(0xFFFFFFFF);
fill.setStyle(Paint.Style.FILL);
fill.setShader(fillShader);
c.drawPath(triangle_mask, fill);
start_angle += angle;
}
kal.setImageBitmap(imageview_bitmap);
}
The output of the above function looks like so:
If anyone could provide some insight on how to properly do the image rotations/mirroring that would be greatly appreciated.
Okay I ended up going about this a different way. Instead of rotating the source image I simply draw the image mask to the same spot on the canvas, and then rotate the canvas itself. Let's say I have 12 image 'slices'. I draw 6 alternating segments, flip the canvas via canvas.scale(-1, 1) and then draw another 6 segments in where the blank spaces are. Here's the code I ended up with:
private Bitmap generateKaleidoscopeBitmap(float start_angle) {
Canvas canvas = new Canvas(imageview_bitmap);
canvas.drawColor(Color.BLACK);
BitmapShader fillShader;
Path triangle_mask = new Path();
RectF r = new RectF(0, 0, imageview_bitmap.getWidth(), imageview_bitmap.getHeight()); // create new rectangle to match the dimensions of our image
int centerX = imageview_bitmap.getWidth() / 2;
int centerY = imageview_bitmap.getHeight() / 2;
// how much to rotate the canvas by after the image is flipped
float offset = calculateCanvasSymmetryOffset(start_angle);
// Create a pie-slice shaped clipping mask
triangle_mask.moveTo(r.centerX(), r.centerY());
triangle_mask.arcTo(r, start_angle, angle);
triangle_mask.close();
// Fill the triangle masked area with our shader now
Paint fill = new Paint();
fill.setColor(0xFFFFFFFF);
fill.setStyle(Paint.Style.FILL);
fillShader = new BitmapShader(source_image, Shader.TileMode.MIRROR, Shader.TileMode.MIRROR);
fill.setShader(fillShader);
// Rotate the canvas and draw the clipping mask to the canvas
for (int i = 0; i < this.segments / 2; i++) {
canvas.drawPath(triangle_mask, fill);
canvas.rotate(angle * 2, centerX, centerY);
}
// mirror the canvas and rotate it once to counter the symmetrical offset
canvas.scale(-1, 1, centerX, centerY);
canvas.rotate(offset, centerX, centerY);
// Rotate the now mirrored canvas and draw the clipping mask to it
// This is a cheap and easy way of creating mirrored segments
for (int i = 0; i < this.segments / 2; i++) {
canvas.drawPath(triangle_mask, fill);
canvas.rotate(angle * 2, centerX, centerY);
}
return imageview_bitmap;
}

How to cut a circle from a different shapes of bitmap in android

How can i cut a circle from a different shapes of bitmap in android.
I tried this code, but some images are stretched:
public Bitmap getRoundedShape(Bitmap scaleBitmapImage) {
int targetWidth = 240;
int targetHeight = 200;
Bitmap targetBitmap = Bitmap.createBitmap(targetWidth,
targetHeight,Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(targetBitmap);
Path path = new Path();
path.addCircle(((float) targetWidth - 1) / 2,
((float) targetHeight - 1) / 2,
(Math.min(((float) targetWidth),
((float) targetHeight)) / 2),
Path.Direction.CCW);
canvas.clipPath(path);
Bitmap sourceBitmap = scaleBitmapImage;
canvas.drawBitmap(sourceBitmap,new Rect(0, 0, sourceBitmap.getWidth(),
sourceBitmap.getHeight()),
new Rect(0, 0, targetWidth, targetHeight), null);
return targetBitmap;
}
If you want a circular cut of an image, you need to find the largest square that centers the image. Considering this, following line fixes your stretching problem:
Bitmap bitmap = ThumbnailUtils.extractThumbnail(bitmap, radius, radius, ThumbnailUtils.OPTIONS_RECYCLE_INPUT);
This method creates a circular cut of the target bitmap:
private Bitmap getCircularBitmap(int radius, Bitmap bitmap) {
Bitmap.Config conf = Bitmap.Config.ARGB_8888;
Bitmap bmp = Bitmap.createBitmap(radius, radius, conf);
Canvas canvas = new Canvas(bmp);
// creates a centered bitmap of the desired size
bitmap = ThumbnailUtils.extractThumbnail(bitmap, radius, radius, ThumbnailUtils.OPTIONS_RECYCLE_INPUT);
BitmapShader shader = new BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
Paint paint = new Paint();
paint.setAntiAlias(true);
paint.setShader(shader);
RectF rect = new RectF(0, 0, radius, radius);
canvas.drawRoundRect(rect, radius, radius, paint);
return bmp;
}
One approach would be to use a BitmapShader.
The idea is to use a Paint with a BitmapShader to draw a texture using the bitmap. Then you just draw a circle on the canvas.
Here is an excellent example of using the BitmapShader. In this example, a rectangle with rounded corners is drawn, but it could just as easily be a circle.
Android Recipe #1, image with rounded corners

Triangle not showing

I am trying to display a triangle in an image. Unfortunately, is doesn't display the triangle and I can't find the reason for that. Where did I mess up?
Here is the code:
double hypotenuse = Math.sqrt(Math.pow((width_index-standard),2)+Math.pow((high_index-base_index),2));
angle *= Math.asin(((width_index-standard)/hypotenuse));
angle = angle*(180/Math.PI);
angle = Math.round(angle);
TextView t = (TextView) findViewById(R.id.result_angle);
t.setText(String.valueOf(angle));
// return_b is the bitmap to be displayed
Canvas canvas = new Canvas(return_b);
Path p = new Path();
Paint paint = new Paint();
p.moveTo(standard, (base_index+(float)hypotenuse));
p.lineTo(standard, height-1);
p.moveTo(standard, height-1);
p.lineTo(width_index, high_index);
p.moveTo(width_index, high_index);
//p.addArc(standard, (base_index+(float)hypotenuse), width_index, high_index, 0, (float)((-1)*angle));
p.lineTo(standard, (base_index+(float)hypotenuse));
p.close();
paint.setColor(Color.BLACK);
paint.setStyle(Paint.Style.FILL);
paint.setAntiAlias(true);
canvas.drawPath(p, paint);
Thanks.
The issue was in the moveTos. When I removed them the triangle showed up.

Get a vignette effect by shaders

Im trying to create a vignette effect for my app. I've been searching a lot for help achieving this but was unable to find anything.
I recently found this tutorial.
And i tried to implement it in my app with this code:
public int[] drawBitmap(Bitmap originalBitmap){
Bitmap mask;
Paint paint = new Paint();
mask = convertToAlphaMask(BitmapFactory.decodeResource(context.getResources(), R.drawable.spot_mask));
Shader shader = createShader(mask);
paint.setShader(shader);
Bitmap tempBit = Bitmap.createBitmap(mask.getWidth(), mask.getHeight(), Config.ARGB_8888);
Canvas canvas = new Canvas(tempBit);
canvas.drawBitmap(originalBitmap, 0, 0,paint);
tempBit.getPixels(pixels, 0, tempBit.getWidth(), 0, 0, tempBit.getWidth(), tempBit.getHeight());
return pixels;
}
private static Bitmap convertToAlphaMask(Bitmap input) {
Bitmap a = Bitmap.createBitmap(input.getWidth(), input.getHeight(), Bitmap.Config.ALPHA_8);
Canvas c = new Canvas(a);
c.drawBitmap(input, 0.0f, 0.0f, null);
return a;
}
private static Shader createShader(Bitmap b) {
return new BitmapShader(b, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
}
But the effect of this looks like this:(the only change is at the top of the image)
http://postimg.org/image/rrivq28v1/
What have I done wrong?
Also, are there any other alternatives for applying a vignette effect on a bitmap?
Thanks!
After long time i found it
public Bitmap vignett(Bitmap bm, int p){
Bitmap image = Bitmap.createBitmap(bm.getWidth(),bm.getHeight(), Bitmap.Config.ARGB_8888);
int rad;
Canvas canvas = new Canvas(image);
canvas.drawBitmap(bm, 0, 0, new Paint());
if(bm.getWidth()<bm.getHeight()){
int o = (bm.getHeight()*2)/100;
rad = bm.getHeight() - o*p/3;
}else{
int o = (bm.getWidth()*2)/100;
rad = bm.getWidth() - o*p/3;
}
Rect rect = new Rect(0, 0, bm.getWidth(), bm.getHeight());
RectF rectf = new RectF(rect);
int[] colors = new int[] { 0, 0, Color.BLACK };
float[] pos = new float[] { 0.0f, 0.1f, 1.0f };
Shader linGradLR = new RadialGradient(rect.centerX(), rect.centerY(),rad, colors, pos, Shader.TileMode.CLAMP);
Paint paint = new Paint();
paint.setShader(linGradLR);
paint.setAntiAlias(true);
paint.setDither(true);
paint.setAlpha(255);
canvas.drawRect(rectf, paint);
return image;
}
here int p is standard value of seekbar from 1 to 100;
for intensity of effect u can set paint.setAlpha 0 to 255!!!
My first answer got deleted because i pointed to my solution via link. So I'll answer your question right here. The trick is to use 4 linear gradients. Applying them will give you a result that comes pretty close to a true Vignette effect. And it's freaking fast too ;) So here's part of my solution.
First you must create a canvas:
Canvas canvas = new Canvas(bitmapOut);
canvas.drawBitmap(mVignette.getBitmapIn(), 0, 0, null);
Then you define how far the effect should reach into your image:
int tenthLeftRight = (int)(width/5);
int tenthTopBottom = (int)(height/5);
Now you create your four shaders:
// Gradient left - right
Shader linGradLR = new LinearGradient(0, height/2, tenthLeftRight/2, height/2, Color.BLACK, Color.TRANSPARENT, Shader.TileMode.CLAMP);
// Gradient top - bottom
Shader linGradTB = new LinearGradient(width/2, 0, width/2, tenthTopBottom, Color.BLACK, Color.TRANSPARENT, Shader.TileMode.CLAMP);
// Gradient right - left
Shader linGradRL = new LinearGradient(width, height/2, (width-tenthLeftRight), height/2, Color.BLACK, Color.TRANSPARENT, Shader.TileMode.CLAMP);
// Gradient bottom - top
Shader linGradBT = new LinearGradient(width/2, height, width/2, (height - tenthTopBottom), Color.BLACK, Color.TRANSPARENT, Shader.TileMode.CLAMP);
Now all that's left to do is to draw on the canvas:
Paint paint = new Paint();
paint.setShader(linGradLR);
paint.setAntiAlias(true);
paint.setDither(true);
paint.setAlpha(125);
// Rect for Grad left - right
Rect rect = new Rect(0, 0, tenthLeftRight, height);
RectF rectf = new RectF(rect);
canvas.drawRect(rectf, paint);
// Rect for Grad top - bottom
paint.setShader(linGradTB);
rect = new Rect(0, 0, width, tenthTopBottom);
rectf = new RectF(rect);
canvas.drawRect(rectf, paint);
// Rect for Grad right - left
paint.setShader(linGradRL);
rect = new Rect(width, 0, width - tenthLeftRight, height);
rectf = new RectF(rect);
canvas.drawRect(rectf, paint);
// Rect for Grad bottom - top
paint.setShader(linGradBT);
rect = new Rect(0, height - tenthTopBottom, width, height);
rectf = new RectF(rect);
canvas.drawRect(rectf, paint);

Categories