Package es.felixcoto.tuenti

Source Code of es.felixcoto.tuenti.AnglePortion

package es.felixcoto.tuenti;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Scanner;

public class Main {
  public static double DOUBLE_PI=Math.PI*2;
 
 
 
  public static void main(String[] args) {
    try {
      Scanner sc=new Scanner(System.in);
      sc.useLocale(Locale.ENGLISH);
      int iNumCases=sc.nextInt();
      int iCasesExecuted=0;
      while (iCasesExecuted<iNumCases){
        Point2D objCenter=new Point2D(sc.nextDouble(), sc.nextDouble());
        Vector2D objTransformToCenterPizza=objCenter.getVectorToPoint(Point2D.ORIGIN);
        double radius=sc.nextDouble();
        int iDifferentIngredientsType=sc.nextInt();
        int iIngredientsTypesProcessed=0;
        Map<String, List<RegularPolygon2D>> objIngredentsList=new HashMap<String, List<RegularPolygon2D>>();
        while (iIngredientsTypesProcessed<iDifferentIngredientsType){
          String sIngredentName=sc.next();
          List<RegularPolygon2D> objCurrentIngredentList;
          if (objIngredentsList.containsKey(sIngredentName)){
            objCurrentIngredentList=objIngredentsList.get(sIngredentName);
          }else{
            objCurrentIngredentList=new ArrayList<RegularPolygon2D>();
            objIngredentsList.put(sIngredentName, objCurrentIngredentList);
          }
          int iSidesOfPolygon=sc.nextInt();
          int iQuantityOfCurrentIngredentType=sc.nextInt();
          int iIngredentsProccesed=0;
          while (iIngredentsProccesed<iQuantityOfCurrentIngredentType){
            // translate all points to make center of pizza the origin of coordinates
            Point2D centerOfPolygon=new Point2D(sc.nextDouble(), sc.nextDouble());
            centerOfPolygon=centerOfPolygon.translate(objTransformToCenterPizza);
            Point2D firstVertex=new Point2D(sc.nextDouble(), sc.nextDouble());
            firstVertex=firstVertex.translate(objTransformToCenterPizza);
            objCurrentIngredentList.add(new RegularPolygon2D(centerOfPolygon, firstVertex, iSidesOfPolygon));
            iIngredentsProccesed++;
          }
          iIngredientsTypesProcessed++;
        }
        boolean bResult=isSolomonicCutPossible( radius, objIngredentsList);
        System.out.println(String.format("Case #%d: %s", iCasesExecuted+1,Boolean.toString(bResult).toUpperCase()));
        iCasesExecuted++;
      }
    } catch (Exception e) {
      e.printStackTrace();
    }
  }
 
 
  private static boolean isSolomonicCutPossible(double objRadius, Map<String, List<RegularPolygon2D>> objIngredentsList) throws Exception {
    boolean bEvenIngredents=true;
    Iterator<List<RegularPolygon2D>> itIngredentsList=objIngredentsList.values().iterator();
   
    // test if there are even number of all types of ingredients
    while (itIngredentsList.hasNext()&& bEvenIngredents){
      List<RegularPolygon2D> objCurrentIngredentList=itIngredentsList.next();
      bEvenIngredents=(objCurrentIngredentList.size()%2)==0;
     
    }
   
    boolean bResult;
   
    if (!bEvenIngredents){
      bResult=false;
    }else{
     
      // find all possible cuts without cut any ingredent
      itIngredentsList=objIngredentsList.values().iterator();
      List<AnglePortion> objCurrentPossibleCuts=new ArrayList<AnglePortion>();
      objCurrentPossibleCuts.add(new AnglePortion(0, Math.PI));
     
     
     
      //debug lists
      List<List<AnglePortion>> objListOfAnglesToSubstract=new ArrayList<List<AnglePortion>>();
      List<Double> objListOfRelativeAngle=new ArrayList<Double>();
      List<Vector2D[]> objListOfVectors=new ArrayList<Vector2D[]>();
      List<Vector2D> objListOfHighVectors=new ArrayList<Vector2D>();
      List<Vector2D> objListOfLowVectors=new ArrayList<Vector2D>();

     
      // iterate for every ingredient polygon
      while (itIngredentsList.hasNext()&&!objCurrentPossibleCuts.isEmpty()){
        List<RegularPolygon2D> ingredientPositions=itIngredentsList.next();
        Iterator<RegularPolygon2D> itPolygon=ingredientPositions.iterator();
        while (itPolygon.hasNext()&&!objCurrentPossibleCuts.isEmpty()){
          RegularPolygon2D objCurrentPolygon2d=itPolygon.next();
          Point2D[] ingredientVertex=objCurrentPolygon2d.generatePolygonVertex();
         
         
          // convert points to vectors
          Vector2D[] centerToVertex=new Vector2D[ingredientVertex.length];
          for (int i=0;i<centerToVertex.length;i++){
            centerToVertex[i]=Point2D.ORIGIN.getVectorToPoint(ingredientVertex[i]);
          }
         
         
         
          objListOfVectors.add(centerToVertex);
         
          // check limits of angle affected by this polygon
          Vector2D objLowVector=null;
          Vector2D objHighVector=null;
          boolean bCenterInsidePolygonDetected=false;
          for (int i=0;i<centerToVertex.length&&!bCenterInsidePolygonDetected;i++){
            boolean bIsLow=false;
            boolean bIsHigh=false;
            Vector2D objCurrentVector=centerToVertex[i];
            if (objLowVector==null){
              objLowVector=objCurrentVector;
            }else{
              double dRelative=objLowVector.getRelativeAngle(objCurrentVector);
              if (dRelative<0){
                objLowVector=objCurrentVector;
                bIsLow=true;
              }
            }
           
            if (objHighVector==null){
              objHighVector=objCurrentVector;
            }else{
              double dRelative=objHighVector.getRelativeAngle(objCurrentVector);
              if (dRelative>0){
                objHighVector=objCurrentVector;
                bIsHigh=true;
              }
            }
            bCenterInsidePolygonDetected=bIsLow&&bIsHigh;
          }
         
          // check if center is inside polygon
          double dRelativeLowToHigh=objLowVector.getRelativeAngle(objHighVector);
         
          objListOfHighVectors.add(objHighVector);
          objListOfLowVectors.add(objLowVector);
          objListOfRelativeAngle.add(dRelativeLowToHigh);
         
         
          if (bCenterInsidePolygonDetected|| dRelativeLowToHigh<0){
            // center is inside of a polygon, the cut is impossible
            objCurrentPossibleCuts.clear();
          }else{
            // Determine the limits of the polygon and make what angles have to subtract to current cut possibilities
            List<AnglePortion> anglesToSubstract=new ArrayList<AnglePortion>();
            if (objLowVector.getRelativeAngleTo0()>=0 && objHighVector.getRelativeAngleTo0()>=0){
              anglesToSubstract.add(new AnglePortion(objLowVector.getRelativeAngleTo0(), objHighVector.getRelativeAngleTo0()));
            }else if (objLowVector.getRelativeAngleTo0()<=0 && objHighVector.getRelativeAngleTo0()<=0){
              anglesToSubstract.add(new AnglePortion(objLowVector.getRelativeAngleTo0()+Math.PI, objHighVector.getRelativeAngleTo0()+Math.PI));
            }else{
              if (objHighVector.getRelativeAngleTo0()<0){
                anglesToSubstract.add(new AnglePortion(0, objHighVector.getRelativeAngleTo0()+Math.PI));
                anglesToSubstract.add(new AnglePortion(objLowVector.getRelativeAngleTo0(), Math.PI));
              }
             
              if (objLowVector.getRelativeAngleTo0()<0){
                anglesToSubstract.add(new AnglePortion(0, objHighVector.getRelativeAngleTo0()));
                anglesToSubstract.add(new AnglePortion(objLowVector.getRelativeAngleTo0()+Math.PI, Math.PI));
              }
            }
            if (anglesToSubstract.isEmpty()){
              throw new Exception("angles to substract empty");
            }else{
             
              // Subtract angle
              objListOfAnglesToSubstract.add(anglesToSubstract);
              for(AnglePortion objCurrentAngleToSubstract:anglesToSubstract){
                List<AnglePortion> objNewPossiblePortions=new ArrayList<AnglePortion>();
                for(AnglePortion objCurrentPossibleCut:objCurrentPossibleCuts){
                  objNewPossiblePortions.addAll(objCurrentPossibleCut.substract(objCurrentAngleToSubstract));
                }
                objCurrentPossibleCuts=objNewPossiblePortions;
              }
            }
          }
         
        }

      }
     
      if (objCurrentPossibleCuts.isEmpty()){
        bResult=false;
      }else{
        boolean bPosibleCutEven=false;
        // if is possible to make cuts without cut any ingredient, check if any of the possible cuts make possible to divide to half all ingredients
        // to check this, make rotations to simulate the cut is horizontal. If y component is positive ingredient is in upper side, else is in lower side
        Iterator<AnglePortion> itPosibleCuts=objCurrentPossibleCuts.iterator();
        while (!bPosibleCutEven&&itPosibleCuts.hasNext()){
          AnglePortion objCurrentAngle=itPosibleCuts.next();
         
          bPosibleCutEven=true;
          itIngredentsList=objIngredentsList.values().iterator();
          while (bPosibleCutEven&&itIngredentsList.hasNext()){
            List<RegularPolygon2D> ingredientPositions=itIngredentsList.next();
            Iterator<RegularPolygon2D> itPolygon=ingredientPositions.iterator();
            int iDifferenceBetweenHalfs=0;
            while (itPolygon.hasNext()){
              RegularPolygon2D objCurrentPolygon=itPolygon.next();
              Point2D center=objCurrentPolygon.getCenter();
              Point2D centerRotated=center.rotateFromOrigin(-objCurrentAngle.getAngleLow());
              if (centerRotated.getY()>0){
                // Ingredient is in upper side
                iDifferenceBetweenHalfs++;
              }else{
                // Ingredient is in lower side
                iDifferenceBetweenHalfs--;
              }
            }
            bPosibleCutEven=iDifferenceBetweenHalfs==0;
          }
         
        }
        bResult=bPosibleCutEven;
       
       
       
       
       
      }
     
     
    }
   
   
    return bResult;
  }


 
 
 
 
 
 
 
 
}

