360 degrees landscape

AlpVir

Well-Known Member
Licensed User
Longtime User
To view a 360 degrees landscape (8000x600 pixels around) I thought it best to use the schema in the attached drawing.
Two identical images (color black) are loaded in 2 ImageView (color red).
A HorizzontalScrollView (color blue) embraces the two ImageView.
Smartphone screen (color green) show only a small part of HorizzontalScrollView.

Here's the code I used:

B4X:
HS.Initialize (LargImg * 2, "HS")
IV1.Initialize ("")
IV2.Initialize ("")
IV1.Gravity = Gravity.FILL
IV2.Gravity = Gravity.Fill
Activity.AddView (HS, 0, 0, 100% x, y 100%)
BMP.Initialize (File.DirRootExternal, Main.FileName)
IV1.Bitmap = BMP
IV2.Bitmap = BMP
HS.Panel.AddView (IV1, 0.0, LargImg, 600)
HS.Panel.AddView (IV2, LargImg, 0, LargImg, 600)

But I believe that this system does not eat up many resources and above all allows seamless navigation. There are shots in the management of the scroll, it is not smooth.

B4X:
Sub HS_ScrollChanged (Position As Int)
   '--- Scroll right
   If Position> * 1.5 Then LargImg
       HS.ScrollPosition = LargImg / 2
   else
     '--- Left scroll
     If Position <LargImg / 2 Then
        HS.ScrollPosition LargImg * 1.5 =
     end If
   end If
end Sub

Does anyone have any suggestions for improving the situation?
Thanks in advance.
 

Attachments

  • Schema.jpg
    Schema.jpg
    33.4 KB · Views: 592

warwound

Expert
Licensed User
Longtime User
Hi again AlpVir.

My new OSMDroid (MapView) library can be used as a panorama viewer!

Cut your panoramic image into tiles and get the MapView to display those tiles as a custom tile layer and you have an instant panorama viewer.

The released version of OSMDroid has no methods to implement a custom tile layer - i'm considering how best to add the required methods.

This code WILL NOT COMPILE with the released version of OSMDroid but shows all the code that is required:

B4X:
Sub Process_Globals
   '   create a process global for each map state to be saved and restored on orientation change
   
   '   use a GeoPoint object to save the map center
   Dim MapCenter As GeoPoint
   
   '   an Int is all that's required to save the map zoom level
   Dim ZoomLevel As Int
End Sub

Sub Globals
   Dim MapView1 As MapView
End Sub

Sub Activity_Create(FirstTime As Boolean)
   If FirstTime Then
      Dim OfflineTileCacheFilename, TileCacheDir As String
      OfflineTileCacheFilename="panorama.zip"
      TileCacheDir=File.DirRootExternal&"/osmdroid"
      '   check if the offline tile cache has already been copied to the OSMDroid cache folder
      If File.Exists(TileCacheDir, OfflineTileCacheFilename)=False Then
         '   copy the offline tile cache to the OSMDroid cache folder
         File.MakeDir(File.DirRootExternal, "osmdroid")
         File.Copy(File.DirAssets, OfflineTileCacheFilename, TileCacheDir, OfflineTileCacheFilename)
      End If
   End If
   MapView1.Initialize("")
   MapView1.SetDataConnectionEnabled(False)
   MapView1.SetMultiTouchEnabled(True)
   MapView1.SetTileSource("Panorama")
   MapView1.SetZoomEnabled(True)
   Activity.AddView(MapView1, 0, 0, 100%x, 100%y)
   
   If FirstTime Then
      '   set the default initial map center and zoom level
      MapCenter.Initialize(0, 0)
      ZoomLevel=3
   End If
   
   MapView1.Zoom=ZoomLevel
   MapView1.SetCenter3(MapCenter)
End Sub

Sub Activity_Resume
End Sub

Sub Activity_Pause (UserClosed As Boolean)
   '   save the current map zoom level and center
   MapCenter=MapView1.GetCenter
   ZoomLevel=MapView1.Zoom
End Sub

