ViewPoint3D units

A discussion forum for Orson Charts (a 3D chart library for the Java platform).
Locked
daress
Posts: 23
Joined: Tue Mar 13, 2007 4:52 pm
Contact:

ViewPoint3D units

Post by daress » Thu Oct 13, 2016 10:08 pm

First of all, thank you for Orson Charts! This software has been fun to learn and implement in a program for displaying inspection data.

Constructor:

Code: Select all

ViewPoint3D(double theta, double phi, double rho, double orientation)
If I understand the ViewPoint3D javadocs correctly, the theta, phi, and orientation values are in radians. However, the javadocs say that rho is the "distance of the viewing point from the origin." Given that it is a distance, what are the units associated with rho?

I ask as I am developing an application where the user can manually enter the theta, phi, rho, and orientation values, and there should be units specified in the dialog box.
Thanks!

david.gilbert
JFreeChart Project Leader
Posts: 11734
Joined: Fri Mar 14, 2003 10:29 am
antibot: No, of course not.
Contact:

Re: ViewPoint3D units

Post by david.gilbert » Fri Oct 14, 2016 7:20 pm

The charts are constructed inside a virtual box with fairly arbitrary dimensions. I think the default in XYZPlot is a cube with sides of length 10, you can override this to any size with the setDimensions() method. The relative lengths of the x, y and z sides are more important than the actual units themselves, since the plot and its axes will scale to fit the space.

The viewpoint has a distance from the origin specified in the same units as this virtual box that is defining the size of the plot.
David Gilbert
JFreeChart Project Leader

:idea: Read my blog
:idea: Support JFree via the Github sponsorship program

daress
Posts: 23
Joined: Tue Mar 13, 2007 4:52 pm
Contact:

Re: ViewPoint3D units

Post by daress » Mon Oct 17, 2016 4:04 pm

Thank you David.

I have come across something else about ViewPoint3D objects: where is the best place to set/get them in the Orson Charts heirarchy?

In the application I am developing, I create the Chart3D object from the Chart3DFactory.createScatterChart() method (love these utility methods), then set the view point to the Chart3D object. I then wrap the Chart3D object with a Chart3DPanel object, which in turn is wrapped by a DisplayPanel3D object for placing into the content of a JFrame, bascially

Code: Select all

Chart3D chart = Chart3DFactory.createScatterChart(.....);
ViewPoint3D vp3D = new ViewPoint3D(0.52, 1.42, 22.87, 3.11);
chart.setViewPoint( vp3D );
Chart3DPanel mChartPanel = new Chart3DPanel( chart );
DisplayPanel3D mDisplayPanel = new DisplayPanel3D( mChartPanel );
My current issue is when I query the ViewPoint3D after the chart has been rendered, the orientation parameter value has changed without touching any of the toolbar buttons. The values of the ViewPoint3D, before and after rendering, are:

Theta of 0.52 to 0.52
Phi of 1.42 to 1.42
Rho of 22.87 to 22.87
Orientation of 3.11 to -0.005 (from calcRollAngle() )

After rendering the chart, clicking any of the toolbar navigation buttons causes the chart to "flip" upside down.

So, I am curious if you have any suggestions as to what I am doing wrong?
Question: is the orientation returned from calcRollAngle() the same as the orientation provided to the constructor?
Question: Once a chart is displayed, what object should the current ViewPoint3D be read from?
Question: Once a chart is displayed, what object should be used for changing the view point with new values from the user in the form of a ViewPoint3D object?

Thank you in advance. David

david.gilbert
JFreeChart Project Leader
Posts: 11734
Joined: Fri Mar 14, 2003 10:29 am
antibot: No, of course not.
Contact:

Re: ViewPoint3D units

Post by david.gilbert » Sun Oct 23, 2016 6:23 am

Hi,

It is probably a bit counter-intuitive but the ViewPoint3D is an attribute of the Chart3D object - this ensures that the chart can "draw itself" which it does through the following method:

Code: Select all

public RenderingInfo draw(Graphics2D g2, Rectangle2D bounds);
...and of course for the chart to draw itself it needs to know the viewing point. It might have made some sense to pass the view point as a parameter to the draw method, but I didn't do that (not sure if I considered it at the time or not). So you should always be able to modify the view point by accessing the chart directly. Or from the Chart3DPanel by calling the getChart() method first (same result). Or from the DisplayPanel3D by calling getContent().getDrawable() which also returns the chart object (but using the interface type Drawable3D that the Chart3D class implements).

