Allow defining different fonts for major/minor ticks and for HiDPI/NoHiDPI case

This commit is contained in:
Martin Pernollet 2021-04-24 11:28:20 +02:00
parent 362b2f0862
commit 9dcb6de60d
17 changed files with 269 additions and 168 deletions

View File

@ -1,7 +1,5 @@
package org.jzy3d.painters;
import org.checkerframework.checker.fenum.qual.AwtFlowLayout;
/**
* A Font subset supported both by OpenGL 1 and AWT. These fonts can be used both for charts based
* on native OpenGL and charts based on raw AWT.
@ -22,6 +20,13 @@ import org.checkerframework.checker.fenum.qual.AwtFlowLayout;
* {@link IPainter#BITMAP_HELVETICA_12} will apply.
*/
public class Font {
public enum HiDPI{
ON,OFF;
public static HiDPI from(boolean hidpi) {
if(hidpi) return ON; return OFF;
}
}
private static final int STYLE_UNDEFINED = -1;
// Font constants below are picked from GLU object in JOGL
protected static final int STROKE_ROMAN = 0;

View File

@ -11,7 +11,7 @@ import org.jzy3d.painters.IPainter;
import org.jzy3d.painters.RenderMode;
import org.jzy3d.plot3d.primitives.PolygonFill;
import org.jzy3d.plot3d.primitives.PolygonMode;
import org.jzy3d.plot3d.primitives.axis.layout.AxisBoxLayout;
import org.jzy3d.plot3d.primitives.axis.layout.AxisLayout;
import org.jzy3d.plot3d.primitives.axis.layout.IAxisLayout;
import org.jzy3d.plot3d.primitives.axis.layout.ZAxisSide;
import org.jzy3d.plot3d.rendering.view.Camera;
@ -33,7 +33,7 @@ public class AxisBox implements IAxis {
static Logger LOGGER = Logger.getLogger(AxisBox.class);
public AxisBox(BoundingBox3d bbox) {
this(bbox, new AxisBoxLayout());
this(bbox, new AxisLayout());
}
public AxisBox(BoundingBox3d bbox, IAxisLayout layout) {
@ -43,7 +43,7 @@ public class AxisBox implements IAxis {
else
setAxe(new BoundingBox3d(-1, 1, -1, 1, -1, 1));
wholeBounds = new BoundingBox3d();
textRenderer = new TextBitmapRenderer(layout.getFont());
textRenderer = new TextBitmapRenderer();
init();
}

View File

@ -2,15 +2,77 @@ package org.jzy3d.plot3d.primitives.axis.layout;
import org.jzy3d.colors.Color;
import org.jzy3d.painters.Font;
import org.jzy3d.painters.Font.HiDPI;
import org.jzy3d.plot3d.primitives.axis.layout.providers.ITickProvider;
import org.jzy3d.plot3d.primitives.axis.layout.providers.SmartTickProvider;
import org.jzy3d.plot3d.primitives.axis.layout.renderers.DefaultDecimalTickRenderer;
import org.jzy3d.plot3d.primitives.axis.layout.renderers.ITickRenderer;
public class AxisBoxLayout implements IAxisLayout {
public class AxisLayout implements IAxisLayout {
protected boolean tickLineDisplayed = true;
protected Font font = Font.Helvetica_12;
protected Font fontNoHiDPI = Font.Helvetica_12;
protected Font fontHiDPI = Font.Helvetica_18;
protected Font fontMajorHiDPI = Font.Helvetica_18;
protected Font fontMinorHiDPI = Font.Helvetica_12;
protected Font fontMajorNoHiDPI = Font.Helvetica_12;
protected Font fontMinorNoHiDPI = Font.Helvetica_10;
// protected Font hiDPIMajourFont
protected String xAxeLabel;
protected String yAxeLabel;
protected String zAxeLabel;
protected boolean xAxeLabelDisplayed;
protected boolean yAxeLabelDisplayed;
protected boolean zAxeLabelDisplayed;
protected double xTicks[];
protected double yTicks[];
protected double zTicks[];
protected ITickProvider xTickProvider;
protected ITickProvider yTickProvider;
protected ITickProvider zTickProvider;
protected ITickRenderer xTickRenderer;
protected ITickRenderer yTickRenderer;
protected ITickRenderer zTickRenderer;
protected Color xTickColor;
protected Color yTickColor;
protected Color zTickColor;
protected boolean xTickLabelDisplayed;
protected boolean yTickLabelDisplayed;
protected boolean zTickLabelDisplayed;
protected boolean faceDisplayed;
protected Color quadColor;
protected Color gridColor;
protected double lastXmin = Float.NaN;
protected double lastXmax = Float.NaN;
protected double lastYmin = Float.NaN;
protected double lastYmax = Float.NaN;
protected double lastZmin = Float.NaN;
protected double lastZmax = Float.NaN;
protected Color mainColor;
protected ZAxisSide zAxisSide = ZAxisSide.RIGHT;
/** Default AxeBox layout */
public AxisBoxLayout() {
public AxisLayout() {
setXAxisLabel("X");
setYAxisLabel("Y");
setZAxisLabel("Z");
@ -320,6 +382,17 @@ public class AxisBoxLayout implements IAxisLayout {
this.tickLineDisplayed = tickLineDisplayed;
}
@Override
public ZAxisSide getZAxisSide() {
return zAxisSide;
}
@Override
public void setZAxisSide(ZAxisSide zAxisSide) {
this.zAxisSide = zAxisSide;
}
@Override
public Font getFont() {
return font;
@ -330,68 +403,83 @@ public class AxisBoxLayout implements IAxisLayout {
this.font = font;
}
public ZAxisSide getZAxisSide() {
return zAxisSide;
/**
* Get registered font according to conditions
*
* @param type the major/minor font case
* @param hidpi the HiDPI context for this font, allowing to define bigger fonts in case screen
* resolution is high (and text small)
*/
@Override
public Font getFont(FontType type, HiDPI hidpi) {
if (type == null) {
// most frequent case so keep first in this selection
if (HiDPI.ON.equals(hidpi)) {
return fontMajorHiDPI;
} else if (HiDPI.OFF.equals(hidpi)) {
return fontMajorNoHiDPI;
}
public void setZAxisSide(ZAxisSide zAxisSide) {
this.zAxisSide = zAxisSide;
} else if (FontType.Major.equals(type)) {
if (HiDPI.ON.equals(hidpi)) {
return fontMajorHiDPI;
} else if (HiDPI.OFF.equals(hidpi)) {
return fontMajorNoHiDPI;
}
} else if (FontType.Minor.equals(type)) {
if (HiDPI.ON.equals(hidpi)) {
return fontMinorHiDPI;
} else if (HiDPI.OFF.equals(hidpi)) {
return fontMinorNoHiDPI;
}
}
return null;
// return font;
}
/**********************************************************/
protected boolean tickLineDisplayed = true;
protected Font font = Font.Helvetica_10;
protected String xAxeLabel;
protected String yAxeLabel;
protected String zAxeLabel;
protected boolean xAxeLabelDisplayed;
protected boolean yAxeLabelDisplayed;
protected boolean zAxeLabelDisplayed;
protected double xTicks[];
protected double yTicks[];
protected double zTicks[];
protected ITickProvider xTickProvider;
protected ITickProvider yTickProvider;
protected ITickProvider zTickProvider;
protected ITickRenderer xTickRenderer;
protected ITickRenderer yTickRenderer;
protected ITickRenderer zTickRenderer;
protected Color xTickColor;
protected Color yTickColor;
protected Color zTickColor;
protected boolean xTickLabelDisplayed;
protected boolean yTickLabelDisplayed;
protected boolean zTickLabelDisplayed;
protected boolean faceDisplayed;
protected Color quadColor;
protected Color gridColor;
protected double lastXmin = Float.NaN;
protected double lastXmax = Float.NaN;
protected double lastYmin = Float.NaN;
protected double lastYmax = Float.NaN;
protected double lastZmin = Float.NaN;
protected double lastZmax = Float.NaN;
protected Color mainColor;
protected ZAxisSide zAxisSide = ZAxisSide.RIGHT;
/**
* Get font according to a given context
*
* @param font the font to use for the context
* @param type the major/minor font possibilites that a drawable or colorbar may use
* @param hidpi the HiDPI context for this font, allowing to define bigger fonts in case screen
* resolution is high (and text small)
*/
@Override
public void setFont(Font font, FontType type, HiDPI hidpi) {
if (FontType.Major.equals(type)) {
if (HiDPI.ON.equals(hidpi)) {
fontMajorHiDPI = font;
} else if (HiDPI.OFF.equals(hidpi)) {
fontMajorNoHiDPI = font;
}
} else if (FontType.Minor.equals(type)) {
if (HiDPI.ON.equals(hidpi)) {
fontMinorHiDPI = font;
} else if (HiDPI.OFF.equals(hidpi)) {
fontMinorNoHiDPI = font;
}
}
}
@Override
public Font getFont(HiDPI hidpi) {
if (HiDPI.ON.equals(hidpi)) {
return fontHiDPI;
} else if (HiDPI.OFF.equals(hidpi)) {
return fontNoHiDPI;
}
return font;
}
@Override
public void setFont(Font font, HiDPI hidpi) {
if (HiDPI.ON.equals(hidpi)) {
fontHiDPI = font;
} else if (HiDPI.OFF.equals(hidpi)) {
fontNoHiDPI = font;
}
}
}

View File

@ -125,6 +125,16 @@ public interface IAxisLayout {
public Color getZTickColor();
public Font getFont();
public void setFont(Font font);
public Font getFont(FontType type, Font.HiDPI hidpi);
public void setFont(Font font, FontType type, Font.HiDPI hidpi);
public Font getFont(Font.HiDPI hidpi);
public void setFont(Font font, Font.HiDPI hidpi);
public enum FontType{
Major,Minor
}
}

View File

@ -115,9 +115,11 @@ public interface ICanvas {
public List<ICanvasListener> getCanvasListeners();
/**
* Temporary way of enabling/disabling a thread watching pixel scale change of a native canvas
* Temporary way of enabling/disabling a thread watching pixel scale change of a native canvas.
*
* Set to false if you encounter threading issues with a native Canvas.
*/
@Deprecated
public static final boolean ALLOW_WATCH_PIXEL_SCALE = false;
public static final boolean ALLOW_WATCH_PIXEL_SCALE = true;
}

View File

@ -17,6 +17,7 @@ import org.jzy3d.maths.Coord2d;
import org.jzy3d.maths.Coord3d;
import org.jzy3d.maths.Rectangle;
import org.jzy3d.painters.Font;
import org.jzy3d.painters.Font.HiDPI;
import org.jzy3d.painters.IPainter;
import org.jzy3d.plot3d.primitives.axis.AxisBox;
import org.jzy3d.plot3d.primitives.axis.IAxis;
@ -31,7 +32,6 @@ import org.jzy3d.plot3d.rendering.scene.Scene;
import org.jzy3d.plot3d.rendering.view.modes.CameraMode;
import org.jzy3d.plot3d.rendering.view.modes.ViewBoundMode;
import org.jzy3d.plot3d.rendering.view.modes.ViewPositionMode;
import org.jzy3d.plot3d.text.renderers.TextBitmapRenderer;
import org.jzy3d.plot3d.transform.Scale;
import org.jzy3d.plot3d.transform.Transform;
import org.jzy3d.plot3d.transform.space.SpaceTransformer;
@ -100,6 +100,7 @@ public class View {
// view states
protected boolean first = true;
protected Font.HiDPI hidpi = HiDPI.OFF;
// constants
public static final float PI_div2 = (float) Math.PI / 2;
@ -194,34 +195,52 @@ public class View {
// if(ICanvas.ALLOW_WATCH_PIXEL_SCALE)
canvas.addCanvasListener(new ICanvasListener() {
/**
* Upon pixel scale change, either at startup or during execution of the program,
* the listener will
* Upon pixel scale change, either at startup or during execution of the program, the listener
* will
* <ul>
* <li>reconfigure the current font of the axis text renderer
* <li>reconfigure the current font of the colorbar
* </ul>
*
* TODO : verify that pixel scale change event do not trigger if hdpi disabled
* AND running on HiDPI screen
* TODO : verify that pixel scale change event do not trigger if hdpi disabled AND running on
* HiDPI screen
*
* TODO : add unit test to verify view changes text when pixelscale change
*/
@Override
public void pixelScaleChanged(double pixelScaleX, double pixelScaleY) {
TextBitmapRenderer txt = (TextBitmapRenderer)axis.getTextRenderer();
System.out.println("View:scale " + pixelScaleX);
if (pixelScaleX <= 1) {
//txt.setFont(Font.TimesRoman_10);
txt.setFont(Font.Helvetica_12);
}
else {
//txt.setFont(Font.TimesRoman_24);
txt.setFont(Font.Helvetica_18);
hidpi = HiDPI.OFF;
//axis.getLayout().setFont(Font.Helvetica_12);
} else {
hidpi = HiDPI.ON;
//axis.getLayout().setFont(Font.Helvetica_18);
}
LOGGER.info("Apply HiDPI " + hidpi);
//System.out.println("Apply HiDPI " + pixelScaleX);
Font font = axis.getLayout().getFont(hidpi);
axis.getLayout().setFont(font);
}
});
}
/**
* Return HiDPI status as ACTUALLY possible by the ICanvas on the current screen and computer,
* regardless of the {@link Quality#setHiDPIEnabled(true)}.
*
* Will always return {@link HiDPI.OFF} is chart is set to {@link Quality#setHiDPIEnabled(false)}
* as this forces the canvas to NOT make use of HiDPI.
*
* @return
*/
public HiDPI getHiDPI() {
return hidpi;
}
public IPainter getPainter() {
return painter;
}
@ -1070,10 +1089,11 @@ public class View {
}
/**
* Update the camera configuration without triggering the {@link Camera#shoot(IPainter, CameraMode)} method.
* Update the camera configuration without triggering the
* {@link Camera#shoot(IPainter, CameraMode)} method.
*
* This is useful in rare case where one need to manually invoke only a subset of OpenGL methods that
* are invoked by shoot method.
* This is useful in rare case where one need to manually invoke only a subset of OpenGL methods
* that are invoked by shoot method.
*/
public void updateCameraWithoutShooting(ViewportConfiguration viewport, BoundingBox3d bounds,
float sceneRadiusScaled, ViewPositionMode viewmode, Coord3d viewpoint, Camera cam,

View File

@ -1,5 +1,6 @@
package org.jzy3d.plot3d.text.renderers;
import java.awt.Graphics2D;
import org.apache.log4j.Logger;
import org.jzy3d.colors.Color;
import org.jzy3d.maths.BoundingBox3d;
@ -14,36 +15,25 @@ import org.jzy3d.plot3d.text.align.TextLayout;
import org.jzy3d.plot3d.text.align.Vertical;
/**
* could enhance using http://www.angelcode.com/products/bmfont/
* The {@link ITextRenderer} is able to draw basic OpenGL font as supported by
* {@link IPainter#glutBitmapString(Font, String, Coord3d, Color)}.
*
* @author Martin
* Concrete painters might rely on
* <ul>
* <li>EmulGL : AWT Font rendering by {@link Graphics2D#drawString(String, float, float)} by using
* jGL AWT helpers.
* <li>Native : GLUT.glutBitmapString(Font, String, Coord3d, Color)
* </ul>
*
* As EmulGL painter relies on AWT, much more font than the base OpenGL one can be used as it is
* backed by AWT.
*/
public class TextBitmapRenderer extends AbstractTextRenderer implements ITextRenderer {
protected static Logger LOGGER = Logger.getLogger(TextBitmapRenderer.class);
protected Font font;
protected TextLayout layout = new TextLayout();
/**
* The TextBitmap class provides support for drawing ASCII characters Any non ascii caracter will
* be replaced by a square.
*/
public TextBitmapRenderer() {
this(Font.Helvetica_10);
}
public TextBitmapRenderer(Font font) {
this.font = font;
}
public Font getFont() {
return font;
}
public void setFont(Font font) {
this.font = font;
}
public TextBitmapRenderer() {}
/**
* Draw a string at the specified position and return the 3d volume occupied by the string
@ -75,7 +65,7 @@ public class TextBitmapRenderer extends AbstractTextRenderer implements ITextRen
painter.glutBitmapString(font, text, positionAligned, color);
// Return text bounds
return computeTextBounds(painter, screenAligned, textWidth);
return computeTextBounds(painter, font, screenAligned, textWidth);
}
/** Left as a helper for subclasses. TODO delete me and subclass */
@ -101,8 +91,8 @@ public class TextBitmapRenderer extends AbstractTextRenderer implements ITextRen
return model;
}
protected BoundingBox3d computeTextBounds(IPainter painter, Coord3d posScreenShifted,
float strlen) {
protected BoundingBox3d computeTextBounds(IPainter painter, Font font,
Coord3d posScreenShifted, float strlen) {
Coord3d botLeft = new Coord3d();
Coord3d topRight = new Coord3d();
botLeft.x = posScreenShifted.x;

View File

@ -112,18 +112,6 @@ public class TestChart {
Assert.assertFalse(mouse.getThread().isUpdateViewDefault());
}
@Ignore
@Test
public void whenChartAxisLayoutHasCustomFont_ThenAxisBoxHasThisFont() {
Chart chart = new EmulGLChartFactory().newChart();
chart.getAxisLayout().setFont(Font.TimesRoman_24);
AxisBox axis = (AxisBox) chart.getView().getAxis();
TextBitmapRenderer tbr = (TextBitmapRenderer) axis.getTextRenderer();
Assert.assertEquals(Font.TimesRoman_24, tbr.getFont());
}
@Test
public void givenEmulatedChart_whenAddSurface_thenViewIsInAutotFitMode() {

View File

@ -51,8 +51,8 @@ public class ITTestHiDPI {
Chart chart = factory.newChart(q);
chart.add(surface);
chart.getAxisLayout().setZAxisSide(ZAxisSide.LEFT);
TextBitmapRenderer tbr = ((TextBitmapRenderer)((AxisBox)chart.getView().getAxis()).getTextRenderer());
tbr.setFont(Font.TimesRoman_24);
chart.getAxisLayout().setFont(Font.TimesRoman_24);
surface.setLegend(new AWTColorbarLegend(surface, chart.getView().getAxis().getLayout()));
// --------------------------------

View File

@ -81,9 +81,7 @@ public class SurfaceDemoEmulGL_Multithreaded {
EmulGLCanvas c = (EmulGLCanvas) chart.getCanvas();
c.setProfileDisplayMethod(true);
c.getGL().setAutoAdaptToHiDPI(true);
//chart.getAxisLayout().setFont(Font.Helvetica_18);
((TextBitmapRenderer)((AxisBox)chart.getView().getAxis()).getTextRenderer()).setFont(Font.TimesRoman_10);
chart.getAxisLayout().setFont(Font.TimesRoman_10);
chart.open();
// --------------------------------

View File

@ -122,7 +122,7 @@ public class AxisBox2d extends AxisBox {
glRasterPos(painter, sceneOffset, Coord3d.ORIGIN);
painter.glutBitmapString(font.getCode(), text);
return computeTextBounds(painter, screenAligned, textWidth);
return computeTextBounds(painter, font, screenAligned, textWidth);
}
// CUSTOM ROTATION

View File

@ -91,15 +91,15 @@ public class CanvasAWT extends GLCanvas implements IScreenCanvas, INativeCanvas
exec.schedule(new PixelScaleWatch() {
@Override
public double getPixelScaleY() {
return getPixelScaleX();
return CanvasAWT.this.getPixelScaleX();
}
@Override
public double getPixelScaleX() {
return getPixelScaleY();
return CanvasAWT.this.getPixelScaleY();
}
@Override
protected void firePixelScaleChanged(double pixelScaleX, double pixelScaleY) {
firePixelScaleChanged(pixelScaleX, pixelScaleY);
CanvasAWT.this.firePixelScaleChanged(pixelScaleX, pixelScaleY);
}
}, 0, TimeUnit.SECONDS);
}

View File

@ -94,15 +94,15 @@ public class CanvasNewtAwt extends Panel implements IScreenCanvas, INativeCanvas
exec.schedule(new PixelScaleWatch() {
@Override
public double getPixelScaleY() {
return getPixelScaleX();
return CanvasNewtAwt.this.getPixelScaleX();
}
@Override
public double getPixelScaleX() {
return getPixelScaleY();
return CanvasNewtAwt.this.getPixelScaleY();
}
@Override
protected void firePixelScaleChanged(double pixelScaleX, double pixelScaleY) {
firePixelScaleChanged(pixelScaleX, pixelScaleY);
CanvasNewtAwt.this.firePixelScaleChanged(pixelScaleX, pixelScaleY);
}
}, 0, TimeUnit.SECONDS);
}

View File

@ -87,15 +87,15 @@ public class CanvasSwing extends GLJPanel implements IScreenCanvas, INativeCanva
exec.schedule(new PixelScaleWatch() {
@Override
public double getPixelScaleY() {
return getPixelScaleX();
return CanvasSwing.this.getPixelScaleX();
}
@Override
public double getPixelScaleX() {
return getPixelScaleY();
return CanvasSwing.this.getPixelScaleY();
}
@Override
protected void firePixelScaleChanged(double pixelScaleX, double pixelScaleY) {
firePixelScaleChanged(pixelScaleX, pixelScaleY);
CanvasSwing.this.firePixelScaleChanged(pixelScaleX, pixelScaleY);
}
}, 0, TimeUnit.SECONDS);
}

View File

@ -39,10 +39,10 @@ public class SurfaceDemoEmulGL {
// (tutorials built with Java 8 for backward compatibility, update your runtime to get HiDPI)
Chart chart = factory.newChart(q);
chart.add(surface);
chart.getAxisLayout().setFont(Font.Helvetica_12);
EmulGLSkin skin = EmulGLSkin.on(chart);
skin.getCanvas().setProfileDisplayMethod(true);
skin.getAxisTextRenderer().setFont(Font.Helvetica_12);
chart.open();
chart.addMouseCameraController();

Binary file not shown.

Before

Width:  |  Height:  |  Size: 359 KiB

After

Width:  |  Height:  |  Size: 359 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 200 KiB

After

Width:  |  Height:  |  Size: 200 KiB