<commit_before>package experimentalcode.erich.jogl;

/*
 This file is part of ELKI:
 Environment for Developing KDD-Applications Supported by Index-Structures

 Copyright (C) 2013
 Ludwig-Maximilians-Universität München
 Lehr- und Forschungseinheit für Datenbanksysteme
 ELKI Development Team

 This program is free software: you can redistribute it and/or modify
 it under the terms of the GNU Affero General Public License as published by
 the Free Software Foundation, either version 3 of the License, or
 (at your option) any later version.

 This program is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU Affero General Public License for more details.

 You should have received a copy of the GNU Affero General Public License
 along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

import java.awt.Color;
import java.awt.Font;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.geom.Rectangle2D;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import javax.media.opengl.DebugGL2;
import javax.media.opengl.GL;
import javax.media.opengl.GL2;
import javax.media.opengl.GLAutoDrawable;
import javax.media.opengl.GLCapabilities;
import javax.media.opengl.GLEventListener;
import javax.media.opengl.GLProfile;
import javax.media.opengl.awt.GLCanvas;
import javax.media.opengl.glu.GLU;
import javax.swing.JFrame;

import com.jogamp.opengl.util.awt.TextRenderer;

import de.lmu.ifi.dbs.elki.data.Clustering;
import de.lmu.ifi.dbs.elki.data.NumberVector;
import de.lmu.ifi.dbs.elki.data.model.Model;
import de.lmu.ifi.dbs.elki.data.type.TypeUtil;
import de.lmu.ifi.dbs.elki.database.ids.DBIDIter;
import de.lmu.ifi.dbs.elki.database.relation.Relation;
import de.lmu.ifi.dbs.elki.database.relation.RelationUtil;
import de.lmu.ifi.dbs.elki.logging.Logging;
import de.lmu.ifi.dbs.elki.math.MathUtil;
import de.lmu.ifi.dbs.elki.persistent.ByteArrayUtil;
import de.lmu.ifi.dbs.elki.result.HierarchicalResult;
import de.lmu.ifi.dbs.elki.result.Result;
import de.lmu.ifi.dbs.elki.result.ResultHandler;
import de.lmu.ifi.dbs.elki.result.ResultUtil;
import de.lmu.ifi.dbs.elki.result.ScalesResult;
import de.lmu.ifi.dbs.elki.utilities.exceptions.AbortException;
import de.lmu.ifi.dbs.elki.utilities.optionhandling.AbstractParameterizer;
import de.lmu.ifi.dbs.elki.utilities.optionhandling.OptionID;
import de.lmu.ifi.dbs.elki.utilities.optionhandling.parameterization.Parameterization;
import de.lmu.ifi.dbs.elki.utilities.optionhandling.parameters.ObjectParameter;
import de.lmu.ifi.dbs.elki.utilities.pairs.DoubleIntPair;
import de.lmu.ifi.dbs.elki.visualization.colors.ColorLibrary;
import de.lmu.ifi.dbs.elki.visualization.projections.ProjectionParallel;
import de.lmu.ifi.dbs.elki.visualization.projections.SimpleParallel;
import de.lmu.ifi.dbs.elki.visualization.style.ClassStylingPolicy;
import de.lmu.ifi.dbs.elki.visualization.style.ClusterStylingPolicy;
import de.lmu.ifi.dbs.elki.visualization.style.PropertiesBasedStyleLibrary;
import de.lmu.ifi.dbs.elki.visualization.style.StyleLibrary;
import de.lmu.ifi.dbs.elki.visualization.style.StyleResult;
import de.lmu.ifi.dbs.elki.visualization.style.StylingPolicy;
import de.lmu.ifi.dbs.elki.visualization.svg.SVGUtil;
import experimentalcode.erich.jogl.Simple1DOFCamera.CameraListener;
import experimentalcode.shared.parallelcoord.layout.Layout;
import experimentalcode.shared.parallelcoord.layout.Layouter3DPC;
import experimentalcode.shared.parallelcoord.layout.SimpleCircularMSTLayout;
import gnu.trove.list.array.TFloatArrayList;
import gnu.trove.list.array.TIntArrayList;

/**
 * Simple JOGL2 based parallel coordinates visualization.
 * 
 * @author <NAME>
 * 
 *         TODO: Improve generics of Layout3DPC.
 */
public class OpenGL3DParallelCoordinates implements ResultHandler {
  /**
   * Logging class.
   */
  private static final Logging LOG = Logging.getLogger(ResultHandler.class);

  Settings settings = new Settings();

  /**
   * Constructor.
   * 
   * @param layout Layout
   */
  public OpenGL3DParallelCoordinates(Layouter3DPC<? super NumberVector<?>> layout) {
    settings.layout = layout;
  }

