Calculate position of an Image in Absolutelayout when zooming - android

I have a Page which contains an AbsoluteLayout with a PinchZoomContainer (like the one from microsoft docs). In this Container is an image that fills the entire screen. When the user tapes on the image, another image (a pin) is positioned at the tappostion. So far this works. My problem is, that i couldn't figure out, how to calculate the position of the added image (user tapped) when the user zooms in and out.
I want the added image to stay at the tapped position, no matter if the user zooms in or out.
When i put the image in a grid the calculation gets done automatically.
Is there a better way to achieve that? I've chosen AbsoluteLayout because i need to put the image at the tapped position.
The following code is used for zooming. Here I can't figure out how to do the calculation for the added image. The image gets added to the AbsoluteLayout on runtime.
Normal scale
Zoomed in
void OnPinchUpdated(object sender, PinchGestureUpdatedEventArgs e)
{
if (e.Status == GestureStatus.Started)
{
// Store the current scale factor applied to the wrapped user interface element,
// and zero the components for the center point of the translate transform.
startScale = Content.Scale;
Content.AnchorX = 0;
Content.AnchorY = 0;
startTransX = pin.TranslationX;
startTranxY = pin.TranslationY;
}
if (e.Status == GestureStatus.Running)
{
// Calculate the scale factor to be applied.
currentScale = currentScale + (e.Scale - 1) * startScale;
currentScale = Math.Max(1, currentScale);
// The ScaleOrigin is in relative coordinates to the wrapped user interface element,
// so get the X pixel coordinate.
double renderedX = Content.X + xOffset;
double deltaX = renderedX / Width;
double deltaWidth = Width / (Content.Width * startScale);
double originX = (e.ScaleOrigin.X - deltaX) * deltaWidth;
// The ScaleOrigin is in relative coordinates to the wrapped user interface element,
// so get the Y pixel coordinate.
double renderedY = Content.Y + yOffset;
double deltaY = renderedY / Height;
double deltaHeight = Height / (Content.Height * startScale);
double originY = (e.ScaleOrigin.Y - deltaY) * deltaHeight;
// Calculate the transformed element pixel coordinates.
double targetX = xOffset - (originX * Content.Width) * (currentScale - startScale);
double targetY = yOffset - (originY * Content.Height) * (currentScale - startScale);
// Apply translation based on the change in origin.
// needs to use Xamarin.Forms.Internals or Extension
Content.TranslationX = targetX.Clamp(-Content.Width * (currentScale - 1), 0);
Content.TranslationY = targetY.Clamp(-Content.Width * (currentScale - 1), 0);
x = Content.TranslationX;
y = Content.TranslationY;
// Apply scale factor
Content.Scale = currentScale;
}
if (e.Status == GestureStatus.Completed)
{
// Store the translation delta's of the wrapped user interface element.
xOffset = Content.TranslationX;
yOffset = Content.TranslationY;
x = Content.TranslationX;
y = Content.TranslationY;
}
}

Related

How to horizontal/Vertical scroll a panoramic image in Android?