class Point2D{
  public static final Point2D ORIGIN=new Point2D(0, 0);
 
 
  private double x;
  private double y;
 
 
  public Point2D(double x, double y) {
    this.x = x;
    this.y = y;
  }
  public double getX() {
    return x;
  }
  public double getY() {
    return y;
  }
 
  public Point2D translate(Vector2D objVector){
    double newX=x+objVector.getX();
    double newY=y+objVector.getY();
    return new Point2D(newX,newY);
  }
 
  public Point2D rotateFromOrigin(double dRotateAngle){
    double sinAngle=Math.sin(dRotateAngle);
    double cosAngle=Math.cos(dRotateAngle);
   
    double newX=x*cosAngle-y*sinAngle;
    double newY=y*cosAngle+x*sinAngle;
   
    return new Point2D(newX, newY);
  }
 
  public Vector2D getVectorToPoint(Point2D objOtherPoint){
    return new Vector2D(objOtherPoint.getX()-x,objOtherPoint.getY()-y);
  }
  @Override
  public String toString() {
    return String.format("Point2D [x=%s, y=%s]", x, y);
  }

 
}

class Vector2D{
 
 
  private double x;
  private double y;

  private Double relativeAngleTo0=null;
 
  public Vector2D(double x, double y) {
    this.x = x;
    this.y = y;
  }