  @Override
  public void processNewResult(HierarchicalResult baseResult, Result newResult) {
    StyleResult style = getStyleResult(baseResult);
    List<Relation<?>> rels = ResultUtil.getRelations(newResult);
    for (Relation<?> rel : rels) {
      if (!TypeUtil.NUMBER_VECTOR_FIELD.isAssignableFromType(rel.getDataTypeInformation())) {
        continue;
      }
      @SuppressWarnings("unchecked")
      Relation<? extends NumberVector<?>> vrel = (Relation<? extends NumberVector<?>>) rel;
      ScalesResult scales = ResultUtil.getScalesResult(vrel);
      ProjectionParallel proj = new SimpleParallel(scales.getScales());
      new Instance(vrel, proj, settings, style).run();
    }
  }

  /**
   * Hack: Get/Create the style result.
   * 
   * @return Style result
   */
  public StyleResult getStyleResult(HierarchicalResult result) {
    ArrayList<StyleResult> styles = ResultUtil.filterResults(result, StyleResult.class);
    if (styles.size() > 0) {
      return styles.get(0);
    }
    StyleResult styleresult = new StyleResult();
    styleresult.setStyleLibrary(new PropertiesBasedStyleLibrary());
    ResultUtil.ensureClusteringResult(ResultUtil.findDatabase(result), result);
    List<Clustering<? extends Model>> clusterings = ResultUtil.getClusteringResults(result);
    if (clusterings.size() > 0) {
      styleresult.setStylingPolicy(new ClusterStylingPolicy(clusterings.get(0), styleresult.getStyleLibrary()));
      result.getHierarchy().add(result, styleresult);
      return styleresult;
    } else {
      throw new AbortException("No clustering result generated?!?");
    }
  }

  /**
   * Class keeping the visualizer settings.
   * 
   * @author <NAME>
   */
  public static class Settings {
    /**
     * Layouting method.
     */
    public Layouter3DPC<? super NumberVector<?>> layout;

    /**
     * Alpha effect: 1=solid, 0=full alpha effect
     * 
     * Note: since OpenGL usually works with 8 bit color depth, this puts a
     * strong limitation on alpha: computation is not in floats, but has 1/256
     * steps for blending. This in particular affects sloped lines!
     */
    double alpha = .5;

    /**
     * Line width
     */
    public float linewidth = 2f;
  }

  /**
   * Visualizer instance.
   * 
   * @author <NAME>
   */
  public static class Instance implements GLEventListener {
    /**
     * Flag to enable debug rendering.
     */
    private static final boolean DEBUG = false;

    /**
     * Relation to viualize
     */
    Relation<? extends NumberVector<?>> rel;

    /**
     * Projection
     */
    ProjectionParallel proj;

    /**
     * Frame
     */
    JFrame frame = null;

    /**
     * GLU utility class.
     */
    GLU glu;

    /**
     * Settings
     */
    Settings settings;

    /**
     * Style result
     */
    StyleResult style;

    /**
     * Axis labels
     */
    String[] labels;

    /**
     * Layout
     */
    private Layout layout;

    private Parallel3DRenderer prenderer;

    /**
     * Text renderer
     */
    TextRenderer textrenderer;

    /**
     * The OpenGL canvas
     */
    GLCanvas canvas;

    /**
     * Camera handling class
     */
    Simple1DOFCamera camera;

    /**
     * Arcball controller.
     */
    Arcball1DOFAdapter arcball;

    /**
     * Constructor.
     * 
     * @param rel Relation
     * @param proj Projection
     * @param settings Settings
     * @param style Style result
     */
    public Instance(Relation<? extends NumberVector<?>> rel, ProjectionParallel proj, Settings settings, StyleResult style) {
      super();
      this.rel = rel;
      this.proj = proj;
      this.settings = settings;
      this.style = style;
      this.prenderer = new Parallel3DRenderer();

      GLProfile glp = GLProfile.getDefault();
      GLCapabilities caps = new GLCapabilities(glp);
      caps.setDoubleBuffered(true);
      canvas = new GLCanvas(caps);
      canvas.addGLEventListener(this);

      frame = new JFrame("EKLI OpenGL Visualization");
      frame.setSize(600, 600);
      frame.add(canvas);
    }

