0

view panning and the coordinate axis symbol

Frank 3 years ago in Defect? updated by egon sepp 3 years ago 7

I have a HelixViewport3D window in a WPF app, with Pan and axis coordinate features enabled. I am rendering a 'point-cloud' using PointsVisual3D. When I Pan the point-cloud around, the coordinate axis stays in the center of the view instead of moving with the point cloud, and this seems wrong. I thought that the 'Pan' operation simply translated the camera around in the current viewing plane, which would make everything in the model (including the coordinate axis symbol) move together, but clearly this is not the case.


This screenshot shows the situation: The left-hand HelixViewport3D viewport shows a point collection panned off center, while the right-hand viewport shows the original, unpanned setup.



What am I missing, and what do I need to do to make sure the coordinate symbol stays in the same relative position with respect to other model elements when panning the view?


TIA,


Frank


Add a coordinate system urself, do not use the one of the helixviewport with center/center.

The one of the helixviewport is the global axis and always stays relative to the whole viewport.


Easiest way: in your xaml:


<!-- You can also add elements here in the xaml -->
<HelixToolkit:GridLinesVisual3D Width="8" Length="8" MinorDistance="1" MajorDistance="1" Thickness="0.01"/>

<HelixToolkit:CoordinateSystemVisual3D />

Got it - Thanks! Is there any way at present to add labels to the 'geometry-centered' coordinate system? I saw there was an issue (Issue #18) about this, with the notation that labels were added, but I don't see that anywhere in the available properties for CoordinateSystemVisual3D, nor did I see anything in the class code source. Am I missing something?


Frank



Remember, in no way the coordinate system is geometry centered. It is just a coordinate system positioned at (0,0,0).

No, it's not implemented as far as I know.


What you could do is this:

<HelixToolkit:CoordinateSystemVisual3D />
<HelixToolkit:BillboardTextVisual3D Position="1.2 0 0" Text="X" /> <HelixToolkit:BillboardTextVisual3D Position="0 1.2 0" Text="Y" /> <HelixToolkit:BillboardTextVisual3D Position="0 0 1.2" Text="Z" />

Or simply write your own CoordincateSystemVisual-class. If you subclass the existing one it shouldn't be that hard.

Thanks for the info. As an exercise, I attempted to write the subclass you suggested, but got stuck on setting the default property for the axis label. A snippet showing the problem is included below:

        public static readonly DependencyProperty XAxisLabelProperty = DependencyProperty.Register(
            "XAxisLabel",
            typeof(BillboardTextItem),
            typeof(LabeledCoordSysVis3D),
            new UIPropertyMetadata("X"));

The above code compiles fine, but the line


            <local:LabeledCoordSysVis3D />

shows the error "Default value type does not match tpe of property 'XAxisLabel' :-(


I confess that I really don't know what I'm doing in this DependencyPropery declaration, but I tried to copy from the CoordinateSystemVisual3D declaration as much as possible. What I'm trying to do here is set the default property of the X axis label to "X" - what's the proper way to do this?


Full code for the 'LabeledCoordSysVis3D' class is provided below:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using HelixToolkit.Wpf;
using System.Windows;
using System.Windows.Media;
using System.Windows.Media.Media3D;

namespace MyWPFMagViewer2
{
    class LabeledCoordSysVis3D:CoordinateSystemVisual3D
    {
        #region Constants and Fields

        /// <summary>
        /// The arrow lengths property.
        /// </summary>
        public static readonly DependencyProperty AxisLabelSizeProperty = DependencyProperty.Register(
            "AxisLabelSize",
            typeof(double),
            typeof(LabeledCoordSysVis3D),
            new UIPropertyMetadata(1.0, GeometryChanged));

        /// <summary>
        /// The x axis color property.
        /// </summary>
        public static readonly DependencyProperty XAxisLabelProperty = DependencyProperty.Register(
            "XAxisLabel",
            typeof(BillboardTextItem),
            typeof(LabeledCoordSysVis3D),
            new UIPropertyMetadata("X"));

        /// <summary>
        /// The y axis color property.
        /// </summary>
        public static readonly DependencyProperty YAxisLabelProperty = DependencyProperty.Register(
            "YAxisLabel",
            typeof(BillboardTextItem),
            typeof(LabeledCoordSysVis3D),
            new UIPropertyMetadata("Y"));

        /// <summary>
        /// The z axis color property.
        /// </summary>
        public static readonly DependencyProperty ZAxisLabelProperty = DependencyProperty.Register(
            "ZAxisLabel",
            typeof(BillboardTextItem),
            typeof(LabeledCoordSysVis3D),
            new UIPropertyMetadata("Z"));
        #endregion

        #region Constructors and Destructors

        /// <summary>
        ///   Initializes a new instance of the <see cref = "LabeledCoordSysVis3D" /> class.
        /// </summary>
        public LabeledCoordSysVis3D()
        {
            this.OnGeometryChanged();
        }

        #endregion

        #region Public Properties

        /// <summary>
        ///   Gets or sets the label size.
        /// </summary>
        /// <value>The label size.</value>
        public double AxisLabelSize
        {
            get
            {
                return (double)this.GetValue(AxisLabelSizeProperty);
            }

            set
            {
                this.SetValue(AxisLabelSizeProperty, value);
            }
        }

        /// <summary>
        ///   Gets or sets the label of the X axis.
        /// </summary>
        /// <value>The label of the X axis.</value>
        public Color XAxisLabel
        {
            get
            {
                return (Color)this.GetValue(XAxisLabelProperty);
            }

            set
            {
                this.SetValue(XAxisLabelProperty, value);
            }
        }

        /// <summary>
        ///   Gets or sets the label of the Y axis.
        /// </summary>
        /// <value>The label of the Y axis.</value>
        public Color YAxisLabel
        {
            get
            {
                return (Color)this.GetValue(YAxisLabelProperty);
            }

            set
            {
                this.SetValue(YAxisLabelProperty, value);
            }
        }

        /// <summary>
        ///   Gets or sets the label of the Z axis.
        /// </summary>
        /// <value>The label of the Z axis.</value>
        public Color ZAxisLabel
        {
            get
            {
                return (Color)this.GetValue(ZAxisLabelProperty);
            }

            set
            {
                this.SetValue(ZAxisLabelProperty, value);
            }
        }

        #endregion

        #region Methods

        /// <summary>
        /// The geometry changed.
        /// </summary>
        /// <param name="obj">
        /// The obj.
        /// </param>
        /// <param name="args">
        /// The args.
        /// </param>
        protected new static void GeometryChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args)
        {
            ((LabeledCoordSysVis3D)obj).OnGeometryChanged();
        }

        /// <summary>
        /// Called when the geometry has changed.
        /// </summary>
        protected override void OnGeometryChanged()
        {
            this.Children.Clear();
            double h = this.AxisLabelSize;

            var xlabel = new BillboardTextVisual3D();
            xlabel.Text = XAxisLabel.ToString();
            xlabel.Foreground = new SolidColorBrush(this.XAxisColor);
            xlabel.HeightFactor = AxisLabelSize;
            xlabel.Position = new Point3D(ArrowLengths * 1.1, 0, 0);
            this.Children.Add(xlabel);

            var ylabel = new BillboardTextVisual3D();
            ylabel.Text = XAxisLabel.ToString();
            ylabel.Foreground = new SolidColorBrush(this.XAxisColor);
            ylabel.HeightFactor = AxisLabelSize;
            ylabel.Position = new Point3D(ArrowLengths * 1.1, 0, 0);
            this.Children.Add(ylabel);

            var zlabel = new BillboardTextVisual3D();
            zlabel.Text = XAxisLabel.ToString();
            zlabel.Foreground = new SolidColorBrush(this.XAxisColor);
            zlabel.HeightFactor = AxisLabelSize;
            zlabel.Position = new Point3D(ArrowLengths * 1.1, 0, 0);
            this.Children.Add(zlabel);
        }

        #endregion
    }
}


