Package de.lmu.ifi.dbs.elki.visualization.svg

Source Code of de.lmu.ifi.dbs.elki.visualization.svg.SVGHyperSphere

package de.lmu.ifi.dbs.elki.visualization.svg;

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

Copyright (C) 2011
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.util.BitSet;

import org.w3c.dom.Element;

import de.lmu.ifi.dbs.elki.data.NumberVector;
import de.lmu.ifi.dbs.elki.distance.distancevalue.NumberDistance;
import de.lmu.ifi.dbs.elki.math.linearalgebra.Vector;
import de.lmu.ifi.dbs.elki.visualization.projections.Projection2D;

/**
* Utility class to draw hypercubes, wireframe and filled.
*
* @author Erich Schubert
*
* @apiviz.uses SVGPath
* @apiviz.uses Projection2D
*/
public class SVGHyperSphere {
  /**
   * Factor used for approximating circles with cubic beziers.
   *
   * kappa = 4 * (Math.sqrt(2)-1)/3
   */
  public final static double EUCLIDEAN_KAPPA = 0.5522847498;

  /**
   * Wireframe "manhattan" hypersphere
   *
   * @param <V> vector type
   * @param <D> radius
   * @param svgp SVG Plot
   * @param proj Visualization projection
   * @param mid mean vector
   * @param rad radius
   * @return path element
   */
  public static <V extends NumberVector<V, ?>, D extends NumberDistance<?, ?>> Element drawManhattan(SVGPlot svgp, Projection2D proj, V mid, D rad) {
    Vector v_mid = mid.getColumnVector();
    BitSet dims = proj.getVisibleDimensions2D();

    SVGPath path = new SVGPath();
    for(int dim = dims.nextSetBit(0); dim >= 0; dim = dims.nextSetBit(dim + 1)) {
      Vector v1 = v_mid.copy();
      v1.set(dim, v1.get(dim) + rad.doubleValue());
      Vector v2 = v_mid.copy();
      v2.set(dim, v2.get(dim) - rad.doubleValue());
      double[] p1 = proj.fastProjectDataToRenderSpace(v1);
      double[] p2 = proj.fastProjectDataToRenderSpace(v2);
      for(int dim2 = dims.nextSetBit(0); dim2 >= 0; dim2 = dims.nextSetBit(dim2 + 1)) {
        if(dim < dim2) {
          Vector v3 = v_mid.copy();
          v3.set(dim2, v3.get(dim2) + rad.doubleValue());
          Vector v4 = v_mid.copy();
          v4.set(dim2, v4.get(dim2) - rad.doubleValue());
          double[] p3 = proj.fastProjectDataToRenderSpace(v3);
          double[] p4 = proj.fastProjectDataToRenderSpace(v4);

          path.moveTo(p1[0], p1[1]);
          path.drawTo(p3[0], p3[1]);
          path.moveTo(p1[0], p1[1]);
          path.drawTo(p4[0], p4[1]);
          path.moveTo(p2[0], p2[1]);
          path.drawTo(p3[0], p3[1]);
          path.moveTo(p2[0], p2[1]);
          path.drawTo(p4[0], p4[1]);
          path.close();
        }
      }
    }
    return path.makeElement(svgp);
  }

