I want to generate n no of random no whose sum should be m and these no should always be between x and y.
For eg :- If i say I need 20 no, between 3 and 9 inclusive, whose sum should be 100.
I want to specify the sum and required amount of no as well as the limit between which random no should be generated and it should give me the random no of specified amount. Below is my code which do generates no which are greater than 2 but i am not able to put the max limit. Also, the sum which comes out and the sum of no. which it generates is not equal to specified sum. I am totally confused Please help me out.
TextView textView,randomTotaltxt;
int count0 = 0;
int count1 = 0;
int targetSum = 100;
int numberofDraws = 20;
textView = (TextView) findViewById(R.id.textview);
randomTotaltxt = (TextView) findViewById(R.id.randomTptalText);
Random r = new Random();
ArrayList<Integer> load = new ArrayList<>();
//random no
int sum = 0;
for (int i=0; i<numberofDraws;i++){
int next = r.nextInt(targetSum)+1;
Log.d("No",""+next);
load.add(next);
sum += next;
}
//scale it
double scale = 1d*targetSum/sum;
sum=0;
for (int i=0; i<numberofDraws;i++){
load.set(i, (int)(load.get(i)*scale));
sum += load.get(i);
}
while (load.contains(0)|| load.contains(1)){
for (int i=0; i<load.size();i++) {
if (load.get(i).equals(0)) {
load.set(i, load.get(i) + 2);
count0++;
sum = sum+1;
}
if (load.get(i).equals(1)) {
load.set(i, load.get(i) + 2);
sum += load.get(i);
count1++;
sum = sum+1;
}
}
}
// take rounding
while (sum++ <targetSum){
int i = r.nextInt(numberofDraws);
load.set(i, load.get(i) + 1);
}
textView.setText(""+load);
randomTotaltxt.setText(""+(sum-1));
This might not be the optimal solution but this will do your work as required.
int targetSum = 100;
int numberOfDraws = 20;
int uppr=0;
int countt =0;
ArrayList<Integer> load = new ArrayList<>();
Random random;
TextView textView1,randomTotaltxt1;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main2);
textView1 = (TextView) findViewById(R.id.textview1);
randomTotaltxt1 = (TextView) findViewById(R.id.randomTptalText1);
random = new Random();
//random no
int sum = 0;
for (int i=0; i<numberOfDraws;i++){
int next = random.nextInt(targetSum)+1;
load.add(next);
sum += next;
}
//scale it
double scale = 1d*targetSum/sum;
sum=0;
for (int i=0; i<numberOfDraws;i++){
load.set(i, (int)(load.get(i)*scale));
sum += load.get(i);
}
// take rounding
while (sum++ <targetSum){
int i = random.nextInt(numberOfDraws);
load.set(i, load.get(i) + 1);
Log.d("TAG",""+load);
}
checkForUpperRange();
}
public void checkForUpperRange(){
for (int i=0; i<numberOfDraws;i++){
int n = load.get(i);
if (n > 9){
load.set(i, 9);
uppr = n - 9; // getting the required no.
adjustUpper();
break;
}
checkForLowerRange();
}
}
private void adjustUpper() {
for (int j=0; j<numberOfDraws;j++){
if (load.get(j) > 2){
load.set(j, load.get(j)+uppr); // uppr is added
checkForUpperRange();
break;
}
}
}
public void checkForLowerRange(){
for (int i=0; i<numberOfDraws;i++){
int n = load.get(i);
if (n == 0){
load.set(i, load.get(i)+3); // 3 is added in sum
adjust0();
break;
}
if (n == 1){
load.set(i, load.get(i)+2); // 2 is added in sum
adjust1();
break;
}
if (n == 2){
load.set(i, load.get(i)+1); // 1 is added in sum
adjust2();
break;
}
getCount();
}
}
public void getCount(){
countt = 0;
for (int k=0; k<numberOfDraws;k++){
countt = countt+ load.get(k);
showResult();
}
}
public void showResult(){
textView1.setText(""+load);
randomTotaltxt1.setText(""+countt);
}
public void adjust0(){
for (int j=0; j<numberOfDraws;j++){
if (load.get(j) > 3){
load.set(j, load.get(j)-3); // 3 is subtracted
checkForLowerRange();
break;
}
}
}
public void adjust1(){
for (int j=0; j<numberOfDraws;j++){
if (load.get(j) > 3){
load.set(j, load.get(j)-2); // 2 is subtracted
checkForLowerRange();
break;
}
}
}
public void adjust2(){
for (int j=0; j<numberOfDraws;j++){
if (load.get(j) > 3){
load.set(j, load.get(j)-1); // 1 is subtracted
checkForLowerRange();
break;
}
}
}
First of all sorry for my bad English,i am working on Image Splitter app and it is completed,but now the requirement is that when the image is split(divide into pieces/chunks) then the every piece(chunk) of image block is 50*50 or 40*40,and the most important thing is that for example the original image size is 420*320(it is dynamic and i get the image from gallery),then after split(divide) the image into pieces(chunks) the image size will be still the same 420*320 as i mentioned above,and for example the image size is 420*320 and after split the image and divide every block size equivalent 50*50,then the remaining 20 size will be assign to the last or any block,so i have 2 issue:
Note: In my app i am getting the image into gallery then split the image and shuffle the image pieces(chunks), and then merge the image, and create a **canvas for drawing all those small(chunks) images .**
after splitting the 420*320 size of image,need the image block(chunk) size 50*50 or 40*40.
the remaining 20*20 block(chunk) assign to the last block or any of the other block.
This is the original image before splitting and it's dimension is 420*320:
and this is the image after splitting,the overall image dimension is same 420*320,but the piece(chunk) of image block size is 84*64,and i want to block size is 50*50 or 40*40 and overall image size will also be same 420*320,and the remaining size will be assign to the last block.
This is my Activity:
package com.example.imagesplitter;
import java.io.ByteArrayOutputStream;
import java.util.ArrayList;
import java.util.Collections;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.drawable.BitmapDrawable;
import android.net.Uri;
import android.os.Bundle;
import android.provider.MediaStore;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.Window;
import android.widget.Button;
import android.widget.ImageView;
//public class ImageActivity extends Activity implements OnClickListener {
public class ImageActivity extends Activity {
Button split_image;
Button btnGallery;
ImageView image;
Uri selectedImage;
private final int RESULT_LOAD_IMAGE = 1;
int chunkNumbers = 25;
ArrayList<Bitmap> chunkedImages;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.main);
image = (ImageView) findViewById(R.id.source_image);
alertDialogForCameraImage();
}
void pickImageFromGallery() {
Intent pickPhoto = new Intent(Intent.ACTION_PICK,
android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
// startActivityForResult(pickPhoto , 0);
startActivityForResult(pickPhoto, RESULT_LOAD_IMAGE);
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
switch(requestCode){
case RESULT_LOAD_IMAGE:
if(resultCode==Activity.RESULT_OK) {
// takenPictureData = handleResultFromChooser(data);
selectedImage = data.getData();
String[] filePathColumn = { MediaStore.Images.Media.DATA };
Cursor cursor = getContentResolver().query(selectedImage,
filePathColumn, null, null, null);
cursor.moveToFirst();
int columnIndex = cursor.getColumnIndex(filePathColumn[0]);
String picturePath = cursor.getString(columnIndex);
cursor.close();
// ImageView imageView = (ImageView) findViewById(R.id.imgView);
image.setImageBitmap(BitmapFactory.decodeFile(picturePath));
// Function of split the image(divide the image into pieces)
splitImage(image, chunkNumbers);
}
break;
}
//And show the result in the image view when take picture from camera.
}
public void alertDialogForCameraImage() {
AlertDialog.Builder adb = new AlertDialog.Builder(ImageActivity.this);
adb.setTitle("Pick Image From Gallery: ");
adb.setNegativeButton("Gallery", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
pickImageFromGallery();
} });
adb.show();
}
/**
* Splits the source image and show them all into a grid in a new activity
*
* #param image The source image to split
* #param chunkNumbers The target number of small image chunks to be formed from the source image
*/
private void splitImage(ImageView image, int chunkNumbers) {
//For the number of rows and columns of the grid to be displayed
int rows,cols;
//For height and width of the small image chunks
int chunkHeight,chunkWidth;
//To store all the small image chunks in bitmap format in this list
chunkedImages = new ArrayList<Bitmap>(chunkNumbers);
//Getting the scaled bitmap of the source image
BitmapDrawable drawable = (BitmapDrawable) image.getDrawable();
Bitmap bitmap = drawable.getBitmap();
/*ByteArrayOutputStream stream = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.PNG, 100, stream);*/
Bitmap scaledBitmap = Bitmap.createScaledBitmap(bitmap, bitmap.getWidth(), bitmap.getHeight(), true);
rows = cols = (int) Math.sqrt(chunkNumbers);
chunkHeight = bitmap.getHeight()/rows;
chunkWidth = bitmap.getWidth()/cols;
/*chunkHeight = 300/rows;
chunkWidth = 300/cols;*/
//xCoord and yCoord are the pixel positions of the image chunks
int yCoord = 0;
for(int x=0; x<rows; x++){
int xCoord = 0;
for(int y=0; y<cols; y++){
chunkedImages.add(Bitmap.createBitmap(scaledBitmap, xCoord, yCoord, chunkWidth, chunkHeight));
xCoord += chunkWidth;
}
yCoord += chunkHeight;
}
// Function of merge the chunks images(after image divided in pieces then i can call this function to combine and merge the image as one)
mergeImage(chunkedImages);
}
void mergeImage(ArrayList<Bitmap> imageChunks) {
Collections.shuffle(imageChunks);
//Get the width and height of the smaller chunks
int chunkWidth = imageChunks.get(0).getWidth();
int chunkHeight = imageChunks.get(0).getHeight();
//create a bitmap of a size which can hold the complete image after merging
Bitmap bitmap = Bitmap.createBitmap(chunkWidth * 5, chunkHeight * 5, Bitmap.Config.ARGB_4444);
//create a canvas for drawing all those small images
Canvas canvas = new Canvas(bitmap);
int count = 0;
for(int rows = 0; rows < 5; rows++){
for(int cols = 0; cols < 5; cols++){
canvas.drawBitmap(imageChunks.get(count), chunkWidth * cols, chunkHeight * rows, null);
count++;
}
}
/*
* The result image is shown in a new Activity
*/
Intent intent = new Intent(ImageActivity.this, MergedImage.class);
intent.putExtra("merged_image", bitmap);
startActivity(intent);
finish();
}
}
and this is my image split method:
private void splitImage(ImageView image, int chunkNumbers) {
//For the number of rows and columns of the grid to be displayed
int rows,cols;
//For height and width of the small image chunks
int chunkHeight,chunkWidth;
//To store all the small image chunks in bitmap format in this list
chunkedImages = new ArrayList<Bitmap>(chunkNumbers);
//Getting the scaled bitmap of the source image
BitmapDrawable drawable = (BitmapDrawable) image.getDrawable();
Bitmap bitmap = drawable.getBitmap();
/*ByteArrayOutputStream stream = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.PNG, 100, stream);*/
Bitmap scaledBitmap = Bitmap.createScaledBitmap(bitmap, bitmap.getWidth(), bitmap.getHeight(), true);
rows = cols = (int) Math.sqrt(chunkNumbers);
chunkHeight = bitmap.getHeight()/rows;
chunkWidth = bitmap.getWidth()/cols;
/*chunkHeight = 300/rows;
chunkWidth = 300/cols;*/
//xCoord and yCoord are the pixel positions of the image chunks
int yCoord = 0;
for(int x=0; x<rows; x++){
int xCoord = 0;
for(int y=0; y<cols; y++){
chunkedImages.add(Bitmap.createBitmap(scaledBitmap, xCoord, yCoord, chunkWidth, chunkHeight));
xCoord += chunkWidth;
}
yCoord += chunkHeight;
}
mergeImage(chunkedImages);
}
Any help will be highly appreciated Thanks alot in advance.
EDITED:
Updated:
This is the example image and i want it like this:
Updated:
i think it should be like this:
As I understand the task, if the original image size is 420x320 and block size is 50x50 we will have 7x5 50x50 chunks, 5 70x50 chunks (the last column), 7 50x70 chunks (the last row) and one 70x70 chunk (bottom-right corner).
Then after shuffling we need to put it all together. However the most likely there will be collisions if we just randomly merge chunks (red cross on the picture).
So in that case I determine randomly the position (X,Y) of big square chunk (70x70) and put all 70x50 chunks in the X column and all 50x70 chunks in the Y row.
There might be some other cases:
if the original image size is 200x180 then we will have 4x2 50x50 chunks and 4 50x80 chunks. Then we shuffle it and should put one higher chunk to one column to preserve original image size;
if the original image is 230x200 then we will have 3x4 50x50 chunks and 4 80x50 chunks. Then we should put one wider chunk to one row;
if the original image is 200x200 then your code works perfectly.
As we have chunks with different sizes merge becomes a little more complex - we determine each chunk coordinates depending on the previous chunks size.
package com.example.imagesplitter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Random;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Point;
import android.graphics.drawable.BitmapDrawable;
import android.net.Uri;
import android.os.Bundle;
import android.provider.MediaStore;
import android.view.Window;
import android.widget.Button;
import android.widget.ImageView;
public class MainActivity extends Activity {
Button split_image;
Button btnGallery;
ImageView sourceImage;
Uri selectedImage;
private final int RESULT_LOAD_IMAGE = 1;
int chunkSideLength = 50;
ArrayList<Bitmap> chunkedImage;
// Number of rows and columns in chunked image
int rows, cols;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.activity_main);
sourceImage = (ImageView) findViewById(R.id.source_image);
alertDialogForCameraImage();
}
void pickImageFromGallery() {
Intent pickPhoto = new Intent(Intent.ACTION_PICK,
android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
// startActivityForResult(pickPhoto , 0);
startActivityForResult(pickPhoto, RESULT_LOAD_IMAGE);
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
switch (requestCode) {
case RESULT_LOAD_IMAGE:
if (resultCode == Activity.RESULT_OK) {
// takenPictureData = handleResultFromChooser(data);
selectedImage = data.getData();
String[] filePathColumn = { MediaStore.Images.Media.DATA };
Cursor cursor = getContentResolver().query(selectedImage, filePathColumn, null,
null, null);
cursor.moveToFirst();
int columnIndex = cursor.getColumnIndex(filePathColumn[0]);
String picturePath = cursor.getString(columnIndex);
cursor.close();
// ImageView imageView = (ImageView) findViewById(R.id.imgView);
sourceImage.setImageBitmap(BitmapFactory.decodeFile(picturePath));
// Function of split the image(divide the image into pieces)
splitImage(sourceImage, chunkSideLength);
}
break;
}
// And show the result in the image view when take picture from camera.
}
public void alertDialogForCameraImage() {
AlertDialog.Builder adb = new AlertDialog.Builder(MainActivity.this);
adb.setTitle("Pick Image From Gallery: ");
adb.setNegativeButton("Gallery", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
pickImageFromGallery();
}
});
adb.show();
}
/**
* Splits the source image and show them all into a grid in a new activity
*
* #param image
* The source image to split
* #param chunkSideLength
* Image parts side length
*/
private void splitImage(ImageView image, int chunkSideLength) {
Random random = new Random(System.currentTimeMillis());
// height and weight of higher|wider chunks if they would be
int higherChunkSide, widerChunkSide;
// Getting the scaled bitmap of the source image
Bitmap bitmap = ((BitmapDrawable) image.getDrawable()).getBitmap();
rows = bitmap.getHeight() / chunkSideLength;
higherChunkSide = bitmap.getHeight() % chunkSideLength + chunkSideLength;
cols = bitmap.getWidth() / chunkSideLength;
widerChunkSide = bitmap.getWidth() % chunkSideLength + chunkSideLength;
// To store all the small image chunks in bitmap format in this list
chunkedImage = new ArrayList<Bitmap>(rows * cols);
if (higherChunkSide != chunkSideLength) {
if (widerChunkSide != chunkSideLength) {
// picture has both higher and wider chunks plus one big square chunk
ArrayList<Bitmap> widerChunks = new ArrayList<Bitmap>(rows - 1);
ArrayList<Bitmap> higherChunks = new ArrayList<Bitmap>(cols - 1);
Bitmap squareChunk;
int yCoord = 0;
for (int y = 0; y < rows - 1; ++y) {
int xCoord = 0;
for (int x = 0; x < cols - 1; ++x) {
chunkedImage.add(Bitmap.createBitmap(bitmap, xCoord, yCoord, chunkSideLength, chunkSideLength));
xCoord += chunkSideLength;
}
// add last chunk in a row to array of wider chunks
widerChunks.add(Bitmap.createBitmap(bitmap, xCoord, yCoord, widerChunkSide, chunkSideLength));
yCoord += chunkSideLength;
}
// add last row to array of higher chunks
int xCoord = 0;
for (int x = 0; x < cols - 1; ++x) {
higherChunks.add(Bitmap.createBitmap(bitmap, xCoord, yCoord, chunkSideLength, higherChunkSide));
xCoord += chunkSideLength;
}
//save bottom-right big square chunk
squareChunk = Bitmap.createBitmap(bitmap, xCoord, yCoord, widerChunkSide, higherChunkSide);
//shuffle arrays
Collections.shuffle(chunkedImage);
Collections.shuffle(higherChunks);
Collections.shuffle(widerChunks);
//determine random position of big square chunk
int bigChunkX = random.nextInt(cols);
int bigChunkY = random.nextInt(rows);
//add wider and higher chunks into resulting array of chunks
//all wider(higher) chunks should be in one column(row) to avoid collisions between chunks
//We must insert it row by row because they will displace each other from their columns otherwise
for (int y = 0; y < rows - 1; ++y) {
chunkedImage.add(cols * y + bigChunkX, widerChunks.get(y));
}
//And then we insert the whole row of higher chunks
for (int x = 0; x < cols - 1; ++x) {
chunkedImage.add(bigChunkY * cols + x, higherChunks.get(x));
}
chunkedImage.add(bigChunkY * cols + bigChunkX, squareChunk);
} else {
// picture has only number of higher chunks
ArrayList<Bitmap> higherChunks = new ArrayList<Bitmap>(cols);
int yCoord = 0;
for (int y = 0; y < rows - 1; ++y) {
int xCoord = 0;
for (int x = 0; x < cols; ++x) {
chunkedImage.add(Bitmap.createBitmap(bitmap, xCoord, yCoord, chunkSideLength, chunkSideLength));
xCoord += chunkSideLength;
}
yCoord += chunkSideLength;
}
// add last row to array of higher chunks
int xCoord = 0;
for (int x = 0; x < cols; ++x) {
higherChunks.add(Bitmap.createBitmap(bitmap, xCoord, yCoord, chunkSideLength, higherChunkSide));
xCoord += chunkSideLength;
}
//shuffle arrays
Collections.shuffle(chunkedImage);
Collections.shuffle(higherChunks);
//add higher chunks into resulting array of chunks
//Each higher chunk should be in his own column to preserve original image size
//We must insert it row by row because they will displace each other from their columns otherwise
List<Point> higherChunksPositions = new ArrayList<Point>(cols);
for (int x = 0; x < cols; ++x) {
higherChunksPositions.add(new Point(x, random.nextInt(rows)));
}
//sort positions of higher chunks. THe upper-left elements should be first
Collections.sort(higherChunksPositions, new Comparator<Point>() {
#Override
public int compare(Point lhs, Point rhs) {
if (lhs.y != rhs.y) {
return lhs.y < rhs.y ? -1 : 1;
} else if (lhs.x != rhs.x) {
return lhs.x < rhs.x ? -1 : 1;
}
return 0;
}
});
for (int x = 0; x < cols; ++x) {
Point currentCoord = higherChunksPositions.get(x);
chunkedImage.add(currentCoord.y * cols + currentCoord.x, higherChunks.get(x));
}
}
} else {
if (widerChunkSide != chunkSideLength) {
// picture has only number of wider chunks
ArrayList<Bitmap> widerChunks = new ArrayList<Bitmap>(rows);
int yCoord = 0;
for (int y = 0; y < rows; ++y) {
int xCoord = 0;
for (int x = 0; x < cols - 1; ++x) {
chunkedImage.add(Bitmap.createBitmap(bitmap, xCoord, yCoord, chunkSideLength, chunkSideLength));
xCoord += chunkSideLength;
}
// add last chunk in a row to array of wider chunks
widerChunks.add(Bitmap.createBitmap(bitmap, xCoord, yCoord, widerChunkSide, chunkSideLength));
yCoord += chunkSideLength;
}
//shuffle arrays
Collections.shuffle(chunkedImage);
Collections.shuffle(widerChunks);
//add wider chunks into resulting array of chunks
//Each wider chunk should be in his own row to preserve original image size
for (int y = 0; y < rows; ++y) {
chunkedImage.add(cols * y + random.nextInt(cols), widerChunks.get(y));
}
} else {
// picture perfectly splits into square chunks
int yCoord = 0;
for (int y = 0; y < rows; ++y) {
int xCoord = 0;
for (int x = 0; x < cols; ++x) {
chunkedImage.add(Bitmap.createBitmap(bitmap, xCoord, yCoord, chunkSideLength, chunkSideLength));
xCoord += chunkSideLength;
}
yCoord += chunkSideLength;
}
Collections.shuffle(chunkedImage);
}
}
// Function of merge the chunks images(after image divided in pieces then i can call this function to combine
// and merge the image as one)
mergeImage(chunkedImage, bitmap.getWidth(), bitmap.getHeight());
}
void mergeImage(ArrayList<Bitmap> imageChunks, int width, int height) {
// create a bitmap of a size which can hold the complete image after merging
Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_4444);
// create a canvas for drawing all those small images
Canvas canvas = new Canvas(bitmap);
int count = 0;
Bitmap currentChunk = imageChunks.get(0);
//Array of previous row chunks bottom y coordinates
int[] yCoordinates = new int[cols];
Arrays.fill(yCoordinates, 0);
for (int y = 0; y < rows; ++y) {
int xCoord = 0;
for (int x = 0; x < cols; ++x) {
currentChunk = imageChunks.get(count);
canvas.drawBitmap(currentChunk, xCoord, yCoordinates[x], null);
xCoord += currentChunk.getWidth();
yCoordinates[x] += currentChunk.getHeight();
count++;
}
}
/*
* The result image is shown in a new Activity
*/
Intent intent = new Intent(MainActivity.this, MergedImage.class);
intent.putExtra("merged_image", bitmap);
startActivity(intent);
finish();
}
}
And sorry for my bad English :)
EDITED:
If you want to get the original image, you need to comment all shufflings and place big square chunk in its old place: in the bottom-right corner
//shuffle arrays
/* Collections.shuffle(chunkedImage);
Collections.shuffle(higherChunks);
Collections.shuffle(widerChunks);
*/
//determine random position of big square chunk
int bigChunkX = cols - 1;
int bigChunkY = rows - 1;
And this is only true if both image width and height are not divisible by chunkSideLength.
In other cases you should also comment shufflings and put higher/wider chunks in its old place. The full code of splitImage function with disabled shufflings is below
private void splitImage(ImageView image, int chunkSideLength) {
Random random = new Random(System.currentTimeMillis());
// height and weight of higher|wider chunks if they would be
int higherChunkSide, widerChunkSide;
// Getting the scaled bitmap of the source image
Bitmap bitmap = ((BitmapDrawable) image.getDrawable()).getBitmap();
rows = bitmap.getHeight() / chunkSideLength;
higherChunkSide = bitmap.getHeight() % chunkSideLength + chunkSideLength;
cols = bitmap.getWidth() / chunkSideLength;
widerChunkSide = bitmap.getWidth() % chunkSideLength + chunkSideLength;
// To store all the small image chunks in bitmap format in this list
chunkedImage = new ArrayList<Bitmap>(rows * cols);
if (higherChunkSide != chunkSideLength) {
if (widerChunkSide != chunkSideLength) {
// picture has both higher and wider chunks plus one big square chunk
ArrayList<Bitmap> widerChunks = new ArrayList<Bitmap>(rows - 1);
ArrayList<Bitmap> higherChunks = new ArrayList<Bitmap>(cols - 1);
Bitmap squareChunk;
int yCoord = 0;
for (int y = 0; y < rows - 1; ++y) {
int xCoord = 0;
for (int x = 0; x < cols - 1; ++x) {
chunkedImage.add(Bitmap.createBitmap(bitmap, xCoord, yCoord, chunkSideLength, chunkSideLength));
xCoord += chunkSideLength;
}
// add last chunk in a row to array of wider chunks
widerChunks.add(Bitmap.createBitmap(bitmap, xCoord, yCoord, widerChunkSide, chunkSideLength));
yCoord += chunkSideLength;
}
// add last row to array of higher chunks
int xCoord = 0;
for (int x = 0; x < cols - 1; ++x) {
higherChunks.add(Bitmap.createBitmap(bitmap, xCoord, yCoord, chunkSideLength, higherChunkSide));
xCoord += chunkSideLength;
}
//save bottom-right big square chunk
squareChunk = Bitmap.createBitmap(bitmap, xCoord, yCoord, widerChunkSide, higherChunkSide);
//shuffle arrays
/* Collections.shuffle(chunkedImage);
Collections.shuffle(higherChunks);
Collections.shuffle(widerChunks);
*/
//determine random position of big square chunk
int bigChunkX = cols - 1;
int bigChunkY = rows - 1;
//add wider and higher chunks into resulting array of chunks
//all wider(higher) chunks should be in one column(row) to avoid collisions between chunks
//We must insert it row by row because they will displace each other from their columns otherwise
for (int y = 0; y < rows - 1; ++y) {
chunkedImage.add(cols * y + bigChunkX, widerChunks.get(y));
}
//And then we insert the whole row of higher chunks
for (int x = 0; x < cols - 1; ++x) {
chunkedImage.add(bigChunkY * cols + x, higherChunks.get(x));
}
chunkedImage.add(bigChunkY * cols + bigChunkX, squareChunk);
} else {
// picture has only number of higher chunks
ArrayList<Bitmap> higherChunks = new ArrayList<Bitmap>(cols);
int yCoord = 0;
for (int y = 0; y < rows - 1; ++y) {
int xCoord = 0;
for (int x = 0; x < cols; ++x) {
chunkedImage.add(Bitmap.createBitmap(bitmap, xCoord, yCoord, chunkSideLength, chunkSideLength));
xCoord += chunkSideLength;
}
yCoord += chunkSideLength;
}
// add last row to array of higher chunks
int xCoord = 0;
for (int x = 0; x < cols; ++x) {
higherChunks.add(Bitmap.createBitmap(bitmap, xCoord, yCoord, chunkSideLength, higherChunkSide));
xCoord += chunkSideLength;
}
//shuffle arrays
/* Collections.shuffle(chunkedImage);
Collections.shuffle(higherChunks);
*/
//add higher chunks into resulting array of chunks
//Each higher chunk should be in his own column to preserve original image size
//We must insert it row by row because they will displace each other from their columns otherwise
List<Point> higherChunksPositions = new ArrayList<Point>(cols);
for (int x = 0; x < cols; ++x) {
higherChunksPositions.add(new Point(x, rows - 1));
}
//sort positions of higher chunks. THe upper-left elements should be first
Collections.sort(higherChunksPositions, new Comparator<Point>() {
#Override
public int compare(Point lhs, Point rhs) {
if (lhs.y != rhs.y) {
return lhs.y < rhs.y ? -1 : 1;
} else if (lhs.x != rhs.x) {
return lhs.x < rhs.x ? -1 : 1;
}
return 0;
}
});
for (int x = 0; x < cols; ++x) {
Point currentCoord = higherChunksPositions.get(x);
chunkedImage.add(currentCoord.y * cols + currentCoord.x, higherChunks.get(x));
}
}
} else {
if (widerChunkSide != chunkSideLength) {
// picture has only number of wider chunks
ArrayList<Bitmap> widerChunks = new ArrayList<Bitmap>(rows);
int yCoord = 0;
for (int y = 0; y < rows; ++y) {
int xCoord = 0;
for (int x = 0; x < cols - 1; ++x) {
chunkedImage.add(Bitmap.createBitmap(bitmap, xCoord, yCoord, chunkSideLength, chunkSideLength));
xCoord += chunkSideLength;
}
// add last chunk in a row to array of wider chunks
widerChunks.add(Bitmap.createBitmap(bitmap, xCoord, yCoord, widerChunkSide, chunkSideLength));
yCoord += chunkSideLength;
}
//shuffle arrays
/* Collections.shuffle(chunkedImage);
Collections.shuffle(widerChunks);
*/
//add wider chunks into resulting array of chunks
//Each wider chunk should be in his own row to preserve original image size
for (int y = 0; y < rows; ++y) {
chunkedImage.add(cols * y + cols - 1, widerChunks.get(y));
}
} else {
// picture perfectly splits into square chunks
int yCoord = 0;
for (int y = 0; y < rows; ++y) {
int xCoord = 0;
for (int x = 0; x < cols; ++x) {
chunkedImage.add(Bitmap.createBitmap(bitmap, xCoord, yCoord, chunkSideLength, chunkSideLength));
xCoord += chunkSideLength;
}
yCoord += chunkSideLength;
}
/* Collections.shuffle(chunkedImage);
*/ }
}
// Function of merge the chunks images(after image divided in pieces then i can call this function to combine
// and merge the image as one)
mergeImage(chunkedImage, bitmap.getWidth(), bitmap.getHeight());
}
I've divide my screen up into rects, but I'm using a a for loop so I'm not storing the rects there getting remade each time. How would I store them in like an array?
public void drawGrid() {
//android.os.Debug.waitForDebugger();
int height,width;
int column,row;
int maxColumn,maxRow;
maxColumn = 4;
maxRow = 4;
column = 0;
row = 0;
height = c.getHeight()/maxRow;
width = c.getWidth()/maxColumn;
Paint pg = new Paint();
Rect[] test[];
for(int i = 0;i < 5; i++) {
int srcX = column * width;
int srcY = row * height;
Rect src =new Rect(srcX,srcY,srcX + width, srcY +height);
pg.setColor(Color.WHITE);
pg.setStyle(Paint.Style.STROKE);
pg.setStrokeWidth(5);
c.drawRect(src, pg);
if (column == maxColumn && row == maxRow){
i = 5;
} else {i=0;}
if (column == maxColumn){
row = row + 1;
column = 0;
} else {column = column + 1;}
}
}
Allocate them in advance, so that you're not instantiating objects during a drawing operation. So whenever you determine the number of rects that you'll need (i.e. if it's always the same, initialize them in the constructor). Something like this:
Rect[] rects = new Rect[rectCount];
for(int i = 0; i < rectCount; i++) rects[i] = new Rect();
Then, in your drawing loop, use:
rects[i].set(srcX, srcY, srcX + width, srcY + height);
You should avoid allocating objects during a draw operation whenever possible.
EDIT: For a 2D array:
Rect[][] rects = new Rect[rowCount][colCount];
for(int i = 0; i < rowCount; i++) {
for(int j = 0; j < colCount; j++) {
rects[i][j] = new Rect();
}
}
Then in the loop, it's the same thing:
rects[row][col].set(srcX, srcY, srcX + width, srcY + height);
Rect rectArray[] = new Rect[5];
Then inside the loop:
rectArray[i] = new Rect(srcX,srcY,srcX + width, srcY +height);
Are you always going to have a fixed number of Rectangles?
You might want to consider an Array List?
ArrayList<Rect> rects = new ArrayList<Rect>();
rects.add(new Rect(srcX,srcY,srcX + width, srcY +height));
You can do loads of useful stuff easily with these things, here are some examples:
http://javarevisited.blogspot.com.es/2011/05/example-of-arraylist-in-java-tutorial.html
I have this issue with the xlabels in aChartEngine when there is one value in an ArrayList. I generate my own XLabels for a line chart, but when there is one data array value, i get an unwanted TimeStamp on top of my generated XLabels.
my Code:
private XYMultipleSeriesDataset getDemoDataset() {
Calendar cal = Calendar.getInstance();
Date date = new Date();
date_value = new String[list.size()];
value_value = new String[list.size()];
for(int k = 0; k < list.size(); k++){
date_value[k] = list.get(k).get(DATE);
value_value[k] = list.get(k).get(VALUE);
}
TimeSeries series = new TimeSeries("Line Graph");
for(int j=0; j < date_value.length; j++) {
series.add(formatter.stringToDate(date_value[j]), Integer.parseInt());
}
XYMultipleSeriesDataset dataset = new XYMultipleSeriesDataset();
dataset.addSeries(series);
return dataset;
}
setChartSetting:
private void setChartSetting(XYMultipleSeriesRenderer renderer){
renderer.setXRoundedLabels(true);
renderer.setXTitle("DATES");
renderer.setYTitle(kpiname);
renderer.setApplyBackgroundColor(true);
renderer.setFitLegend(false);
renderer.setAxesColor(Color.DKGRAY);
renderer.setShowGrid(true);
renderer.setZoomEnabled(false);
renderer.setXLabels(0);
renderer.setYLabels(10);
renderer.setZoomEnabled(false, false);
renderer.setPanEnabled(false, false);
//String[] date_value = new String[list.size()];
//String[] value_value = new String[list.size()];
if(list.isEmpty() || list.size() == 0 || list == null ){
return;
}
if(name.equals(RECOVERED) || name.equals(CONVERSION)){
largest_size = (int)Double.parseDouble(value_value[0]);
}else{
if(!(value_value.length == 0)){
largest_size = Integer.parseInt(value_value[0]);
}else{
return;
}
}
//used to determine the maximum value for the y-axis
for(int x =0; x < value_value.length; x++){
if(Integer.parseInt(value_value[x]) > largest_size){
largest_size = Integer.parseInt(value_value[x]);
}
}
renderer.setYAxisMax((double)largest_size);
renderer.setYAxisMin(0);
int value_size = value_value.length;
int m = 0;
//int add = value_size/10;
int add = largest_size/10;
/*instance variables for setting the labels on the X-Axis based on weather the values in the array are
* more than 10 items or less*/
double d;
Long l;
Long l1;
double d1;
if(date_value.length <= 1){
int last = date_value.length;
int mod = 0;
//int add_mod = Math.round(last/10);
int add_mod = (int)Math.round((double)Math.round(last));
l = Long.valueOf(formatter.stringToDateReport(date_value[0]).getTime());
d = l.doubleValue();
/*tried this to see if i can remove the timestamp*/
//renderer.addXTextLabel(0.0, "");
//renderer.removeXTextLabel(0.0);
//renderer.clearXTextLabels();
renderer.addXTextLabel(d, date_value[0]);
}
else if(date_value.length < 10){
for(int i = 0; i < date_value.length; i++){
if(i >= date_value.length){
break;
}
l = Long.valueOf(formatter.stringToDateReport(date_value[i]).getTime());
d = l.doubleValue();
renderer.addXTextLabel(d, date_value[i]);
}
} else if(date_value.length >= 10){
int last = date_value.length;
//int last = 28;
//Log.d(TAG, "last is " + last);
int mod = 0;
//int add_mod = Math.round(last/10);
int add_mod = (int)Math.round((double)Math.round(last) /10); // do this to get the decimal value with a double and then round to get nearset whole with int
for(int i =0; i < date_value.length; i++){
if(mod >= date_value.length){
break;
}
l1 = Long.valueOf(formatter.stringToDateReport(date_value[mod]).getTime());
d1 = l1.doubleValue();
renderer.addXTextLabel(d1, date_value[mod]);
mod+=add_mod;
}
}
}
}
and then:
chartView = ChartFactory.getLineChartView(context, getDemoDataset(), setChartSettings(renderer));
When there are multiple values, it plots the graph well with my custom XLabels(format is MMM-yyyy), but when there is only one value in the ArrayList, it generates thats time stamp.
here is an image:
This was a bug, indeed. You can download a version including a fix for it feature here.
I have been killing myself trying to develop an algorithm to determine the positions of the cells in a grid by which row or column they are in.
For example, I have an 8x8 grid and I need to determine all of the positions of the cells in row 3.
The issue that I have is that, without alot of loops, I need to figure out a way to map the position clicked to the row and column that contain that cell.
Here is what I did to create an ArrayList of the cells:
public class GameBoard {
public ArrayList<Row> rows = new ArrayList<Row>();
public ArrayList<Column> columns = new ArrayList<Column>();
private int maxPositions;
public GameBoard(int rowCount, int colCount) {
this.maxPositions = (rowCount * colCount) - 1;
for(int x = 0;x < rowCount;x++){
Row row = new Row(x);
row.cells.addAll(this.getRowCells(x, colCount));
rows.add(row);
}
for(int x = 0;x < colCount;x++){
Column column = new Column(x);
column.cells.addAll(getColumnCells(x, colCount));
columns.add(column);
}
}
private ArrayList<Cell> getRowCells(int rowId, int colCount) {
ArrayList<Cell> row_cells = new ArrayList<Cell>();
int first_position = ((rowId * colCount) -1);
Cell cell = new Cell();
cell.id = first_position;
row_cells.add(cell);
int x = 1;
while(x < colCount) {
cell = new Cell();
cell.id = first_position + x;
row_cells.add(cell);
x++;
}
return row_cells;
}
private ArrayList<Cell> getColumnCells(int columnId, int rowCount) {
ArrayList<Cell> col_cells = new ArrayList<Cell>();
int first_position = columnId;
Cell cell = new Cell();
cell.id = first_position;
col_cells.add(cell);
int x = 1;
while(x < rowCount) {
cell = new Cell();
cell.id = rows.get(x).cells.get(columnId).id;
col_cells.add(cell);
x++;
}
return col_cells;
}
public Cell getColumnNextCell(int position, int columnId) {
Cell cell = null;
if ((position > -1) && (position <= maxPositions)) {
cell = columns.get(columnId).cells.get(position + 1);
}
return cell;
}
public Cell getColumnPreviousCell(int position, int columnId) {
Cell cell = null;
if ((position > 0) && (position <= maxPositions)) {
cell = columns.get(columnId).cells.get(position - 1);
}
return cell;
}
public Cell getRowNextCell(int position, int rowId) {
Cell cell = null;
if ((position > -1) && (position <= maxPositions)) {
cell = rows.get(rowId).cells.get(position + 1);
}
return cell;
}
public Cell getRowPreviousCell(int position, int rowId) {
Cell cell = null;
if ((position > 0) && (position <= maxPositions)) {
cell = rows.get(rowId).cells.get(position - 1);
}
return cell;
}
}
As you can see with the methods like getColumnNextCell() through getRowPreviousCell() the logic is a mess and I am stuck on how to determine the column and row of the clicked cell (as I explained). Any help would be greatly appreciated.
For clarification the Row and Column objects are identical. They look like this.
public class Column {
public int id;
public ArrayList<Cell> cells = new ArrayList<Cell>();
public Column(int idx) {
this.id = idx;
}
}
Can't you just use an array for the cells
int rows, cols;
Cell[][] cells;
public GameBoard(int rowCount, int colCount) {
this.maxPositions = (rowCount * colCount) - 1;
this.rows = rowCount;
this.cols = colCount;
this.cells = new Cell[rows];
for(int i=0; i < rows; i++) {
cells[i] = new Cell[cols];
for(int j = 0; j < cols; j++) {
cells[i][j] = new Cell();
// whatever else you need to do...
}
}
}
This way it would be easy to get the cell you want
Cell getCell(int position) {
return cells[position/rows][position%cols];
}
Why don't you use simple two dimensional array? If your grid is not resized after creation, there is no advantage of using ArrayList objects. So what about having your base class something like this:
public class GameBoard {
private Cell[][] cells;
private int maxPositions;
private int rows;
private int cols;
public GameBoard(int rowCount, int colCount) {
this.rows = rowCount;
this.cols = colCount;
cells = new Cell[rowCount][colCount];
for (int i = 0; i < rowCount; i++) {
for (int j = 0; j < colCount; j++) {
cells[i][j] = new Cell();
}
}
this.maxPositions = (rowCount * colCount) - 1;
}
...
}
Now you don't have row and column objects, just array of cells. Isn't those cells actually what you need or do those row and column arrays have another purpose? So I think you are trying to do simple thing with too difficult way.