"x" is string

XAxisLabel has type Color... why?

XAxisLabelProperty is registered with type BillboardTextItem.. why?

Egon,


Thanks! With the clues you provided, I have been able to get the subclass working properly. Here's a screenshot of my magnetometer calibration tool, with the left-hand 'raw' viewport coordinate axis symbol created using '<local:LabeledCoordSysVis3D />', and the right-hand 'calibrated' viewport symbol created using

            <h:CoordinateSystemVisual3D /> <!--added 07/12/16 for 'geometry-centered' vs 'viewport-centered' coord sys -->
            <h:BillboardTextVisual3D Position="1.2 0 0" Text="X" />
            <h:BillboardTextVisual3D Position="0 1.2 0" Text="Y" />
            <h:BillboardTextVisual3D Position="0 0 1.2" Text="Z" />

The only visible difference between the two is that the 'X', 'Y', & 'Z' labels on the left are colored the same as the axis arrows, while the ones on the right are all black text.



The next screenshot shows the XAML for both windows and the exposed properties for both the LabeledCoordSysVis3D and CoordinateSystemVisual3D classes



And here is the complete - now working thanks to Egon! - subclass code:


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using HelixToolkit.Wpf;
using System.Windows;
using System.Windows.Media;
using System.Windows.Media.Media3D;

namespace MyWPFMagViewer2
{
    class LabeledCoordSysVis3D:CoordinateSystemVisual3D
    {
        #region Constants and Fields

        /// <summary>
        /// The arrow lengths property.
        /// </summary>
        public static readonly DependencyProperty AxisLabelSizeProperty = DependencyProperty.Register(
            "AxisLabelSize",
            typeof(double),
            typeof(LabeledCoordSysVis3D),
            new UIPropertyMetadata(1.0, GeometryChanged));

