OtsRenderableLabeled.java
package org.opentrafficsim.animation;
import javax.naming.OperationNotSupportedException;
import org.djutils.exceptions.Throw;
import org.opentrafficsim.base.geometry.OtsShape;
import nl.tudelft.simulation.naming.context.Contextualized;
/**
* Renderable with label.
* <p>
* Copyright (c) 2026-2026 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
* BSD-style license. See <a href="https://opentrafficsim.org/docs/license.html">OpenTrafficSim License</a>.
* </p>
* @param <L> source type
* @param <T> text renderable type
* @author Wouter Schakel
*/
public abstract class OtsRenderableLabeled<L extends OtsShape, T extends RenderableTextSource<L, T>> extends OtsRenderable<L>
{
/** Text object to destroy when the animation is destroyed. */
private T text;
/**
* Constructor. This constructor uses no label prefix.
* @param source the source
* @param contextualized the object that can provide the context to store the animation objects
*/
public OtsRenderableLabeled(final L source, final Contextualized contextualized)
{
this(source, contextualized, "");
}
/**
* Constructor.
* @param source the source
* @param contextualized the object that can provide the context to store the animation objects
* @param prefix prefix for the label
*/
public OtsRenderableLabeled(final L source, final Contextualized contextualized, final String prefix)
{
super(source, contextualized);
this.text = createText(source, contextualized, prefix);
}
/**
* Sets the animation as dynamic, obtaining geometry at each draw.
* @param dynamic whether the animation is dynamic, {@code false} by default
* @return this animation for method chaining
*/
@SuppressWarnings("unchecked")
@Override
public OtsRenderableLabeled<L, T> setDynamic(final boolean dynamic)
{
if (this.text != null)
{
this.text.setDynamic(dynamic);
}
return (OtsRenderableLabeled<L, T>) super.setDynamic(dynamic);
}
@Override
public void destroy(final Contextualized contextProvider)
{
super.destroy(contextProvider);
if (this.text != null)
{
this.text.destroy(contextProvider);
}
}
/**
* Returns a text object that is co-animated with the object itself. Sub-classes of {@link OtsRenderableLabeled} typically
* define a {@code .Text} class that extends {@link RenderableTextSource} such that a separate class exists that can be
* toggled on/off. In this way labels of renderables can be show separately from the object itself. The {@code prefix} may
* be ignore depending on the sub-class knowing it provided no prefix to this class, its super class.
* @param source the object for which the text is displayed
* @param contextualized context provider
* @param prefix prefix for the label
* @return text renderable, may be {@code null} to omit a label
*/
protected abstract T createText(L source, Contextualized contextualized, String prefix);
/**
* Convenience class to use when the renderable wants to omit having a label. The {@link #createText} should return
* {@code null}.
* @param <L> source type
*/
public static class NoText<L extends OtsShape> extends RenderableTextSource<L, NoText<L>>
{
/**
* Constructor.
* @throws OperationNotSupportedException whenever this constructor is called
*/
NoText() throws OperationNotSupportedException
{
super(Throw.when(null, true, OperationNotSupportedException.class,
"Method createText should return null when NoText is used."), null, 0.0f, 0.0f, null, null, null, null);
}
}
}