panaorama.zip is an archive of (panorama) tiles cut and named according to the slippy tile naming convention.
The tiles cover zoom levels 0 to 5, i could have created tiles for zoom level 6 but that would have made the compiled app much larger.

If you'd like to see it in action you can get the compiled APK from here: http://code.martinpearman.co.uk/deleteme/B4APanoramaViewer.zip

You mentioned before that you'd like to annotate parts of your panoramas with labels - you can do all of that with OSMDroid (once i implement the custom tiles methods).

Your comments would be welcome.

Martin.
 
Upvote 0

AlpVir

Well-Known Member
Licensed User
Longtime User
The problems are two:
A) SCROLL NOT GOOD
I confirm that the scroll is not uniform.
I try to explain (I hope that the Google translator does it :)).
The scroll can be of 2 types:
1) with a finger and moving it down, still holding it down. In this case, the scroll is almost always good because you can better capture the event
HS_ScrollChanged. The scroll has a jolt when it intervenes
B4X:
HS.ScrollPosition = LargImg / 2
which reports on the left half of the screen the right side of the first image (ImageViewer1) and on the right half of the screen on the left side of the second image (ImageViewer2).

2) pointing the finger and moving it down abruptly, then lifting the finger. In this case the image scrolls quickly and then gradually slows to a stop.
The event HS_ScrollChanged does not have the opportunity to follow in real time the movement and therefore the quality of the scroll is bad.
The scroll has the same jolt as before, but worse.

I modified the code
B4X:
If Position > LargImg*1.5 Then 
HS.ScrollPosition = LargImg / 2
end If
and by the time I manage ONLY the scroll to the right.
At the left, then I think about it.

I do not think that the image size (400 KB / 1 MB) influences.

B) CONSUMPTION OF RESOURCES
You could use a single ImageView to divert the image to a "circular buffer".
There are several Java applets that run optimally at 360 degrees views.
Here is a code snippet
B4X:
      g.drawImage(pano, -v, 0, this); //disegna applet da pixel 0
    if (v > (panow - applw)) {
      g.drawImage(pano, panow - v, 0, this); //disegna seconda parte
    }
I have yet to try to translate it into B4A.
 
Upvote 0

AlpVir

Well-Known Member
Licensed User
Longtime User
Hi Warwound
Your library OSMDroid can not be used to display the views I have.
They are more than just JPG images. They have a lot of information in the EXIF data that display the labels with the names of the peaks.
In other words my jpg files CAN NOT be broken ("Cut your panoramic image into tiles").
I enclose a screenshot of my app is already running. Has only two problems (scroll and consumer-resources) reported.
Thank you for your interest.
 

Attachments

  • P2.jpg
    P2.jpg
    73.4 KB · Views: 537
Upvote 0

warwound

Expert
Licensed User
Longtime User
Hi Warwound
Your library OSMDroid can not be used to display the views I have.
They are more than just JPG images. They have a lot of information in the EXIF data that display the labels with the names of the peaks.
In other words my jpg files CAN NOT be broken ("Cut your panoramic image into tiles").
I enclose a screenshot of my app is already running. Has only two problems (scroll and consumer-resources) reported.
Thank you for your interest.

You could do much the same with a MapView, instead of embedding data about panorama features in the image EXIF you could store that 'features data' in a database or flatfile and when the MapView loads the custom tiles it could overlay icons, polylines and labels on the tile layer based on the database or flatfile features data.

BUT your app looks to have reached an advanced stage and changing to a MapView would be a lot of work and a steep learning curve.

I shall be adding new methods to my library to allow custom tiles and then text labels, until then it won't be able to replace your existing code.
Also the process of cutting a 1MB JPG into tiles for zoom levels 0 to 6 creates a tile archive of 3.2MBs so that is an inefficient way to include a panorama in a project.
You can see your aiera.jpg in a MapView here: http://android.martinpearman.co.uk/osmdroid/misc/aiera_panorama_viewer.zip, that APK is 3.3MBs in size - only 0.1MB is MapView code the rest is the tiles (all cut at 70% quality).

