[Kst] Kst2DRenderer + Refactoring Proposal

Barth Netterfield netterfield at physics.utoronto.ca
Mon Oct 24 23:55:05 CEST 2005


I will read this in more detail, but my first comment it:

Our #1 priority needs to be to get kst, with its current feature set, into a 
solid and bugfree state ASAP.  Any re-factoring, or optimizing, or whatever 
else which is detrimental to this goal needs to be avoided until 1.2 is 
released.  We have added a huge number of great new things over the last few 
months, but it has introduced more regressions than you can shake a stick at.

So: if we are going to do any major changes to 2dplot, they can't be started 
until 1.2 is released.

cbn

On October 24, 2005 05:09 pm, Ted Kisner wrote:
> Hello kst folks,
>
> here is a more detailed proposal to accomodate painting data in
> non-cartesian coordinate systems.  Also includes some refactoring of
> Kst2DPlot.
>
> Basically I have tried to go through all the existing code and determine
> what kind of class interface is needed and then have tried to create that
> class. Feedback is very welcome- especially anything I missed in the
> "implementation" section.
>
> If you all like these ideas, then we can move to the next step of testing
> some code.  Since there are so many changes involved, I think it would be
> safest if I either made a temporary patchset against svn HEAD and posted
> this for people play with, or created an "experimental" branch in svn for a
> few weeks-- but I recall George mentioning that this is a maintenance
> nightmare.  Also, I have no idea how difficult it is to merge changes
> between branches later.  I imagine this is done by hand by taking an svn
> diff from one branch and attempting to merge it to the other...
>
> Also, I see on the list that there is talk of changing the plotdialog
> around- so this would impact a couple steps in the implementation below.
>
> -Ted
>
>
> Background
> -----------
>
> A)  Current configuration.  The painting code is currently set up like
> this:
>
> KstApp : KMdiMainFrm
>   \
>    ---> KstViewWindow : KMdiChildFrm
>           \
>             ---> KstTopLevelView
>                  (friend) KstViewWidget
>                  o The top level view has an instance of a QPainter
>                    which is set to draw on the KstViewWidget.
>                  o The top level view has a list of KstViewObjects
>                    which it calls on to paint on the QPainter.
>
> B)  One such descendent of KstViewObject is
> Kst2DPlot : KstPlotBase : KstMetaPlot : KstBorderedViewObject :
> KstViewObject
>
> C)  Kst2DPlot draws the axes, legends, tick marks, etc and then calls on
> all KstBaseCurves to paint themselves.  The base curves are provided with
> the QPainter reference to paint to.
>
>
> Definitions
> ------------
>
> 1.  For this discussion, 2D "rendering" is the act of taking data lying in
> a general 2D coordinate space (U,V) and drawing it (using QPainter
> primitives) in a section of the cartesian (window space) plane.
>
> 2.  For this discussion, 3D "rendering" is the act of taking data lying in
> a general 3D coordinate space (U,V,W) and drawing it (using, e.g. OpenGL)
> in a section of cartesian space.
>
> So when I say "render", what I really mean is a combination of a coordinate
> transformation/projection to cartesian space and then painting this
> cartesian data to a window.
>
>
> Proposal
> ----------
>
> I propose the creation of a new Kst2DRenderer (3D will come later, once we
> have Kst3DPlot working).  This new object will wrap a QPainter and provide
> an interface for drawing in terms of native U/V coordinates.  The goals are
> the following:
>
> a)  Remove all notion of "X and Y" coordinates-- unless we decide to keep
> calling it "X" and "Y" when we mean U/V, in order to minimize code changes.
> All work is done in native (U,V) coordinates and the window coordinates of
> a QPainter.  The currently selected Kst2DRenderer determines how things in
> (U,V) space are drawn to the QPainter.
>
> b)  All QPainter commands in 2DPlot and the basecurves that involve (U,V)
> space coordinates are converted into calls to a Kst2DRenderer.  This does
> not affect things like drawing the legend or other calls to the QPainter
> that are in terms of pixels.
>
> This new Kst2DRenderer will have the following members/methods:
>
> 0.  Normal QDom handling and save/load/etc functionality
>
> 1.  Coordinate Range.  The current Min/Max values of the (U,V) coordinate
> space.  There is no a priori restriction on these values, since in some
> cases Min > Max, e.g. a plot of spherical data centered on the prime
> meridian where phi=(3Pi/2...Pi/2).
>
> 2.  Range checking methods.  Each descendent of Kst2DRenderer should check
> that the current range makes sense for the specific type of rendering. 
> Also include methods to check individual U/V values for validity.  If
> values are out of range, return sensible default for this type of
> rendering.  Also provide test functions to determine if a value lies within
> the current range.
>
> 3.  Simple functions for doing coordinate transformations for a single
> ordered pair (U,V) <--> (Xwindow,Ywindow), given the currently specified
> range of the (U,V) space and the current window coordinates of the
> QPainter.
>
> 4.  Graphics primitives, given in terms of (U,V) coordinates, including:
> 	drawPoint
> 	drawLine
> 	drawRect
> 	drawEllipse
> 	drawPixmap
> 	drawPolyLine
> 	Others?
>
> 5.  config dialog, with options specific to the type of rendering being
> done.
>
> See attached files for a rough definition of this class.  In order to
> support polylines in (U,V) coordinates, I have also created a simple
> QValueVector of pairs of doubles-- does such a class already exist?  If so,
> we could just use that instead of the DPointArray I came up with.
>
>
> Typical Useage
> ---------------
>
> Here is a typical example of useage from within Kst2DPlot:
>
> 1.  In Kst2DPlot, the Kst2DRenderer is allocated in the constructor and set
> to the default type (cartesian).
>
> 2.  A combobox in the plotdialog is used to select the desired type of
> Renderer.  Kst2DPlot has a method (called by the dialog) to switch to a new
> type of Renderer (allocate the new and delete the old).
>
> 3.  In the paint/draw functions, the Kst2DRenderer._painter is set to the
> current painter.  The U/V range is set based on the min/max values stored
> in 2DPlot.  The painter window and viewport are set up as they are now. 
> The Kst2DRenderer._pSpace is set to the desired sub-rectangle (in window
> coordinates) of the QPainter  All U/V drawing functions perform the
> necessary projection/painting based on the U/V range and the current
> subsection of the QPainter.window.
>
>
> Implementation
> (including some unrelated refactoring of Kst2DPlot)
> ----------------------------------------------------
>
> Implementation requires some refactoring of Kst2DPlot and modifications to
> the basecurves.  However, I think things will be simpler in the long run
> ;-) Here is (I think) a mostly complete list of the changes needed to
> implement this:
>
> 0.  Do we want to actually rename X and Y in the code to U/V or something
> else?  If not, then "X" and "Y" become our generalized coordinates- they
> are no longer assumed to be cartesian.
>
> 1.  Add a member to Kst2DPlot that is an instance of a Kst2DRenderer.
>
> 2.  Create descendents of Kst2DRenderer for the existing types of plots
> (cartesian and Log).
>
> 3.  Create config dialogs for the cartesian and Log renderers which
> contain the options currently found in the Plotdialog->{X,Y} Axis->Scale
> block (i.e. time display, reversal, etc).
>
> 4.  In Plotdialog.ui, combine the X Axis and Y Axis tabs into a single
> "Axes" tab.  This is similar to how the "Range" tab is set up.  Remove the
> "Scale" sub blocks from these.  Using the resulting extra space in the
> "Axes" tab, add a combobox to choose between the available Kst2DRenderers. 
> Beneath this combo box, have a "configure" button, that can pop up a
> detailed config dialog depending on the selected type of Rendering. 
> Cartesian and Log renderers would have options like displaying interpreted
> axis labels. Spherical/Sinusoidal renderer might have options like display
> in RA/DEC, lat/long, or radians.
>
> 5.  In Kst2DPlot, we no longer need the (many) xlog and ylog boolean flags.
> As far as 2DPlot is concerned, it always draws in U,V coordinates.  Remove
> members _xLog and _yLog.  Remove bools from common constructor.
>
> 6.  In Kst2DPlot, commonConstructor:  call range checking functions in the
> Renderer instead.
>
> 7.  In Kst2DPlot, Move CheckRange and CheckLRange to their respective
> Renderers.
>
> 8.  In Kst2DPlot, have setScale, setXScale and setYscale call the range
> functions in the Renderer.  Remove setLScale, setLXScale and setLYScale.
>
> 9.  In Kst2DPlot, updateScale:  remove all reference to boolean _xLog and
> _yLog.  Simply query basecurves for min/max values.  The autoborder option
> will create a border in U,V coordinates.  Use Renderer's checkRange
> functions.
>
> 10.  In Kst2DPlot, time functions:  Can't we move all this time stuff to a
> "KstTime" class?  We could remove ~330 lines here alone.  I can do this at
> some point, but it's low priority now...
>
> 11.  In Kst2DPlot, time functions and genAxisTick*Label :  Remove log mode
> stuff- "z" will always be either just a number in U/V coordinates or
> interpretted.
>
> 12.  TICK MARKS:  there is a ton of crazy stuff going on in 2DPlot for
> computing where to draw ticks.  There may need to be some changes.  The
> basic method should be:  determine desired U/V tick spacing, check that
> ticks are not too close or far apart in pixel space, if so then autotick,
> draw ticks at locations determined by calling the renderobject's UVtoPix
> function.
>
> 13.  In Kst2DPlot::draw, KstCurveRenderContext should contain a reference
> to the Kst2DRenderer, rather than the raw QPainter.  Basecurves should
> never be drawing directly in pixel coordinates (except for specifying
> certain pixel-sized features in the renderer's primitives).
>
> 14.  In Kst2DPlot, setTicks:  Again, we need to figure out a reworking of
> the tick handling that calls the render object to find out how far apart
> the ticks will be in pixel space.
>
> 15.  In Kst2DPlot, setCursorPos:  getNearestDataPoint finds the closest
> point in U/V space.  Set _cursor_x and _cursor_y by calling render object
> to convert mouse.tracker coordinates to data coordinates.
>
> 16.  In Kst2DPlot, updateMousePos:  use render object to find xpos and ypos
>
> 17.  In Kst2DPlot, getNearestDataPoint:  Use render object to compute the
> current mouse location in U,V coordinates.
>
> 18.  In Kst2DPlot, highlightNearestDataPoint:  Use render object primitive
> to draw highlighted point.
>
> 19.  In Kst2DPlot, mouseReleaseEvent:  Call the render object's coordinate
> transforms to figure out the new U/V range values based on the mouse's
> QRect.
>
> 20.  In Kst2DPlot, remove menuXLogSlot and menuYLogSlot.
>
> 21.  In Kst2DPlot, moveToNextMarker/moveToPrevMarker:  mostly OK, need to
> remove log stuff.  currCenter and newCenter are in terms of U/V
> coordinates.
>
> 22.  In Kst2DPlot, zoomSelfYLocalMax:  Curves return their min/max as
> currently coded.  Call render object for range checking and to get sensible
> values.
>
> 23.  In Kst2DPlot, xZoomNormal/yZoomNormal:  Use renderobject's functions
> to compute new min/max.
>
> 24.  In Kst2DPlot, plotMarkers:  call render object to determine if marker
> value is within the current range.
>
> 25.  In Kst2DPlot, plotPlotMarkers:  call render object's drawLine
> primitive instead.
>
> 26.  In Kst2DPlot, plotAxes:  More tick issues.  Assuming we have already
> determined the correct major/minor spacing in (U,V) coordinates (i.e. in
> setTicks), all we need to do here is for each tick, find the pixel location
> by calling the renderobject's conversion, then draw the tick at this
> location in pixel space using the QPainter.drawLine primitive.  Lots of
> code saving from removing all the Log-based stuff.
>
> 27.  In Kst2DPlot, plotGridLines:  simply call the renderobject's drawLine
> function instead of the QPainter one.
>
> 28.  In Kst2DPlot, mouseDoubleClickEvent:  Use renderobject to find mouse
> location in U/V coordinates.
>
> 29.  In Kst2DPlot, draw:  The KstCurveRenderContext contains too much info.
> We don't need the x_min, y_min, etc that are used for log plots.  We also
> don't need the L/H/m/b variables, since basecurves should not need to know
> about the conversion from U,V to pixels.  All they need is the min/max U/V
> range and a pointer to the Kst2DRenderer.
>
> 29.  In KstBaseCurve:  Change KstCurveRenderContext to contain a pointer to
> a Kst2DRenderer.  Remove useless members.
>
> 30.  In KstVCurve:  When painting, call renderobject's primitives.  Use
> DPointArray (see attached files) of U/V values for polyline function.  This
> should clean out a ton of code in this function, since we don't need to do
> any pixelspace stuff.  For some drawing, we may want objects that have a
> fixed size in pixels (error bar ends, plot symbols, etc).  We can then use
> the "fixed" drawing primitives in Kst2DRenderer.
>
> 31.  In KstImage, paint function:  For colormap, rather than building up a
> QImage and painting it, we should draw each matrix element as a filled
> rectangle in (U,V) space using Kst2DRenderer->fillRect.  This allows the
> renderer to morph each rectangle into some other shape based on the type
> of rendering.  Remove all the pixel crap.  Simply iterate through all
> matrix elements and call fillRect based on the U/V range.
>
> 32.  In KstImage, paint function:  For contours, we have a problem.  The
> contour step is currently specified in pixels.  I don't know what to do
> here- any suggestions?  Aside from this, I think we just need to call
> Kst2DRenderer->drawLine instead of using the QPainter.
>
> 33. Add Kst2DRenderers for other types of display (polar coordinates,
> spherical/sinusoidal, spherical/polar, etc)
>
>
> Future Benefits
> --------------------
>
> OpenGL for 3D and 2D:  one could imagine having KstViewWidget inherit from
> QGLWidget instead of QWidget.  In this case, all KstViewObjects (including
> Kst2DPlot) would have a QGLContext rather than a QPainter reference.  We
> could then modify Kst2DRenderer to draw primitives with OpenGL commands,
> and all basecurve painting would immediately benefit from this enhancement.



More information about the Kst mailing list