    public void run() {
      layout = settings.layout.layout(rel.getDatabase(), rel);

      assert (frame != null);
      frame.setVisible(true);
      frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
      frame.addWindowListener(new WindowAdapter() {
        @Override
        public void windowClosed(WindowEvent e) {
          stop();
        }
      });
    }<commit_msg>Use 16 bpp depth for better visuals.<commit_after>package experimentalcode.erich.jogl;

/*
 This file is part of ELKI:
 Environment for Developing KDD-Applications Supported by Index-Structures

 Copyright (C) 2013
 Ludwig-Maximilians-Universität München
 Lehr- und Forschungseinheit für Datenbanksysteme
 ELKI Development Team

 This program is free software: you can redistribute it and/or modify
 it under the terms of the GNU Affero General Public License as published by
 the Free Software Foundation, either version 3 of the License, or
 (at your option) any later version.

 This program is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU Affero General Public License for more details.

 You should have received a copy of the GNU Affero General Public License
 along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

import java.awt.Color;
import java.awt.Font;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.geom.Rectangle2D;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import javax.media.opengl.DebugGL2;
import javax.media.opengl.GL;
import javax.media.opengl.GL2;
import javax.media.opengl.GLAutoDrawable;
import javax.media.opengl.GLCapabilities;
import javax.media.opengl.GLEventListener;
import javax.media.opengl.GLProfile;
import javax.media.opengl.awt.GLCanvas;
import javax.media.opengl.glu.GLU;
import javax.swing.JFrame;

import com.jogamp.opengl.util.awt.TextRenderer;

import de.lmu.ifi.dbs.elki.data.Clustering;
import de.lmu.ifi.dbs.elki.data.NumberVector;
import de.lmu.ifi.dbs.elki.data.model.Model;
import de.lmu.ifi.dbs.elki.data.type.TypeUtil;
import de.lmu.ifi.dbs.elki.database.ids.DBIDIter;
import de.lmu.ifi.dbs.elki.database.relation.Relation;
import de.lmu.ifi.dbs.elki.database.relation.RelationUtil;
import de.lmu.ifi.dbs.elki.logging.Logging;
import de.lmu.ifi.dbs.elki.math.MathUtil;
import de.lmu.ifi.dbs.elki.persistent.ByteArrayUtil;
import de.lmu.ifi.dbs.elki.result.HierarchicalResult;
import de.lmu.ifi.dbs.elki.result.Result;
import de.lmu.ifi.dbs.elki.result.ResultHandler;
import de.lmu.ifi.dbs.elki.result.ResultUtil;
import de.lmu.ifi.dbs.elki.result.ScalesResult;
import de.lmu.ifi.dbs.elki.utilities.exceptions.AbortException;
import de.lmu.ifi.dbs.elki.utilities.optionhandling.AbstractParameterizer;
import de.lmu.ifi.dbs.elki.utilities.optionhandling.OptionID;
import de.lmu.ifi.dbs.elki.utilities.optionhandling.parameterization.Parameterization;
import de.lmu.ifi.dbs.elki.utilities.optionhandling.parameters.ObjectParameter;
import de.lmu.ifi.dbs.elki.utilities.pairs.DoubleIntPair;
import de.lmu.ifi.dbs.elki.visualization.colors.ColorLibrary;
import de.lmu.ifi.dbs.elki.visualization.projections.ProjectionParallel;
import de.lmu.ifi.dbs.elki.visualization.projections.SimpleParallel;
import de.lmu.ifi.dbs.elki.visualization.style.ClassStylingPolicy;
import de.lmu.ifi.dbs.elki.visualization.style.ClusterStylingPolicy;
import de.lmu.ifi.dbs.elki.visualization.style.PropertiesBasedStyleLibrary;
import de.lmu.ifi.dbs.elki.visualization.style.StyleLibrary;
import de.lmu.ifi.dbs.elki.visualization.style.StyleResult;
import de.lmu.ifi.dbs.elki.visualization.style.StylingPolicy;
import de.lmu.ifi.dbs.elki.visualization.svg.SVGUtil;
import experimentalcode.erich.jogl.Simple1DOFCamera.CameraListener;
import experimentalcode.shared.parallelcoord.layout.Layout;
import experimentalcode.shared.parallelcoord.layout.Layouter3DPC;
import experimentalcode.shared.parallelcoord.layout.SimpleCircularMSTLayout;
import gnu.trove.list.array.TFloatArrayList;
import gnu.trove.list.array.TIntArrayList;

/**
 * Simple JOGL2 based parallel coordinates visualization.
 * 
 * @author <NAME>
 * 
 *         TODO: Improve generics of Layout3DPC.
 */
public class OpenGL3DParallelCoordinates implements ResultHandler {
  /**
   * Logging class.
   */
  private static final Logging LOG = Logging.getLogger(ResultHandler.class);

  Settings settings = new Settings();

  /**
   * Constructor.
   * 
   * @param layout Layout
   */
  public OpenGL3DParallelCoordinates(Layouter3DPC<? super NumberVector<?>> layout) {
    settings.layout = layout;
  }