You mention that your JPG is only ~1MB in size so not a problem with memory resources...
I downloaded aiera.jpg (you linked to it in your PM) and even though it's a 1MB JPG, as an uncompressed bitmap it is 18.38MBs in size.
Android uncompresses images and works with bitmaps so you should bear that in mind when trying to find a reason for the unsmooth scrolling.

I do not think i can update TouchImageView to wrap an image left to right - i'd have the same problem that you have now - keeping two copies of an image in memory and synchronising drawing as the left or right hand edge of an image scrolls into view.
I shall be thinking though - there may be a straightforward solution.

There is a native Android panorama viewer here: here.
I planned to make it into a B4A library a couple of months back BUT it was so buggy i gave up.

Martin.
 
Upvote 0

AlpVir

Well-Known Member
Licensed User
Longtime User
Actually, my app (350 ALP Panorama) is almost finished.
Use MapView might mean having to rewrite.
I sent a private message to Warwound where I provide the link to download the current version of this app (is and will be free).
Surely if you would Warwound will give me some suggestions to improve the horizontal scroll, that is its main flaw.
 
Upvote 0

warwound

Expert
Licensed User
Longtime User
Surely if you would Warwound will give me some suggestions to improve the horizontal scroll, that is its main flaw.

You've reminded me of a java applet i wrote back in 2006(!!) that was my first attempt to write a 360 degree panorama viewer...

I've uploaded it to here: Applet Test.

Hover your mouse to the left or right of the image and it'll pan in that direction - the speed of the panning is controlled by how far from the vertical center of the image that your mouse is.

This method is responsible for the 360 degree wrapping:

B4X:
   public void displayRedraw(Graphics g)
   {
      g.drawImage(vrImage,panPosition,0,this);
      if (fullPanorama==1)
      {
         if (panPosition<(imageWidth-displayWidth)) g.drawImage(vrImage,panPosition+imageWidth,0,this);
         if (panPosition>0) g.drawImage(vrImage,panPosition-imageWidth,0,this);
      }
   }

I know that's of little practical use to you but here's theory:

Take your panorama image and draw it to on a canvas, test whether the left or right hand edge of your panorama image is within the canvas.
If either edge is visible then draw the panorama image a second time with a suitable offset to create the 360 degree wrapping effect.

If you can work out how to do that in B4A then you can do away with your horizontal scroll view and hopefully have a smooth scrolling panorama viewer.
You should also be able to re-use most, if not all, of your existing code for drawing the panorama features from the EXIF onto the canvas.

I've attached the java source for my applet to this post.

Let me know what you think - i'm happy to help if i can.

Martin.
 

Attachments

  • panViewer.zip
    1.6 KB · Views: 523
Upvote 0

AlpVir

Well-Known Member
Licensed User
Longtime User
Unfortunately my knowledge of Java are not such as to allow me to turn this code into code B4a.
Is there anyone who would like to create a library with a view almost identical to HorizzontalScrollView, but that takes a 360-degree views, and properly handle (without jumps) the scroll?
The competent and courteous Warwound ?
I propose the name (HorizzontalScrollView360) and someone else code ;-)
 
Upvote 0

warwound

Expert
Licensed User
Longtime User
The competent and courteous Warwound ?

:sign0148:

Take a look at the attached project.
You'll need the Gestures library.

I've used a Canvas object to draw your aiera.jpg panorama onto a Panel.
And then used some Rect objects to keep track of the wrapping.

aiera.jpg is NOT included in the attached project.

I've scrolled left and right three times in each direction and it seems to carry on working after the first 360 degree wrap in either direction.

On my ZTE Blade i get a Force Close if i change orientation - Bitmap exceeds VM budget.
But for your app locked to landscape mode that shoudn't be a problem.


B4X:
'Activity module
Sub Process_Globals
End Sub

Sub Globals
   Dim Bitmap1 As Bitmap
   Dim Canvas1 As Canvas
   Dim Gestures1 As Gestures
   Dim Panel1 As Panel
   Dim SrcRect, DestRect, SrcWrapRect, DestWrapRect As Rect
   Dim TouchInProgress As Boolean
   Dim LastX, LastY As Int
End Sub

Sub Activity_Create(FirstTime As Boolean)
   Panel1.Initialize("")
   Activity.AddView(Panel1, 0, 0, 100%x, 100%y)
   
   Gestures1.SetOnTouchListener(Panel1, "HandleTouch")
   TouchInProgress=False
   
   Bitmap1.Initialize(File.DirAssets, "aiera.jpg")
   Canvas1.Initialize(Panel1)
   
   SrcRect.Initialize(0, 0, Panel1.Width, Panel1.Height)
   DestRect.Initialize(0, 0, Panel1.Width, Panel1.Height)
   
   Canvas1.DrawBitmap(Bitmap1, SrcRect, DestRect)
   Panel1.Invalidate
   
End Sub

Sub Activity_Resume
End Sub

Sub Activity_Pause (UserClosed As Boolean)
End Sub

Sub HandleTouch(Object1 As Object, PointerId As Int, Action As Int, X As Float, Y As Float) As Boolean
   Select Action
      Case Gestures1.ACTION_DOWN
         If TouchInProgress=False Then
            LastX=X
            LastY=Y
            TouchInProgress=True
         End If
      Case Gestures1.ACTION_MOVE
         Dim MoveX, MoveY As Int
         MoveX=LastX-X
         MoveY=LastY-Y
         
         SrcRect.Left=SrcRect.Left+MoveX
         '   SrcRect.Top=SrcRect.Top+MoveY
         SrcRect.Right=SrcRect.Right+MoveX
         '   SrcRect.Bottom=SrcRect.Bottom+MoveY
         Log(SrcRect)
         Canvas1.DrawBitmap(Bitmap1, SrcRect, DestRect)
         
         If SrcRect.Left<0 Then
            '    need to draw the right hand edge of the image to the left hand edge of the panel
            SrcWrapRect.Initialize(Bitmap1.Width+SrcRect.Left, 0, Bitmap1.Width, Bitmap1.Height)
            DestWrapRect.Initialize(0, 0, Abs(SrcRect.Left), Bitmap1.Height)
            Canvas1.DrawBitmap(Bitmap1, SrcWrapRect, DestWrapRect)
            
            '   normalise SrcRect
            SrcRect.Left=SrcRect.Left+Bitmap1.Width
            SrcRect.Right=SrcRect.Right+Bitmap1.Width
         Else
            If SrcRect.Right>Bitmap1.Width Then
               '    need to draw the left hand edge of the image to the right hand edge of the panel
               SrcWrapRect.Initialize(0, 0, SrcRect.Right-Bitmap1.Width, Bitmap1.Height)
               DestWrapRect.Initialize(Panel1.Width-SrcWrapRect.Right, 0, Panel1.Width, Bitmap1.Height)
               Canvas1.DrawBitmap(Bitmap1, SrcWrapRect, DestWrapRect)
               
               '   normalise SrcRect
               SrcRect.Left=SrcRect.Left-Bitmap1.Width
               SrcRect.Right=SrcRect.Right-Bitmap1.Width
            End If
         End If
         
         LastX=X
         LastY=Y
         Panel1.Invalidate
      Case Gestures1.ACTION_UP
         TouchInProgress=False
   End Select
   Return True
End Sub

The code is far from being complete - it doesn't scroll up or down and probably creates too many Rect objects rather than reusing existing Rects.

But take a look and see if you can follow how it works.
I'll probably have time to finish it tomorrow unless you can finish it yourself.

Martin.
 
Last edited:
Upvote 0

AlpVir

Well-Known Member
Licensed User
Longtime User
Perfect!
The solution proposed by Warwound is fully satisfactory. The scroll of the 360-degree panorama is continuous both in one way or another.
The other elements of my app, with some modifications, are perfectly integrated with the whole. It remains for me to scroll vertically, but this I do it with two small buttons.
However, I have the impression that this solution will consume more resources because two landscape (large 14000 pixels) cause an error. This did not happen with the previous version that included a HorizzontalScrollView and 2 ImageView.
Perhaps it would need some adjustment and reuse of some rectangle, just like it says the same Warwound; thank you again.
 
Upvote 0

warwound

Expert
Licensed User
Longtime User
And now better than perfect - technically an impossibility LOL!

I had a think and came up with a better technique to draw the wrapped image - much more efficient then my previous post.

Here's the code:

B4X:
'Activity module
Sub Process_Globals
   'These global variables will be declared once when the application starts.
   'These variables can be accessed from all modules.

End Sub

Sub Globals
   'These global variables will be redeclared each time the activity is created.
   'These variables can only be accessed from this module.
   
   Dim Bitmap1 As Bitmap
   Dim Canvas1 As Canvas
   Dim CurrentX, CurrentY, LastX, LastY As Int
   Dim DestRect, SrcRect As Rect
   Dim Gestures1 As Gestures
   Dim Panel1 As Panel
   Dim TouchInProgress As Boolean
End Sub

Sub Activity_Create(FirstTime As Boolean)
   CurrentX=0
   CurrentY=0
   TouchInProgress=False
   
   Panel1.Initialize("")
   Activity.AddView(Panel1, 0, 0, 100%x, 100%y)
   Canvas1.Initialize(Panel1)
   
   Bitmap1.Initialize(File.DirAssets, "aiera.jpg")
   
   DestRect.Initialize(CurrentX, CurrentY, Bitmap1.Width-CurrentX, Bitmap1.Height-CurrentY)
   SrcRect.Initialize(0, 0, Bitmap1.Width, Bitmap1.Height)
   
   Gestures1.SetOnTouchListener(Panel1, "HandleTouch")
   
   '   draw the image for the first time with no movement in X or Y direction
   DrawBitmap(0, 0)
End Sub

Sub Activity_Resume

End Sub

Sub Activity_Pause (UserClosed As Boolean)
   '   free up resources used by the panorama image
   Dim Reflector1 As Reflector
   Reflector1.Target=Bitmap1
   Reflector1.RunMethod("recycle")
End Sub

Sub HandleTouch(Object1 As Object, PointerId As Int, Action As Int, X As Float, Y As Float) As Boolean
   Select Action
      Case Gestures1.ACTION_DOWN
         If TouchInProgress=False Then
            LastX=X
            LastY=Y
            TouchInProgress=True
         End If
      Case Gestures1.ACTION_MOVE
         Dim MoveX, MoveY As Int
         MoveX=LastX-X
         MoveY=LastY-Y
         
         '   only update display if image is dragged more then 10 pixels
         
         '   without this check in place even a single tap on the screen is likely to be interpreted as a small drag to to hardware inaccuracies
         '   choose a value that's large enough to prevent a single tap being interpreted as a small drag but small enough to make a real drag smooth
         '   as long as you choose a value that is less than Bitmap1.Width everything will work ok
         
         If MoveX>=10 OR MoveX<=-10 OR MoveY>=10 OR MoveY<=-10 Then
            DrawBitmap(MoveX, MoveY)
            LastX=X
            LastY=Y
         End If
         
      Case Gestures1.ACTION_UP
         TouchInProgress=False
   End Select
   Return True
End Sub

Sub DrawBitmap(MoveX As Int, MoveY As Int)
   Dim i As Int
   
   CurrentX=CurrentX-MoveX
   CurrentY=CurrentY-MoveY
   
   '   normalise CurrentX if wrapping has occurred
   If CurrentX>0 Then
      CurrentX=CurrentX-Bitmap1.Width
   Else If CurrentX<-(Bitmap1.Width) Then
      CurrentX=CurrentX+Bitmap1.Width
   End If
   
   '   normalise CurrentY to keep Bitmap1 from dragging too far up or down
   '   this will fail if Bitmap1.Height<Panel1.Height
   '   (with aiera.jpg that will happen in portrait mode with a 800x480 screen)
   If CurrentY>0 Then
      CurrentY=0
   Else If Abs(CurrentY)>Bitmap1.Height-Panel1.Height Then
      CurrentY=-(Bitmap1.Height-Panel1.Height)
   End If
   
   For i=CurrentX To Panel1.Width Step Bitmap1.Width
      DestRect.Left=i
      DestRect.Right=i+Bitmap1.Width
      DestRect.Top=CurrentY
      DestRect.Bottom=CurrentY+Bitmap1.Height
      Canvas1.DrawBitmap(Bitmap1, SrcRect, DestRect)
   Next
   
   '   force the panel to redraw itself
   Panel1.Invalidate
   
End Sub

Sub HandleTouch is updated so a drag of less than 10 pixels will not cause a redraw of the image - the comments explain the logic.

Then a new Sub DrawBitmap handles all the drawing.
Again the comments should explain everything.

Finally the new logic made it easy to add vertical scrolling so you can now drag the panorama horizontally ad infinitum and vertically without dragging the panorama top or bottom from the edge of the panel.

You'll need to include the Reflection library as in Activity_pause i've used that to call the native Bitmap recycle() method to free up resources used by the Bitmap.

Hope you like it :cool:.

Martin.

[edit]PS a link to a version of your app which uses this code would be appreciated when available - you have taken some wonderful pictures![/edit]
 
Last edited:
Upvote 0

AlpVir

Well-Known Member
Licensed User
Longtime User
The improvement in this second version is great and allows you to delete the two buttons to scroll vertically.
However, it seems you can compile your code obfuscata mode. In "debug" and "release" is fine, but in mode "release (obfuscated)" as soon as we tend to move the image appears the message ""The application PanoViewer (process uj.co. martin .... panoviewer) has stopped unexpectedly. Pease try again"".
This seems to me serious and I do not know how to act. Depends on the library Gestures?
Another thing: the code inside the loop
B4X:
For i = CurrentX To Step Panel1.Width Bitmap1.Width
  DestRect.Left = i
  DestRect.Right = i + Bitmap1.Width
  DestRect.Top = CurrentY
  DestRect.Bottom = + CurrentY Bitmap1.Height
  Canvas1.DrawBitmap (Bitmap1, srcRect, destRect)
  Log ("DrawBitmap")
Next
is also performed when the image is fully up or fully down.

Here is the log of the error

** Activity (main) Create, isFirst = true **
DrawBitmap
** Activity (main) Resume **
java.lang.NullPointerException
at anywheresoftware.b4a.agraham.gestures.Gestures$1.onTouch(Gestures.java:96)
at android.view.View.dispatchTouchEvent(View.java:3881)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:903)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:869)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:869)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:869)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:869)
at com.android.internal.policy.impl.PhoneWindow$DecorView.superDispatchTouchEvent(PhoneWindow.java:1691)
at com.android.internal.policy.impl.PhoneWindow.superDispatchTouchEvent(PhoneWindow.java:1125)
at android.app.Activity.dispatchTouchEvent(Activity.java:2096)
at com.android.internal.policy.impl.PhoneWindow$DecorView.dispatchTouchEvent(PhoneWindow.java:1675)
at android.view.ViewRoot.deliverPointerEvent(ViewRoot.java:2194)
at android.view.ViewRoot.handleMessage(ViewRoot.java:1878)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:123)
at android.app.ActivityThread.main(ActivityThread.java:3683)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:507)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:839)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:597)
at dalvik.system.NativeStart.main(Native Method)
 
Upvote 0

warwound

Expert
Licensed User
Longtime User
Here's an update for you then.

The problem with the obfuscation process was easily fixed by renaming Sub HandleTouch to Handle_Touch.
(The obfuscator will not obfuscate a Sub name with an underscore).

Here's the new code (better commented than previous versions!):

B4X:
'   Activity module WrappingImageViewer
'   requires Gestures and Reflection libraries
Sub Process_Globals
End Sub

Sub Globals
   Dim Bitmap1 As Bitmap
   Dim Canvas1 As Canvas
   Dim CurrentPointerId, CurrentX, CurrentY, LastX, LastY, MinDragMove As Int
   Dim DestRect, SrcRect As Rect
   Dim Gestures1 As Gestures
   Dim Panel1 As Panel
End Sub

Sub Activity_Create(FirstTime As Boolean)
   CurrentPointerId=-1
   CurrentX=0
   CurrentY=0
   MinDragMove=10
   
   Panel1.Initialize("")
   Activity.AddView(Panel1, 0, 0, 100%x, 100%y)
   Canvas1.Initialize(Panel1)
   
   Bitmap1.Initialize(File.DirAssets, "brain.jpg")
   
   DestRect.Initialize(CurrentX, CurrentY, Bitmap1.Width-CurrentX, Bitmap1.Height-CurrentY)
   SrcRect.Initialize(0, 0, Bitmap1.Width, Bitmap1.Height)
   
   Gestures1.SetOnTouchListener(Panel1, "Handle_Touch")
   
   '   draw the image for the first time with no movement in X or Y direction
   DrawBitmap(0, 0)
End Sub

Sub Activity_Resume

End Sub

Sub Activity_Pause (UserClosed As Boolean)
   '   free up resources used by Bitmap1
   Dim Reflector1 As Reflector
   Reflector1.Target=Bitmap1
   Reflector1.RunMethod("recycle")
End Sub

Sub Handle_Touch(Object1 As Object, PointerId As Int, Action As Int, X As Float, Y As Float) As Boolean
   '   the first touch on Panel1 will be handled, touches after that first touch will be discarded
   Select Action
      Case Gestures1.ACTION_DOWN
         If CurrentPointerId=-1 Then
            LastX=X
            LastY=Y
            CurrentPointerId=PointerId
         End If
      Case Gestures1.ACTION_MOVE
         If CurrentPointerId=PointerId Then
            Dim MoveX, MoveY As Int
            MoveX=LastX-X
            MoveY=LastY-Y
            
            '   only update display if image is dragged more then MinDragMove pixels
            
            '   without this check in place even a single tap on the screen is likely to be interpreted as a small drag to to hardware inaccuracies
            '   choose a value that's large enough to prevent a single tap being interpreted as a small drag but small enough to make a real drag smooth
            '   as long as you choose a value that is less than Bitmap1.Width everything will work ok
            
            If MoveX>=MinDragMove OR MoveX<=-(MinDragMove) OR MoveY>=MinDragMove OR MoveY<=-(MinDragMove) Then
               DrawBitmap(MoveX, MoveY)
               LastX=X
               LastY=Y
            End If
         End If
      Case Gestures1.ACTION_UP
         If CurrentPointerId=PointerId Then
            CurrentPointerId=-1
         End If
   End Select
   Return True
End Sub

Sub DrawBitmap(MoveX As Int, MoveY As Int)
   Dim X As Int
   
   CurrentX=CurrentX-MoveX
   CurrentY=CurrentY-MoveY
   
   '   normalise CurrentX if wrapping has occurred
   '   this will fail if MoveX>Bitmap1.Width
   If CurrentX>0 Then
      CurrentX=CurrentX-Bitmap1.Width
   Else If CurrentX<-(Bitmap1.Width) Then
      CurrentX=CurrentX+Bitmap1.Width
   End If
   
   '   normalise CurrentY
   If CurrentY>0 Then
      '   do not allow the Bitmap1 top edge to be dragged down from the top of Panel1
      CurrentY=0
   Else If Bitmap1.Height<Panel1.Height Then
      '   do not allow vertical dragging
      CurrentY=0
   Else If Abs(CurrentY)>Bitmap1.Height-Panel1.Height Then
      '   do not allow the Bitmap1 bottom edge to be dragged down from the bottom of Panel1
      CurrentY=-(Bitmap1.Height-Panel1.Height)
   End If
   
   '   draw Bitmap1 repeatedly on Panel1 from CurrentX, CurrentY until Panel1 is fully covered by Bitmap1
   For X=CurrentX To Panel1.Width Step Bitmap1.Width
      DestRect.Left=X
      DestRect.Right=X+Bitmap1.Width
      DestRect.Top=CurrentY
      DestRect.Bottom=CurrentY+Bitmap1.Height
      Canvas1.DrawBitmap(Bitmap1, SrcRect, DestRect)
   Next
   
   '   force the panel to redraw itself
   Panel1.Invalidate
   
End Sub

