Changing the position of an android.graphics.Path on a canvas - android

I've been browsing for some days now, but I can't seem to find a way to do this. I hope that maybe some of you are more experienced then I am with the Android SDK and its abilities :)
Say you draw the path on the canvas with the upper- and left-most control point x=300 and y=500 (the scribble in the image below). I want to be able to set the position of its "rectangle" to the canvas coordinates e.g. x=10 and y=10
So basically, it is the rectangle with the path that I am interested in. The idea is "cutting" this area out and moving it to a given position (but I don't want to include the underlying draws that are already on the canvas).
What I have tried:
Converting the Path into a PathShape and then a ShapeDrawable. I am able to skew the position of the Drawable, but it is too inexact to be used to position it.
ShapeDrawable sd = new ShapeDrawable(new PathShape(path, getWidth(), getHeight());
sd.getPaint().set(p);
sd.setBounds(0, 0, getWidth(), getHeight());
getWidth() and getHeight() are respectively getting the width and height of the canvas.
Can you please help me think of a way to do this by a new idea or by correcting my ShapeDrawable idea? Thank you very much for any help in advance!

Path transform looks like exactly what you need.

Related

Android drawing position on view

As I am a beginner of Android developement, I need someone to give me an answer or any comments on my question.
When I draw a simple rectangle on a view with the following code, the rectangle doesn't show in the way in which I would expect.
canvas.drawLine(0, 0, getWidth(), getHeight(), framePaint);
wrong
But when I changed it like this, it shows properly.
canvas.drawRect(1, 0, getWidth(), getHeight()-1, framePaint);
Correct
That looks like the left and the bottom lines are clipped out of the view.
I was expecting that the position of view starts zero-indexed such as 0 ~ (size of view)-1. Do I understand wrong or did i do something wrong?
The framePaint is configured like this;
framePaint = new Paint();
framePaint.setColor(Color.rgb(255,0,0));
framePaint.setStrokeWidth(1);
framePaint.setStyle(Paint.Style.STROKE);
Here's what happens:
When you subtract one from the total pixels, it draws the line(s) in the image, not outside of it.
Also the "1" at the start also helps the code stay in the canvas.
You may want to try replacing the 1's in the code with 2's, as the canvas uses an extra pixel to automatically remove "aliasing".

how to resolve overlapping on draw of multiple path

i want to draw multiple path with multiple paint stroke width on the canvas, but overlapping problem occurs on collision of path.
color overlapping when drawing multiple path
Above link contains explanation. Overlapping occurs when i set alpha to paint. But this is requirement of application. If other way to make paint semi-transparent with using alpha.
Please suggest.
Thanks
I think it'll help you
mPaint.setARGB(90, 255, 0, 0);
mPaint.setXfermode(new AvoidXfermode(Color.RED, 90, Mode.AVOID));
if you are drawing on canvas than you need to set transparent bitmap to canvas otherwise AvoidXfermode will detect rgb of image.

Why is drawLine offset by 1 pixel?

This is probably an easy one for Android experts. I am trying to draw into a Bitmap via a Canvas. I want exact colors, no anti-aliasing, and lines located at exact absolute coordinates within the Bitmap. Sometimes the lines are in the correct position and sometimes they are offset by 1 pixel. I have a feeling this has something to do with scaling. But I'm not sure. Here's the code:
Paint mPaint = new Paint();
mPaint.setColor(Paint.WHITE);
mPaint.setStrokeWidth(0);
mPaint.setAntiAlias(false);
mPaint.setDither(false);
mPaint.setStyle(Paint.Style.STROKE);
drawingContext.mycanvas.drawLine(20, 0, 10, 10, mPaint);
This actually draws a line from (19,0) to (10,9). Why?
I'll answer. I had to give up on this and write a Bresenham algorithm, setting pixels one by one. That works OK for what I'm doing. I suspect a drawLine bug when drawing left to right, bottom to top lines.

Using a gradient along a path

I'm trying to create a 'glow' effect using the Android Path class. However, the gradient is not being warped to fit around the path. Instead, it is simply being display 'above' it and clipped to the path's stroke. Using a square path, the image below shows what I mean:
Instead, that should look more like this:
In other words, the gradient follows the path, and in particular wraps around the corners according to the radius set in the CornerPathEffect.
Here is the relevant part of the code:
paint = new Paint();
paint.setStyle(Style.STROKE);
paint.setStrokeWidth(20);
paint.setAntiAlias(true);
LinearGradient gradient = new LinearGradient(30, 0, 50, 0,
new int[] {0x00000000, 0xFF0000FF, 0x00000000}, null, Shader.TileMode.MIRROR);
paint.setShader(gradient);
PathEffect cornerEffect = new CornerPathEffect(10);
paint.setPathEffect(cornerEffect);
canvas.drawPath(boxPath, paint);
Any ideas?
Another alternative is to get a 'soft-edged brush' effect when defining the stroke width. I've experimented with BlurMaskFilters, but those give a uniform blur rather than a transition from opaque to transparent. Does anyone know if that's possible?
How about drawing with a soft brush bitmap? Make a soft circular brush with opacity decreasing radially outward using image editing software like Photoshop. Save as drawable, load it in a bitmap and draw it evenly spaced along your path. Make the bitmap with white coloured brush. This way you can simply multiply the given colour(Here blue) to your bitmap using PorterDuffColorFilter.
brush1=BitmapFactory.decodeResource(getResources(), R.drawable.brush_custom_one);
//This contains radially decreasing opacity brush
porter_paint.setColorFilter(new PorterDuffColorFilter(paint.getColor(), Mode.MULTIPLY));
for (int i=1;i<matrix.size();i++) {
//matrix contains evenly spaced points along path
Point point = matrix.get(matrix.get(i));
canvas.drawBitmap(brush1, point.x,point.y, porter_paint);}
The brush used is (It's there):
The final result is:
Turns out there was a stupidly obvious way of doing this. Simply re-use the same path, and adjust the stroke width and alpha on each drawing pass. Example code:
float numberOfPasses = 20;
float maxWidth = 15;
for (float i = 0; i <= numberOfPasses; i++){
int alpha = (int) (i / numberOfPasses * 255f);
float width = maxWidth * (1 - i / numberOfPasses);
paint.setARGB(alpha, 0, 0, 255);
paint.setStrokeWidth(width);
canvas.drawPath(path, paint);
}
See below for an example of the result. The left path was drawn using this method, the right path, for comparison, is drawn in a single stroke with maxWidth and 255 alpha.
This mainly works. There are two problems:
The gradient isn't as smooth as it could be. This is because each pass being drawn over the previous one results in the alpha building up too quickly, reaching 255 before the final strokes. Experimenting a bit with the line int alpha = (int) (i / numberOfPasses * 125f); (note the change to 125f rather than 255f) helps.
The path looks like it has been 'cut' on the insides of the corners. Probably some result of the CornerPathEffect applied.
What you're wanting to do, if I understand it right, is to have the gradient effectively form a "brush" for the stroke.
This is exactly what I also was trying to achieve recently, but as far as I can tell the API doesn't provide any straightforward means to do it. I have recently created an SVG to Android Canvas converter class and so I am working a lot in Inkscape lately, too. So, when I was looking into it, I wondered if it's even possible to do it in Inkscape. However, even in Inkscape it's a very non-trivial thing to do. After some searching I eventually came across this image of a gradient being applied along the course of a path, together with a download link for a tutorial beneath:
http://www.flickr.com/photos/35772571#N03/3312087295/
What I was personally trying to do at the time was to create some semi-circles where the path is a kind of neon glow as opposed to a flat colour. Talking in terms of both the Android API and the SVG standard, it seems that the only way to to do this is to create a radial gradient that's centred perfectly on the circle, and position a series of color stops in exactly the right places. Pretty tricky to do, and I certainly don't know how you'd do it to a shape like a square.
Sorry that this is a bit of a 'I couldn't do it either' rather than a useful answer! I'll follow this with interest as I'm eager to know a solution for a kind of 'soft brush' effect too.
Can be very complicated to draw a gradient than follow a path.
So I suggest you to use some library already done than make it for you.
One can be Sc-Gauges.
Have some usefully classe than you can use for your goal.
For first include the library:
dependencies {
...
compile 'com.github.paroca72:sc-gauges:3.0.7'
}
After create an image or what you want with a canvas where draw:
<ImageView
android:id="#+id/image"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
Now the code:
// Dimensions
int padding = 24;
Rect drawArea = new Rect(padding, padding, 700 - padding, 500 - padding);
// Get the main layout
ImageView imageContainer = (ImageView) this.findViewById(R.id.image);
assert imageContainer != null;
// Create a bitmap and link a canvas
Bitmap bitmap = Bitmap.createBitmap(
drawArea.width() + padding * 2, drawArea.height() + padding * 2,
Bitmap.Config.ARGB_8888
);
Canvas canvas = new Canvas(bitmap);
canvas.drawColor(Color.parseColor("#f5f5f5"));
// Create the path building a bezier curve from the left-top to the right-bottom angles of
// the drawing area.
Path path = new Path();
path.moveTo(drawArea.left, drawArea.top);
path.quadTo(drawArea.centerX(), drawArea.top, drawArea.centerX(), drawArea.centerY());
path.quadTo(drawArea.centerX(), drawArea.bottom, drawArea.right, drawArea.bottom);
// Feature
ScCopier copier = new ScCopier();
copier.setPath(path);
copier.setColors(Color.RED, Color.GREEN, Color.BLUE);
copier.setWidths(20);
copier.draw(canvas);
// Add the bitmap to the container
imageContainer.setImageBitmap(bitmap);
And this the result:
The first part of the code is just for create a bitmap where draw.
What you interest is the second part where use ScCopier.
Just give the path, the color and the with.
Note than is you are inside a view you can use onDraw for draw directly on the view canvas.
This library can used to create gauge of every kind.
If you want take a look to this site ScComponents have some free and not gauges components.

moving a path with a repeating Bitmap image in android

I'm currently writing an android side-scrolling game and am having trouble filling a path with a repeating bitmap image. I'm creating a path from a number of coordinates to make up the "ground" area. I have a character who is fixed in the middle of the canvas and screen and am moving the path to represent the movement of the character. I've been able to fill the path with a repeating image using a BitmapShader. Also I can move the path shape from side to side on the screen. However, the Bitmapshader seems to be using a default origin of 0,0 which means the shader is always drawing the ground repeating image in the same place. This means that even though the path is moving the ground repeated image never appears to move. Does anyone have any idea how to change the origin of the shader or know of a better way to fill the path with a repeating image?
Alternatively, can anyone suggest a better solution for filling a drawable shape with an image?
Thanks
Andy
Thanks, had a look at those...Replica Island seems to use OpenGL quite a lot which is a bit beyond me at present and Snake didn't quite do what I was looking for...eventually got there..
//Shape pathShape = this.getPathShape();
Bitmap groundImage = ImageHandler.getmGroundImage();
int offset = groundImage.getWidth()-(xPosition%groundImage.getWidth());
Path path = new Path();
path.moveTo(coordinates.get(0).getmX(), coordinates.get(0).getmY());
for ( ShapeCoordinate coordinate : coordinates ) {
path.lineTo(coordinate.getmX(), coordinate.getmY());
}
path.lineTo(coordinates.get(coordinates.size()-1).getmX(), mYBase);
path.lineTo(coordinates.get(0).getmX(), mYBase);
path.lineTo(coordinates.get(0).getmX(), coordinates.get(0).getmY());
path.close();
PathShape shape = new PathShape(path,canvas.getWidth(),canvas.getHeight());
BitmapShader bs = new BitmapShader(groundImage, Shader.TileMode.REPEAT,Shader.TileMode.REPEAT);
Matrix matrix = new Matrix();
matrix.reset();
matrix.setScale(1,1);
matrix.preTranslate(offset, 0);
bs.setLocalMatrix(matrix);
ShapeDrawable sd = new ShapeDrawable(shape);
sd.setColorFilter(Color.argb(255, 50*(mLevel+1), 50*(mLevel+1), 50*(mLevel+1)), Mode.LIGHTEN);
sd.getPaint().setShader(bs);
sd.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
sd.draw(canvas);
Have you looked at the Snake example in the android sdk? Also Replica Island is another example of how to do a tile engine in android.

Categories

Resources