  /**
   * Wireframe "euclidean" hypersphere
   *
   * @param <V> vector type
   * @param <D> radius
   * @param svgp SVG Plot
   * @param proj Visualization projection
   * @param mid mean vector
   * @param rad radius
   * @return path element
   */
  public static <V extends NumberVector<V, ?>, D extends NumberDistance<?, ?>> Element drawEuclidean(SVGPlot svgp, Projection2D proj, V mid, D rad) {
    Vector v_mid = mid.getColumnVector();
    BitSet dims = proj.getVisibleDimensions2D();

    SVGPath path = new SVGPath();
    for(int dim = dims.nextSetBit(0); dim >= 0; dim = dims.nextSetBit(dim + 1)) {
      Vector v1 = v_mid.copy();
      v1.set(dim, v1.get(dim) + rad.doubleValue());
      Vector v2 = v_mid.copy();
      v2.set(dim, v2.get(dim) - rad.doubleValue());
      double[] p1 = proj.fastProjectDataToRenderSpace(v1);
      double[] p2 = proj.fastProjectDataToRenderSpace(v2);
      // delta vector
      Vector dt1 = new Vector(v1.getDimensionality());
      dt1.set(dim, rad.doubleValue());
      double[] d1 = proj.fastProjectRelativeDataToRenderSpace(dt1);
      for(int dim2 = dims.nextSetBit(0); dim2 >= 0; dim2 = dims.nextSetBit(dim2 + 1)) {
        if(dim < dim2) {
          Vector v3 = v_mid.copy();
          v3.set(dim2, v3.get(dim2) + rad.doubleValue());
          Vector v4 = v_mid.copy();
          v4.set(dim2, v4.get(dim2) - rad.doubleValue());
          double[] p3 = proj.fastProjectDataToRenderSpace(v3);
          double[] p4 = proj.fastProjectDataToRenderSpace(v4);
          // delta vector
          Vector dt2 = new Vector(v2.getDimensionality());
          dt2.set(dim2, rad.doubleValue());
          double[] d2 = proj.fastProjectRelativeDataToRenderSpace(dt2);

          path.moveTo(p1[0], p1[1]);
          path.cubicTo(p1[0] + d2[0] * EUCLIDEAN_KAPPA, p1[1] + d2[1] * EUCLIDEAN_KAPPA, p3[0] + d1[0] * EUCLIDEAN_KAPPA, p3[1] + d1[1] * EUCLIDEAN_KAPPA, p3[0], p3[1]);
          path.cubicTo(p3[0] - d1[0] * EUCLIDEAN_KAPPA, p3[1] - d1[1] * EUCLIDEAN_KAPPA, p2[0] + d2[0] * EUCLIDEAN_KAPPA, p2[1] + d2[1] * EUCLIDEAN_KAPPA, p2[0], p2[1]);
          path.cubicTo(p2[0] - d2[0] * EUCLIDEAN_KAPPA, p2[1] - d2[1] * EUCLIDEAN_KAPPA, p4[0] - d1[0] * EUCLIDEAN_KAPPA, p4[1] - d1[1] * EUCLIDEAN_KAPPA, p4[0], p4[1]);
          path.cubicTo(p4[0] + d1[0] * EUCLIDEAN_KAPPA, p4[1] + d1[1] * EUCLIDEAN_KAPPA, p1[0] - d2[0] * EUCLIDEAN_KAPPA, p1[1] - d2[1] * EUCLIDEAN_KAPPA, p1[0], p1[1]);
          path.close();
        }
      }
    }
    return path.makeElement(svgp);
  }