I've created a new variable MinDragMove to more easily enable you to set the minimum drag move that should cause a redraw.

TouchInProgress is gone, replaced by CurrentPointerId.
If a user causes more than one touch event then the second touch event is discarded.
That stops occasional glitches when more than one finger is in contact with the screen.

Then i've updated the code which normalises CurrentY.
This won't make any changes to your use of the code as a panorama viewer.
But as others may find this code and want to use it with images that are smaller than the dimensions of Panel1 then CurrentY is now better normalised.

The attached code draws a small 216 pixel square to Panel1.
Run the code and you should now be able to follow how the For loop in DrawBitmap draws Bitmap1 repeatedly if required until the wrapping effect is achieved.

That loop will execute each time a touch of more than MinDragMove pixels is detected - regardless of whether the image is fully up or down.

For your panorama viewer that loop will mostly loop just once, and twice when your panorama image needs wrapping.

With a image with less width than Panel1 it will loop more times to achive the wrapping.

Have you thought about adding a live wallpaper module to your app?
It could find all the downloaded panoramas in the PANORAMI folder and cycle through them every ?? period displaying them as device wallpaper...
Just an idea!

Martin.
 

Attachments

  • WrappingImageViewer.zip
    31.6 KB · Views: 559
Upvote 0

AlpVir

Well-Known Member
Licensed User
Longtime User
Further additions of Warhound still grow the capabilities of this code to offer a particular view of a certain type of images.
In the case of my views at 360 degrees viewing is optimal.
But I think that the sub DrawBitmap runs even when it would be useless when the scroll that has reached its limits.
I made a small addition to display overlaid on a single label. The label can scroll horizontally properly but when you move vertically, the label lost its alignment.
Apparently I made ​​some mistakes but I can not find it, unlike Warwound that surely will put things right.
Attached is the draft modified Warhound.
 

Attachments

  • 20120404b_mod.zip
    31.9 KB · Views: 485
Upvote 0

warwound

Expert
Licensed User
Longtime User
Hi.

You want to add one or more Labels so they appear over the image?

Do you want the Labels to remain fixed in relation to the Panel or scroll with the Image?

If you want the Labels to remain fixed relative to the Panel then it's probably best to update the DrawBitmap Sub - after the wrapping images have been drawn make sure the Labels are visible (on top).

If you want the Labels to scroll with the image then it's probably best to draw them onto Bitmap1 (when BitMap1 is initialized) so they get drawn and scrolled with the image.

Let me know what you want and i'll look for a solution.

And i'll check that the drawing loop does not execute if it is not necessary.

Martin.
 
Upvote 0

AlpVir

Well-Known Member
Licensed User
Longtime User
Hi Warwound
The labels (an array of 40-80 labels) must move with the image (representing the name of the mountains). See figure 1.
With the labels there are many panel (width=1, 2 or 3 pixels): are visually the vertical lines.
Unfortunately, the vertical sliding door to the errors seen in image 2.
This is the code that performs the scroll of the labels and panels :

B4X:
Sub ScrollLblPeak (X As Int, Y As Int)
   Dim I As Int 
   '--- Scroll X
   For I=0 To TotID-1
      Linea(I).Left=Linea(I).Left - X
      LblPeak(I).Left=LblPeak(I).Left - X
      If Linea(I).Left>intLargImg Then Linea(I).Left=Linea(I).Left-intLargImg
      If LblPeak(I).Left>intLargImg Then LblPeak(I).Left=LblPeak(I).Left-intLargImg
      If Linea(I).Left<0 Then Linea(I).Left=Linea(I).Left+intLargImg
      If LblPeak(I).Left<0 Then LblPeak(I).Left=LblPeak(I).Left+intLargImg
   Next 
        '--- Scroll Y
        '  If ...
   For I=0 To TotID-1
      Linea(I).top=Linea(I).Top - Y
      LblPeak(I).top=LblPeak(I).Top - Y
   Next 
End Sub

The current version of the app is available from several minutes to the usual URL
Tanks
 

Attachments

  • V1.jpg
    V1.jpg
    74.8 KB · Views: 537
Last edited:
Upvote 0
Top