Package hs.javafx.control

Source Code of hs.javafx.control.RayCarouselSkin

package hs.javafx.control;

import javafx.beans.InvalidationListener;
import javafx.beans.Observable;
import javafx.geometry.Point2D;
import javafx.geometry.Point3D;
import javafx.scene.effect.Effect;
import javafx.scene.effect.PerspectiveTransform;
import javafx.scene.effect.Reflection;
import javafx.scene.shape.Polygon;
import javafx.scene.shape.Shape;

public class RayCarouselSkin<T> extends AbstractCarouselSkin<T> {

  public RayCarouselSkin(final Carousel<T> carousel) {
    super(carousel);

    InvalidationListener invalidationListener = new InvalidationListener() {
      @Override
      public void invalidated(Observable observable) {
        requestLayout();
      }
    };

    carousel.cellAlignmentProperty().addListener(invalidationListener);
    carousel.reflectionEnabledProperty().addListener(invalidationListener);
    carousel.clipReflectionsProperty().addListener(invalidationListener);
    carousel.fieldOfViewRatioProperty().addListener(invalidationListener);
    carousel.radiusRatioProperty().addListener(invalidationListener);
    carousel.viewDistanceRatioProperty().addListener(invalidationListener);
  }

  private class CellConfigurator {
    private final CarouselCell<T> cell;
    private final double index;

    private Effect reflection;
    private double reflectionTop;
    private double reflectionSpace;

    private Point3D ul;
    private Point3D ur;
    private Point3D ll;
    private Point3D lr;
    private Point3D ulReflection;
    private Point3D urReflection;
    private Point2D ulReflection2d;
    private Point2D urReflection2d;

    private PerspectiveTransform perspectiveTransform;

    public CellConfigurator(CarouselCell<T> cell, double index) {
      this.cell = cell;
      this.index = index;
    }

    public void addReflection() {
      double reflectionMaxHeight = 50;

      double h = cell.prefHeight(50);

      double verticalAlignment = getSkinnable().getCellAlignment();
      double maxCellHeight = getSkinnable().getMaxCellHeight();

      double topOfCell = (maxCellHeight - h) * verticalAlignment;
      double reflectionTop = 2 * (maxCellHeight - topOfCell - h);
      double reflectionTopOpacity = 0.5 - 0.5 / reflectionMaxHeight * reflectionTop / 2;
      double reflectionBottomOpacity = 0;
      double reflectionPortion = (reflectionMaxHeight - reflectionTop / 2) / h;

      if(reflectionPortion < 0 || reflectionTopOpacity < 0) {
        reflectionTopOpacity = 0;
        reflectionPortion = 0;
      }
      if(reflectionPortion > 1) {
        reflectionBottomOpacity = 0.5 - 0.5 / reflectionPortion;
        reflectionPortion = 1;
      }

      double reflectionHeight = h * reflectionPortion;

      //System.err.println(">>> cell : " + cell.getSkin());
//      Insets insets = ((StackPane)cell
//          .getSkin()
//          .getNode())
//          .getInsets();
//      double insetHeight = insets.getBottom();

//      reflection = new Blend(
//        BlendMode.OVERLAY,
//        new Reflection(reflectionTop - insetHeight - 1, reflectionPortion, reflectionTopOpacity, reflectionBottomOpacity),
//        new ColorInput(0.0, reflectionTop + h, w, reflectionHeight, Color.WHITE)
//      );

      if(reflectionPortion > 0) {
        this.reflection = new Reflection(reflectionTop, reflectionPortion, reflectionTopOpacity, reflectionBottomOpacity);

        this.reflectionTop = reflectionTop;
        this.reflectionSpace = reflectionHeight + reflectionTop;
      }
    }

    public void calculateCarouselCoordinates() {
      double visibleAngle = Math.PI * 0.75;
      double visibleCellsCount = getVisibleCellsCount();
      double angleOnCarousel = visibleAngle / visibleCellsCount * index + Math.PI * 0.5;

      double carouselRadius = getSkinnable().getWidth() * getSkinnable().getRadiusRatio();
      double halfCellWidth = cell.prefWidth(50) * 0.5;
      double h = cell.prefHeight(50);
      double maxCellHeight = getSkinnable().getMaxCellHeight();

      double uy = -maxCellHeight * 0.5 + (maxCellHeight - h) * getSkinnable().getCellAlignment();
      double ly = uy + h + reflectionSpace;

      double cos = Math.cos(angleOnCarousel);
      double sin = -Math.sin(angleOnCarousel);

      ul = new Point3D((carouselRadius + halfCellWidth) * cos, uy, (carouselRadius + halfCellWidth) * sin);
      ur = new Point3D((carouselRadius - halfCellWidth) * cos, uy, (carouselRadius - halfCellWidth) * sin);
      ll = new Point3D((carouselRadius + halfCellWidth) * cos, ly, (carouselRadius + halfCellWidth) * sin);
      lr = new Point3D((carouselRadius - halfCellWidth) * cos, ly, (carouselRadius - halfCellWidth) * sin);

      if(reflection != null) {
        ulReflection = new Point3D((carouselRadius + halfCellWidth) * cos, uy + h + reflectionTop, (carouselRadius + halfCellWidth) * sin);
        urReflection = new Point3D((carouselRadius - halfCellWidth) * cos, uy + h + reflectionTop, (carouselRadius - halfCellWidth) * sin);
      }

    //Equivalent code:
//    Point3D ul = new Point3D(carouselRadius / scaleFactor + w / 2, -h / 2, 0);
//    Point3D ur = new Point3D(carouselRadius / scaleFactor - w / 2, -h / 2, 0);
//    Point3D ll = new Point3D(carouselRadius / scaleFactor + w / 2, h / 2, 0);
//    Point3D lr = new Point3D(carouselRadius / scaleFactor - w / 2, h / 2, 0);
//
//    Point3D carouselAxis = new Point3D(0, 0, 0);
//
//    ul = rotateY(ul, carouselAxis, angleOnCarousel);
//    ur = rotateY(ur, carouselAxis, angleOnCarousel);
//    ll = rotateY(ll, carouselAxis, angleOnCarousel);
//    lr = rotateY(lr, carouselAxis, angleOnCarousel);
    }

