Advertisement
bekovski

algovi_newPropsPrior

Jul 29th, 2018
105
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Java 46.43 KB | None | 0 0
  1. /*
  2.  * Separating Axis Theorem (Circle - Triangle).java
  3.  * Bekir Özkara, 2018 for the Animal project at TU Darmstadt.
  4.  * Copying this file for educational purposes is permitted without further authorization.
  5.  */
  6. //package generators.misc;
  7.  
  8. import generators.framework.Generator;
  9. import generators.framework.GeneratorType;
  10. import generators.framework.ValidatingGenerator;
  11.  
  12. import java.util.Locale;
  13.  
  14. import algoanim.primitives.Circle;
  15. import algoanim.primitives.Point;
  16. import algoanim.primitives.Polyline;
  17. import algoanim.primitives.Rect;
  18. import algoanim.primitives.SourceCode;
  19. import algoanim.primitives.Text;
  20. import algoanim.primitives.Triangle;
  21. import algoanim.primitives.generators.Language;
  22.  
  23. import java.awt.Color;
  24. import java.awt.Font;
  25. import java.util.ArrayList;
  26. import java.util.Hashtable;
  27. import java.util.List;
  28.  
  29. import generators.framework.properties.AnimationPropertiesContainer;
  30. import interactionsupport.models.MultipleChoiceQuestionModel;
  31. import algoanim.animalscript.AnimalCircleGenerator;
  32. import algoanim.animalscript.AnimalPolylineGenerator;
  33. import algoanim.animalscript.AnimalRectGenerator;
  34. import algoanim.animalscript.AnimalScript;
  35. import algoanim.animalscript.AnimalTextGenerator;
  36. import algoanim.animalscript.AnimalTriangleGenerator;
  37. import algoanim.properties.AnimationPropertiesKeys;
  38. import algoanim.properties.CircleProperties;
  39. import algoanim.properties.PointProperties;
  40. import algoanim.properties.PolylineProperties;
  41. import algoanim.properties.RectProperties;
  42. import algoanim.properties.SourceCodeProperties;
  43. import algoanim.properties.TextProperties;
  44. import algoanim.properties.TriangleProperties;
  45. import algoanim.util.Coordinates;
  46. import algoanim.util.Node;
  47. import algoanim.util.TicksTiming;
  48. import algoanim.util.Timing;
  49. import animal.main.Animal;
  50. import auxiliary.Vector2f;
  51.  
  52. public class SATGenerator implements ValidatingGenerator {
  53.     // auto gen
  54.     private Language lang;
  55.    
  56.     // primitives
  57.     private double vertex_a_x;
  58.     private double vertex_a_y;
  59.     private double vertex_b_x;
  60.     private double vertex_b_y;
  61.     private double vertex_c_x;
  62.     private double vertex_c_y;
  63.     private double circle_center_x;
  64.     private double circle_center_y;
  65.     private double radius;
  66.    
  67.     // properties
  68.     private CircleProperties circleProps;
  69.     private TriangleProperties triangleProps;
  70.         // new
  71.     private RectProperties boxProps;
  72.     private PolylineProperties coordSystemProps;
  73.     private SourceCodeProperties sourceCodeProps;
  74.     private TextProperties textProps;
  75.     private TextProperties vertexNameProps;
  76.     private CircleProperties vertexHighlightProps;
  77.     private PolylineProperties edgeHighlightProps;
  78.     private PolylineProperties radiusHighlightProps;
  79.     private PolylineProperties distanceHighlightProps;
  80.     private PolylineProperties vectorProps;
  81.     private PolylineProperties vectorHighlightProps;
  82.    
  83.    
  84.     // my own
  85.             public static final Color LINE_DEFAULT_COLOR    = Color.BLACK;
  86.             public static final Color VECTOR_DEFAULT_COLOR  = Color.RED;
  87.            
  88.             Text text;
  89.             Point point;
  90.             Circle circle;
  91.             Polyline line;
  92.             Polyline edge;
  93.             Polyline vector;
  94.             Polyline separatingAxis;
  95.             Triangle triangle;
  96.            
  97.             // temp
  98.             Polyline[] vectors = new Polyline[3];
  99.            
  100.             SourceCode sc;
  101.             Timing timing;
  102.            
  103.             // might need these properties
  104.             TextProperties textPropsOld;
  105.             RectProperties rectProps;
  106.             PointProperties pointProps;
  107.             // CircleProperties circleProps;
  108.             PolylineProperties lineProps;
  109.             PolylineProperties vectorPropsOld;
  110.             // TriangleProperties triangleProps;
  111.            
  112.             int x = 40;
  113.             int y = 140;
  114.             int startY;
  115.             int offsetY = 20;
  116.             String vertexName;
  117.             String neighbor1Name;
  118.             String neighbor2Name;
  119.            
  120.             Vector2f separatingAxisStart;
  121.             Vector2f separatingAxisEnd;
  122.            
  123.             List<Text> textList = new ArrayList<>();
  124.     // end my own
  125.  
  126.     public void init(){
  127. //        lang = new AnimalScript("Separating Axis Theorem (Circle - Triangle)", "Bekir Özkara", 800, 600);
  128.         lang = new AnimalScript("Separating Axis Theorem (Circle-Triangle)", "Bekir Oezkara", 640, 480);
  129.         lang.setStepMode(true);
  130.         lang.setInteractionType(Language.INTERACTION_TYPE_AVINTERACTION);
  131.        
  132.         timing = new TicksTiming(200);
  133.        
  134.         textPropsOld = new TextProperties();
  135.         textPropsOld.set(AnimationPropertiesKeys.COLOR_PROPERTY, Color.BLACK);
  136.         textPropsOld.set(AnimationPropertiesKeys.FONT_PROPERTY, new Font("Monospaced", Font.PLAIN, 12));
  137.        
  138.         rectProps = new RectProperties();
  139.         rectProps.set(AnimationPropertiesKeys.COLOR_PROPERTY, Color.DARK_GRAY);
  140.         rectProps.set(AnimationPropertiesKeys.FILLED_PROPERTY, true);
  141.         rectProps.set(AnimationPropertiesKeys.FILL_PROPERTY, Color.LIGHT_GRAY);
  142.         rectProps.set(AnimationPropertiesKeys.DEPTH_PROPERTY, 2);
  143.        
  144.         pointProps = new PointProperties();
  145.         pointProps.set(AnimationPropertiesKeys.COLOR_PROPERTY, Color.CYAN);
  146.        
  147. //      circleProps = new CircleProperties();
  148. //      circleProps.set(AnimationPropertiesKeys.COLOR_PROPERTY, Color.RED);
  149. //      circleProps.set(AnimationPropertiesKeys.FILL_PROPERTY, Color.RED);
  150. //      circleProps.set(AnimationPropertiesKeys.FILLED_PROPERTY, true);
  151. //      circleProps.set(AnimationPropertiesKeys.DEPTH_PROPERTY, 2);
  152.        
  153.         lineProps = new PolylineProperties();
  154.         lineProps.set(AnimationPropertiesKeys.COLOR_PROPERTY, LINE_DEFAULT_COLOR);
  155.        
  156.         vectorPropsOld = new PolylineProperties();
  157.         vectorPropsOld.set(AnimationPropertiesKeys.COLOR_PROPERTY, VECTOR_DEFAULT_COLOR);
  158.         vectorPropsOld.set(AnimationPropertiesKeys.FWARROW_PROPERTY, true);
  159.        
  160. //      triangleProps = new TriangleProperties();
  161. //      triangleProps.set(AnimationPropertiesKeys.COLOR_PROPERTY, Color.GREEN);
  162. //      triangleProps.set(AnimationPropertiesKeys.FILL_PROPERTY, Color.WHITE);
  163.     }
  164.    
  165.    
  166.     public static void main(String[] args) {
  167.         ValidatingGenerator generator = new SATGenerator();
  168.         Animal.startGeneratorWindow(generator);
  169.     }
  170.  
  171.     public String generate(AnimationPropertiesContainer props,Hashtable<String, Object> primitives) {
  172. //      lang.setInteractionType(Language.INTERACTION_TYPE_AVINTERACTION);
  173.        
  174.         // primitives
  175.         vertex_a_x = (double)primitives.get("vertex_a_x");
  176.         vertex_a_y = (double)primitives.get("vertex_a_y");
  177.         vertex_b_x = (double)primitives.get("vertex_b_x");
  178.         vertex_b_y = (double)primitives.get("vertex_b_y");
  179.         vertex_c_x = (double)primitives.get("vertex_c_x");
  180.         vertex_c_y = (double)primitives.get("vertex_c_y");
  181.         circle_center_x = (double)primitives.get("circle_center_x");
  182.         circle_center_y = (double)primitives.get("circle_center_y");
  183.         radius = (double)primitives.get("radius");
  184.        
  185.         // properties
  186.         circleProps = (CircleProperties)props.getPropertiesByName("circleProps");
  187.         triangleProps = (TriangleProperties)props.getPropertiesByName("triangleProps");
  188.             // new ones
  189.         boxProps = (RectProperties)props.getPropertiesByName("boxProps");
  190.         coordSystemProps = (PolylineProperties)props.getPropertiesByName("coordSystemProps");
  191.         sourceCodeProps = (SourceCodeProperties)props.getPropertiesByName("sourceCodeProps");
  192.         textProps = (TextProperties)props.getPropertiesByName("textProps");
  193.         vertexNameProps = (TextProperties)props.getPropertiesByName("vertexNameProps");
  194.         vertexHighlightProps = (CircleProperties)props.getPropertiesByName("vertexHighlightProps");
  195.         edgeHighlightProps = (PolylineProperties)props.getPropertiesByName("edgeHighlightProps");
  196.         radiusHighlightProps = (PolylineProperties)props.getPropertiesByName("radiusHighlightProps");
  197.         distanceHighlightProps = (PolylineProperties)props.getPropertiesByName("distanceHighlightProps");
  198.         vectorProps = (PolylineProperties)props.getPropertiesByName("vectorProps");
  199.         vectorHighlightProps = (PolylineProperties)props.getPropertiesByName("vectorHighlightProps");
  200.        
  201.         init();
  202.        
  203.         List<Text> texts = showIntroText();
  204.         lang.nextStep();
  205.         for(Text t : texts) {
  206.             t.hide();
  207.         }
  208.        
  209.         showIntroQuestion();
  210.         lang.nextStep();
  211.        
  212.         createScene();
  213.        
  214.        
  215.         auxiliary.Circle C = new auxiliary.Circle(new Vector2f((float)circle_center_x, (float)circle_center_y), (float)radius);
  216.         // auxiliary.Triangle T = new auxiliary.Triangle(new Vector2f(1, 1), new Vector2f(3, 1), new Vector2f(2, 4));
  217.         auxiliary.Triangle T = new auxiliary.Triangle(
  218.                 new Vector2f((float)vertex_a_x, (float)vertex_a_y),
  219.                 new Vector2f((float)vertex_b_x, (float)vertex_b_y),
  220.                 new Vector2f((float)vertex_c_x, (float)vertex_c_y));
  221.         hasSA(C, T);
  222.        
  223.         clearScreen();
  224.        
  225.         circleProps.set(AnimationPropertiesKeys.DEPTH_PROPERTY, 1);
  226.         triangleProps.set(AnimationPropertiesKeys.DEPTH_PROPERTY, 1);
  227.        
  228.         showOutroQuestions();
  229.         lang.nextStep();
  230.         clearScreen();
  231.        
  232.         showOutroText();
  233.        
  234.        
  235.         lang.finalizeGeneration();
  236.         return lang.toString();
  237.     }
  238.    
  239.     // ====================================================================================================================================
  240.     // ====================================================================================================================================
  241.     // ====================================================================================================================================
  242.     // ====================================================================================================================================
  243.     // ====================================================================================================================================
  244.     // ====================================================================================================================================
  245.  
  246.     public void createScene() {
  247.         makeHeader();
  248.         makeSideBox();
  249.         drawCoordSystem();
  250.     }
  251.    
  252.     public boolean hasSA(auxiliary.Circle circle, auxiliary.Triangle triangle) {
  253.        
  254.         makeCircle(circle.center.x, circle.center.y, circle.radius);
  255.         makeTriangle(triangle.A, triangle.B, triangle.C);
  256.         lang.nextStep();
  257.        
  258.         x = 910;
  259.         startY = 160;
  260.         y = startY;
  261.        
  262.         // vertices
  263.         showSourceCodeVertexSA();
  264.         Circle vertexHighlightCircle;
  265.         boolean isFilled = true;
  266.        
  267.         makeText("A", 600 + 40 * (int)triangle.A.x + 5 , 300 - 40 * (int)triangle.A.y);
  268.         makeText("B", 600 + 40 * (int)triangle.B.x + 5 , 300 - 40 * (int)triangle.B.y);
  269.         makeText("C", 600 + 40 * (int)triangle.C.x + 5 , 300 - 40 * (int)triangle.C.y);
  270.        
  271.         vertexName = "A";
  272.         neighbor1Name = "B";
  273.         neighbor2Name = "C";
  274.         vertexHighlightCircle = makeCircle(triangle.A.x, triangle.A.y, 0.1f, Color.PINK, isFilled);
  275.         textAndStep("Vertex A");
  276.         vertexHighlightCircle.hide();
  277.         boolean separatedByVertexA = isVertexSA(circle, triangle, triangle.A);
  278.        
  279.         clearText();
  280.         y = startY;
  281.        
  282.         vertexName = "B";
  283.         neighbor1Name = "A";
  284.         neighbor2Name = "C";
  285.         vertexHighlightCircle = makeCircle(triangle.B.x, triangle.B.y, 0.1f, Color.PINK, isFilled);
  286.         textAndStep("Vertex B");
  287.         vertexHighlightCircle.hide();
  288.         boolean separatedByVertexB = isVertexSA(circle, triangle, triangle.B);
  289.        
  290.         clearText();
  291.         y = startY;
  292.        
  293.         vertexName = "C";
  294.         neighbor1Name = "A";
  295.         neighbor2Name = "B";
  296.         vertexHighlightCircle = makeCircle(triangle.C.x, triangle.C.y, 0.1f, Color.PINK, isFilled);
  297.         textAndStep("Vertex C");
  298.         vertexHighlightCircle.hide();
  299.         boolean separatedByVertexC = isVertexSA(circle, triangle, triangle.C);
  300.        
  301.         clearText();
  302.         y = startY;
  303.        
  304.         // edges
  305.         sc.changeColor("", Color.WHITE, null, null);
  306.         showSourceCodeEdgeSA();
  307.        
  308.         edge = makeLine(triangle.A, triangle.B, false, true);
  309.         edge.changeColor("", Color.PINK, null, null);
  310.         textAndStep("Edge from A to B");
  311.         boolean separatedByEdgeAB = isEdgeSA(circle, triangle, triangle.edgeAB, triangle.A, triangle.B, triangle.C);
  312.         edge.hide();
  313.        
  314.         clearText();
  315.         y = startY;
  316.        
  317.         edge = makeLine(triangle.A, triangle.C, false, true);
  318.         edge.changeColor("", Color.PINK, null, null);
  319.         textAndStep("Edge from A to C");
  320.         boolean separatedByEdgeAC = isEdgeSA(circle, triangle, triangle.edgeAC, triangle.A, triangle.C, triangle.B);
  321.         edge.changeColor("", Color.BLACK, null, null);
  322.        
  323.         clearText();
  324.         y = startY;
  325.        
  326.         edge = makeLine(triangle.B, triangle.C, false, true);
  327.         edge.changeColor("", Color.PINK, null, null);
  328.         textAndStep("Edge from B to C");
  329.         boolean separatedByEdgeBC = isEdgeSA(circle, triangle, triangle.edgeBC, triangle.B, triangle.C, triangle.A);
  330.         edge.hide();
  331.        
  332.         clearText();
  333.         y = startY;
  334.        
  335.         boolean result = separatedByVertexA || separatedByVertexB || separatedByVertexC || separatedByEdgeAB || separatedByEdgeAC || separatedByEdgeBC;
  336.         if(result) {
  337.             separatingAxis = makeLine(separatingAxisStart, separatingAxisEnd, false, true);
  338.             separatingAxis.changeColor("", Color.GREEN, null, null);
  339.         }
  340.         textAndStep("we found separating axis = " + result);
  341.         return result;
  342.     }
  343.    
  344.    
  345.     /**
  346.      *
  347.      * @param circle
  348.      * @param triangle
  349.      * @param vertex
  350.      * @return
  351.      */
  352.     private boolean isVertexSA(auxiliary.Circle circle, auxiliary.Triangle triangle, Vector2f vertex) {
  353.         line = makeLine(circle.center.x, circle.center.y, circle.center.x + circle.radius, circle.center.y, false, true);
  354.         line.changeColor("", Color.BLUE, null, null);
  355.         textAndStep("radius = " + circle.radius);
  356.         line.hide();
  357.        
  358.         sc.highlight(1);
  359.         float distToCenter = vertex.dist(circle.center);
  360.         line = makeLine(vertex, circle.center, false, true);
  361.         line.changeColor("", Color.BLUE, null, null);
  362.         textAndStep("distance to center = " + distToCenter);
  363.         line.hide();
  364.         sc.unhighlight(1);
  365.        
  366.        
  367.         sc.highlight(2);
  368.         Vector2f vertexToCenter = circle.center.sub(vertex);
  369.         vectors[0] = makeLine(vertex, circle.center, true, true);
  370.         textAndStep("vector from vertex to center = " + vertexToCenter);
  371.         sc.unhighlight(2);
  372.        
  373.         Vector2f vertexToNeighbor1;
  374.         Vector2f vertexToNeighbor2;
  375.        
  376.         if(vertex == triangle.A) {
  377.             sc.highlight(6);
  378.             sc.highlight(7);
  379.             sc.highlight(9);
  380.             vertexToNeighbor1 = triangle.B.sub(vertex); // AB
  381.             vertexToNeighbor2 = triangle.C.sub(vertex); // AC
  382.             neighbor1Name = "B";
  383.             neighbor2Name = "C";
  384.             vectors[1] = makeLine(vertex, triangle.B, true, true);
  385.             textAndStep("vector from " + vertexName + " to " + neighbor1Name + " = " + vertexToNeighbor1);
  386.             sc.unhighlight(7);
  387.            
  388.             sc.highlight(8);
  389.             vectors[2] = makeLine(vertex, triangle.C, true, true);
  390.             textAndStep("vector from " + vertexName + " to " + neighbor2Name + " = " + vertexToNeighbor2);
  391.             sc.unhighlight(6);
  392.             sc.unhighlight(8);
  393.             sc.unhighlight(9);
  394.         }
  395.         else if(vertex == triangle.B) {
  396.             sc.highlight(10);
  397.             sc.highlight(11);
  398.             sc.highlight(13);
  399.             vertexToNeighbor1 = triangle.A.sub(vertex); // BA
  400.             vertexToNeighbor2 = triangle.C.sub(vertex); // BC
  401.             neighbor1Name = "A";
  402.             neighbor2Name = "C";
  403.             vectors[1] = makeLine(vertex, triangle.A, true, true);
  404.             textAndStep("vector from " + vertexName + " to " + neighbor1Name + " = " + vertexToNeighbor1);
  405.             sc.unhighlight(11);
  406.            
  407.             sc.highlight(12);
  408.             vectors[2] = makeLine(vertex, triangle.C, true, true);
  409.             textAndStep("vector from " + vertexName + " to " + neighbor2Name + " = " + vertexToNeighbor2);
  410.             sc.unhighlight(10);
  411.             sc.unhighlight(12);
  412.             sc.unhighlight(13);
  413.         }
  414.         else if(vertex == triangle.C) {
  415.             sc.highlight(14);
  416.             sc.highlight(15);
  417.             sc.highlight(17);
  418.             vertexToNeighbor1 = triangle.A.sub(vertex); // CA
  419.             vertexToNeighbor2 = triangle.B.sub(vertex); // CB
  420.             neighbor1Name = "A";
  421.             neighbor2Name = "B";
  422.             vectors[1] = makeLine(vertex, triangle.A, true, true);
  423.             textAndStep("vector from " + vertexName + " to " + neighbor1Name + " = " + vertexToNeighbor1);
  424.             sc.unhighlight(15);
  425.            
  426.             sc.highlight(16);
  427.             vectors[2] = makeLine(vertex, triangle.B, true, true);
  428.             textAndStep("vector from " + vertexName + " to " + neighbor2Name + " = " + vertexToNeighbor2);
  429.             sc.unhighlight(14);
  430.             sc.unhighlight(16);
  431.             sc.unhighlight(17);
  432.         }
  433.         else {
  434.             throw new IllegalArgumentException("The provided vertex: " + vertex + " does not match with any of the triangle's vertices.");
  435.         }
  436.        
  437. //      textAndStep("vector from " + vertexName + " to " + neighbor1Name + " = " + vertexToNeighbor1);
  438. //      textAndStep("vector from " + vertexName + " to " + neighbor2Name + " = " + vertexToNeighbor2);
  439.  
  440.         // they are on opposite sides if the dot product is less than zero
  441.         vectors[0].changeColor("", Color.ORANGE, null, null);
  442.        
  443.         sc.highlight(21);
  444.         sc.highlight(22);
  445.         boolean isOppositeNeighbor1 = vertexToCenter.dot(vertexToNeighbor1) < 0;
  446.         vectors[1].changeColor("", Color.ORANGE, null, null);
  447.         textAndStep(neighbor1Name + " is on opposite side = " + isOppositeNeighbor1);
  448.         vectors[1].changeColor("", VECTOR_DEFAULT_COLOR, null, null);
  449.         sc.unhighlight(21);
  450.         sc.unhighlight(22);
  451.        
  452.         sc.highlight(23);
  453.         sc.highlight(24);
  454.         boolean isOppositeNeighbor2 = vertexToCenter.dot(vertexToNeighbor2) < 0;
  455.         vectors[2].changeColor("", Color.ORANGE, null, null);
  456.         textAndStep(neighbor2Name + " is on opposite side = " + isOppositeNeighbor2);
  457.         sc.unhighlight(23);
  458.         sc.unhighlight(24);
  459.        
  460.         vectors[0].hide();
  461.         vectors[1].hide();
  462.         vectors[2].hide();
  463.        
  464.         sc.highlight(26);
  465.         boolean radius_less_than_dist = circle.radius < distToCenter;
  466.         textAndStep("radius smaller than distance = " + radius_less_than_dist);
  467.        
  468.         boolean result = radius_less_than_dist && isOppositeNeighbor1 && isOppositeNeighbor2;
  469.         line = makeLine(vertex, circle.center, false, true);
  470.         line.changeColor("", result ? Color.GREEN : Color.RED, null, null);
  471.         if(result) {
  472.             separatingAxisStart = new Vector2f(vertex.x, vertex.y);
  473.             separatingAxisEnd   = new Vector2f(circle.center.x, circle.center.y);
  474. //          separatingAxis =  makeLine(vertex, circle.center, false, true);
  475.         }
  476.         sc.highlight(27);
  477.         textAndStep("vertex is separating axis = " + result);
  478.         line.hide();
  479.         sc.unhighlight(26);
  480.         sc.unhighlight(27);
  481. //      if(separatingAxis != null) {
  482. //          separatingAxis.hide(); 
  483. //      }
  484.         return result;
  485.     }
  486.    
  487.    
  488.     /**
  489.      *
  490.      * @param circle
  491.      * @param triangle
  492.      * @param edge
  493.      * @param start
  494.      * @param end
  495.      * @param other
  496.      * @return
  497.      */
  498.     private boolean isEdgeSA(auxiliary.Circle circle, auxiliary.Triangle triangle, Vector2f edge, Vector2f start, Vector2f end, Vector2f other) {
  499.         line = makeLine(circle.center.x, circle.center.y, circle.center.x + circle.radius, circle.center.y, false, true);
  500.         // line.getProperties().set(AnimationPropertiesKeys.COLOR_PROPERTY, Color.BLUE);
  501.         line.changeColor("", Color.BLUE, null, null);
  502.         textAndStep("radius = " + circle.radius);
  503.         line.hide();
  504.        
  505.         sc.highlight(1);
  506.         Vector2f normalizedEdge = edge.normalize();
  507.         vector = makeLine(start.x, start.y, start.x + normalizedEdge.x, start.y + normalizedEdge.y, true, true);
  508.         vector.changeColor("", VECTOR_DEFAULT_COLOR, null, null);
  509.         textAndStep("normalized edge = " + normalizedEdge);
  510.         vector.hide();
  511.         sc.unhighlight(1);
  512.        
  513.         Vector2f vecToCircle;
  514.         if(edge == triangle.edgeAB) {
  515.             sc.highlight(4);
  516.             sc.highlight(5);
  517.             sc.highlight(6);
  518.             vecToCircle = circle.center.sub(triangle.A);
  519.             vector = makeLine(triangle.A, circle.center, true, true);
  520.             textAndStep("vector to circle = " + vecToCircle);
  521.             vector.hide();
  522.             sc.unhighlight(4);
  523.             sc.unhighlight(5);
  524.             sc.unhighlight(6);
  525.         }
  526.         else if(edge == triangle.edgeAC) {
  527.             sc.highlight(7);
  528.             sc.highlight(8);
  529.             sc.highlight(9);
  530.             // TODO: why not C, or: when A, when C ?
  531.             vecToCircle = circle.center.sub(triangle.A);
  532.             vector = makeLine(triangle.A, circle.center, true, true);
  533.             textAndStep("vector to circle = " + vecToCircle);
  534.             vector.hide();
  535.             sc.unhighlight(7);
  536.             sc.unhighlight(8);
  537.             sc.unhighlight(9);
  538.         }
  539.         else if(edge == triangle.edgeBC) {
  540.             sc.highlight(10);
  541.             sc.highlight(11);
  542.             sc.highlight(12);
  543.             vecToCircle = circle.center.sub(triangle.B);
  544.             vector = makeLine(triangle.B, circle.center, true, true);
  545.             textAndStep("vector to circle = " + vecToCircle);
  546.             vector.hide();
  547.             sc.unhighlight(10);
  548.             sc.unhighlight(11);
  549.             sc.unhighlight(12);
  550.         }
  551.         else {
  552.             throw new IllegalArgumentException("The provided edge: " + edge + " does not match with any of the triangle's edges.");
  553.         }
  554.        
  555.         sc.highlight(13);
  556.         float dot = normalizedEdge.dot(vecToCircle);
  557.         // line = makeLine(start.x, start.y, start.x + dot, start.y + dot, false, true);
  558.         // TODO: fix dot product (get direction right!)
  559.         line = makeLine(start, start.add(normalizedEdge.mul(dot)), false, true);        // is this right ?
  560.         line.changeColor("", Color.CYAN, null, null);
  561.         textAndStep("dot product of normalizedEdge and vectorToCircle = " + dot);
  562.         line.hide();
  563.         sc.unhighlight(13);
  564.        
  565.         Vector2f closestPointToCircle;
  566.         int codeLine1 = 0;
  567.         int codeLine2 = 0;
  568.         if(dot <= 0) {
  569.             codeLine1 = 16;
  570.             sc.highlight(codeLine1);
  571.             closestPointToCircle = start;
  572.         }
  573.         else if(dot >= edge.length()) {
  574.             codeLine1 = 19;
  575.             sc.highlight(codeLine1);
  576.             closestPointToCircle = end;
  577.         }
  578.         else {
  579.             codeLine1 = 22;
  580.             codeLine2 = 23;
  581.             sc.highlight(codeLine1);
  582.             sc.highlight(codeLine2);
  583.             closestPointToCircle = normalizedEdge.mul(dot).add(start);
  584.         }
  585.        
  586.         Circle pointToHighlight;
  587.         boolean isFilled = true;
  588.        
  589.         line = makeLine(start, closestPointToCircle, false, true);
  590.         line.changeColor("", Color.CYAN, null, null);
  591.         pointToHighlight = makeCircle(closestPointToCircle.x, closestPointToCircle.y, 0.1f, Color.PINK, isFilled);
  592.         textAndStep("closest point to circle = " + closestPointToCircle);
  593.         pointToHighlight.hide();
  594.         line.hide();
  595.         sc.unhighlight(codeLine1);
  596.         sc.unhighlight(codeLine2);
  597.        
  598.         // check if the other vertex (the one that is not part of the current edge) and the circle-center lie on opposite sides of the edge
  599.         sc.highlight(29);
  600.         sc.highlight(30);
  601.         Vector2f vecFromClosestPointToCircle        = circle.center.sub(closestPointToCircle);
  602.         vectors[0] = makeLine(closestPointToCircle, circle.center, true, true);
  603.         textAndStep("vector from closest point to circle = " + vecFromClosestPointToCircle);
  604.         sc.unhighlight(29);
  605.         sc.unhighlight(30);
  606.        
  607.         sc.highlight(31);
  608.         sc.highlight(32);
  609.         Vector2f vecFromClosestPointToOtherVertex   = other.sub(closestPointToCircle);
  610.         vectors[1] = makeLine(closestPointToCircle, other, true, true);
  611.         textAndStep("vector from closest point to other vertex = " + vecFromClosestPointToOtherVertex);
  612.         sc.unhighlight(31);
  613.         sc.unhighlight(32);
  614.        
  615.         sc.highlight(33);
  616.         boolean isOppositeOtherVertex               = vecFromClosestPointToCircle.dot(vecFromClosestPointToOtherVertex) < 0;
  617.         vectors[0].changeColor("", Color.BLUE, null, null);
  618.         vectors[1].changeColor("", Color.BLUE, null, null);
  619.         textAndStep("other vertex on opposite side of circle = " + isOppositeOtherVertex);
  620.         sc.unhighlight(33);
  621.        
  622.         vectors[0].hide();
  623.         vectors[1].hide();
  624.        
  625.         sc.highlight(35);
  626.         boolean radius_less_than_dist_to_closest_point = circle.radius < vecFromClosestPointToCircle.length();
  627.         textAndStep("radius less than distance to closest point = " + radius_less_than_dist_to_closest_point);
  628.        
  629.         boolean result = radius_less_than_dist_to_closest_point && isOppositeOtherVertex;
  630.         line = makeLine(closestPointToCircle, circle.center, false, true);
  631.         line.changeColor("", result ? Color.GREEN : Color.RED, null, null);
  632.         if(result) {
  633.             separatingAxisStart = new Vector2f(closestPointToCircle.x, closestPointToCircle.y);
  634.             separatingAxisEnd   = new Vector2f(circle.center.x, circle.center.y);
  635. //          separatingAxis = makeLine(closestPointToCircle, circle.center, false, true);
  636.         }
  637.         textAndStep("is separating axis = " + result);
  638.         line.hide();
  639.         sc.unhighlight(35);
  640. //      if(separatingAxis != null) {
  641. //          separatingAxis.hide(); 
  642. //      }
  643.         return result;
  644.     }
  645.    
  646.    
  647.     // ====================================================================================================================================
  648.     // ====================================================================================================================================
  649.    
  650.     private Circle makeCircle(float x, float y, float radius) {
  651.         return new Circle(new AnimalCircleGenerator(lang), transformCoords(x, y), transformRadius(radius), "circle", null, circleProps);
  652.     }
  653.    
  654.     private Circle makeCircle(float x, float y, float radius, Color color, boolean isFilled) {
  655.         CircleProperties props = new CircleProperties();
  656.         props.set(AnimationPropertiesKeys.FILL_PROPERTY, color);
  657.         props.set(AnimationPropertiesKeys.FILLED_PROPERTY, isFilled);
  658.         return new Circle(new AnimalCircleGenerator(lang), transformCoords(x, y), transformRadius(radius), "circle", null, props);
  659.     }
  660.    
  661.     private Triangle makeTriangle(Vector2f A, Vector2f B, Vector2f C) {
  662.         return makeTriangle(A.x, A.y, B.x, B.y, C.x, C.y);
  663.     }
  664.    
  665.     private Triangle makeTriangle(float Ax, float Ay, float Bx, float By, float Cx, float Cy) {
  666.         return new Triangle(new AnimalTriangleGenerator(lang),
  667.                 transformCoords(Ax, Ay),
  668.                 transformCoords(Bx, By),
  669.                 transformCoords(Cx, Cy),
  670.                 "triangle",
  671.                 null,
  672.                 triangleProps);
  673.     }
  674.    
  675.     private Coordinates transformCoords(float x, float y) {
  676.         float newX = 600 + 40 * x;
  677.         float newY = 300 - 40 * y;
  678.         return new Coordinates((int)newX, (int)newY);
  679.     }
  680.    
  681.     private int transformRadius(float radius) {
  682.         float newRadius = 40 * radius;
  683.         return (int)newRadius;
  684.     }
  685.    
  686.     private Rect makeRect(int upperLeftX, int upperLeftY, int lowerRightX, int lowerRightY) {
  687.         return new Rect(new AnimalRectGenerator(lang), new Coordinates(upperLeftX, upperLeftY), new Coordinates(lowerRightX, lowerRightY), "rect", null, rectProps);
  688.     }
  689.    
  690.     private Rect makeRect(int upperLeftX, int upperLeftY, int lowerRightX, int lowerRightY, RectProperties rectProps) {
  691.         return new Rect(new AnimalRectGenerator(lang), new Coordinates(upperLeftX, upperLeftY), new Coordinates(lowerRightX, lowerRightY), "rect", null, rectProps);
  692.     }
  693.    
  694.     private Text makeText(String text, int x, int y) {
  695.         return new Text(new AnimalTextGenerator(lang), new Coordinates(x, y), text, "text", null, textPropsOld);
  696.     }
  697.    
  698.     private void textAndStep(String text) {
  699.         textAndStep(text, this.x, this.y);
  700.     }
  701.    
  702.     private void textAndStep(String text, int x, int y) {
  703.         textList.add(makeText(text, x, y));
  704.         this.y += offsetY;
  705.         lang.nextStep();
  706.     }
  707.    
  708.     private void clearText() {
  709.         for(Text text : textList) {
  710.             text.setText("", null, null);
  711.         }
  712.        
  713.         textList = new ArrayList<>();
  714.     }
  715.    
  716.    
  717.     private Polyline makeLine(Vector2f from, Vector2f to, boolean isVector, boolean needsTransform) {
  718.         return makeLine(from.x, from.y, to.x, to.y, isVector, needsTransform);
  719.     }
  720.    
  721.     private Polyline makeLine(float startX, float startY, float endX, float endY, boolean isVector, boolean needsTransform) {
  722.         Node[] nodeArray;
  723.         if(needsTransform) {
  724.             nodeArray = new Node[] {
  725.                     transformCoords(startX, startY),
  726.                     transformCoords(endX, endY)
  727.             };
  728.         }
  729.         else {
  730.             nodeArray = new Node[] {
  731.                     new Coordinates((int)startX, (int)startY),
  732.                     new Coordinates((int)endX, (int)endY)
  733.             };
  734.         }
  735.        
  736.         return new Polyline(new AnimalPolylineGenerator(lang), nodeArray, "line", null, isVector ? vectorPropsOld : lineProps);
  737.     }
  738.    
  739.     private Polyline makeLine(float startX, float startY, float endX, float endY, boolean needsTransform, PolylineProperties lineProps) {
  740.         Node[] nodeArray;
  741.         if(needsTransform) {
  742.             nodeArray = new Node[] {
  743.                     transformCoords(startX, startY),
  744.                     transformCoords(endX, endY)
  745.             };
  746.         }
  747.         else {
  748.             nodeArray = new Node[] {
  749.                     new Coordinates((int)startX, (int)startY),
  750.                     new Coordinates((int)endX, (int)endY)
  751.             };
  752.         }
  753.        
  754.         return new Polyline(new AnimalPolylineGenerator(lang), nodeArray, "line", null, lineProps);
  755.     }
  756.    
  757.    
  758.     private void makeHeader() {
  759.         makeRect(430, 25, 790, 50);
  760.        
  761.         TextProperties titleProps = new TextProperties();
  762.         titleProps.set(AnimationPropertiesKeys.FONT_PROPERTY, new Font("SansSerif", Font.BOLD, 16));
  763.         new Text(new AnimalTextGenerator(lang), new Coordinates(450, 27), "Separating Axis Theorem (Circle-Triangle)", "title", null, titleProps);
  764.     }
  765.    
  766.     private void makeSideBox() {
  767.         makeRect(900, 150, 1400, 380, boxProps);
  768.     }
  769.    
  770.     private void drawCoordSystem() {
  771.         int xAxis       = 300;
  772.         int xAxisStart  = 400;
  773.         int xAxisEnd    = 800;
  774.        
  775.         int yAxis       = 600;
  776.         int yAxisStart  = 500;
  777.         int yAxisEnd    = 100;
  778.        
  779.         makeLine(xAxisStart, xAxis, xAxisEnd, xAxis, false, coordSystemProps);  // x-axis (600px)
  780.         makeLine(yAxis, yAxisStart, yAxis, yAxisEnd, false, coordSystemProps);  // y-axis (400px)
  781.        
  782.         int offset = 40;    // 60px = 1cm
  783.        
  784.         // x-axis
  785.         for(int i=xAxisStart; i <= xAxisEnd; i+=offset) {
  786.             makeLine(i, xAxis-5, i, xAxis+5, false, false);
  787.         }
  788.        
  789.         // y-axis
  790.         for(int i=yAxisStart; i >= yAxisEnd; i-=offset) {
  791.             makeLine(yAxis-5, i, yAxis+5, i, false, false);
  792.         }
  793.     }
  794.    
  795.    
  796.     // ====================================================================================================================================
  797.     // ====================================================================================================================================
  798.     // ====================================================================================================================================
  799.     // ====================================================================================================================================
  800.     // ====================================================================================================================================
  801.     // ====================================================================================================================================
  802.    
  803.     public void clearScreen() {
  804.         RectProperties rectProps = new RectProperties();
  805.         rectProps.set(AnimationPropertiesKeys.COLOR_PROPERTY, Color.WHITE);
  806.         rectProps.set(AnimationPropertiesKeys.FILLED_PROPERTY, true);
  807.         rectProps.set(AnimationPropertiesKeys.FILL_PROPERTY, Color.WHITE);
  808.        
  809.         new Rect(new AnimalRectGenerator(lang), new Coordinates(0, 0), new Coordinates(2048, 1024), "rect", null, rectProps);
  810.     }
  811.    
  812.    
  813.     public List<Text> showIntroText() {
  814.         List<Text> texts = new ArrayList<>();
  815.        
  816.         Text header = makeText("Separating Axis Theorem (Circle - Triangle)", 100, 100);
  817.         header.changeColor("", Color.BLUE, null, null);
  818.        
  819.         String t1 = "The Separating Axis Theorem (SAT) can be used to check for collisions between two polygons or between a circle and a polygon.";
  820.         String t2 = "The polygons have to be convex, which, roughly speaking, means that any line drawn through the shape crosses it twice, and no more.";
  821.         String t3 = "To help visualizing it in your head: if there is a separating axis, you can draw a line (perpendicular to that separating axis) ";
  822.         String t4 = "which does not touch the objects -> no collision.";
  823.         String t5 = "In the animation there is a small coordinate system. A smaller range was needed because otherwise normalized vectors wouldn't be drawn correctly.";
  824.         String t6 = "The box on the right hand side keeps track of important values/calculations that are needed for the test.";
  825.        
  826.         texts.add(header);
  827.         texts.add(makeText(t1, 100, 150));
  828.         texts.add(makeText(t2, 100, 170));
  829.         texts.add(makeText(t3, 100, 190));
  830.         texts.add(makeText(t4, 100, 210));
  831.         texts.add(makeText(t5, 100, 250));
  832.         texts.add(makeText(t6, 100, 270));
  833.        
  834.         return texts;
  835.     }
  836.    
  837.     public void showIntroQuestion() {
  838.         MultipleChoiceQuestionModel introQuestion = new MultipleChoiceQuestionModel("Intro");
  839.         introQuestion.setPrompt("The dot product of two vectors is less than zero. What can we infer from this?");
  840.         introQuestion.addAnswer("The angle between them is exactly 90 degrees (~they are perpendicular to each other)", 0,
  841.                 "Wrong! That would be the case if their dot product was equal to zero.");
  842.         introQuestion.addAnswer("The angle between them is less than 90 degrees (~ they point in the same direction)", 0,
  843.                 "Wrong! That would be the case if the dot product was greater than zero.");
  844.         introQuestion.addAnswer("The angle between them is greater than 90 degrees (~ they point in opposite directions)", 0, "Correct!");
  845.         lang.addMCQuestion(introQuestion);
  846.     }
  847.    
  848.     public void showOutroQuestions() {
  849.         Text q11 = makeText("Which is a separating axis, the blue/horizontal line, ", 50, 50);
  850.         q11.changeColor("", Color.BLUE, null, null);
  851.         Text q12 = makeText("or the orange/vertical line?", 50, 70);
  852.         q12.changeColor("", Color.BLUE, null, null);
  853.        
  854.         makeCircle(-5, 3, 1, Color.BLACK, false);
  855.         makeTriangle(1, 2, 3, 2, 2, 5);
  856.         Polyline lineHorizontal = makeLine(-10, 0, 10, 0, false, true);
  857.         lineHorizontal.changeColor("", Color.BLUE, null, null);
  858.         Polyline lineVertical = makeLine(-1.5f, 10, -1.5f, -10, false, true);
  859.         lineVertical.changeColor("", Color.ORANGE, null, null);
  860.        
  861.         // insert quiz 1
  862.         MultipleChoiceQuestionModel axisQuestion = new MultipleChoiceQuestionModel("Axis");
  863.         axisQuestion.setPrompt("Which is a separating axis, the blue/horizontal line, or the orange/vertical line?");
  864.         axisQuestion.addAnswer("blue/horizontal", 1, "Correct!");
  865.         axisQuestion.addAnswer("orange/vertical", 0,
  866.                 "Wrong! This line simply goes through the objects, whereby it shows that a separating axis exists, but it itself is not one.");
  867.         lang.addMCQuestion(axisQuestion);
  868.        
  869.         lang.nextStep();
  870.         clearScreen();
  871.        
  872.         Text q21 = makeText("The objects are clearly not colliding. The algorithm currently iterates over vertex A and says there is no separating axis. Why?", 50, 50);
  873.         q21.changeColor("", Color.BLUE, null, null);
  874.         Text q22 = makeText("Does this mean the algorithm has failed?", 50, 70);
  875.         q22.changeColor("", Color.BLUE, null, null);
  876.        
  877.         makeCircle(2, 2, 1, Color.BLACK, false);
  878.         makeTriangle(-2, 1, 0, 2, -3, 3);
  879.         makeText("A", 600 + 40 * (-2) + 5 , 300 - 40 * 1);
  880.         makeText("B", 600 + 40 * 0 + 5 , 300 - 40 * 2);
  881.         makeText("C", 600 + 40 * (-3) + 5 , 300 - 40 * 3);
  882.        
  883.         // insert quiz 2.1
  884.         MultipleChoiceQuestionModel question21 = new MultipleChoiceQuestionModel("Q2.1");
  885.         question21.setPrompt("The objects are clearly not colliding. The algorithm currently iterates over vertex A and says there is no separating axis. Why?");
  886.         question21.addAnswer("The distance from A to the center of the circle is greater than the circle's radius", 0, "Wrong!");
  887.         question21.addAnswer("Vertex B is not on the opposite side of the center", 1, "Correct!");
  888.         question21.addAnswer("Vertex C is not on the opposite side of the center", 0, "Wrong!");
  889.         lang.addMCQuestion(question21);
  890.        
  891.         lang.nextStep();
  892.         // insert quiz 2.2
  893.         MultipleChoiceQuestionModel question22 = new MultipleChoiceQuestionModel("Q2.2");
  894.         question22.setPrompt("Does this mean the algorithm has failed?");
  895.         question22.addAnswer("No, it will find a separating axis when it iterates over B", 1, "Correct!");
  896.         question22.addAnswer("No, it will find a separating axis when it iterates over C", 0, "Wrong!");
  897.         question22.addAnswer("Yes, the algorithm cannot find a separating axis for this case", 0, "Wrong!");
  898.         lang.addMCQuestion(question22);
  899.     }
  900.    
  901.     public void showOutroText() {
  902.         // final words
  903.         Text header = makeText("Final words", 100, 100);
  904.         header.changeColor("", Color.BLUE, null, null);
  905.        
  906.         makeText("SAT for circles and triangles is a special case.", 100, 150);
  907.         makeText("The case can be generalized for circle/polygon or polygon/polygon, as long as the polygons are convex.", 100, 170);
  908.         makeText("The principles remain roughly the same, the biggest difference being the number of vertices and edges that are involved.", 100, 190);
  909.         makeText("Also, keep in mind that we could short-circuit out of the algorithm the moment we find one separating axis.", 100, 230);
  910.         makeText("I have not done so for illustration purposes, so that all cases are shown at all times.", 100, 250);
  911.     }
  912.    
  913.    
  914.     public void showSourceCodeVertexSA() {
  915.         // first set the visual properties for the source code
  916.         SourceCodeProperties scProps = new SourceCodeProperties();
  917.         scProps.set(AnimationPropertiesKeys.CONTEXTCOLOR_PROPERTY, Color.BLUE);
  918.         scProps.set(AnimationPropertiesKeys.FONT_PROPERTY, new Font("Monospaced", Font.PLAIN, 12));
  919.         scProps.set(AnimationPropertiesKeys.HIGHLIGHTCOLOR_PROPERTY, Color.RED);
  920.         scProps.set(AnimationPropertiesKeys.COLOR_PROPERTY, Color.BLACK);
  921.        
  922.         // now create the source code entity
  923.         sc = lang.newSourceCode(new Coordinates(10, 50), "sourceCode", null, scProps);
  924.        
  925.         // add code lines (the actual sorting algo)
  926.         // parameters: code itself, name (can be null), indention level, display options
  927.         sc.addCodeLine("boolean isVertexSA(Circle circle, Triangle triangle, Vector2f vertex) {", null, 0, null);
  928.         sc.addCodeLine("float distToCenter = vertex.dist(circle.center);", null, 1, null);
  929.         sc.addCodeLine("Vector2f vertexToCenter = circle.center.sub(vertex);", null, 1, null);
  930.         sc.addCodeLine("Vector2f vertexToNeighbor1;", null, 1, null);
  931.         sc.addCodeLine("Vector2f vertexToNeighbor2;", null, 1, null);
  932.         sc.addCodeLine("", null, 0, null);
  933.         sc.addCodeLine("if(vertex == triangle.A) {", null, 1, null);
  934.         sc.addCodeLine("vertexToNeighbor1 = triangle.B.sub(vertex); // AB", null, 2, null);
  935.         sc.addCodeLine("vertexToNeighbor2 = triangle.C.sub(vertex); // AC", null, 2, null);
  936.         sc.addCodeLine("}", null, 1, null);
  937.         sc.addCodeLine("else if(vertex == triangle.B) {", null, 1, null);
  938.         sc.addCodeLine("vertexToNeighbor1 = triangle.A.sub(vertex); // BA", null, 2, null);
  939.         sc.addCodeLine("vertexToNeighbor2 = triangle.C.sub(vertex); // BC", null, 2, null);
  940.         sc.addCodeLine("}", null, 1, null);
  941.         sc.addCodeLine("else if(vertex == triangle.C) {", null, 1, null);
  942.         sc.addCodeLine("vertexToNeighbor1 = triangle.A.sub(vertex); // CA", null, 2, null);
  943.         sc.addCodeLine("vertexToNeighbor2 = triangle.B.sub(vertex); // CB", null, 2, null);
  944.         sc.addCodeLine("}", null, 1, null);
  945.         sc.addCodeLine("", null, 0, null);
  946.         sc.addCodeLine("// they are on opposite sides", null, 1, null);
  947.         sc.addCodeLine("// if the dot product is less than zero", null, 1, null);
  948.         sc.addCodeLine("boolean isOppositeNeighbor1 = ", null, 1, null);
  949.         sc.addCodeLine("vertexToCenter.dot(vertexToNeighbor1) < 0;", null, 2, null);
  950.         sc.addCodeLine("boolean isOppositeNeighbor2 = ", null, 1, null);
  951.         sc.addCodeLine("vertexToCenter.dot(vertexToNeighbor2) < 0;", null, 2, null);
  952.         sc.addCodeLine("", null, 0, null);
  953.         sc.addCodeLine("return circle.radius < distToCenter", null, 1, null);
  954.         sc.addCodeLine("&& isOppositeNeighbor1 && isOppositeNeighbor2;", null, 2, null);
  955.     } // showSourceCodeVertexSA()
  956.    
  957.    
  958.     public void showSourceCodeEdgeSA() {
  959.         // first set the visual properties for the source code
  960.         SourceCodeProperties scProps = new SourceCodeProperties();
  961.         scProps.set(AnimationPropertiesKeys.CONTEXTCOLOR_PROPERTY, Color.BLUE);
  962.         scProps.set(AnimationPropertiesKeys.FONT_PROPERTY, new Font("Monospaced", Font.PLAIN, 12));
  963.         scProps.set(AnimationPropertiesKeys.HIGHLIGHTCOLOR_PROPERTY, Color.RED);
  964.         scProps.set(AnimationPropertiesKeys.COLOR_PROPERTY, Color.BLACK);
  965.        
  966.         // now create the source code entity
  967.         sc = lang.newSourceCode(new Coordinates(10, 50), "sourceCode", null, scProps);
  968.        
  969.         // add code lines (the actual sorting algo)
  970.         // parameters: code itself, name (can be null), indention level, display options
  971.         sc.addCodeLine("boolean isEdgeSA(Circle circle, Triangle triangle, Vector2f edge, Vector2f start, Vector2f end, Vector2f other) {", null, 0, null);
  972.         sc.addCodeLine("Vector2f normalizedEdge = edge.normalize();", null, 1, null);
  973.         sc.addCodeLine("Vector2f vecToCircle;", null, 1, null);
  974.         sc.addCodeLine("", null, 0, null);
  975.         sc.addCodeLine("if(edge == triangle.edgeAB) {", null, 1, null);
  976.         sc.addCodeLine("vecToCircle = circle.center.sub(triangle.A);", null, 2, null);
  977.         sc.addCodeLine("}", null, 1, null);
  978.         sc.addCodeLine("else if(edge == triangle.edgeAC) {", null, 1, null);
  979.         sc.addCodeLine("vecToCircle = circle.center.sub(triangle.A);", null, 2, null);
  980.         sc.addCodeLine("}", null, 1, null);
  981.         sc.addCodeLine("else if(edge == triangle.edgeBC) {", null, 1, null);
  982.         sc.addCodeLine("vecToCircle = circle.center.sub(triangle.B);", null, 2, null);
  983.         sc.addCodeLine("}", null, 1, null);
  984.         sc.addCodeLine("float dot = normalizedEdge.dot(vecToCircle);", null, 1, null);
  985.         sc.addCodeLine("Vector2f closestPointToCircle;", null, 1, null);
  986.         sc.addCodeLine("if(dot <= 0) {", null, 1, null);
  987.         sc.addCodeLine("closestPointToCircle = start;", null, 2, null);
  988.         sc.addCodeLine("}", null, 1, null);
  989.         sc.addCodeLine("else if(dot >= edge.length()) {", null, 1, null);
  990.         sc.addCodeLine("closestPointToCircle = end;", null, 2, null);
  991.         sc.addCodeLine("}", null, 1, null);
  992.         sc.addCodeLine("else {", null, 1, null);
  993.         sc.addCodeLine("closestPointToCircle = ", null, 2, null);
  994.         sc.addCodeLine("normalizedEdge.mul(dot).add(start);", null, 3, null);
  995.         sc.addCodeLine("}", null, 1, null);
  996.         sc.addCodeLine("", null, 0, null);
  997.         sc.addCodeLine("// check if the other vertex", null, 1, null);
  998.         sc.addCodeLine("// (the one that is not part of the current edge)", null, 1, null);
  999.         sc.addCodeLine("// and the circle-center lie on opposite sides of the edge", null, 1, null);
  1000.         sc.addCodeLine("Vector2f vecFromClosestPointToCircle        = ", null, 1, null);
  1001.         sc.addCodeLine("circle.center.sub(closestPointToCircle);", null, 2, null);
  1002.         sc.addCodeLine("Vector2f vecFromClosestPointToOtherVertex   = ", null, 1, null);
  1003.         sc.addCodeLine("other.sub(closestPointToCircle); ", null, 2, null);
  1004.         sc.addCodeLine("boolean isOppositeOtherVertex               = vecFromClosestPointToCircle.dot(vecFromClosestPointToOtherVertex) < 0;", null, 1, null);
  1005.         sc.addCodeLine("", null, 0, null);
  1006.         sc.addCodeLine("return circle.radius < vecFromClosestPointToCircle.length() && isOppositeOtherVertex;", null, 1, null);
  1007.     } // showSourceCodeEdgeSA()
  1008.    
  1009.    
  1010.    
  1011.    
  1012.    
  1013.    
  1014.    
  1015.    
  1016.     // ================================================================================================================================
  1017.     // ================================================================================================================================
  1018.     // ================================================================================================================================
  1019.     // ================================================================================================================================
  1020.     // ================================================================================================================================
  1021.     // ================================================================================================================================
  1022.     // ================================================================================================================================
  1023.     // ================================================================================================================================
  1024.    
  1025.    
  1026.  
  1027.     public String getName() {
  1028.         return "Separating Axis Theorem (Circle - Triangle)";
  1029.     }
  1030.  
  1031.     public String getAlgorithmName() {
  1032.         return "Separating Axis Theorem";
  1033.     }
  1034.  
  1035.     public String getAnimationAuthor() {
  1036.         return "Bekir Özkara";
  1037.     }
  1038.  
  1039.     public String getDescription(){
  1040.         return " The Separating Axis Theorem (SAT) can be used to check for collisions between two polygons or"
  1041.  +"\n"
  1042.  +" between a circle and a polygon. The polygons have to be convex, which, roughly speaking, means that "
  1043.  +"\n"
  1044.  +"any line drawn through the shape crosses it twice, and no more. "
  1045.  +"\n"
  1046.  +"To help visualizing it in your head: if there is a separating axis, you can draw a line (perpendicular to that "
  1047.  +"\n"
  1048.  +"separating axis) which does not touch the objects -> no collision."
  1049.  +"\n"
  1050.  +"\n"
  1051.  +"In the animation there is a small coordinate system. A smaller range was needed because otherwise "
  1052.  +"\n"
  1053.  +"normalized vectors wouldn't be drawn correctly."
  1054.  +"\n"
  1055.  +"The box on the right hand side keeps track of important values/calculations that are needed for the test.";
  1056.     }
  1057.  
  1058.     public String getCodeExample(){
  1059.         return "// the implementations of isVertexSA() and isEdgeSA() are shown in the animation"
  1060.  +"\n"
  1061.  +"public static boolean hasSA(Circle circle, Triangle triangle) {"
  1062.  +"\n"
  1063.  +"  boolean separatedByVertexA = isVertexSA(circle, triangle, triangle.A);"
  1064.  +"\n"
  1065.  +"  boolean separatedByVertexB = isVertexSA(circle, triangle, triangle.B);"
  1066.  +"\n"
  1067.  +"  boolean separatedByVertexC = isVertexSA(circle, triangle, triangle.C);"
  1068.  +"\n"
  1069.  +"     "
  1070.  +"\n"
  1071.  +"  boolean separatedByEdgeAB = isEdgeSA(circle, triangle, triangle.edgeAB, triangle.A, triangle.B, triangle.C);"
  1072.  +"\n"
  1073.  +"  boolean separatedByEdgeAC = isEdgeSA(circle, triangle, triangle.edgeAC, triangle.A, triangle.C, triangle.B);"
  1074.  +"\n"
  1075.  +"  boolean separatedByEdgeBC = isEdgeSA(circle, triangle, triangle.edgeBC, triangle.B, triangle.C, triangle.A);"
  1076.  +"\n"
  1077.  +"     "
  1078.  +"\n"
  1079.  +"  return separatedByVertexA || separatedByVertexB || separatedByVertexC || separatedByEdgeAB || separatedByEdgeAC || separatedByEdgeBC;"
  1080.  +"\n"
  1081.  +"}";
  1082.     }
  1083.  
  1084.     public String getFileExtension(){
  1085.         return "asu";
  1086.     }
  1087.  
  1088.     public Locale getContentLocale() {
  1089.         return Locale.ENGLISH;
  1090.     }
  1091.  
  1092.     public GeneratorType getGeneratorType() {
  1093.         return new GeneratorType(GeneratorType.GENERATOR_TYPE_MORE);
  1094.     }
  1095.  
  1096.     public String getOutputLanguage() {
  1097.         return Generator.JAVA_OUTPUT;
  1098.     }
  1099.  
  1100.     @Override
  1101.     public boolean validateInput(AnimationPropertiesContainer props, Hashtable<String, Object> primitives) throws IllegalArgumentException {
  1102.         // TODO
  1103.         // coord-system from -5 to 5 on both axes
  1104.        
  1105.         vertex_c_y = (double)primitives.get("vertex_c_y");
  1106.         vertex_b_y = (double)primitives.get("vertex_b_y");
  1107.         vertex_c_x = (double)primitives.get("vertex_c_x");
  1108.         vertex_a_y = (double)primitives.get("vertex_a_y");
  1109.         vertex_b_x = (double)primitives.get("vertex_b_x");
  1110.         circle_center_x = (double)primitives.get("circle_center_x");
  1111.         circle_center_y = (double)primitives.get("circle_center_y");
  1112.         radius = (double)primitives.get("radius");
  1113.         vertex_a_x = (double)primitives.get("vertex_a_x");
  1114.        
  1115.         boolean inBoundsVertexA = vertexWithinBounds(vertex_a_x) && vertexWithinBounds(vertex_a_y);
  1116.         boolean inBoundsVertexB = vertexWithinBounds(vertex_b_x) && vertexWithinBounds(vertex_b_y);
  1117.         boolean inBoundsVertexC = vertexWithinBounds(vertex_c_x) && vertexWithinBounds(vertex_c_y);
  1118.        
  1119.         return radius > 0 && inBoundsVertexA && inBoundsVertexB && inBoundsVertexC && circleWithinBounds(circle_center_x, circle_center_y, radius) ;
  1120.     }
  1121.    
  1122.     private boolean vertexWithinBounds(double vertex) {
  1123.         return vertex >= -5 && vertex <= 5;
  1124.     }
  1125.    
  1126.     private boolean circleWithinBounds(double center_x, double center_y, double radius) {
  1127.         // TODO: maybe y-coord must be inverted ??
  1128. //      return radius + Math.abs(center_x) <= 5 && radius + Math.abs(center_y) <= 5;
  1129.         return center_x - radius >= -5 && center_x + radius <= 5 && center_y - radius >= -5 && center_y + radius <= 5;
  1130.     }
  1131. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement