Menu

Fit 3D Points to Screen

Help
hckr
2017-12-15
2018-08-16
  • hckr

    hckr - 2017-12-15

    Hello,

    I put my 3D points to a TGLPoints instance and then display them. The user is able to rotate/translate the view. The problem is when I try to display a different set of 3D points, and if the area represented by the new points is smaller than the previous one, they look far away. What I want is to zoom to the new set of points automatically to fit them to screen. It would also be great if I did not have to change the rotation of the camera.

    I tried the formulae given here https://www.opengl.org/discussion_boards/showthread.php/169865-Zoom-to-fit-screen. However, it did not work. Maybe because I do not have bounding sphere center.

    How can I achieve what I want with GLScene?

    Thanks in advance.

     

    Last edit: hckr 2017-12-15
  • Jerome.D (BeanzMaster)

    Hi, it's hard to answer without a bit of code. so describe how you do. Do you compute MaxX/Y/Z from your cloud Points ? How you set camera ?

     
  • hckr

    hckr - 2017-12-15

    Hi,

    I did not really compute the Max X/Y/Z from my cloud points, instead I relied on 'BoundingSphereRadius' function which I now realize is not what I want.

       radius:=GLPoints.BoundingSphereRadius;
       fov:=GLSceneViewer1.FieldOfView*pi/180;
       distance:=abs(tan(fov*0.5));
       GLCamera1.AdjustDistanceToTarget((radius/distance)/GLCamera1.DistanceToTarget);
    

    The camera's target is the GLPoints object.
    Here is the settings for GLScene and the camera

     

    Last edit: hckr 2017-12-15
  • Sami M.

    Sami M. - 2018-07-17

    Hello,

    Have just gotten the feel of this nice GLScene (using it with Lazarus). Am also interested in using it with point clouds, wonder if you ever found a nice solution to scaling the data to the screen..?

    Am especially wondering where to put any code for scaling the points
    without slowing down the points processing, would
    the BeforeRender event of the SceneViewer be the correct place..?

    Tried using NormalizeVector() and ScaleVector() for scaling without success.

    Below is a sample of my code:

    Much obliged for any help,
    Regards,
    Sami


    at the event FormCreate,
    after the file containing the points (X, Y and Z as well as RGB) has been
    read and loaded into a TstringList, I process each
    line by reading in the X-cordinate into XX_, Y -coordinate into YY_,
    Z -coordinate into ZZ and the RGB into RedText, Green_Text
    and Blue_Text respectively
    as follows in a for loop:

    Var
    color_vector  :TVector4f;
    vertex_:TVector3f;
    i:Longint;
    For i  := 0 To NrPoints - 1 Do
    Begin
      // here  code to read each line and break string into coordinates and RGB values..
      // now handle the Coordinates 
       vertex_       := AffineVectorMake(XX_,YY_,ZZ_);
       // add the point to GLPointCloud which is a  TGLPoints component on the Main form
     AMain.GLPointCloud.Positions.Add(vertex_.X,vertex_.Y,vertex_.Z);
    
      // now handle the Color
       color_vectori := VectorMake(StrToInt(Red_Text)/255,
                                  StrToInt(Green_Text)/255,
                                  StrToInt(Blue_Text)/255,1);
    
     AMain.GLPointCloud.Colors.Add(color_vectori_);                               
    End;                              
    
     

    Last edit: Sami M. 2018-07-17
  • Jerome.D (BeanzMaster)

    Hi Sami can you attach a complete test case . Like i said you must compute the Min/Max boundig box

    Quick and dirty code from scratch :

    Procedure TForm1.FormCreate(Sender : TObject);
    Var
      color_vectori  : TVector4f;
      vertex_, vmin,vmax: TVector3f;
      i:Longint;
      Radius, fov, distance :Single;
    begin
      For i  := 0 To 99 Do
      Begin
        // here  code to read each line and break string into coordinates and RGB values..
        // now handle the Coordinates
         vertex_       := AffineVectorMake(-10+Random(20),-10+Random(20),-10+Random(20));
         // add the point to GLPointCloud which is a  TGLPoints component on the Main form
         GLPoints1.Positions.Add(vertex_.X,vertex_.Y,vertex_.Z);
    
        // now handle the Color
         color_vectori := VectorMake(Random(255)/255,
                                    Random(255)/255,
                                    Random(255)/255,1);
    
         GLPoints1.Colors.Add(color_vectori);
      End;
      vmin := GLPoints1.Positions.Items[0];
      vmax := GLPoints1.Positions.Items[0];
      For i  := 1 To 99 Do
      Begin
        if VectorLessEqualThen(vmin, GLPoints1.Positions.Items[i]) then vmin := GLPoints1.Positions.Items[i];
        if VectorMoreEqualThen(vmax, GLPoints1.Positions.Items[i]) then vmax := GLPoints1.Positions.Items[i];
      End;
      radius:= VectorDistance(vmin,vmax) * 0.5;
      fov:=DegToRad(GLSceneViewer1.FieldOfView)*0.5;
      distance:= Radius / abs(tan(fov));
      GLCamera1.AdjustDistanceToTarget(Distance*0.5);
      GLCamera1.DepthOfView := 2 * GLCamera1.DistanceToTarget + 2 * radius;
    end; 
    

    Becarefull each time you'll change GLPoints you need reset GLCamera1 and GLSceneViewer1.FieldOfView.

    GLCamera2 = Same as GLCamera1

    Procedure TForm1.Button1Click(Sender : TObject);
    Var
      color_vectori  : TVector4f;
      vertex_, vmin,vmax: TVector3f;
      i:Longint;
      Radius, fov, distance :Single;
    begin
      Randomize;
      // Reset camera
      GLCamera1.Assign(GLCamera2);
      GLPoints1.Positions.Clear;
      GLPoints1.Colors.Clear;
     // GLSceneViewer1.FieldOfView := LastFov;
      For i  := 0 To 99 Do
      Begin
        // here  code to read each line and break string into coordinates and RGB values..
        // now handle the Coordinates
         vertex_       := AffineVectorMake(-10+Random(20),-10+Random(20),-10+Random(20));
         // add the point to GLPointCloud which is a  TGLPoints component on the Main form
         GLPoints1.Positions.Add(vertex_.X,vertex_.Y,vertex_.Z);
    
        // now handle the Color
         color_vectori := VectorMake(Random(255)/255,
                                    Random(255)/255,
                                    Random(255)/255,1);
    
         GLPoints1.Colors.Add(color_vectori);
      End;
      vmin := GLPoints1.Positions.Items[0];
      vmax := GLPoints1.Positions.Items[0];
      For i  := 1 To 99 Do
      Begin
        if VectorLessEqualThen(vmin, GLPoints1.Positions.Items[i]) then vmin := GLPoints1.Positions.Items[i];
        if VectorMoreEqualThen(vmax, GLPoints1.Positions.Items[i]) then vmax := GLPoints1.Positions.Items[i];
      End;
      radius:= VectorDistance(vmin,vmax) * 0.5;
      fov:=DegToRad(GLSceneViewer1.FieldOfView)*0.5;
      distance:= Radius / abs(tan(fov));
      GLCamera1.AdjustDistanceToTarget(Distance*0.5);
      GLCamera1.DepthOfView := 2 * GLCamera1.DistanceToTarget + 2 * radius;
    end;            
    
     

    Last edit: Jerome.D (BeanzMaster) 2018-07-17
  • Sami M.

    Sami M. - 2018-07-18

    Hello Jerome,

    Thanks a lot for your kind help. Your example cleared a lot as to where to place
    the Camera adjustment code after the min and max are known. It was helpful to know
    it's only done once at the end after processing all the points...

    The problem had so far was that the points were appearing way too far from the
    screen center, and after modifying some parameters, seem to have lost
    any visibility (am not seeing any points).

    Have made sure that vmin and vmax are working properly
    and that the variables radius, fov and distance yield sensible values. Checked that the target object of the camera is indeed 'DummyCube', but am not so sure about how to position the camera (Direction/Position). Am including the settings and would be very grateful if you could please just take a quick look and may be comment on them.

    Much obliged for your help,
    Sami

     
  • Jerome.D (BeanzMaster)

    Hi, you need to play with TGLPoints 's size and pointparameters properties

    See attached sample

     
  • Sami M.

    Sami M. - 2018-07-18

    Hello,

    Many many thanks for all your help and pointers.
    Changed a bit the routine to find the min/max by just testing separately for
    x,y,and z as so:

    if vertex.x < vmin.x then
       vmin.x :=  vertex.x;
    

    instead of using:

    VectorLessEqualThen()
    

    Did manage to get some point clouds files to display OK, whereas for the some, there's
    just one dot on the screen, perhaps it's the scaling..

    As the point cloud files can really get huge (2 million points/rows is considered small)
    testing is rather slow :-)

    Regards,
    Sami

     
  • Jerome.D (BeanzMaster)

    Hello Sami

    Changed a bit the routine to find the min/max by just testing separately for
    x,y,and z as so:

    Yes you can also avoid testing Z. or you can can add 1more dimension examples you are in the case of XY view just compute XY min and max for each axis, same for XZ, YZ view so globally you can compute what point have the min and max for each axis depend of the view. (sorry for my bad english)

    For increase performances perhaps in you're file you'll can include default camera properties and "min" "max" of each axis for the clouds. Like thisyou'll not need to compute at start, just at saving

    Did manage to get some point clouds files to display OK, whereas for the some, there's
    just one dot on the screen, perhaps it's the scaling..

    Yes it's due to the point size scaling. Just adjust (Distance * 0.5) where 0.5 is the zoom factor (0.65 will be good enought)

     
    • Sami M.

      Sami M. - 2018-07-19

      Hello ,

      Thanks a lot Jerome for all your kind help and comments . Am trying out your hints and
      things are progressing nicely, was helpful to know that 0.5 is the zoom.
      Defining the min and max properties earlier on sounds like a very good idea.

      How to efficiently read huge text files seems to be
      a main issue here (reading in millions of lines can take a few mins), but then that is beyond the scope of GLScene..

      //and BTW, your English is just fine : )
      Regards
      Sami

       
  • Sami M.

    Sami M. - 2018-08-03

    Hello,

    Have been now able to load several point (cloud) files, for
    the very large ones am reading only a part of the points (for instance every 50th point)
    to get a speed increase.

    Am now trying to make a simple interface for letting the user scale and zoom
    on the resulting image.

    Scaling works nicely with the following code which is called any time
    the user changes the scale in the edit box 'AMain.Ed_Scale':

    With   AMAin.GLPointCloud Do
            Begin
            Scale.X:= get_scale_AMAINER;Scale.Y:= get_scale_AMAINER;
            Scale.Z:= get_scale_AMAINER;
            End;
    

    where get_scale_AMAINER is obtained from a user set value, defined as follows:

    Function get_scale_AMAINER:Currency;
    BEGIN
    Result := (StrToCurr(AMain.Ed_Scale.Text)/2)/100;
    END;
    

    However, for zooming, cannot get similar results...
    Any change by the user on the zoom factor (say from 0.5 to 0.65)
    will make the image nearly invisible. This is strange as both 0.5 and 0.65
    work the first time the image is displayed, but any subsequent change in the zoom
    renders the image very very small...As I understand it, in the following code, 'zoomer'
    is the only parameter which needs to be set to affect the zooming percentage..?

    ~~~
    Var
    Radius, fov, distance :Single;
    BEGIN
    With AMain Do
    Begin
    radius := VectorDistance(vmin,vmax) * 0.5;
    fov := DegToRad(SceneViewer.FieldOfView)*0.5;

    distance := Radius / Abs(tan(fov));

    GLCamera.AdjustDistanceToTarget(distance*zoomer);
    GLCamera.DepthOfView := 2 * GLCamera.DistanceToTarget + 2 * radius;
    ~~~
    where zoomer can be modified by the user so that an OnChangeEvent calls the above
    code.

    Would be very grateful for any hints here.

    Regards,
    Sami

     
  • Jerome.D (BeanzMaster)

    Hi Sami, i think the problems come from "GLCamera1.AdjustDistanceToTarget" this is the help

    Adjusts distance from camera to target by applying a ratio.
    If TargetObject is nil, nothing happens. This method helps in quickly
    implementing camera controls. Only the camera's position is changed.

    So the the behaviours is normal before making computing you must reset the camera. But for what you can do the best way is to use Mouse and setup the camera. See attached sample

    LMB and LMB+Shift : Adjust Distance by 1.25%
    RMB : Adjust Focal Length
    Wheel : Adjust Distance

    Just a question why do you use Currency instead of Double or Single ?

     

    Last edit: Jerome.D (BeanzMaster) 2018-08-03
  • Sami M.

    Sami M. - 2018-08-03

    Thanks so much for your help Jerome, really appreciate it.

    Tried your code and indeed it looks much better now.
    Though with a large point cloud, when rotating the mouse wheel inwards (towards yourself), the image first grows but then seems to 'collapse' on itself so that it eventually disappears altogether..probably something to do with the parameters...

    Yes you're right, Currency should be Single/Double, was using it only as a reminder that the value is provided by the user with a max. 2-decimal accuracy..

     
  • Jerome.D (BeanzMaster)

    Though with a large point cloud, when rotating the mouse wheel inwards (towards yourself), the image first grows but then seems to 'collapse' on itself so that it eventually disappears

    It's probably come from a range overflow or casue by the using of the power function. If you can provide me a simple sample i'll can test and see

    I think you can set the number of decimal in Lazarus with TFloatSpinEdit component you have DecimalPlaces property for that

     

    Last edit: Jerome.D (BeanzMaster) 2018-08-03
    • Sami M.

      Sami M. - 2018-08-14

      Hello Jerome,

      Wonder if you found time to test the sample application I posted last week, would be very grateful for your comments.

      Regards,
      Sami

       
  • Sami M.

    Sami M. - 2018-08-06

    Hello,
    Thanks for your kind help, Jerome. Am attaching the full application and a sample data, the sample data that was referring to is huge (even when compressed), and could not reproduce the problem every time.
    However, something incorrect seems to occur with this simpler file (file dog.txt, each row contains X Y Z and RGB colors). After launching the applic, the file dog.txt is selected, then button 'Analyze' is pressed and the image should appear. After rotating the dog (using the left mouse button) a bit and keeping the head in front, then zooming in using the wheel button, it would appear that the end part/tail-part of the dog is not in proportion with its front part...

    Regards,
    Sami

     
  • sxbug

    sxbug - 2018-08-11

    Hello
    Can you make a Delphi version of the program for me?
    thanks you!
    sxbug@163.com

     
  • sxbug

    sxbug - 2018-08-11

    Hello
    At first thank you for your pragram. Now I have changed it from lazarus to delphi. If I build it to 32bit program ,it is ok. But build it to 64bit program , it can not run and display error mesage"Floating point division by zero", Why?

    I am using win10 64bit sys , GLScene 1.6. thanks.

     
  • Sami M.

    Sami M. - 2018-08-13

    Hello,

    Sorry for late reply, am not yet running GLScene with Delphi, so unfortunately can't reproduce the error. But would imagine you can track the error by checking at what point it occurs...Were you able to zoom in on the dog..?

     
  • Jerome.D (BeanzMaster)

    Hi, I've a lot of work. I'll take look at soon as possible

     
  • Sami M.

    Sami M. - 2018-08-15

    Ok sure, no hurries, thanks :-)

     
  • sxbug

    sxbug - 2018-08-15

    Hello

    Thanks at first. I have builded this program for 64Bit in this attachment. You can run this EXE file to see the error. If you run this program, you can not display this dog.

    How can I do? Thanks

    sxbug
    
     
  • Jerome.D (BeanzMaster)

    Hi can you put your sample code as attachement please

     

Log in to post a comment.

Want the latest updates on software, tech news, and AI?
Get latest updates about software, tech news, and AI from SourceForge directly in your inbox once a month.