  public double getX() {
    return x;
  }


  public double getY() {
    return y;
  }
 
  public Vector2D invertComponents(){
    return new Vector2D(-x, -y);
  }

  public double getRelativeAngle(Vector2D objOtherVector2d){
    double dResult=objOtherVector2d.getRelativeAngleTo0() -this.getRelativeAngleTo0();
    if (dResult>Math.PI){
      dResult=dResult-Main.DOUBLE_PI;
    }else if (dResult<-Math.PI){
      dResult=dResult+Main.DOUBLE_PI;
    }
    return dResult;
  }
 
  public double getRelativeAngleTo0(){
    if (relativeAngleTo0==null){
      relativeAngleTo0=Math.atan2(y,x);
    }
    return relativeAngleTo0;
  }


  @Override
  public String toString() {
    return String.format("Vector2D [x=%s, y=%s, relativeAngleTo0=%s]", x, y, relativeAngleTo0);
  }
 
 
}


class RegularPolygon2D{
  private Point2D center;
  private Point2D firstVertex;
  private int iSides;
  private Point2D[] polygonVertex=null;
 
  /**
   * @param objCenter
   * @param objFirstVertex
   * @param iSides
   */
  public RegularPolygon2D(Point2D objCenter, Point2D objFirstVertex, int iSides) {
    center = objCenter;
    firstVertex = objFirstVertex;
    this.iSides = iSides;
  }
 
 
  public Point2D[] generatePolygonVertex(){
    if (this.polygonVertex==null){
      polygonVertex=new Point2D[iSides];
     
      //Translate vertex to center
      polygonVertex[0]=firstVertex.translate(center.getVectorToPoint(Point2D.ORIGIN));
     
      // Make rotations to find other points
     
      double centerAngle=Main.DOUBLE_PI/iSides;
      double sinCenterAngle=Math.sin(centerAngle);
      double cosCenterAngle=Math.cos(centerAngle);
      for (int i=1;i<iSides;i++){
        Point2D lastPoint=polygonVertex[i-1];
        double newX=lastPoint.getX()*cosCenterAngle-lastPoint.getY()*sinCenterAngle;
        double newY=lastPoint.getY()*cosCenterAngle+lastPoint.getX()*sinCenterAngle;

        polygonVertex[i]=new Point2D(newX, newY);
      }
     
      // translate to position
      Vector2D translationVector=Point2D.ORIGIN.getVectorToPoint(center);
      for (int i=0;i<polygonVertex.length;i++){
        polygonVertex[i]=polygonVertex[i].translate(translationVector);
      }
    }
    return polygonVertex;
  }