        ///// <summary>
        ///// The x axis label property.
        ///// </summary>
        //public static readonly DependencyProperty XAxisLabelProperty = DependencyProperty.Register(
        //    "XAxisLabel",
        //    typeof(BillboardTextItem),
        //    typeof(LabeledCoordSysVis3D),
        //    new UIPropertyMetadata("X"));
        /// <summary>
        /// The x axis label property.
        /// </summary>
        public static readonly DependencyProperty XAxisLabelProperty = DependencyProperty.Register(
            "XAxisLabel",
            typeof(string),
            typeof(LabeledCoordSysVis3D),
            new UIPropertyMetadata("X"));

        /// <summary>
        /// The y axis color property.
        /// </summary>
        public static readonly DependencyProperty YAxisLabelProperty = DependencyProperty.Register(
            "YAxisLabel",
            typeof(string),
            typeof(LabeledCoordSysVis3D),
            new UIPropertyMetadata("Y"));

        /// <summary>
        /// The z axis color property.
        /// </summary>
        public static readonly DependencyProperty ZAxisLabelProperty = DependencyProperty.Register(
            "ZAxisLabel",
            typeof(string),
            typeof(LabeledCoordSysVis3D),
            new UIPropertyMetadata("Z"));
        #endregion

        #region Constructors and Destructors

        /// <summary>
        ///   Initializes a new instance of the <see cref = "LabeledCoordSysVis3D" /> class.
        /// </summary>
        public LabeledCoordSysVis3D()
        {
            base.OnGeometryChanged();
            this.OnGeometryChanged();
        }

        #endregion

        #region Public Properties

        /// <summary>
        ///   Gets or sets the label size.
        /// </summary>
        /// <value>The label size.</value>
        public double AxisLabelSize
        {
            get
            {
                return (double)this.GetValue(AxisLabelSizeProperty);
            }

            set
            {
                this.SetValue(AxisLabelSizeProperty, value);
            }
        }

        /// <summary>
        ///   Gets or sets the label of the X axis.
        /// </summary>
        /// <value>The label of the X axis.</value>
        public string XAxisLabel
        {
            get
            {
                return (string)GetValue(XAxisLabelProperty);
            }

            set
            {
                this.SetValue(XAxisLabelProperty, value);
            }
        }

        /// <summary>
        ///   Gets or sets the label of the Y axis.
        /// </summary>
        /// <value>The label of the Y axis.</value>
        public string YAxisLabel
        {
            get
            {
                return (string)GetValue(YAxisLabelProperty);
            }

            set
            {
                this.SetValue(YAxisLabelProperty, value);
            }
        }

        /// <summary>
        ///   Gets or sets the label of the Z axis.
        /// </summary>
        /// <value>The label of the Z axis.</value>
        public string ZAxisLabel
        {
            get
            {
                return (string)GetValue(ZAxisLabelProperty);
            }

            set
            {
                this.SetValue(ZAxisLabelProperty, value);
            }
        }

        #endregion

        #region Methods

        /// <summary>
        /// The geometry changed.
        /// </summary>
        /// <param name="obj">
        /// The obj.
        /// </param>
        /// <param name="args">
        /// The args.
        /// </param>
        protected new static void GeometryChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args)
        {
            ((LabeledCoordSysVis3D)obj).OnGeometryChanged();
        }

        /// <summary>
        /// Called when the geometry has changed.
        /// </summary>
        protected override void OnGeometryChanged()
        {
            base.OnGeometryChanged();
            //this.Children.Clear();
            double h = this.AxisLabelSize;

            var xlabel = new BillboardTextVisual3D();
            xlabel.Text = XAxisLabel.ToString();
            xlabel.Foreground = new SolidColorBrush(this.XAxisColor);
            xlabel.HeightFactor = AxisLabelSize;
            xlabel.Position = new Point3D(ArrowLengths * 1.2, 0, 0);
            this.Children.Add(xlabel);

            var ylabel = new BillboardTextVisual3D();
            ylabel.Text = YAxisLabel.ToString();
            ylabel.Foreground = new SolidColorBrush(this.YAxisColor);
            ylabel.HeightFactor = AxisLabelSize;
            ylabel.Position = new Point3D(0, ArrowLengths * 1.2, 0);
            this.Children.Add(ylabel);

            var zlabel = new BillboardTextVisual3D();
            zlabel.Text = ZAxisLabel.ToString();
            zlabel.Foreground = new SolidColorBrush(this.ZAxisColor);
            zlabel.HeightFactor = AxisLabelSize;
            zlabel.Position = new Point3D(0, 0, ArrowLengths * 1.2);
            this.Children.Add(zlabel);
        }

        #endregion
    }
}

I'm sure others can do a better job than this, but I learned a LOT getting this far, and I really appreciate the help from Egon and others - THANKS!!


Frank


If you don't like the Labels having the same colors as the axis, remove the lines


zlabel.Foreground = new SolidColorBrush(this.ZAxisColor);

also maybe think about using zlabel.FontSize instead of zlabel.HeightFactor. I like the result more ;)