Android Open Source - android-plotter Default Plotter






From Project

Back to project page android-plotter.

License

The source code is released under:

Apache License

If you think the Android project android-plotter listed in this page is inappropriate, such as containing malicious code/tools or violating the copyright, please email info at java2s dot com, thanks.

Java Source Code

package org.solovyev.android.plotter;
// w  w  w  .j av a  2  s .c om
import org.solovyev.android.plotter.meshes.*;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import javax.annotation.concurrent.GuardedBy;
import javax.microedition.khronos.opengles.GL11;
import java.util.Arrays;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.atomic.AtomicInteger;

final class DefaultPlotter implements Plotter {

  @Nonnull
  private final DoubleBufferGroup<FunctionGraph> functionMeshes = DoubleBufferGroup.create(FunctionGraphSwapper.INSTANCE);

  @Nonnull
  private final DoubleBufferGroup<Mesh> otherMeshes = DoubleBufferGroup.create(null);

  @Nonnull
  private final Group<Mesh> allMeshes = ListGroup.create(Arrays.<Mesh>asList(functionMeshes, otherMeshes));

  @Nonnull
  private final Pool<FunctionGraph> pool = new ListPool<FunctionGraph>(new ListPool.Callback<FunctionGraph>() {
    @Nonnull
    @Override
    public FunctionGraph create() {
      if (is3d()) {
        return FunctionGraph3d.create(Dimensions.empty(), Function0.ZERO);
      } else {
        return FunctionGraph2d.create(Dimensions.empty(), Function0.ZERO);
      }
    }

    @Override
    public void release(@Nonnull FunctionGraph mesh) {
      mesh.setFunction(Function0.ZERO);
    }
  });

  @Nonnull
  private PlotData plotData = PlotData.create();

  @Nonnull
  private final Initializer initializer = new Initializer(allMeshes);

  @Nonnull
  private final MeshConfig config = MeshConfig.create();

  @Nonnull
  private final Executor background = Executors.newFixedThreadPool(4, new ThreadFactory() {

    @Nonnull
    private final AtomicInteger counter = new AtomicInteger(0);

    @Override
    public Thread newThread(@Nonnull Runnable r) {
      return new Thread(r, "PlotBackground #" + counter.getAndIncrement());
    }
  });

  @Nonnull
  private final Object lock = new Object();

  @GuardedBy("lock")
  @Nonnull
  private final EmptyPlottingView emptyView = new EmptyPlottingView();

  @GuardedBy("lock")
  @Nonnull
  private PlottingView view = emptyView;

  @GuardedBy("lock")
  @Nonnull
  private Dimensions dimensions = new Dimensions();

  @GuardedBy("lock")
  private boolean d3 = D3;

  @Nonnull
  private final Runnable dimensionsChangedRunnable = new Runnable() {
    @Override
    public void run() {
      onDimensionsChanged();
    }
  };

  DefaultPlotter() {
    set3d(false);
  }

  public void add(@Nonnull Mesh mesh) {
    otherMeshes.addMesh(mesh);
    setDirty();
  }

  public void add(@Nonnull DoubleBufferMesh<? extends Mesh> mesh) {
    otherMeshes.add((DoubleBufferMesh<Mesh>) mesh);
    setDirty();
  }

  @Override
  public void initGl(@Nonnull GL11 gl, boolean firstTime) {
    if (firstTime) {
      // fill the background
      final int bg = plotData.axisStyle.backgroundColor;
      gl.glClearColor(Color.red(bg), Color.green(bg), Color.blue(bg), Color.alpha(bg));
    }
    allMeshes.initGl(gl, config);
  }

  @Override
  public void draw(@Nonnull GL11 gl) {
    allMeshes.draw(gl);
  }

  private void ensureFunctionsSize() {
    Check.isMainThread();

    final Dimensions dimensions = getDimensions();

    // for each functions we should assign mesh
    // if there are not enough meshes => create new
    // if there are too many meshes => release them
    int i = 0;
    for (PlotFunction function : plotData.functions) {
      final Color lineColor = Color.create(function.lineStyle.color);
      if (i < functionMeshes.size()) {
        final DoubleBufferMesh<FunctionGraph> dbm = functionMeshes.get(i);
        final FunctionGraph next = dbm.getNext();
        final FunctionGraph current = dbm.getOther(next);
        next.setFunction(function.function);
        next.setColor(lineColor);
        next.setDimensions(dimensions);
        current.setColor(lineColor);
      } else {
        final FunctionGraph mesh = pool.obtain();
        mesh.setFunction(function.function);
        mesh.setColor(lineColor);
        mesh.setDimensions(dimensions);
        functionMeshes.add(DoubleBufferMesh.wrap(mesh, FunctionGraphSwapper.INSTANCE));
      }
      i++;
    }

    for (int k = functionMeshes.size() - 1; k >= i; k--) {
      final DoubleBufferMesh<FunctionGraph> dbm = functionMeshes.remove(k);
      pool.release(dbm.getNext());
    }
  }