I'm looking for to some way for make a scroll, or scan of a panoramic image in Android. With this I mean show a part of my image adjusting the height of the image (or width in vertical) and automatically moving slowly the view scrolling all the image. For example:
this image its so big to try to see it in a 16:9 device(with a bit of detail i mean), so i want to do something like:
Just show that part in the screen and move it slowly to the right till the end of the image. Achieving a "scroll" effect across the image.
I have been looking in the website and internet last days and I just found the library of PanoramicGL or some ways to watch 360ยบ images.
This Is For Scroll Click Here
You must use PanoramaClient (which is part of Google Play Services) to open PhotoSphere photos.
An example of how to do this can be found on this Android developer blog post:
// This listener will be called with information about the given panorama.
OnPanoramaInfoLoadedListener infoLoadedListener =
new OnPanoramaInfoLoadedListener() {
#Override
public void onPanoramaInfoLoaded(ConnectionResult result,
Intent viewerIntent) {
if (result.isSuccess()) {
// If the intent is not null, the image can be shown as a
// panorama.
if (viewerIntent != null) {
// Use the given intent to start the panorama viewer.
startActivity(viewerIntent);
}
}
// If viewerIntent is null, the image is not a viewable panorama.
}
};
// Create client instance and connect to it.
PanoramaClient client = ...
...
// Once connected to the client, initiate the asynchronous check on whether
//the image is a viewable panorama.
client.loadPanoramaInfo(infoLoadedListener, panoramaUri);
Thanks to kishu, I made my own method to animate a panoramic image dynamically depending if its in landscape or portrait mode.
You can ignore the orientation value of the method, I only use it to change the animation of the video from X to Y if I want to see the image in landscape.
public void animatePanorama(int orientation) {
int duration;
// The milisecons that we will use dinamically for the animation, been this is 1,31milisecons for pixel
float miliseconsPixel = 1.31f;
float imageWidth;
//Delta X and Y values for the animation
float deltaX = 0f;
float deltaY = 0f;
float aspectRatio;
//We get the drawable from the container to calcule his real Width and Height
final Drawable d = mImageContainer.getDrawable();
final int origWidth = d.getIntrinsicWidth();
final int origHeight = d.getIntrinsicHeight();
//With that we get the real aspect ratio and a duration
if (origWidth > origHeight) {
aspectRatio = (float) origWidth / (float) origHeight;
duration = (int) (miliseconsPixel * origWidth);
imageWidth = mImageContainer.getMeasuredHeight() * aspectRatio;
} else {
aspectRatio = (float) origHeight / (float) origWidth;
duration = (int) (miliseconsPixel * origHeight);
imageWidth = mImageContainer.getMeasuredWidth() * aspectRatio;
}
//Set if the animation will be horizontal(Portrait) or Vertical(landscape)
if (orientation == 0 || orientation == 180)
deltaX = imageWidth / 2f - mImageContainer.getMeasuredWidth() / 2;
else
deltaY = imageWidth / 2f - mImageContainer.getMeasuredHeight() / 2;
//New Animation
Animation animation = new TranslateAnimation(deltaX, -deltaX, deltaY, -deltaY);
//Add Duration
animation.setDuration(duration);
animation.setFillAfter(true);
//Add cycle for repeating mode
animation.setRepeatCount(-1);
animation.setRepeatMode(Animation.REVERSE);
mImageContainer.startAnimation(animation);
}

Afree chart : How to increase X axis values(gap or domain range) while zooming

Can anyone help me on below zooming!
While doing horizontal zoom, I would like to increase and display the gap or range.
Now the range is on attached link is 10,12,14,16... while zooming it should display as 10,11,12,13,...
How I can increase this domain range while zooming. Please guide me.
protected static int gapValue; //gap between two dates
private void zoom(PointF source, double startDistance, double endDistance) {
Plot plot = this.chart.getPlot();
PlotRenderingInfo info = this.info.getPlotInfo();
if (plot instanceof Zoomable) {
float scaleDistance = (float) (startDistance / endDistance);
//for maintaining the limit of zooming range horizontally
if (this.mScale * scaleDistance <= 1.0f
&& this.mScale * scaleDistance > 0.1f) {
this.mScale *= scaleDistance;
Zoomable z = (Zoomable) plot;
z.zoomDomainAxes(scaleDistance, info, source, false);
int sealValue = (int) (gapValue * this.mScale);
// gap shoud be greater than zero
if (sealValue == 0)
sealValue = 1;
// To re-render the graph dates in domain axis
((DateAxis) this.getChart().getXYPlot().getDomainAxis())
.setTickUnit(new DateTickUnit(DateTickUnitType.DAY,
sealValue, new SimpleDateFormat("MM/dd")));
}
}
// repaint
invalidate();

How to keep a circle inside another circle android view control

I am trying to create a pad-like view in android. I got a circle that follows user's gestures and I am using distance to keep the circle of going outside the main circle of the pad control.
My problem is I want the circle to keep following the gesture, but to stay inside of the main circle. I am using the formula for finding a point using angle and radius, but it does some funky stuff.
I am translating the canvas, so that the center of the main circle is at 0, 0.
Here is the code:
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.translate(this.mainRadius, this.mainRadius);
canvas.drawCircle(0, 0, this.mainRadius, this.debugPaint);
canvas.drawCircle(this.handleX, this.handleY, this.handleRadius, this.handlePaint);
}
private void translateHandle(MotionEvent event) {
int x = (int) (event.getX() - this.mainRadius);
int y = (int) (event.getY() - this.mainRadius);
double distance = distanceFromCenter(x, y);
if (distance <= this.maxDistance) {
this.handleX = x;
this.handleY = y;
} else {
float angle = (float) Math.toDegrees(Math.atan2(y, x));
if (angle < 0)
angle += 360;
this.handleX = (int) ((this.mainRadius - this.handleRadius) * Math.cos(angle));
this.handleY = (int) ((this.mainRadius - this.handleRadius) * Math.sin(angle));
}
//onTranslateHandle(distance);
}
And here is the funky stuff in a gif image:
I cannot verify this change into your code snippet but do hope it gives some idea how to proceed further anyway;
private void translateHandle(MotionEvent event) {
float x = event.getX() - this.mainRadius;
float y = event.getY() - this.mainRadius;
double distance = distanceFromCenter(x, y);
if (distance > this.maxDistance) {
// If distance is i.e 2.0 and maxDistance is 1.0 ==> adjust is 0.5
// which repositions x and y making distance 1.0 maintaining direction
double adjust = this.maxDistance / distance;
x = (float)(x * adjust);
y = (float)(y * adjust);
}
this.handleX = (int)x;
this.handleY = (int)y;
}
I can update the answer where needed if this does not give any useful results.