  @Override
  public void processNewResult(HierarchicalResult baseResult, Result newResult) {
    StyleResult style = getStyleResult(baseResult);
    List<Relation<?>> rels = ResultUtil.getRelations(newResult);
    for (Relation<?> rel : rels) {
      if (!TypeUtil.NUMBER_VECTOR_FIELD.isAssignableFromType(rel.getDataTypeInformation())) {
        continue;
      }
      @SuppressWarnings("unchecked")
      Relation<? extends NumberVector<?>> vrel = (Relation<? extends NumberVector<?>>) rel;
      ScalesResult scales = ResultUtil.getScalesResult(vrel);
      ProjectionParallel proj = new SimpleParallel(scales.getScales());
      new Instance(vrel, proj, settings, style).run();
    }
  }

  /**
   * Hack: Get/Create the style result.
   * 
   * @return Style result
   */
  public StyleResult getStyleResult(HierarchicalResult result) {
    ArrayList<StyleResult> styles = ResultUtil.filterResults(result, StyleResult.class);
    if (styles.size() > 0) {
      return styles.get(0);
    }
    StyleResult styleresult = new StyleResult();
    styleresult.setStyleLibrary(new PropertiesBasedStyleLibrary());
    ResultUtil.ensureClusteringResult(ResultUtil.findDatabase(result), result);
    List<Clustering<? extends Model>> clusterings = ResultUtil.getClusteringResults(result);
    if (clusterings.size() > 0) {
      styleresult.setStylingPolicy(new ClusterStylingPolicy(clusterings.get(0), styleresult.getStyleLibrary()));
      result.getHierarchy().add(result, styleresult);
      return styleresult;
    } else {
      throw new AbortException("No clustering result generated?!?");
    }
  }

  /**
   * Class keeping the visualizer settings.
   * 
   * @author <NAME>
   */
  public static class Settings {
    /**
     * Layouting method.
     */
    public Layouter3DPC<? super NumberVector<?>> layout;

    /**
     * Alpha effect: 1=solid, 0=full alpha effect
     * 
     * Note: since OpenGL usually works with 8 bit color depth, this puts a
     * strong limitation on alpha: computation is not in floats, but has 1/256
     * steps for blending. This in particular affects sloped lines!
     */
    double alpha = .1;

    /**
     * Line width
     */
    public float linewidth = 2f;
  }

  /**
   * Visualizer instance.
   * 
   * @author <NAME>
   */
  public static class Instance implements GLEventListener {
    /**
     * Flag to enable debug rendering.
     */
    private static final boolean DEBUG = false;

    /**
     * Relation to viualize
     */
    Relation<? extends NumberVector<?>> rel;

    /**
     * Projection
     */
    ProjectionParallel proj;

    /**
     * Frame
     */
    JFrame frame = null;

    /**
     * GLU utility class.
     */
    GLU glu;

    /**
     * Settings
     */
    Settings settings;

    /**
     * Style result
     */
    StyleResult style;

    /**
     * Axis labels
     */
    String[] labels;

    /**
     * Layout
     */
    private Layout layout;

    private Parallel3DRenderer prenderer;

    /**
     * Text renderer
     */
    TextRenderer textrenderer;

    /**
     * The OpenGL canvas
     */
    GLCanvas canvas;

    /**
     * Camera handling class
     */
    Simple1DOFCamera camera;

    /**
     * Arcball controller.
     */
    Arcball1DOFAdapter arcball;

    /**
     * Constructor.
     * 
     * @param rel Relation
     * @param proj Projection
     * @param settings Settings
     * @param style Style result
     */
    public Instance(Relation<? extends NumberVector<?>> rel, ProjectionParallel proj, Settings settings, StyleResult style) {
      super();
      this.rel = rel;
      this.proj = proj;
      this.settings = settings;
      this.style = style;
      this.prenderer = new Parallel3DRenderer();

      GLProfile glp = GLProfile.getDefault();
      GLCapabilities caps = new GLCapabilities(glp);
      // Increase color depth.
      caps.setBlueBits(16);
      caps.setRedBits(16);
      caps.setGreenBits(16);
      caps.setDoubleBuffered(true);
      canvas = new GLCanvas(caps);
      canvas.addGLEventListener(this);

      frame = new JFrame("EKLI OpenGL Visualization");
      frame.setSize(600, 600);
      frame.add(canvas);
    }

    public void run() {
      layout = settings.layout.layout(rel.getDatabase(), rel);

      assert (frame != null);
      frame.setVisible(true);
      frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
      frame.addWindowListener(new WindowAdapter() {
        @Override
        public void windowClosed(WindowEvent e) {
          stop();
        }
      });
    }
{'fraction_non_alphanumeric': 0.10746873943899966, 'fraction_numerical': 0.004843978821673989, 'mean_word_length': 3.406800694961529, 'pattern_counts': {'":': 0, '<': 47, '<?xml version=': 0, '>': 51, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 4, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3435656', 'n_tokens_mistral': 5714, 'n_tokens_neox': 5516, 'n_words': 1212}