  private void setDirty() {
    background.execute(initializer);
  }

  @Override
  public void add(@Nonnull Function function) {
    plotData.add(function);
    onFunctionsChanged();
  }

  private void onDimensionsChanged() {
    Check.isMainThread();

    final Dimensions dimensions = getDimensions();

    for (DoubleBufferMesh<Mesh> dbm : otherMeshes) {
      final Mesh mesh = dbm.getNext();
      if (mesh instanceof DimensionsAware) {
        ((DimensionsAware) mesh).setDimensions(dimensions);
      }
    }
    onFunctionsChanged();
  }

  private void onFunctionsChanged() {
    ensureFunctionsSize();
    setDirty();
  }

  @Override
  public void add(@Nonnull PlotFunction function) {
    plotData.add(function.copy());
    onFunctionsChanged();
  }

  @Override
  public void update(@Nonnull PlotFunction function) {
    plotData.update(function.copy());
    onFunctionsChanged();
  }

  @Override
  public void clearFunctions() {
    plotData.functions.clear();
    onFunctionsChanged();
  }

  @Override
  @Nonnull
  public PlotData getPlotData() {
    Check.isMainThread();
    return plotData.copy();
  }

  @Override
  public void attachView(@Nonnull PlottingView newView) {
    Check.isMainThread();
    synchronized (lock) {
      Check.same(emptyView, view);
      view = newView;
      if (emptyView.shouldRender) {
        emptyView.shouldRender = false;
        view.requestRender();
      }

      if (emptyView.shouldUpdateFunctions) {
        emptyView.shouldUpdateFunctions = false;
        dimensionsChangedRunnable.run();
      }

      if (emptyView.requested3d != null) {
        view.set3d(emptyView.requested3d);
        emptyView.requested3d = null;
      }
    }
  }

  @Override
  public void detachView(@Nonnull PlottingView oldView) {
    Check.isMainThread();
    synchronized (lock) {
      Check.same(oldView, view);
      emptyView.shouldRender = false;
      emptyView.shouldUpdateFunctions = false;
      view = emptyView;
      updateDimensions(Dimensions.empty());
    }
  }

  @Override
  public void setDimensions(@Nonnull Dimensions newDimensions) {
    Check.isMainThread();
    synchronized (lock) {
      updateDimensions(newDimensions);
      view.resetZoom();
    }
  }

  private void updateDimensions(@Nonnull Dimensions newDimensions) {
    Check.isAnyThread();
    synchronized (lock) {
      if (!dimensions.equals(newDimensions)) {
        dimensions = newDimensions;
        if (!Plot.isMainThread() || view == emptyView) {
          view.post(dimensionsChangedRunnable);
        } else {
          dimensionsChangedRunnable.run();
        }
      }
    }
  }

  @Override
  public void updateDimensions(float zoom, int viewWidth, int viewHeight) {
    synchronized (lock) {
      if (dimensions.shouldUpdate(zoom, viewWidth, viewHeight)) {
        final Dimensions newDimensions = dimensions.copy();
        newDimensions.update(zoom, viewWidth, viewHeight);
        updateDimensions(newDimensions);
      }
    }
  }

  @Override
  @Nonnull
  public Dimensions getDimensions() {
    synchronized (lock) {
      return dimensions.copy();
    }
  }

  @Override
  public boolean is3d() {
    synchronized (lock) {
      return d3;
    }
  }

  public boolean is2d() {
    return !is3d();
  }

  @Override
  public void set3d(boolean d3) {
    Check.isMainThread();
    if (set3d0(d3)) {
      while (functionMeshes.size() > 0) {
        final DoubleBufferMesh<FunctionGraph> dbm = functionMeshes.remove(functionMeshes.size() - 1);
        pool.release(dbm.getNext());
      }
      pool.clear();
      otherMeshes.clear();
      makeSetting(d3);
      onDimensionsChanged();
      synchronized (lock) {
        view.set3d(d3);
      }
    }
  }

  private void makeSetting(boolean d3) {
    otherMeshes.clear();
    final Dimensions dimensions = getDimensions();
    final float size = dimensions.graph.width();
    add(AxisGrid.xz(dimensions).toDoubleBuffer());
    if (d3) {
      add(AxisGrid.xy(dimensions).toDoubleBuffer());
      add(AxisGrid.yz(dimensions).toDoubleBuffer());
    }
    add(Axis.x(dimensions).toDoubleBuffer());
    add(Axis.y(dimensions).toDoubleBuffer());
    if (d3) {
      add(new WireFrameCube(size, size, size));
      add(Axis.z(dimensions).toDoubleBuffer());
    }
  }