android opengl check visibility of a point with camera zoom

I m woring on an android opengl 1.1 2d game with a top view on a vehicule and a camera zoom relative to the vehicule speed. When the speed increases the camera zoom out to offer the player a best road visibility.
I have litte trouble finding the exact way to detect if a sprite is visible or not regarding his position and the current camera zoom.
Important precision, all of my game's objects are on the same z coord. I use 3d just for camera effect. (that's why I do not need frustrum complicated calculations)
here is a sample of my GLSurfaceView.Renderer class
public static float fov_degrees = 45f;
public static float fov_radians = fov_degrees / 180 * (float) Math.PI;
public static float aspect; //1.15572 on my device
public static float camZ; //927 on my device
#Override
public void onSurfaceChanged(GL10 gl, int x, int y) {
aspect = (float) x / (float) y;
camZ = y / 2 / (float) Math.tan(fov_radians / 2);
Camera.MINIDECAL = y / 4; // minimum cam zoom out (192 on my device)
if (x == 0) { // Prevent A Divide By Zero By
x = 1; // Making Height Equal One
}
gl.glViewport(0, 0, x, y); // Reset The Current Viewport
gl.glMatrixMode(GL10.GL_PROJECTION); // Select The Projection Matrix
gl.glLoadIdentity(); // Reset The Projection Matrix
// Calculate The Aspect Ratio Of The Window
GLU.gluPerspective(gl, fov_degrees, aspect , camZ / 10, camZ * 10);
GLU.gluLookAt(gl, 0, 0, camZ, 0, 0, 0, 0, 1, 0); // move camera back
gl.glMatrixMode(GL10.GL_MODELVIEW); // Select The Modelview Matrix
gl.glLoadIdentity(); // Reset The Modelview Matrix
when I draw any camera relative object I use this translation method :
gl.glTranslatef(position.x - camera.centerPosition.x , position.y -camera.centerPosition.y , - camera.zDecal);
Eveything is displayed fine, the problem comes from my physic thread when he checks if an object is visible or not:
public static boolean isElementVisible(Element element) {
xDelta = (float) ((camera.zDecal + GameRenderer.camZ) * GameRenderer.aspect * Math.atan(GameRenderer.fov_radians));
yDelta = (float) ((camera.zDecal + GameRenderer.camZ)* Math.atan(GameRenderer.fov_radians));
//(xDelta and yDelta are in reallity updated only ones a frame or when camera zoom change)
Camera camera = ObjectRegistry.INSTANCE.camera;
float xMin = camera.centerPosition.x - xDelta/2;
float xMax = camera.centerPosition.x + xDelta/2;
float yMin = camera.centerPosition.y - yDelta/2;
float yMax = camera.centerPosition.y + yDelta/2;
//xMin and yMin are supposed to be the lower bounds x and y of the visible plan
// same for yMax and xMax
// then i just check that my sprite is visible on this rectangle.
Vector2 phD = element.getDimToTestIfVisibleOnScreen();
int sizeXd2 = (int) phD.x / 2;
int sizeYd2 = (int) phD.y / 2;
return (element.position.x + sizeXd2 > xMin)
&& (element.position.x - sizeXd2 < xMax)
&& (element.position.y - sizeYd2 < yMax)
&& (element.position.y + sizeYd2 > yMin);
}
Unfortunately the object were disapearing too soon and appearing to late so i manuelly added some zoom out on the camera for test purpose.
I did some manual test and found that by adding approx 260 to the camera z index while calculating xDelta and yDelta it, was good.
So the line is now :
xDelta = (float) ((camera.zDecal + GameRenderer.camZ + 260) * GameRenderer.aspect * Math.atan(GameRenderer.fov_radians));
yDelta = (float) ((camera.zDecal + GameRenderer.camZ + 260)* Math.atan(GameRenderer.fov_radians));
Because it's a hack and the magic number may not work on every device I would like to understand what i missed. I guess there is something in that "260" magic number that comes from the fov or ration width/height and that could be set as a formula parameter for pixel perfect detection.
Any guess ?
My guess is that you should be using Math.tan(GameRenderer.fov_radians) instead of Math.atan(GameRenderer.fov_radians).
Reasoning:
If you used a camera with 90 degree fov, then xDelta and yDelta should be infinitely large, right? Since the camera would have to view the entire infinite plane.
tan(pi/2) is infinite (and negative infinity). atan(pi/2) is merely 1.00388...
tan(pi/4) is 1, compared to atan(pi/4) of 0.66577...

Shooting the Opposite Way? - AndEngine classic tutorial

Ok, this should be simple enough, but I'm tripping myself up on the math. Using AndEngine BTW>
I'm using some of the tutorials out there... hero on the left of the screen (landscape) shooting right. Everything works wonderfully. Now I'd like to have the hero on the right side of the screen shooting left. I'm going in circles and would great appreciate some help. Here is the code I'm using for left hero, shooting right.
/** shoots a projectile from the player's position along the touched area */
private void shootProjectile(final float pX, final float pY) {
int offX = (int) (pX - (hero.getX()));
int offY = (int) (pY - (hero.getY() + hero.getHeight()/2));
if (offX <= 0) return;
// position the projectile on the player and set up path
projectile = pPool.obtainPoolItem();
int realX = (int) (mCamera.getWidth() - (hero.getX() ) );
float ratio = (float) realX / (float) offX;
int realY = (int) ((offY * ratio));
float length = (float) Math.sqrt((realX * realX) + (realY * realY));
float velocity = 280.0f / .5f; // 480 pixels per (sec)f on screen
float realMoveDuration = length / velocity;
// defining a moveBymodifier from the projectile's position to the
// calculated one
//this code angles the projectile sprite
double PI = 3.14159265;
float dx = pX - hero.getX();
float dy = pY - hero.getY()-50;
double Radius = Math.atan2(dy,dx);
double Angle = Radius * 180 / PI;
projectile.setRotation((float)Angle); // sets the angle of the projectile
//Move modifier for projectile
MoveByModifier movMByod = new MoveByModifier(realMoveDuration, realX, realY);
final ParallelEntityModifier par = new ParallelEntityModifier(movMByod);
DelayModifier dMod = new DelayModifier(0.001f);
dMod.addModifierListener(new IModifierListener<IEntity>() {
#Override
public void onModifierStarted(IModifier<IEntity> arg0, IEntity arg1) {
}
#Override
public void onModifierFinished(IModifier<IEntity> arg0, IEntity arg1) {
// TODO Auto-generated method stub
shootingSound.play();
projectile.setVisible(true);
projectile.setPosition(hero.getX(), hero.getY() + hero.getHeight() / 2);
projectilesToBeAdded.add(projectile);
projectile.animate(50);
}
});
SequenceEntityModifier seq = new SequenceEntityModifier(dMod, par);
projectile.registerEntityModifier(seq);
projectile.setVisible(false);
mMainScene.attachChild(projectile, 1);
I've got the hero positioned fine on the right side. What do I need to do to get the projectile to move to the left correctly?
Thanks a ton for any help.
MWM
You shouldn't use DelayModifier the way you do. Instead create a PhysicsHandler for your sprites and then set velocity to the PhysicsHandler. Something like:
PhysicsHandler phys = new PhysicsHandler();
projectile.registerUpdateHandler(phys);
phys.setVelocityX(50);
and this will take care of moving your projectile. You can also set acceleration on the physics handler the same way. So if you set the initial velocity to point up and left and then set the acceleration pointing down, the projectile will first fly left and up and then gradually fall down. And you don't have to do any calculations yourself.
This code looks like the one from http://jimmaru.wordpress.com/2011/09/28/andengine-simple-android-game-tutorial/
if it is, try this:
private void shootProjectile(final float pX, final float pY) {
int side = 1;
int offX = (int) (pX - (hero.getX()));
int offY = (int) (pY - (hero.getY() + hero.getHeight()/2));
if (offX <= 0){
side=-1
}
// position the projectile on the player and set up path
projectile = pPool.obtainPoolItem();
int realX = (int) (mCamera.getWidth() - (hero.getX() ) ) * side;
....
I got the same problem with the code from link, with this change i could shoot fot both sides with a player in the middle of screen.

Categories

Resources