    /**
     * Rotates the Cell towards the Viewer when it is close to the center.  Also mirrors
     * the cells after they passed the center to keep the Cells correctly visible for the
     * viewer.
     */
    public void applyViewRotation() {
      if(index < 3) {
        double angle = index > -3 ? Math.PI / 2 * -index / 3 + Math.PI / 2 : Math.PI;

        Point3D axis = new Point3D((ul.getX() + ur.getX()) / 2, 0, (ul.getZ() + ur.getZ()) / 2);

        ul = rotateY(ul, axis, angle);
        ur = rotateY(ur, axis, angle);
        ll = rotateY(ll, axis, angle);
        lr = rotateY(lr, axis, angle);

        if(reflection != null) {
          ulReflection = rotateY(ulReflection, axis, angle);
          urReflection = rotateY(urReflection, axis, angle);
        }
      }
    }

    public Shape getReflectionClip() {
      if(reflection == null || !getSkinnable().getClipReflections()) {
        return null;
      }

      return new Polygon(
        ulReflection2d.getX(), ulReflection2d.getY(),
        urReflection2d.getX(), urReflection2d.getY(),
        perspectiveTransform.getLrx(), perspectiveTransform.getLry(),
        perspectiveTransform.getLlx(), perspectiveTransform.getLly()
      );
    }

    public PerspectiveTransform build() {
      double w = cell.prefWidth(50);
      double h = cell.prefHeight(50);

      double viewDistance = getWidth() * getSkinnable().getViewDistanceRatio() + getWidth() * getSkinnable().getRadiusRatio();
      double fov = getSkinnable().getFieldOfViewRatio() * getSkinnable().getWidth();
      double cw = w / 2;
      double ch = h / 2;

      Point2D ul2d = project(ul, viewDistance, fov, cw, ch);
      Point2D ur2d = project(ur, viewDistance, fov, cw, ch);
      Point2D ll2d = project(ll, viewDistance, fov, cw, ch);
      Point2D lr2d = project(lr, viewDistance, fov, cw, ch);

      perspectiveTransform = new PerspectiveTransform(ul2d.getX(), ul2d.getY(), ur2d.getX(), ur2d.getY(), lr2d.getX(), lr2d.getY(), ll2d.getX(), ll2d.getY());

      if(reflection != null) {
        ulReflection2d = project(ulReflection, viewDistance, fov, cw, ch);
        urReflection2d = project(urReflection, viewDistance, fov, cw, ch);

        perspectiveTransform.setInput(reflection);
      }

      return perspectiveTransform;
    }
  }

  @Override
  public Shape layoutCell(CarouselCell<T> cell, double index) {
    CellConfigurator configurator = new CellConfigurator(cell, index);

    if(getSkinnable().getReflectionEnabled()) {
      configurator.addReflection();
    }
    configurator.calculateCarouselCoordinates();
    configurator.applyViewRotation();

    PerspectiveTransform perspectiveTransform = configurator.build();

    cell.setEffect(perspectiveTransform);

    return configurator.getReflectionClip();
  }

  private static Point2D project(Point3D p, double viewDistance, double fov, double cw, double ch) {
    return new Point2D(p.getX() * fov / (p.getZ() + viewDistance) + cw, p.getY() * fov / (p.getZ() + viewDistance) + ch);
  }

  private static Point3D rotateY(Point3D p, Point3D axis, double radians) {
    Point3D input = new Point3D(p.getX() - axis.getX(), p.getY() - axis.getY(), p.getZ() - axis.getZ());

    return new Point3D(
      input.getZ() * Math.sin(radians) + input.getX() * Math.cos(radians) + axis.getX(),
      input.getY() + axis.getY(),
      input.getZ() * Math.cos(radians) - input.getX() * Math.sin(radians) + axis.getZ()
    );
  }
}
TOP

Related Classes of hs.javafx.control.RayCarouselSkin

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.