  @Override
  public String toString() {
    return String.format("RegularPolygon2D [center=%s, firstVertex=%s, iSides=%s, polygonVertex=%s]", center, firstVertex, iSides,
        Arrays.toString(polygonVertex));
  }


  public Point2D getCenter() {
    return center;
  }


  public Point2D getFirstVertex() {
    return firstVertex;
  }


  public int getSides() {
    return iSides;
  }

 
 
 
 
}


class AnglePortion{
  private double angleLow;
  private double angleHigh;
 
  public AnglePortion(double angleLow, double angleHigh) {
    this.angleLow = angleLow;
    this.angleHigh = angleHigh;
    if (angleHigh<angleLow){
      throw new IllegalArgumentException("high is lower than low");
    }
  }

  public double getAngleLow() {
    return angleLow;
  }

  public double getAngleHigh() {
    return angleHigh;
  }
 
  public List<AnglePortion> substract(AnglePortion otherPortion){
    List<AnglePortion> result=new ArrayList<AnglePortion>();
    if (otherPortion.getAngleLow()<=angleLow && otherPortion.getAngleHigh()>=angleHigh){
      // other portion subtract all angle
    }else{
      if (otherPortion.getAngleLow()>=angleHigh || otherPortion.getAngleHigh()<=angleLow){
        // other portion don't intersect with portion
        result.add(this);
      }else{
        if (otherPortion.getAngleLow()>angleLow && otherPortion.getAngleHigh()<angleHigh){
          // split the angle in 2
          result.add(new AnglePortion(angleLow, otherPortion.getAngleLow()));
          result.add(new AnglePortion(otherPortion.getAngleHigh(), angleHigh));
        }else{
          // The result is quit some part of angle
          if (otherPortion.getAngleLow()>angleLow){
            result.add(new AnglePortion(angleLow,otherPortion.getAngleLow()));
          }else{
            result.add(new AnglePortion(otherPortion.getAngleHigh(),angleHigh));
          }
         
        }
      }
    }
    return result;
  }

  @Override
  public String toString() {
    return String.format("AnglePortion [angleLow=%s, angleHigh=%s]", angleLow, angleHigh);
  }
 
 
}
TOP

Related Classes of es.felixcoto.tuenti.AnglePortion

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.