  /**
   * Wireframe "Lp" hypersphere
   *
   * @param <V> vector type
   * @param <D> radius
   * @param svgp SVG Plot
   * @param proj Visualization projection
   * @param mid mean vector
   * @param rad radius
   * @param p L_p value
   * @return path element
   */
  public static <V extends NumberVector<V, ?>, D extends NumberDistance<?, ?>> Element drawLp(SVGPlot svgp, Projection2D proj, V mid, D rad, double p) {
    Vector v_mid = mid.getColumnVector();
    BitSet dims = proj.getVisibleDimensions2D();

    final double kappax, kappay;
    if(p > 1.) {
      double kappal = Math.pow(0.5, 1. / p);
      kappax = Math.min(1.3, 4. * (2 * kappal - 1) / 3.);
      kappay = 0;
    }
    else if(p < 1.) {
      double kappal = 1 - Math.pow(0.5, 1. / p);
      kappax = 0;
      kappay = Math.min(1.3, 4. * (2 * kappal - 1) / 3.);
    }
    else {
      kappax = 0;
      kappay = 0;
    }
    // LoggingUtil.warning("kappax: " + kappax + " kappay: " + kappay);

    SVGPath path = new SVGPath();
    for(int dim = dims.nextSetBit(0); dim >= 0; dim = dims.nextSetBit(dim + 1)) {
      Vector vp0 = v_mid.copy();
      vp0.set(dim, vp0.get(dim) + rad.doubleValue());
      Vector vm0 = v_mid.copy();
      vm0.set(dim, vm0.get(dim) - rad.doubleValue());
      double[] pvp0 = proj.fastProjectDataToRenderSpace(vp0);
      double[] pvm0 = proj.fastProjectDataToRenderSpace(vm0);
      // delta vector
      Vector tvd0 = new Vector(vp0.getDimensionality());
      tvd0.set(dim, rad.doubleValue());
      double[] vd0 = proj.fastProjectRelativeDataToRenderSpace(tvd0);
      for(int dim2 = dims.nextSetBit(0); dim2 >= 0; dim2 = dims.nextSetBit(dim2 + 1)) {
        if(dim < dim2) {
          Vector v0p = v_mid.copy();
          v0p.set(dim2, v0p.get(dim2) + rad.doubleValue());
          Vector v0m = v_mid.copy();
          v0m.set(dim2, v0m.get(dim2) - rad.doubleValue());
          double[] pv0p = proj.fastProjectDataToRenderSpace(v0p);
          double[] pv0m = proj.fastProjectDataToRenderSpace(v0m);
          // delta vector
          Vector tv0d = new Vector(vm0.getDimensionality());
          tv0d.set(dim2, rad.doubleValue());
          double[] v0d = proj.fastProjectRelativeDataToRenderSpace(tv0d);

          if(p > 1) {
            // p > 1
            path.moveTo(pvp0[0], pvp0[1]);
            // support points, p0 to 0p
            final double s_pp1_x = pvp0[0] + v0d[0] * kappax;
            final double s_pp1_y = pvp0[1] + v0d[1] * kappax;
            final double s_pp2_x = pv0p[0] + vd0[0] * kappax;
            final double s_pp2_y = pv0p[1] + vd0[1] * kappax;
            path.cubicTo(s_pp1_x, s_pp1_y, s_pp2_x, s_pp2_y, pv0p[0], pv0p[1]);
            // support points, 0p to m0
            final double s_mp1_x = pv0p[0] - vd0[0] * kappax;
            final double s_mp1_y = pv0p[1] - vd0[1] * kappax;
            final double s_mp2_x = pvm0[0] + v0d[0] * kappax;
            final double s_mp2_y = pvm0[1] + v0d[1] * kappax;
            path.cubicTo(s_mp1_x, s_mp1_y, s_mp2_x, s_mp2_y, pvm0[0], pvm0[1]);
            // support points, m0 to 0m
            final double s_mm1_x = pvm0[0] - v0d[0] * kappax;
            final double s_mm1_y = pvm0[1] - v0d[1] * kappax;
            final double s_mm2_x = pv0m[0] - vd0[0] * kappax;
            final double s_mm2_y = pv0m[1] - vd0[1] * kappax;
            path.cubicTo(s_mm1_x, s_mm1_y, s_mm2_x, s_mm2_y, pv0m[0], pv0m[1]);
            // support points, 0m to p0
            final double s_pm1_x = pv0m[0] + vd0[0] * kappax;
            final double s_pm1_y = pv0m[1] + vd0[1] * kappax;
            final double s_pm2_x = pvp0[0] - v0d[0] * kappax;
            final double s_pm2_y = pvp0[1] - v0d[1] * kappax;
            path.cubicTo(s_pm1_x, s_pm1_y, s_pm2_x, s_pm2_y, pvp0[0], pvp0[1]);
            path.close();
          }
          else if(p < 1) {
            // p < 1
            // support points, p0 to 0p
            final double s_vp0_x = pvp0[0] - vd0[0] * kappay;
            final double s_vp0_y = pvp0[1] - vd0[1] * kappay;
            final double s_v0p_x = pv0p[0] - v0d[0] * kappay;
            final double s_v0p_y = pv0p[1] - v0d[1] * kappay;
            final double s_vm0_x = pvm0[0] + vd0[0] * kappay;
            final double s_vm0_y = pvm0[1] + vd0[1] * kappay;
            final double s_v0m_x = pv0m[0] + v0d[0] * kappay;
            final double s_v0m_y = pv0m[1] + v0d[1] * kappay;
            // Draw the star
            path.moveTo(pvp0[0], pvp0[1]);
            path.cubicTo(s_vp0_x, s_vp0_y, s_v0p_x, s_v0p_y, pv0p[0], pv0p[1]);
            path.cubicTo(s_v0p_x, s_v0p_y, s_vm0_x, s_vm0_y, pvm0[0], pvm0[1]);
            path.cubicTo(s_vm0_x, s_vm0_y, s_v0m_x, s_v0m_y, pv0m[0], pv0m[1]);
            path.cubicTo(s_v0m_x, s_v0m_y, s_vp0_x, s_vp0_y, pvp0[0], pvp0[1]);
            path.close();
          }
          else {
            // p == 1 - Manhattan
            path.moveTo(pvp0[0], pvp0[1]);
            path.lineTo(pv0p[0], pv0p[1]);
            path.lineTo(pvm0[0], pvm0[1]);
            path.lineTo(pv0m[0], pv0m[1]);
            path.lineTo(pvp0[0], pvp0[1]);
            path.close();
          }
        }
      }
    }
    return path.makeElement(svgp);
  }

  /**
   * Wireframe "cross" hypersphere
   *
   * @param <V> vector type
   * @param <D> radius
   * @param svgp SVG Plot
   * @param proj Visualization projection
   * @param mid mean vector
   * @param rad radius
   * @return path element
   */
  public static <V extends NumberVector<V, ?>, D extends NumberDistance<?, ?>> Element drawCross(SVGPlot svgp, Projection2D proj, V mid, D rad) {
    Vector v_mid = mid.getColumnVector();
    BitSet dims = proj.getVisibleDimensions2D();

    SVGPath path = new SVGPath();
    for(int dim = dims.nextSetBit(0); dim >= 0; dim = dims.nextSetBit(dim + 1)) {
      Vector v1 = v_mid.copy();
      v1.set(dim, v1.get(dim) + rad.doubleValue());
      Vector v2 = v_mid.copy();
      v2.set(dim, v2.get(dim) - rad.doubleValue());
      double[] p1 = proj.fastProjectDataToRenderSpace(v1);
      double[] p2 = proj.fastProjectDataToRenderSpace(v2);
      path.moveTo(p1[0], p1[1]);
      path.drawTo(p2[0], p2[1]);
      path.close();
    }
    return path.makeElement(svgp);
  }
}
TOP

Related Classes of de.lmu.ifi.dbs.elki.visualization.svg.SVGHyperSphere

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.