  private boolean set3d0(boolean d3) {
    synchronized (lock) {
      if (this.d3 != d3) {
        this.d3 = d3;
        return true;
      }
      return false;
    }
  }

  @Nonnull
  public final class Initializer implements Runnable {

    @Nonnull
    private final Group<Mesh> group;

    public Initializer(@Nonnull Group<Mesh> group) {
      this.group = group;
    }

    @Override
    public void run() {
      group.init();
      synchronized (lock) {
        view.requestRender();
      }
    }
  }

  /**
   * Dummy plotting view which tracks render requests. If the real view is set and this view detected render request
   * then {@link PlottingView#requestRender()} of the new view will be called.
   */
  private final class EmptyPlottingView implements PlottingView {
    private boolean shouldRender;
    private boolean shouldUpdateFunctions;
    @Nullable
    private Boolean requested3d;

    @Override
    public void requestRender() {
      shouldRender = true;
    }

    @Override
    public void zoom(boolean in) {
    }

    @Override
    public void resetZoom() {
    }

    @Override
    public boolean post(@Nonnull Runnable runnable) {
      if (!shouldUpdateFunctions) {
        shouldUpdateFunctions = dimensionsChangedRunnable == runnable;
      }
      return true;
    }

    @Override
    public void set3d(boolean d3) {
      requested3d = d3;
    }
  }
}




Java Source Code List

com.android.texample.GLText.java
com.android.texample.SpriteBatch.java
com.android.texample.TexampleRenderer.java
com.android.texample.TextureRegion.java
com.android.texample.Vertices.java
org.solovyev.android.plotter.Angle.java
org.solovyev.android.plotter.AxisStyle.java
org.solovyev.android.plotter.Check.java
org.solovyev.android.plotter.Color.java
org.solovyev.android.plotter.DefaultPlotter.java
org.solovyev.android.plotter.Dimensions.java
org.solovyev.android.plotter.Frustum.java
org.solovyev.android.plotter.Function0.java
org.solovyev.android.plotter.Function1.java
org.solovyev.android.plotter.Function2.java
org.solovyev.android.plotter.Function.java
org.solovyev.android.plotter.LineStyle.java
org.solovyev.android.plotter.MeshConfig.java
org.solovyev.android.plotter.MultisampleConfigChooser.java
org.solovyev.android.plotter.PinchZoomTracker.java
org.solovyev.android.plotter.PlotData.java
org.solovyev.android.plotter.PlotFunction.java
org.solovyev.android.plotter.PlotRenderer.java
org.solovyev.android.plotter.PlotView.java
org.solovyev.android.plotter.Plot.java
org.solovyev.android.plotter.Plotter.java
org.solovyev.android.plotter.PlottingView.java
org.solovyev.android.plotter.Spf.java
org.solovyev.android.plotter.SuperFunction.java
org.solovyev.android.plotter.TouchHandler.java
org.solovyev.android.plotter.ZoomLevels.java
org.solovyev.android.plotter.Zoomer.java
org.solovyev.android.plotter.app.MainActivity.java
org.solovyev.android.plotter.app.PlotterApplication.java
org.solovyev.android.plotter.meshes.Arrays.java
org.solovyev.android.plotter.meshes.AxisGrid.java
org.solovyev.android.plotter.meshes.Axis.java
org.solovyev.android.plotter.meshes.BaseCube.java
org.solovyev.android.plotter.meshes.BaseCurve.java
org.solovyev.android.plotter.meshes.BaseMesh.java
org.solovyev.android.plotter.meshes.BaseSurface.java
org.solovyev.android.plotter.meshes.DimensionsAwareSwapper.java
org.solovyev.android.plotter.meshes.DimensionsAware.java
org.solovyev.android.plotter.meshes.DoubleBufferGroup.java
org.solovyev.android.plotter.meshes.DoubleBufferMesh.java
org.solovyev.android.plotter.meshes.FunctionGraph2d.java
org.solovyev.android.plotter.meshes.FunctionGraph3d.java
org.solovyev.android.plotter.meshes.FunctionGraphSwapper.java
org.solovyev.android.plotter.meshes.FunctionGraph.java
org.solovyev.android.plotter.meshes.Graph.java
org.solovyev.android.plotter.meshes.Group.java
org.solovyev.android.plotter.meshes.IndicesOrder.java
org.solovyev.android.plotter.meshes.ListGroup.java
org.solovyev.android.plotter.meshes.ListPool.java
org.solovyev.android.plotter.meshes.Mesh.java
org.solovyev.android.plotter.meshes.Meshes.java
org.solovyev.android.plotter.meshes.Pool.java
org.solovyev.android.plotter.meshes.Scene.java
org.solovyev.android.plotter.meshes.SolidCube.java
org.solovyev.android.plotter.meshes.SurfaceInitializer.java
org.solovyev.android.plotter.meshes.WireFrameCube.java