Is it possible to create and draw a Moving Grid on a canvas that recycles its points? I want to create a Grid on an android canvas that moves downwards and recycles its points when a point reaches the bottom of the screen.
The First part of the question is: How do I draw a grid with lines on an Android Canvas?
The Second part: How do I make it scroll and repeat?
The grid should look something like this:
I have tried doing this with a Bitmap , but I am not sure if that is as efficient as doing it By using the Draw Line feature. Plus, I cannot access the girds points when using a bitmap, so it is not very useful when trying to draw a graph for example.
I am developing a drawing app, and I encountered the same problem. I searched everywhere, but I could not found a direct solution. That is why I developed a library that do exactly that. It creates a infinite grid that can be transformed, include transformations are: Translate, Rotate and Scale. The library generates only the visible lines, that are shown on the View and are generated in real time using simple math. Here is a direct link to the library
The explanation is pretty simple, if you want to learn more about how it works your can check the Wiki page.
Here is a link to the library source code, if you are interested.
To tag onto Balha's answer:
the android/java equivalent looks something like this:
int canvasWidth = 0;
int canvasHeight = 0;
float gridSize = 20f;
float ecart = Math.max(mCanvasHeight, mCanvasWidth) / gridSize;
//last j index value
int lj= 0;
//last i index value
int li = 0;
canvasWidth = canvas.getWidth();
canvasHeight = canvas.getHeight();
for (int j = 0; j <= Math.min(canvasWidth, canvasHeight); j += (int)ecart)
{
for (int i = 0; i <= Math.max(canvasWidth, canvasHeight); i += (int)ecart)
{
li = i;
}
lj = j;
}
canvas.clipRect(0, 0, lj, canvas.getHeight());
for (int j = 0; j <= Math.min(canvasWidth, canvasHeight); j += (int)ecart)
{
for (int i = 0; i <= Math.max(canvasWidth, canvasHeight); i += (int)ecart)
{
//horizontal lines
canvas.drawLine(j, i, i, i, paint);
//vertical lines
canvas.drawLine(j, i, j, j, paint);
}
}
I know its too late but It can help someone else;
This Draws a perfect grid mesh
Note: This is a c# code
float gridSize = 20f;
var ecart = Math.Max(MaxHeight, MaxWidth) / gridSize;
//last j index value
int lj= 0;
//last i index value
int li = 0;
for (int j = 0; j <= Math.Min(canvas.Width, canvas.Height); j += (int)ecart)
{
for (int i = 0; i <= Math.Max(canvas.Width, canvas.Height); i += (int)ecart)
{
li = i;
}
lj = j;
}
canvas.ClipRect(0, 0, lj, canvas.Height);
for (int j = 0; j <= Math.Min(canvas.Width, canvas.Height); j += (int)ecart)
{
for (int i = 0; i <= Math.Max(canvas.Width, canvas.Height); i += (int)ecart)
{
//horizontal lines
canvas.DrawLine(j, i, i, i, paint);
//vertical lines
canvas.DrawLine(j, i, j, j, paint);
}
}
Related
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
im struggeling for a long while now. Im trying to change the alpha channel on a specific pixel of a image. I want to convert an image to a 2D array with only alpha channels. I got this working in Android, but don't know how in UWP.
Android version
short[][] dotMapArray;
short[][] heatMapArray;
int[] scolorGradiant;
void init() {
Bitmap dotBitmap = loadImageFromResources(DOT);
Bitmap gradiantBitmap = loadImageFromResources(SPECTRUMPIC);
// initializing the 'dot' for the points on the heatmap
dotMapArray = new short[dotBitmap.getWidth()][dotBitmap.getHeight()];
print(true, "Converting Dot image to black image");
for (int x = 0; x < dotBitmap.getWidth(); x++) {
for (int y = 0; y < dotBitmap.getHeight(); y++) {
dotMapArray[x][y] = (short) (Color.alpha(dotBitmap.getPixel(x, y)));
if (dotMapArray[x][y] > 255)
dotMapArray[x][y] = 255;
}
}
// initializing the color gradiant
scolorGradiant = new int[gradiantBitmap.getHeight()];
int gradiant, pixelColor;
for (int y = 0; y < scolorGradiant.length; y++) {
gradiant = gradiantBitmap.getPixel(0, y); // color
pixelColor = Color.argb(90, Color.red(gradiant), Color.green(gradiant), Color.blue(gradiant));
scolorGradiant[y] = pixelColor;
}
}
How do I do this in UWP?
Can anybody help me?
Here's a loop that checks 1st channel (BGRA) if blue = 255 then all channels go to 0
var pixels = yourWriteableBitmap.PixelBuffer.ToArray();
for (int i = 0; i < pixels.Length; i += 4)
{
if (pixels[i] == 255)
{
pixels[i] = 0;
pixels[i + 1] = 0;
pixels[i + 2] = 0;
pixels[i + 3] = 0;
}
}
using (var stream = yourWriteableBitmap.PixelBuffer.AsStream())
{
await stream.WriteAsync(pixels, 0, pixels.Length);
}
I'm designing a puzzle game in android eclipse. I have a picture in resources drawable file named "puzzle_image01". i want to divide this image to 9 parts and put it to some variables. then using them for the puzzle pieces. Now, how can i divide the image to 9 parts?
thank you for your advice.
for(int i = 0; i < 9; ++i) {
int indexY = 0;
if(i < 3) {
imageStartY = 0;
imageFinishY = sourceBitmap.height() / 3;
}
else if(i < 6) {
imageStartY = sourceBitmap.height() / 3;
imageFinishY = (sourceBitmap-height() / 3) * 2;
}
else if(i < 9) {
imageStartY = (sourceBitmap.height() / 3) * 2;
imageFinishY = sourceBitmap.height();
}
Bitmap resizedbitmap = Bitmap.createBitmap(sourceBitmap
, ((sourceBitmap.width()) / 3) * i
, imageStartY
,((sourceBitmap.width()) / 3) * i + sourceBitmap.width()
, imageFinishY)
}
Interesting challenge. Didn't test this, but it should work for any row/column combination where the image's dimensions divided by their respective value is greater than zero:
private Bitmap[][] split(Bitmap bitmap, int rows, int columns){
int[] dimens = new int[]{ bitmap.getWidth() / rows, bitmap.getHeight() / columns };
Bitmap[][] splitMap = new Bitmap[rows][columns];
for(int i = 0; i < rows; i++){
for(int j = 0; j < columns; j++){
splitMap[i][j] = Bitmap.createBitmap(bitmap, i * dimens[0], j * dimens[1], dimens[0], dimens[1]);
}
}
return splitMap;
}
I need to create ViewGroup custom shape. Its may be FrameLayout.It should look like
Its must be ViewGroup cause I need to add text or image inside.How can i do this? Thanks a lot.
There is a good tutorial here on creating custom polygon shapes. It is a fairly long process, but you will get there. In short, you will have to create custom XML attributes for a custom View.
The real magic is here:
#Override
protected void onDraw(Canvas canvas) {
int measuredWidth = getMeasuredWidth();
int measuredHeight = getMeasuredHeight();
int x = (measuredWidth/2) ;
int y = (measuredHeight/2) ;
int radius = Math.min(x,y) ;
if (sides < 3) return;
float a = (float) (Math.PI * 2)/sides;
int workingRadius = radius;
polyPath.reset();
// The poly is created as a shape in a path.
// If there is a hole in the poly, draw a 2nd shape inset from the first
for(int j = 0; j < ((fillPercent < 100) ? 2 : 1) ; j++){
polyPath.moveTo(workingRadius,0);
for (int i = 1; i < sides; i++) {
polyPath.lineTo((float)(workingRadius*Math.cos(a*i)),
(float)(workingRadius*Math.sin(a*i)));
}
polyPath.close();
workingRadius -= radius * fillPercent;
a = -a;
}
canvas.save();
canvas.translate(x, y);
canvas.rotate(startAngle);
canvas.drawPath(polyPath, fillPaint);
canvas.restore();
if(showInscribedCircle){
canvas.drawCircle(x,y,radius, inscribedCirclePaint);
}
super.onDraw(canvas);
}
i am trying to create gradient of two colors like Photoshop.
r,g,b of two colors is input and result will be the Mat of gradient. I tried it like for 5 hours at least and i could not find exact effect as of the Photoshop.
I tried to create my own formula (as i could not find any on the web), by changing RGB to HSV and then adding the difference of hue, with respect to the total number of rows, to each row of Mat with and also decreasing intensity to the center of image and then increasing it again. The code is self explanatory.
Additionally if anyone can tell me the exact formula for creating a gradient it will be really helpful.
here is how Photoshop gradient looks like
and this is what i get from my code
int r1, g1, b1, r2, g2, b2;
r1 = 255;
g1 = 0;
b1 = 0;
r2 = 0;
g2 = 255;
b2 = 0;
Mat input = imread("img.jpg");
Mat color1(input.size(), input.type());
Mat color2(input.size(), input.type());
vector<Mat> bgr1;
vector<Mat> bgr2;
split(color1, bgr1);
bgr1[0] = b1;
bgr1[1] = g1;
bgr1[2] = r1;
merge(bgr1, color1);
split(color2, bgr2);
bgr2[0] = b2;
bgr2[1] = g2;
bgr2[2] = r2;
merge(bgr2, color2);
vector<Mat> hls1;
vector<Mat> hls2;
cvtColor(color1, color1, CV_BGRA2BGR);
cvtColor(color1, color1, CV_BGR2HSV);
split(color1, hls1);
cvtColor(color2, color2, CV_BGRA2BGR);
cvtColor(color2, color2, CV_BGR2HSV);
split(color2, hls2);
double h1 = hls1[0].at<uchar>(0, 0);
double h2 = hls2[0].at<uchar>(0, 0);
double dif = (h2 - h1) / input.rows;
double h = h1;
double halfL = 255 / 2;
double halfR = input.rows / 2;
double ldif = halfL / halfR;
double l = 255;
bool isHalf = false;
for (int i = 0; i < input.rows; i++)
{
for (int j = 0; j < input.cols; j++)
{
hls1[0].at<uchar>(i, j) = h;
hls1[2].at<uchar>(i, j) = l;
}
if (isHalf == false){
l -= ldif;
}
else{
l += ldif;
}
if (i < input.rows * 0.40)
{
h += dif * 0.40;
}
else if (i < input.rows * 0.60)
{
h += dif * 3;
}
else
{
h += dif * 0.40;
}
if (i >= input.rows / 2)
{
isHalf = true;
}
}
merge(hls1, color1);
merge(hls2, color2);
cvtColor(color1, color1, CV_HSV2BGR);
cvtColor(color1, color1, CV_BGR2BGRA);
cvtColor(color2, color2, CV_HSV2BGR);
cvtColor(color2, color2, CV_BGR2BGRA);
namedWindow("Color1", cv::WINDOW_NORMAL);
resizeWindow("Color1", color1.size().width / 2, color1.size().height / 2);
imshow("Color1", color1);
waitKey(0);
destroyAllWindows();
system("pause");
I corrected my first code
It seems to be a really complex code for something that should be easier.
I would do something like that.
int taille = 500;
Mat image(taille,taille,CV_8UC3);
for(int y = 0; y < taille; y++){
Vec3b val;
val[0] = 0; val[1] = (y*255)/taille; val[2] = (taille-y)*255/taille;
for(int x = 0; x < taille; x++)
image.at<Vec3b>(y,x) = val;
}
On Micka's advice, I add a picture of the result with taille = 400;