If I recall correctly, the calcRollAngle() method should initially return the same value that you pass to the constructor. The idea here is that the chart is a 3D model centered on the origin of the coordinate space and the viewer is looking directly at the origin from a point some distance away. As the viewer looks at the chart, it is possible to stay at the same viewing point but "rotate" the viewers eye to get a different view of the chart (rotating the viewers eye by 180 degrees would turn the chart upside down, even though the viewing point in 3D space hasn't changed).

It's possible that you've come across a bug if the first click on the buttons in the display panel is flipping the chart upside down. If you have a small demo app that shows the problem I will try to take a look.
David Gilbert
JFreeChart Project Leader

:idea: Read my blog
:idea: Support JFree via the Github sponsorship program

daress
Posts: 23
Joined: Tue Mar 13, 2007 4:52 pm
Contact:

Re: ViewPoint3D units

Post by daress » Thu Nov 10, 2016 3:51 pm

OK, a demo of the problem I am having. This demo was done with Orson Charts 1.5.

I took the ScatterPot3DDemo2 class and duplicated it as ScatterPlot3Demo4. I then changed the JCheckBox to a JButton and rewrote the actionPerformed() method. Everytime the button is clicked, the current viewport data is extracted from the chart, displays viewpoint data, and the sets it back to the chart (see code below).

Code: Select all

package com.orsoncharts.demo.swing; 
 
import java.awt.BorderLayout; 
import java.awt.FlowLayout; 
import java.awt.LayoutManager; 
import java.awt.event.ActionEvent; 
import java.awt.event.ActionListener; 
 
import javax.swing.JButton;
import javax.swing.JFrame; 
import javax.swing.JPanel; 
 
import com.orsoncharts.Chart3DPanel; 
import com.orsoncharts.Chart3D; 
import com.orsoncharts.axis.LabelOrientation; 
import com.orsoncharts.axis.LogAxis3D; 
import com.orsoncharts.axis.NumberAxis3D; 
import com.orsoncharts.data.xyz.XYZDataset; 
import com.orsoncharts.demo.ScatterPlot3D2;
import com.orsoncharts.graphics3d.swing.DisplayPanel3D;
import com.orsoncharts.graphics3d.ViewPoint3D;
import com.orsoncharts.plot.XYZPlot; 
import com.orsoncharts.style.ChartStyler; 
 
/** * A demonstration of a scatter plot in 3D. 
 */ 
@SuppressWarnings("serial") 
public class ScatterPlot3DDemo4 extends JFrame {
 
    static class CustomDemoPanel extends DemoPanel implements ActionListener { 
        
        private JButton     button;
         
        public CustomDemoPanel(LayoutManager layout) { 
            super(layout); 
            this.button = new JButton("ViewPoint Test");
            this.button.addActionListener(this);
            JPanel controlPanel = new JPanel(new FlowLayout()); 
            controlPanel.add(this.button);
            add(controlPanel, BorderLayout.SOUTH); 
        }     
 
        @Override 
        public void actionPerformed(ActionEvent e) { 
            Chart3D chart = (Chart3D) getChartPanel().getDrawable();
            
            ViewPoint3D vp3D = chart.getViewPoint();
            System.out.println("vp3D.toString() = " + vp3D.toString() );
            System.out.println("vp3D.calcRollAngle() = " + vp3D.calcRollAngle() );
            
            /**
             
             first click of JButton produces:
             
             vp3D.toString() = [theta=2.556252890799462, phi=2.498263473155706, rho=46.079368591308594]
             vp3D.calcRollAngle() = 2.2626321404381216
             
             when setViewPoint() is set, all is ok with the plot
             
             second click of JButton produces:
             
             vp3D.toString() = [theta=2.556252890799462, phi=2.498263473155706, rho=46.079368591308594]
             vp3D.calcRollAngle() = 1.6494463074004122
             
             when setViewPoint() is set, plot inverts due to the roll angle (orientation) being different
             
            */
            
            double theta = vp3D.getTheta();
            double phi = vp3D.getPhi();
            double rho = vp3D.getRho();
            double orientation = vp3D.calcRollAngle();
            
            vp3D = new ViewPoint3D(theta, phi, rho, orientation);
            chart.setViewPoint(vp3D);
            
        } 
    } 
 
    /**     * Creates a new test app. 
     * 
     * @param title  the frame title. 
     */ 
    public ScatterPlot3DDemo4(String title) {
        super(title); 
        addWindowListener(new ExitOnClose()); 
        getContentPane().add(createDemoPanel()); 
    } 
 
    /**     * Returns a panel containing the content for the demo.  This method is 
     * used across all the individual demo applications to allow aggregation  
     * into a single "umbrella" demo (OrsonChartsDemo). 
     *  
     * @return A panel containing the content for the demo. 
     */ 
    public static JPanel createDemoPanel() { 
        DemoPanel content = new CustomDemoPanel(new BorderLayout()); 
        content.setPreferredSize(OrsonChartsDemo.DEFAULT_CONTENT_SIZE); 
        XYZDataset dataset = ScatterPlot3D2.createDataset();
        Chart3D chart = ScatterPlot3D2.createChart(dataset);
        Chart3DPanel chartPanel = new Chart3DPanel(chart); 
        content.setChartPanel(chartPanel); 
        chartPanel.zoomToFit(OrsonChartsDemo.DEFAULT_CONTENT_SIZE); 
        content.add(new DisplayPanel3D(chartPanel)); 
        return content; 
    } 
     
    /**     * Starting point for the app. 
     * 
     * @param args  command line arguments (ignored). 
     */ 
    public static void main(String[] args) { 
        ScatterPlot3DDemo4 app = new ScatterPlot3DDemo4(
                "OrsonCharts : ScatterPlot3DDemo4.java");
        app.pack(); 
        app.setVisible(true); 
    } 
}
The first time the button is clicked, everything is fine. But, on the second click, the plot inverts due to the changed value of the orientation (2.26 to 1.65).

I am still not saying there is a bug in Orson Charts - it could be I just do not understand the 3D orientation. But, for the project I am working on, the user needs to be able to open a window that allows him/her to set the theta, phi, rho and orientation values to quickly reposition the plot, as the plot models are so large, the controls can take 5 to 10 seconds to respond to a single click.

Any thoughts?

Thanks, David

david.gilbert
JFreeChart Project Leader
Posts: 11734
Joined: Fri Mar 14, 2003 10:29 am
antibot: No, of course not.
Contact:

Re: ViewPoint3D units

Post by david.gilbert » Thu Nov 17, 2016 9:54 am

It is still on my TODO list to look at this one. I think it could be a bug that I have to fix.
David Gilbert
JFreeChart Project Leader

:idea: Read my blog
:idea: Support JFree via the Github sponsorship program

david.gilbert
JFreeChart Project Leader
Posts: 11734
Joined: Fri Mar 14, 2003 10:29 am
antibot: No, of course not.
Contact:

Re: ViewPoint3D units

Post by david.gilbert » Thu Aug 03, 2017 11:35 am

I figured out the issue here. The following constructor for ViewPoint3D:

Code: Select all

public ViewPoint3D(double theta, double phi, double rho, double orientation);
...when populated with the values from an existing ViewPoint3D will *not* create an exact replica in all (or most) cases. The reason is that the ViewPoint3D instance maintains an internal reference vector that determines the direction "up" from the perspective of the viewer. This vector is updated as the viewpoint is adjusted, but the constructor above initialises a default vector that won't match the setting from an existing viewpoint.

The solution will be either to add a new constructor like this:

Code: Select all

    public ViewPoint3D(double theta, double phi, double rho, double orientation, Point3D up) {
        this.theta = theta;
        this.phi = phi;
        this.rho = rho;
        updateMatrixElements();
        this.rotation = new Rotate3D( Point3D.ORIGIN, Point3D.UNIT_Z, 
                orientation);
        this.up = up;
        this.workspace = new double[3];  
    }
...or a copy constructor, or make the class cloneable. I'll consider the options and make a new release soon.
David Gilbert
JFreeChart Project Leader

:idea: Read my blog
:idea: Support JFree via the Github sponsorship program

daress
Posts: 23
Joined: Tue Mar 13, 2007 4:52 pm
Contact:

Re: ViewPoint3D units

Post by daress » Fri May 25, 2018 7:03 pm

Thank you David!

I added the constructor to accept the Point3D up to my local copy of Orson charts, and that fixed my issues.

Thank you again for both Orson Charts and JFreeCharts - they have made my work look great!

David

AMADO
Posts: 1
Joined: Mon Jul 22, 2019 11:27 am
antibot: No, of course not.

Re: ViewPoint3D units

Post by AMADO » Sat Jul 27, 2019 8:40 am

Decent, need to accomplish something like this with mine.

Locked