Related
I implemented the algorithm from the answer in here Maze (recursive division) algorithm design.
but I ran into a problem that there isn't always a path from start(+) to finish(-)
like this image.
also there is another problem that the start(+) or finish(-) node will be surrounded by wall see start node (+)
but I think it's easy to fix.
remove the walls around that node [x-1][y], [x][y+1], [x+1][y] and [x][y-1].
I don't know if it's the right fix or not.
that's my maze class
class Maze {
private G: INode[][];
private rows: number;
private cols: number;
constructor(G: INode[][]) {
this.G = G.map((row) =>
row.map((node) => ({
...node,
isWall: false,
}))
);
this.rows = this.G.length;
this.cols = this.G[0].length;
// border walls
for (let i = 0; i < this.rows; i++) {
this.G[i][0].isWall = true;
this.G[i][this.cols - 1].isWall = true;
}
for (let i = 0; i < this.cols; i++) {
this.G[0][i].isWall = true;
this.G[this.rows - 1][i].isWall = true;
}
}
private rand(min: number, max: number) {
return Math.floor(Math.random() * (max - min + 1) + min);
}
private isNodeStartOrFinish(row: number, col: number) {
return this.G[row][col].isStart || this.G[row][col].isFinish;
}
// call perfectMaze to get the generate the maze
public perfectMaze() {
this.divide(true, 1, this.cols - 2, 1, this.rows - 2);
}
private divide(
h: boolean,
minX: number,
maxX: number,
minY: number,
maxY: number
) {
if (h) {
if (maxX - minX < 2) return;
const y = Math.floor(this.rand(minY, maxY) / 2) * 2;
this.addHWall(minX, maxX, y);
this.divide(!h, minX, maxX, minY, y - 1);
this.divide(!h, minX, maxX, y + 1, maxY);
} else {
if (maxY - minY < 2) return;
const x = Math.floor(this.rand(minX, maxX) / 2) * 2;
this.addVWall(minY, maxY, x);
this.divide(!h, minX, x - 1, minY, maxY);
this.divide(!h, x + 1, maxX, minY, maxY);
}
}
private addHWall(minX: number, maxX: number, y: number) {
const hole = Math.floor(this.rand(minX, maxX) / 2) * 2 + 1;
for (let i = minX; i <= maxX; i++) {
if (i !== hole && !this.isNodeStartOrFinish(y, i)) {
this.G[y][i].isWall = true;
}
}
}
private addVWall(minY: number, maxY: number, x: number) {
const hole = Math.floor(this.rand(minY, maxY) / 2) * 2 + 1;
for (let i = minY; i <= maxY; i++) {
if (i !== hole && !this.isNodeStartOrFinish(i, x)) {
this.G[i][x].isWall = true;
}
}
}
public getMaze() {
return this.G;
}
}
okay i was stupid
i didn't remove the wall when i === hole
in the addHWall and addVWall methods
you must delete the wall if i === hole otherwise the wall will be added again
private addHWall(minX: number, maxX: number, y: number) {
const hole = Math.floor(this.rand(minX, maxX) / 2) * 2 + 1;
for (let i = minX; i <= maxX; i++) {
if (i === hole || this.isNodeStartOrFinish(y, i)) {
this.G[y][i].isWall = false;
} else {
this.G[y][i].isWall = true;
}
}
}
the same with addVWall
if (i === hole || this.isNodeStartOrFinish(i, x)) {
this.G[y][i].isWall = false;
} else {
this.G[i][x].isWall = true;
}
and i ended up deleting the walls around the start and finish node still don't know if it's the right solution or not
I have a game currently which has a player and some obstacles, I want to navigate this player with some commands, but the problem is that the command get executed but the rectangle does not get updated so I have to do some weird while logic with break and a global variable, because otherwise the player would jump. Is there a way to make the functions only count once and maybe loop with for and while normally? this is my code so far:
int border = 20;
int sqsize = 96;
int i = 0;
ArrayList<player> players = new ArrayList<player>();
ArrayList<obstacle> obstacles = new ArrayList<obstacle>();
void setup() {
size(1000, 1000);
players.add(new player(9, 0));
obstacles.add(new obstacle(4, 0));
obstacles.add(new obstacle(4, 1));
obstacles.add(new obstacle(4, 2));
obstacles.add(new obstacle(4, 3));
obstacles.add(new obstacle(4, 4));
obstacles.add(new obstacle(4, 5));
}
void draw() {
background(#767C7C);
for (int l = 0; l < 10; l++) {
for (int w = 0; w < 10; w++) {
fill(#F6F9EF);
stroke(#BABAB6);
strokeWeight(0.5);
rect(border + l*sqsize, border + w*sqsize, sqsize, sqsize);
}
}
players.get(0).draw();
for ( int i = obstacles.size()-1; i>= 0; i--) {
obstacles.get(i).draw();
}
for ( int i = obstacles.size()-1; i>= 0; i--) {
obstacles.get(i).ask();
}
while (i < 5) {
players.get(0).links();
players.get(0).unten();
break;
}
i++;
}
class player {
int x, y;
player(int ix, int iy) {
x = border + ix*sqsize;
y = border + iy*sqsize;
}
void draw() {
fill(255, 0, 0);
rect(x, y, sqsize, sqsize);
}
void right() {
if (x < 1000-2*sqsize) {
x = x + sqsize;
}
}
void left() {
if (x > 20) {
x = x - sqsize;
}
}
void up() {
if (y > 20+sqsize) {
y = y + sqsize;
}
}
void down() {
if (y < 1000-2*sqsize) {
y = y + sqsize;
}
}
void destroy() {
textSize(64);
text("Game Over", 500-2*sqsize, 500-sqsize/2);
noLoop();
}
int[] request() {
int[] pos = {x, y};
return pos;
}
}
class obstacle {
int x, y;
obstacle(int ix, int iy) {
x = border + ix*sqsize;
y = border + iy*sqsize;
}
void draw() {
fill(255, 0, 0);
rect(x, y, sqsize, sqsize);
}
void rechts() {
if (x < 1000-2*sqsize) {
x = x + sqsize;
}
}
void links() {
if (x > 20) {
x = x - sqsize;
}
}
void oben() {
if (y > 20+sqsize) {
y = y + sqsize;
}
}
void unten() {
if (y < 1000-2*sqsize) {
y = y + sqsize;
}
}
void ask() {
for ( int i = players.size()-1; i>= 0; i--) {
int[] check = players.get(i).request();
if (/*dist(check[0]+sqsize, check[1]+sqsize, x, y) == 0 || dist(check[0]-sqsize, check[1]-sqsize, x, y) == 0 ||*/ dist(check[0], check[1], x, y) == 0) {
players.get(i).destroy();
}
}
}
}
Is there a way also to detect which side of the player has touched the obstacle.
thank you very much (I’m a newbie).
This is how I solved my problem (I used cases):
int border = 20;
int sqsize = 96;
int n = 0;
boolean f = true;
long lastTime = 0;
int count = 0;
int[] list = new int[100];
ArrayList<Player> Players = new ArrayList<Player>();
ArrayList<Obstacle> Obstacles = new ArrayList<Obstacle>();
void setup() {
size(1000, 1000);
Players.add(new Player(9, 0));
Obstacles.add(new Obstacle(4, 0));
Obstacles.add(new Obstacle(4, 1));
Obstacles.add(new Obstacle(4, 2));
Obstacles.add(new Obstacle(2, 3));
Obstacles.add(new Obstacle(4, 4));
Obstacles.add(new Obstacle(4, 5));
lastTime = millis();
}
void draw() {
background(#767C7C);
for (int l = 0; l < 10; l++) {
for (int w = 0; w < 10; w++) {
fill(#F6F9EF);
stroke(#BABAB6);
strokeWeight(0.5);
rect(border + l*sqsize, border + w*sqsize, sqsize, sqsize);
}
}
/*Players.get(0).left();
Players.get(0).down();*/
if (f) {
count = 0;
list = new int[50];
player();
f = false;
}
Players.get(0).draw();
for ( int i = Obstacles.size()-1; i>= 0; i--) {
Obstacles.get(i).draw();
}
for ( int i = Obstacles.size()-1; i>= 0; i--) {
Obstacles.get(i).ask();
}
}
class Player {
int x, y;
int posCase = 0;
Player(int ix, int iy) {
x = border + ix*sqsize;
y = border + iy*sqsize;
}
void draw() {
while (n < count) {
if ( millis() - lastTime > 600 ) {
posCase = list[n];
println(n);
if (posCase == 5) {
noLoop();
}
switch(posCase) {
case 1 :
if (x < 1000-2*sqsize) {
x = x + sqsize;
}
break;
case 2 :
if (x > 20) {
x = x - sqsize;
}
break;
case 3 :
if (y > 20+sqsize) {
y = y + sqsize;
}
break;
case 4 :
if (y < 1000-2*sqsize) {
y = y + sqsize;
}
break;
}
n++;
if ( n == count) {
println("yes");
f = true;
}
lastTime = millis();
}
break;
}
fill(255, 0, 0);
rect(x, y, sqsize, sqsize);
}
void right() {
list[count] = 1;
count++;
/*f (x < 1000-2*sqsize) {
x = x + sqsize;
redraw();
}*/
}
void left() {
list[count] = 2;
count++;
/*if (x > 20) {
x = x - sqsize;
redraw();
}*/
}
void up() {
list[count] = 3;
count++;
/*if (y > 20+sqsize) {
y = y + sqsize;
redraw();
}*/
}
void down() {
list[count] = 4;
count++;
/*if (y < 1000-2*sqsize) {
y = y + sqsize;
redraw();*/
}
void ende() {
list[count] = 5;
count++;
}
void destroy() {
textSize(64);
text("Game Over", 500-2*sqsize, 500-sqsize/2);
noLoop();
}
int[] request() {
int[] pos = {x, y};
return pos;
}
}
class Obstacle {
int x, y;
int posCase = 0;
Obstacle(int ix, int iy) {
x = border + ix*sqsize;
y = border + iy*sqsize;
}
void draw() {
while (n < count) {
if ( millis() - lastTime > 600 ) {
posCase = list[n];
println(n);
if (posCase == 5) {
noLoop();
}
switch(posCase) {
case 1 :
if (x < 1000-2*sqsize) {
x = x + sqsize;
}
break;
case 2 :
if (x > 20) {
x = x - sqsize;
}
break;
case 3 :
if (y > 20+sqsize) {
y = y + sqsize;
}
break;
case 4 :
if (y < 1000-2*sqsize) {
y = y + sqsize;
}
break;
}
n++;
if ( n == count) {
println("yes");
f = true;
}
lastTime = millis();
}
break;
}
fill(255, 0, 0);
rect(x, y, sqsize, sqsize);
}
void right() {
list[count] = 1;
count++;
/*f (x < 1000-2*sqsize) {
x = x + sqsize;
redraw();
}*/
}
void left() {
list[count] = 2;
count++;
/*if (x > 20) {
x = x - sqsize;
redraw();
}*/
}
void up() {
list[count] = 3;
count++;
/*if (y > 20+sqsize) {
y = y + sqsize;
redraw();
}*/
}
void down() {
list[count] = 4;
count++;
/*if (y < 1000-2*sqsize) {
y = y + sqsize;
redraw();*/
}
void ende() {
list[count] = 5;
count++;
}
void ask() {
for ( int i = Players.size()-1; i>= 0; i--) {
int[] check = Players.get(i).request();
if ( dist(check[0], check[1], x, y) == 0) {
Players.get(i).destroy();
}
}
}
}
I've added a background image to my processing file which works fine when I run it in Processing locally, however, I'm receiving this error in console when I host the file:
Uncaught Error using image in background(): PImage not loaded.
I can't find anywhere why this may be happening. Please see my code below:
Particle p = new Particle();
final int LIGHT_FORCE_RATIO = 70; final int LIGHT_DISTANCE= 70 * 50; final int BORDER = 100; float baseRed, baseGreen, baseBlue; float baseRedAdd, baseGreenAdd, baseBlueAdd; final float RED_ADD =
3.2; final float GREEN_ADD = 1.7; final float BLUE_ADD = 4.3; float boxX, boxY; float widthSize = width;
int rectWidth = 915; int rectHeight = 197;
PImage img;
void setup() { img = loadImage("https://s3.amazonaws.com/zcom-media/sites/a0iE000000QK9yZIAT/media/mediamanager/bannerbg.jpg");
background(img); size(1840, 400); // surface.setResizable(true); noCursor(); //img = loadImage("flowtoy.jpg"); baseRed = 0; baseRedAdd = RED_ADD;
baseGreen = 0; baseGreenAdd = GREEN_ADD;
baseBlue = 0; baseBlueAdd = BLUE_ADD;
boxX = width/2; boxY = height/2;
img.loadPixels(); for (int i = 0; i < img.pixels.length; i++) { img.pixels[i] = color(0, 90, 102); } img.updatePixels(); }
void draw() { //image(img, 400, 100, img.width/2, img.height/2); if (mouseX>boxX-rectWidth && mouseX<boxX+rectWidth &&
mouseY>boxY-rectHeight && mouseY<boxY+rectHeight) {
//saveFrame("output/LightDrawing_####.png");
baseRed += baseRedAdd;
baseGreen += baseGreenAdd;
baseBlue += baseBlueAdd;
colorOutCheck();
p.move(mouseX, mouseY);
int tRed = (int)baseRed;
int tGreen = (int)baseGreen;
int tBlue = (int)baseBlue;
tRed *= tRed;
tGreen *= tGreen;
tBlue *= tBlue;
loadPixels();
int left = max(0, p.x - BORDER);
int right = min(width, p.x + BORDER);
int top = max(0, p.y - BORDER);
int bottom = min(height, p.y + BORDER);
for (int y = top; y < bottom; y++) {
for (int x = left; x < right; x++) {
int pixelIndex = x + y * width;
int r = pixels[pixelIndex] >>16 & 0xFF;
int g = pixels[pixelIndex] >> 8 & 0xFF;
int b = pixels[pixelIndex] & 0xFF;
int dx = x - p.x;
int dy = y - p.y;
int distance = (dx *dx ) + (dy* dy);
if (distance < LIGHT_DISTANCE) {
int fixFistance = distance * LIGHT_FORCE_RATIO;
if (fixFistance == 0) {
fixFistance = 1;
}
r = r + tRed / fixFistance;
g = g + tGreen / fixFistance;
b = b + tBlue / fixFistance;
}
pixels[x + y * width] = color(r, g, b);
}
}
updatePixels(); } else {
setup(); }
//updatePixels(); }
void colorOutCheck() { if (baseRed < 10) {
baseRed = 10;
baseRedAdd *= -1; } else if (baseRed > 255) {
baseRed = 255;
baseRedAdd *= -1; }
if (baseGreen < 10) {
baseGreen = 10;
baseGreenAdd *= -1; } else if (baseGreen > 255) {
baseGreen = 255;
baseGreenAdd *= -1; }
if (baseBlue < 10) {
baseBlue = 10;
baseBlueAdd *= -1; } else if (baseBlue > 255) {
baseBlue = 255;
baseBlueAdd *= -1; } }
void mousePressed() { setup(); }
class Particle { int x, y; float vx, vy; //float slowLevel;
Particle() {
x = (int)3;
y = (int)2; // slowLevel = random(100) + 1; }
void move(float targetX, float targetY) {
vx = (targetX - x) ;
vy = (targetY - y) ;
x = (int)(x + vx);
y = (int)(y + vy); } }
Can anybody explain why this may be happening? It's much appreciated, thank you.
I assume by 'hosting the file' you mean running the sketch at www.openprocessing.org.
There are two problem with your code:
Using background() inside setup. This will not work, you will get the error you mentioned. You can try moving that to draw().
Using an image which is hosted in another server. You should host your own images.
A workaround to problem 2 is to store the image as a base64 encoded string.
String uriBase64 = "data:image/jpeg;base64,/9j/4AAQSkZJRgA";
img = loadImage(uriBase64);
Full example here: https://www.openprocessing.org/sketch/511424
Can someone please help me with what I'm doing wrong here. I'm completely new to programming, and am currently learning p5js at university. I'm trying to create 'cells' floating around in space, and when they hit each other they combine together. It works for a minute but then I get an error
"Uncaught TypeError: Cannot read property 'eats' of undefined (sketch: line 76)"
This is my code:
function Cell(x, y, r) {
this.x = x;
this.y = y;
this.r = r;
this.speedx = random(-1, 1);
this.speedy = random(-1, 1);
this.width2 = 0.5;
this.col = color(255);
this.show = function() {
fill(this.col);
ellipse(this.x, this.y, this.r * 2);
}
this.move = function() {
this.x = this.x + this.speedx;
this.y = this.y + this.speedy;
}
this.bounce = function() {
if (this.x > width || this.x < 0) {
this.speedx = -this.speedx;
}
if (this.y > height || this.y < 0) {
this.speedy = -this.speedy;
}
}
// this.changeColor = function (){
//this.col = color(random(255), random (255), random(255));
//}
this.eats = function(other) {
var d = dist(this.x, this.y, other.x, other.y);
if (d < this.r + other.r) {
var sum = PI * this.r * this.r + PI * other.r * other.r;
this.r = sqrt(sum / PI);
//this.r += other.r;
return true;
} else {
return false;
}
}
// this.intersects = function(other){
// var d= dist(this.x, this.y, other.x, other.y);
//if (d < this.r + other.r) {
//var sum = PI * this.r * this.r + PI * other.r * other.r;
//this.r = sqrt(sum / PI);
//this.r += other.r;
//return true;
//} else {
//return false;
//}
//}
}
var cells = [];
function setup() {
createCanvas(600, 600);
for (var i = 0; i < 50; i++) {
cells[i] = new Cell(random(width), random(height), 10);
}
}
function draw() {
background(0);
for (var i = cells.length - 1; i >= 0; i--) {
cells[i].show();
cells[i].move();
cells[i].bounce();
for (var j = cells.length - 1; j >= 0; j--) {
if (j != i && cells[i].eats(cells[j])) {
// cells[i].changeColor();
// cells[j].changeColor();
cells.splice(j, 1);
}
}
}
}
You are removing cells from cells array using cells.splice(j, 1);. So when it checks for that on next loop, its throwing error.
My question is most similar to:
Android 4.3 ImageView ScaleType.MATRIX
but also echos:
android zoom image using matrix
However, using the solutions to those answers has solved my problem.
I am using a modified version of Mike Ortiz's TouchImageView to allow for both double tapping and the regular scale gesture to zoom my ImageView. For Android 4.2.2 and lower, commenting out the "setScaleType(ScaleType.MATRIX)" was just fine, the image was centered in the ImageView, and you could zoom in and out at will. Uncommenting, though, would cause the image to be sized incorrectly for the ImageView. All this was just fine, as I just left that line commented, and everything worked.
As of Android 4.3, however, you can't zoom without setScaleType(ScaleType.MATRIX). So I've had to uncomment that line, but the old problem I never solved is back.
So, first and foremost, why do my calculations fail to result in the correct image/ImageView ratio when all I'm doing is setting the ScaleType? Second, why would it zoom just fine on 4.2.2 without setting the scale type, but on 4.3, it won't? And finally, could someone give me some resources to learn more about what ScaleType.MATRIX really does? I've read through some of the sources, and done some googling, but don't totally grasp it.
Thank you in advance, and code below.
public class TouchImageView extends ImageView {
Matrix matrix = new Matrix();
// We can be in one of these 3 states
static final int NONE = 0;
static final int DRAG = 1;
static final int ZOOM = 2;
int mode = NONE;
// Remember some things for zooming
PointF last = new PointF();
PointF start = new PointF();
float minScale = 1f;
float maxScale = 10f;
float[] floatArray;
float unusedWidth, unusedHeight;
float imageViewWidth, imageViewHeight;
float initialScale = 1f;
float right, bottom, origWidth, origHeight, imageWidth, imageHeight;
boolean zoomedInLastTime = false;
PointF zoomCenter;
ScaleGestureDetector mScaleDetector;
GestureDetector mDetector;
Context context;
public TouchImageView(Context context) {
super(context);
sharedConstructing(context);
}
public TouchImageView(Context context, AttributeSet attrs) {
super(context, attrs);
sharedConstructing(context);
}
private void sharedConstructing(Context context) {
super.setClickable(true);
this.context = context;
setScaleType(ScaleType.MATRIX);
//matrix = this.getImageMatrix();
mScaleDetector = new ScaleGestureDetector(context, new ScaleListener());
//this is an empty GestureDetector
mDetector = new GestureDetector(this.context, new GestureDetector.OnGestureListener() {
#Override
public boolean onDown(MotionEvent motionEvent) {
return false;
}
#Override
public void onShowPress(MotionEvent motionEvent) {
}
#Override
public boolean onSingleTapUp(MotionEvent motionEvent) {
return false;
}
#Override
public boolean onScroll(MotionEvent motionEvent, MotionEvent motionEvent2, float v, float v2) {
return false;
}
#Override
public void onLongPress(MotionEvent motionEvent) {
}
#Override
public boolean onFling(MotionEvent motionEvent, MotionEvent motionEvent2, float v, float v2) {
return false;
}
}, null, true);
mDetector.setOnDoubleTapListener(new GestureDetector.OnDoubleTapListener(){
#Override
public boolean onSingleTapConfirmed(MotionEvent motionEvent) {
return false;
}
#Override
public boolean onDoubleTap(MotionEvent motionEvent) {
Log.d("TouchImageView", "double tap heard");
PointF currentTapLocation = new PointF(motionEvent.getX(), motionEvent.getY());
if (!zoomedInLastTime){
(new ScaleListener()).scaleIt(3f,currentTapLocation.x,currentTapLocation.y);
zoomCenter = currentTapLocation;
zoomedInLastTime = true;
}else {
(new ScaleListener()).scaleIt(.33f, zoomCenter.x, zoomCenter.y);
zoomedInLastTime = false;
}
return true;
}
#Override
public boolean onDoubleTapEvent(MotionEvent motionEvent) {
return false;
}
});
matrix.setTranslate(1f, 1f);
floatArray = new float[9];
setImageMatrix(matrix);
setOnTouchListener(new DoubleTapPinchZoomListener());
}
#Override
public void setImageBitmap(Bitmap bm) {
super.setImageBitmap(bm);
if(bm != null) {
if (Build.VERSION.SDK_INT > 17){
imageWidth = bm.getWidth();
imageHeight = bm.getHeight();
} else {
imageWidth = 2*bm.getWidth();
imageHeight = 2*bm.getHeight();
}
}
}
public void setMaxZoom(float x)
{
maxScale = x;
}
private class ScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener {
#Override
public boolean onScaleBegin(ScaleGestureDetector detector) {
mode = ZOOM;
return true;
}
#Override
public boolean onScale(ScaleGestureDetector detector) {
float mScaleFactor = detector.getScaleFactor();
scaleIt(mScaleFactor, detector.getFocusX(), detector.getFocusY());
return true;
}
public void scaleIt(float mScaleFactor, float focusx, float focusy){
float origScale = initialScale;
initialScale *= mScaleFactor;
if (initialScale > maxScale) {
initialScale = maxScale;
mScaleFactor = maxScale / origScale;
} else if (initialScale < minScale) {
initialScale = minScale;
mScaleFactor = minScale / origScale;
}
right = imageViewWidth * initialScale - imageViewWidth - (2 * unusedWidth * initialScale);
bottom = imageViewHeight * initialScale - imageViewHeight - (2 * unusedHeight * initialScale);
if (origWidth * initialScale <= imageViewWidth || origHeight * initialScale <= imageViewHeight) {
matrix.postScale(mScaleFactor, mScaleFactor, imageViewWidth / 2, imageViewHeight / 2);
if (mScaleFactor < 1) {
matrix.getValues(floatArray);
float x = floatArray[Matrix.MTRANS_X];
float y = floatArray[Matrix.MTRANS_Y];
if (mScaleFactor < 1) {
if (Math.round(origWidth * initialScale) < imageViewWidth) {
if (y < -bottom)
matrix.postTranslate(0, -(y + bottom));
else if (y > 0)
matrix.postTranslate(0, -y);
} else {
if (x < -right)
matrix.postTranslate(-(x + right), 0);
else if (x > 0)
matrix.postTranslate(-x, 0);
}
}
}
} else {
matrix.postScale(mScaleFactor, mScaleFactor, focusx, focusy);
matrix.getValues(floatArray);
float x = floatArray[Matrix.MTRANS_X];
float y = floatArray[Matrix.MTRANS_Y];
if (mScaleFactor < 1) {
if (x < -right)
matrix.postTranslate(-(x + right), 0);
else if (x > 0)
matrix.postTranslate(-x, 0);
if (y < -bottom)
matrix.postTranslate(0, -(y + bottom));
else if (y > 0)
matrix.postTranslate(0, -y);
}
}
}
}
#Override
protected void onMeasure (int widthMeasureSpec, int heightMeasureSpec){
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
imageViewWidth = MeasureSpec.getSize(widthMeasureSpec);
imageViewHeight = MeasureSpec.getSize(heightMeasureSpec);
/*RectF drawableRect = new RectF(0, 0, imageWidth, imageHeight);
RectF viewRect = new RectF(0, 0, imageViewWidth, imageViewHeight);
//draw the image in the view
matrix.setRectToRect(drawableRect, viewRect, Matrix.ScaleToFit.CENTER);*/
//Fit to screen.
float scale;
float scaleX = (float) imageViewWidth / (float)(imageWidth);
float scaleY = (float) imageViewHeight / (float)(imageHeight);
scale = Math.min(scaleX, scaleY);
matrix.setScale(scale, scale);
setImageMatrix(matrix);
initialScale = 1f;
// Center the image
unusedHeight = (float) imageViewHeight - (scale * (float) imageHeight) ;
unusedWidth = (float) imageViewWidth - (scale * (float) imageWidth);
unusedHeight /= (float)2;
unusedWidth /= (float)2;
matrix.postTranslate(unusedWidth, unusedHeight);
origWidth = imageViewWidth - 2 * unusedWidth;
origHeight = imageViewHeight - 2 * unusedHeight;
right = imageViewWidth * initialScale - imageViewWidth - (2 * unusedWidth * initialScale);
bottom = imageViewHeight * initialScale - imageViewHeight - (2 * unusedHeight * initialScale);
setImageMatrix(matrix);
}
class DoubleTapPinchZoomListener implements OnTouchListener {
#Override
public boolean onTouch(View v, MotionEvent event) {
mScaleDetector.onTouchEvent(event);
mDetector.onTouchEvent(event);
matrix.getValues(floatArray);
float x = floatArray[Matrix.MTRANS_X];
float y = floatArray[Matrix.MTRANS_Y];
PointF curr = new PointF(event.getX(), event.getY());
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
last.set(event.getX(), event.getY());
start.set(last);
mode = DRAG;
break;
case MotionEvent.ACTION_MOVE:
if (mode == DRAG) {
float deltaX = curr.x - last.x;
float deltaY = curr.y - last.y;
float scaleWidth = Math.round(origWidth * initialScale);
float scaleHeight = Math.round(origHeight * initialScale);
if (scaleWidth < imageViewWidth) {
deltaX = 0;
if (y + deltaY > 0)
deltaY = -y;
else if (y + deltaY < -bottom)
deltaY = -(y + bottom);
} else if (scaleHeight < imageViewHeight) {
deltaY = 0;
if (x + deltaX > 0)
deltaX = -x;
else if (x + deltaX < -right)
deltaX = -(x + right);
} else {
if (x + deltaX > 0)
deltaX = -x;
else if (x + deltaX < -right)
deltaX = -(x + right);
if (y + deltaY > 0)
deltaY = -y;
else if (y + deltaY < -bottom)
deltaY = -(y + bottom);
}
matrix.postTranslate(deltaX, deltaY);
last.set(curr.x, curr.y);
}
break;
case MotionEvent.ACTION_POINTER_UP:
mode = NONE;
break;
}
setImageMatrix(matrix);
invalidate();
return true;
}
}
}
Turns out the issue had nothing to do with MATRIX scaling, though that does remain somewhat of a mystery to me. The problem was 'automagic' rescaling. I had placed my image in the 'drawable' folder, which Android scales automatically to 'best fit the screen size.' For more information on this, see here:
http://developer.android.com/guide/practices/screens_support.html#support
The solution was to put the image in drawable-nodpi. This tells Android NOT to rescale based on the screen size, and as a result, manipulating the scaling manually doesn't conflict with Android's own scaling.