Beispiel #1
0
    public static GameObject GeneratePolygon(List <Vector2> vertices2D, PolygonMapGenerator PMG, float layer)
    {
        // Use the triangulator to get indices for creating triangles
        Triangulator tr = new Triangulator(vertices2D.ToArray());

        int[] indices = tr.Triangulate();

        // Create the Vector3 vertices
        Vector3[] vertices = new Vector3[vertices2D.Count];
        Vector4[] tangents = new Vector4[vertices2D.Count];
        Vector2[] uvs      = new Vector2[vertices2D.Count];
        for (int i = 0; i < vertices.Length; i++)
        {
            vertices[i] = new Vector3(vertices2D[i].x, layer, vertices2D[i].y);
            if (PMG != null)
            {
                uvs[i] = new Vector2(vertices2D[i].x / PMG.GenerationSettings.Width, vertices2D[i].y / PMG.GenerationSettings.Height);
            }


            // tangent calc
            Vector2 beforeVertex = vertices2D[i == 0 ? vertices2D.Count - 1 : i - 1];
            Vector2 thisVertex   = vertices2D[i];
            Vector2 afterVertex  = vertices2D[i == vertices2D.Count - 1 ? 0 : i + 1];

            Vector2 targetPoint = GeometryFunctions.GetOffsetIntersection(beforeVertex, thisVertex, afterVertex, 1f, 1f, false);

            Vector2 tangent = targetPoint - thisVertex;

            /*
             * float angle = Mathf.Abs(Vector2.Angle((beforeVertex - thisVertex).normalized, (afterVertex - thisVertex).normalized));
             * float factor = (180 - angle) * 0.005f;
             * tangent *= (1 + factor);
             */

            tangents[i] = new Vector4(tangent.x, 0, tangent.y, 0);
        }

        // Create the mesh
        Mesh msh = new Mesh();

        msh.vertices  = vertices;
        msh.tangents  = tangents;
        msh.uv        = uvs;
        msh.triangles = indices;
        msh.RecalculateNormals();
        msh.RecalculateBounds();

        // Set up game object with mesh;
        GameObject   polygon  = new GameObject("Polygon (" + vertices2D.Count + ")");
        MeshRenderer renderer = polygon.AddComponent <MeshRenderer>();
        Color        ranCol   = Color.red; // new Color(Random.Range(0f, 0.3f), Random.Range(0.4f, 1f), Random.Range(0.1f, 0.6f));

        renderer.material.color = ranCol;
        MeshFilter filter = polygon.AddComponent(typeof(MeshFilter)) as MeshFilter;

        filter.mesh = msh;

        return(polygon);
    }
        public void Reset()
        {
            //TODO move load to Body
            this.body.modelData = GeometryFunctions.Load();

            if (this.solverType == SolverType.Euler)
            {
                this.solver = new FishEulerSolver();
            }
            else
            {
                this.solver = new FishMatrixSolver();
            }
            this.localDelta.Reset();
            this.muscleMCs.Clear();

            this.runtimeList       = this.body.modelData.FishGraph.Nodes.ToList();
            this.runtimeSpringList = this.body.modelData.FishGraph.Edges.ToList();
            this.runtimeMuscleList = this.body.modelData.GetSpringByType(
                new List <Spring.Type> {
                Spring.Type.MuscleBack,
                Spring.Type.MuscleMiddle,
                Spring.Type.MuscleFront
            }
                );

            this.runtimeFinList = this.body.modelData.FishPectoralFins;
        }
Beispiel #3
0
    /// <summary>
    /// Returns the middle point and angle of a border to an adjacent region. The angle always points to the direction of this region.
    /// </summary>
    public Tuple <Vector2, float> GetBorderCenterPositionTo(Region otherRegion)
    {
        if (!AdjacentRegions.Contains(otherRegion))
        {
            throw new Exception("Other region is not adjacent to this region");
        }

        // Find all borders between the two regions
        List <Border> borders = Borders.Where(x => x.Regions.Contains(otherRegion)).ToList();

        // Split borders into clusters and take longest cluster
        List <List <Border> > clusters       = PolygonMapFunctions.FindBorderClusters(borders);
        List <Border>         longestCluster = clusters.OrderByDescending(x => x.Sum(y => y.Length)).First();

        // Find center of longest cluster
        Tuple <Vector2, float> center = PolygonMapFunctions.FindBorderCenter(longestCluster);

        // Swap angle if the border was reversed
        Vector2 testPoint = center.Item1 + new Vector2(Mathf.Sin(Mathf.Deg2Rad * center.Item2) * 0.01f, Mathf.Cos(Mathf.Deg2Rad * center.Item2) * 0.01f);

        if (!GeometryFunctions.IsPointInPolygon4(Polygon.Nodes.Select(x => x.Vertex).ToList(), testPoint))
        {
            center = new Tuple <Vector2, float>(center.Item1, center.Item2 + 180);
        }

        return(center);
    }
Beispiel #4
0
        public override void LoadContent(ContentManager cm, Scene scene, Layer layer)
        {
            var vertices = new List <Vector2>();

            // Get centroid first
            for (int i = 0; i < WorldPoints.Length; i++)
            {
                vertices.Add(ConvertUnits.ToSimUnits(WorldPoints[i]));
            }
            float area = GeometryFunctions.GetSignedArea(vertices);

            if (area < 0)
            {
                vertices.Reverse();
            }

            Vector2 position = GeometryFunctions.GetCentroid(vertices);

            position = position * layer.ScrollSpeed;

            var gameObject = new GameObject(Name, ConvertUnits.ToDisplayUnits(position), scene, layer);

            var physComponent = gameObject.AddComponent <PhysicsComponent>();

            physComponent.Polygon     = new List <Vector2>(WorldPoints);
            physComponent.Mass        = 10f;
            physComponent.Restitution = 0.5f;
            physComponent.Friction    = 0.8f;
            physComponent.IsStatic    = PhysicsType != "Dynamic";

            //gameObject.BagIndex = layer.GameObjects.Add(gameObject);
        }
                    public float Evaluate(Vector <float> input)
                    {
                        if (this.isDirty)
                        {
                            var logger = new FishLogger();
                            var useSim = true;
                            if (useSim)
                            {
                                //start new simulation to get trajactory
                                var body    = GeometryFunctions.Load();
                                var problem = new FishSimulatorOffline.Problem(body, this.activationData);
                                var dt      = new IterationDelta();
                                var sim     = new FishSimulatorOffline(problem, dt);
                                sim.TryToRun();
                                // wait to finish
                                var sol = sim.CurrentSolution as FishSimulatorOffline.Solution;
                                while (sol.IsDone == false)
                                {
                                }
                                logger = sol.logger.DeepCopy();
                                sim.Dispose();
                            }

                            var e = GetCurrentE(logger, this.activationData);

                            this.LatestE = e;
                            this.isDirty = false;

                            // Debug.Log("end with e = " + this.LatestE);
                        }
                        //cal new E from RandomX2FDiscreteFunction and trajactory

                        return(this.LatestE);
                    }
Beispiel #6
0
    //This script needs to be placed on the object whose immediate child is the mesh
    void Start()
    {
        Mesh mesh = MeshGetters.getMesh(this.gameObject);

        //So my suspicion is that the vertex welding doesn't work on skinned mesh renderers because we're not associating the modified vertices with the appropriate bone anymore.
        GeometryFunctions.weldVertices(mesh);
        perturbMesh();
    }
    /// <summary>
    /// Insert new new vertex into the polygon at the given position.
    /// The vertex is inserted after the closest vertex to this position.
    /// </summary>
    /// <param name="position">Position of the inserted vertex</param>
    /// <param name="forceLast">Vertex will be always inserted after the last vertex of the polygon</param>
    /// <returns>Retruns true if insertion was successful</returns>
    public static bool InsertVertex(this PolygonCollider2D polygon, Vector2 position, bool forceLast = false)
    {
        Undo.RecordObject(polygon, string.Format("Insert vertex in {0}", polygon.name));

        var worldPos = new Vector2(polygon.transform.position.x, polygon.transform.position.y);

        position = position - worldPos;
        var vertices = polygon.points;

        // Handle easy case first.
        if (vertices == null || vertices.Length == 0)
        {
            vertices       = new Vector2[1];
            vertices[0]    = position;
            polygon.points = vertices;
            return(true);
        }

        Vector2[] newVertices = new Vector2[vertices.Length + 1];

        int insertIdx = -1;

        if (forceLast == true || vertices.Length < 2)
        {
            insertIdx = vertices.Length;
        }
        else
        {
            // Find closest line segment.
            float minDist = float.PositiveInfinity;
            for (int i = 0; i < vertices.Length; i++)
            {
                int   ii   = (i + 1) % vertices.Length;
                float dist = GeometryFunctions.DistnacePointSegmentSquared(vertices[i], vertices[ii], position);
                if (dist < minDist)
                {
                    minDist   = dist;
                    insertIdx = ii;
                }
            }
        }

        // Insert new vertex.
        if (insertIdx == -1 || insertIdx >= newVertices.Length)
        {
            return(false);
        }

        System.Array.Copy(vertices, 0, newVertices, 0, insertIdx);
        System.Array.Copy(vertices, insertIdx, newVertices, insertIdx + 1, (vertices.Length - insertIdx));
        newVertices[insertIdx] = position;
        vertices = newVertices;

        polygon.points = vertices;
        UpdateOrder(polygon);

        return(true);
    }
Beispiel #8
0
        public static MyPlane CreateMyPlaneFromFace(Face2 face)
        {
            //KLdebug.Print("FACCIA PIANA", "buildRepeatedEntity.txt");
            //KLdebug.Print(" ", "buildRepeatedEntity.txt");

            double[] planePoint;
            var      normal     = GeometryFunctions.MyGetNormalForPlaneFace(face, out planePoint);
            MyPlane  newMyPlane = new MyPlane(normal, planePoint);

            return(newMyPlane);
        }
Beispiel #9
0
    public static GameObject DrawArrow(Vector2 from, Vector2 to, Color color, float width = 0.1f, float arrowHeadWidth = 0.2f, float arrowHeadLength = 0.1f, float yPos = 0.01f)
    {
        GameObject arrow = new GameObject("Arrow");

        // Create mesh vertices and triangles
        Vector2[] vertices2D = new Vector2[7];

        Vector2 v   = to - from;
        Vector2 v90 = GeometryFunctions.RotateVector(v, 90).normalized;

        vertices2D[0] = from + (v90 * width);
        vertices2D[6] = from - (v90 * width);

        float   arrowHeadLengthRatio = arrowHeadLength / Vector2.Distance(from, to);
        Vector2 headStart            = Vector2.Lerp(from, to, 1f - arrowHeadLengthRatio);

        vertices2D[1] = headStart + (v90 * width);
        vertices2D[5] = headStart - (v90 * width);

        vertices2D[2] = headStart + (v90 * arrowHeadWidth);
        vertices2D[4] = headStart - (v90 * arrowHeadWidth);

        vertices2D[3] = to;

        Vector3[] vertices = new Vector3[vertices2D.Length];
        for (int i = 0; i < vertices2D.Length; i++)
        {
            vertices[i] = new Vector3(vertices2D[i].x, yPos, vertices2D[i].y);
        }

        int[] triangles = { 0, 5, 6, 1, 5, 0, 2, 3, 4 };

        // Add mesh renderer
        MeshRenderer renderer = arrow.AddComponent <MeshRenderer>();

        renderer.shadowCastingMode = UnityEngine.Rendering.ShadowCastingMode.Off;
        renderer.receiveShadows    = false;
        renderer.material          = MapDisplayResources.Singleton.DefaultMaterial;
        renderer.material.color    = color;

        // Create the mesh
        MeshFilter meshFilter = arrow.AddComponent <MeshFilter>();
        Mesh       msh        = new Mesh();

        msh.vertices  = vertices;
        msh.triangles = triangles;
        msh.RecalculateNormals();
        msh.RecalculateBounds();
        meshFilter.mesh = msh;

        return(arrow);
    }
Beispiel #10
0
    Vector3[] newVertices()
    {
        Mesh mesh = MeshGetters.getMesh(this.gameObject);

        int[] triangles = mesh.triangles;

        Vector3[] triangleA = new Vector3[3];//Lets not allocate new vector3s so much
        Vector3[] triangleB = new Vector3[3];

        bool verticesUpdatedSuccessfully;

        Vector3[] newVertices;
        do
        {
            newVertices = mesh.vertices;
            verticesUpdatedSuccessfully = true;
            //Modify the vertices
            for (int i = 0; i < newVertices.Length; i++)
            {
                wiggleVector3(ref newVertices[i]);
            }

            //Check the triangles for collisions
            for (int i = 0; i < triangles.Length; i += 3)
            {
                triangleA[0] = newVertices[triangles[i]];
                triangleA[1] = newVertices[triangles[i + 1]];
                triangleA[2] = newVertices[triangles[i + 2]];

                for (int j = i + 3; j < triangles.Length; j += 3)
                {
                    triangleB[0] = newVertices[triangles[j]];
                    triangleB[1] = newVertices[triangles[j + 1]];
                    triangleB[2] = newVertices[triangles[j + 2]];

                    if (!GeometryFunctions.triangleNonintersectCheck(triangleA, triangleB))
                    {
                        verticesUpdatedSuccessfully = false;
                        break;
                    }
                }
            }
        } while (!verticesUpdatedSuccessfully);

        if (this.saveModel)
        {
            MeshSerializer.serializeMesh(mesh, this.name);
        }


        return(newVertices);
    }
Beispiel #11
0
        public static MyPlane KLCreateMyPlaneFromFace(Face2 face, double[,] transformMatrix)
        {
            //KLdebug.Print("FACCIA PIANA", "buildRepeatedEntity.txt");
            //KLdebug.Print(" ", "buildRepeatedEntity.txt");

            double[] planePoint;
            var      normal  = GeometryFunctions.KLMyGetNormalForPlaneFace(face, out planePoint, transformMatrix);
            var      toPrint = string.Format("Normale calcolata {0}, {1}, {2}", normal[0], normal[1], normal[2]);
            //KLdebug.Print(toPrint, "buildRepeatedEntity.txt");
            MyPlane newMyPlane = new MyPlane(normal, planePoint);

            return(newMyPlane);
        }
 private bool CheckForImpregnation(AlienComponent alienData, PositionComponent alienPos, AbstractEntity target, PositionComponent targetPos)
 {
     if (alienData.impregnateNextEnemy)
     {
         double dist = GeometryFunctions.Distance(alienPos.x, alienPos.y, targetPos.x, targetPos.y);
         if (dist < 2)
         {
             target.AddComponent(new ImpregnatedComponent());
             return(true);
         }
     }
     return(false);
 }
Beispiel #13
0
        public void GeneratePolygon(Polygon polyin, ref MyPoint[] pts, byte numb)// Построение многоугольника
        {
            Polygon t1, t2;

            MyPoint[] t3 = new MyPoint[numb];
            t1.Poly         = new List <MyPoint>();
            t1.NormalVector = new MyPoint();
            t2.Poly         = new List <MyPoint>();
            t2.NormalVector = new MyPoint();
            GeometryFunctions.CopyCoordSystemToPlane(polyin, t1);
            GeometryFunctions.RotatePlaneCoordSystem(t1, t2);
            CalculatePolyConvexEdge(t2, ref t3);
            pts = t3;
        }
Beispiel #14
0
        private void Init()
        {
            Area = GeometryFunctions.GetPolygonArea(Nodes.Select(x => x.Vertex).ToList());

            IsEdgePolygon = Nodes.Any(x => x.Type == BorderPointType.Edge);

            Width      = Nodes.Max(x => x.Vertex.x) - Nodes.Min(x => x.Vertex.x);
            Height     = Nodes.Max(x => x.Vertex.y) - Nodes.Min(x => x.Vertex.y);
            Jaggedness = 1f - (Area / (Width * Height));

            Centroid = new Vector2(Nodes.Average(x => x.Vertex.x), Nodes.Average(x => x.Vertex.y));
            float[] poi = PolygonCenterFinder.GetPolyLabel(ConvertPolygonToFloatArray(), precision: 0.05f);
            CenterPoi = new Vector2(poi[0], poi[1]);
        }
Beispiel #15
0
    /// <summary>
    /// Tries to select the edge at the given positon. Takes specified selection radius into
    /// account. Returns the index of the edge of the given box. Returns -1 if no edge
    /// could be selected
    /// </summary>
    /// <param name="position">The position at which the edge should be selected</param>
    /// <returns>Returns the index of the selected edge within the box. (-1 if selection failed)</returns>
    public static int TrySelectEdge(this BoxCollider2D box, Vector2 position)
    {
        var corners = box.GetWorldCorners();

        for (int i = 0; i < corners.Length; i++)
        {
            int ii = (i + 1) % corners.Length;

            float dist = GeometryFunctions.DistnacePointSegment(corners[i], corners[ii], position);
            if (dist <= BrushSettingsWindow.VertexSize)
            {
                return(i);
            }
        }
        return(-1);
    }
Beispiel #16
0
    // Start is called before the first frame update
    void Start()
    {
        //Get the mesh and the material from the
        this.mesh = MeshGetters.getTriMesh(1f, 2f);
        this.grassRenderMaterial = Resources.Load <Material>("Materials/Grass");
        grassTransforms          = new List <Matrix4x4[]>();

        float grassDensity = 0.3f;//1 blade of grass per area unit

        int[]     triangles = MeshGetters.getMeshTriangles(this.gameObject);
        Vector3[] vertices  = MeshGetters.getMeshVertices(this.gameObject);

        Vector3[] curVertices = new Vector3[3];

        int gtbi = 0;

        Matrix4x4[] grassTransformBuffer = new Matrix4x4[1023];
        //Iterate through our triangles array three at a time (one triangle)
        for (int i = 0; i < triangles.Length; i += 3)
        {
            //Convert to vertices
            curVertices[0] = Vector3.Scale(vertices[triangles[i]], transform.localScale) + transform.position;
            curVertices[1] = Vector3.Scale(vertices[triangles[i + 1]], transform.localScale) + transform.position;
            curVertices[2] = Vector3.Scale(vertices[triangles[i + 2]], transform.localScale) + transform.position;

            float area = GeometryFunctions.getTriangleArea(curVertices);

            int       numBlades = (int)(area * grassDensity);
            Vector3[] grassLocs = GeometryFunctions.getNLocationsOnTriangle(curVertices, numBlades);

            for (int j = 0; j < grassLocs.Length; j++)
            {
                if (gtbi == 1023)
                {
                    gtbi = 0;
                    Matrix4x4[] gtBufferCopy = (Matrix4x4[])grassTransformBuffer.Clone();
                    grassTransforms.Add(gtBufferCopy);
                }
                Quaternion rotationQuat = Quaternion.FromToRotation(transform.up, GeometryFunctions.getTriangleNormal(curVertices));
                grassTransformBuffer[gtbi] = Matrix4x4.TRS(grassLocs[j], rotationQuat, new Vector3(1, 1, 1));
                gtbi++;
            }
        }
        //Get them leftovers
        grassTransforms.Add(grassTransformBuffer);//this should be truncated and then added to the dynamic list based on the current j
        //will deal with it later
    }
        public void Explosion(AbstractEntity entity)
        {
            ExplodesWhenTimerExpiresComponent ewtec = (ExplodesWhenTimerExpiresComponent)entity.GetComponent(nameof(ExplodesWhenTimerExpiresComponent));
            PositionComponent pos = ECSHelper.GetPosition(entity);

            foreach (var e in this.entities)
            {
                PositionComponent epos = ECSHelper.GetPosition(e);
                if (epos != null)
                {
                    if (GeometryFunctions.Distance(epos.x, epos.y, pos.x, pos.y) <= ewtec.range)
                    {
                        if (this.checkVis.CanSee(epos.x, epos.y, pos.x, pos.y))
                        {
                            this.damageSystem.Damage(e, ewtec.power, $"Exploding {entity.name}");
                        }
                    }
                }
            }
        }
Beispiel #18
0
    /// <summary>
    /// Creates a GameObject with a mesh that represents the bounds of multiple polygons. onOutside means the border will be drawn on the outside of the polygons.
    /// All given polygons must be connected by land for this function to work! If they are not, first split it into clusters with PolygonMapFunctions.FindClusters()
    /// </summary>
    public static List <GameObject> CreatePolygonGroupBorder(List <GraphPolygon> polygons, float width, Color c, bool onOutside, float yPos)
    {
        List <GameObject> borders = new List <GameObject>();

        // Find outer mesh vertices
        List <List <GraphNode> > outerNodes    = PolygonMapFunctions.FindOutsideNodes(polygons);
        List <GraphNode>         outsideBorder = outerNodes.First(x => x.Count == outerNodes.Max(y => y.Count));

        foreach (List <GraphNode> border in outerNodes)
        {
            List <Vector2> outerVertices = border.Select(x => x.Vertex).ToList();
            bool           isClockwise   = GeometryFunctions.IsClockwise(outerVertices);
            if (border == outsideBorder)
            {
                borders.Add(CreateSinglePolygonBorder(border, width, c, yPos, onOutside ? !isClockwise : isClockwise));
            }
            else
            {
                borders.Add(CreateSinglePolygonBorder(border, width, c, yPos, onOutside ? isClockwise : !isClockwise));
            }
        }

        return(borders);
    }
        public static GameObject LabelPolygon(List <List <GraphNode> > polygonBorders, string label, Color color)
        {
            // 1. Compute voronoi of given points with "VoronoiLib"
            List <FortuneSite> points = new List <FortuneSite>();
            List <GraphNode>   nodes  = new List <GraphNode>();

            foreach (List <GraphNode> polygonBorder in polygonBorders)
            {
                foreach (GraphNode n in polygonBorder)
                {
                    if (!nodes.Contains(n))
                    {
                        nodes.Add(n);
                    }
                }
            }
            foreach (GraphNode n in nodes)
            {
                points.Add(new FortuneSite(n.Vertex.x, n.Vertex.y));
            }

            float margin = 0.2f;
            float minX   = nodes.Min(x => x.Vertex.x) - margin;
            float maxX   = nodes.Max(x => x.Vertex.x) + margin;
            float minY   = nodes.Min(x => x.Vertex.y) - margin;
            float maxY   = nodes.Max(x => x.Vertex.y) + margin;
            LinkedList <VEdge> voronoi = FortunesAlgorithm.Run(points, minX, minY, maxX, maxY);

            // 2. Remove all edges that have either start or end outside of polygon
            List <Vector2> vertices      = nodes.Select(x => x.Vertex).ToList();
            List <VEdge>   edgesToRemove = new List <VEdge>();

            foreach (VEdge edge in voronoi)
            {
                if (!GeometryFunctions.IsPointInPolygon4(vertices, new Vector2((float)edge.Start.X, (float)edge.Start.Y)) || !GeometryFunctions.IsPointInPolygon4(vertices, new Vector2((float)edge.End.X, (float)edge.End.Y)))
                {
                    edgesToRemove.Add(edge);
                }
            }
            foreach (VEdge edge in edgesToRemove)
            {
                voronoi.Remove(edge);
            }

            // DEBUG voronoi
            foreach (VEdge edge in voronoi)
            {
                Debug.DrawLine(new Vector3((float)edge.Start.X, 0f, (float)edge.Start.Y), new Vector3((float)edge.End.X, 0f, (float)edge.End.Y), Color.red, 30);
            }

            // 3. Turn remaining edges into a graph (create a list of for each point representing the points it is connected to)
            Dictionary <VPoint, List <VPoint> > voronoiGraph = new Dictionary <VPoint, List <VPoint> >();

            foreach (VEdge edge in voronoi)
            {
                // handle start point
                if (!voronoiGraph.ContainsKey(edge.Start))
                {
                    voronoiGraph.Add(edge.Start, new List <VPoint>()
                    {
                        edge.End
                    });
                }
                else if (!voronoiGraph[edge.Start].Contains(edge.End))
                {
                    voronoiGraph[edge.Start].Add(edge.End);
                }

                // handle end point
                if (!voronoiGraph.ContainsKey(edge.End))
                {
                    voronoiGraph.Add(edge.End, new List <VPoint>()
                    {
                        edge.Start
                    });
                }
                else if (!voronoiGraph[edge.End].Contains(edge.Start))
                {
                    voronoiGraph[edge.End].Add(edge.Start);
                }
            }

            // 4. Find longest path (with consideration for straightness) between two leaves in graph - this is the centerline
            Dictionary <VPoint, List <VPoint> > voronoiLeaves = voronoiGraph.Where(x => x.Value.Count == 1).ToDictionary(x => x.Key, x => x.Value);

            float         curvePenalty             = 0.00007f;
            float         longestDistance          = float.MinValue;
            List <VPoint> centerLine               = new List <VPoint>();
            float         longestDistanceNoPenalty = float.MinValue;
            List <VPoint> centerLineNoPenalty      = new List <VPoint>();

            foreach (KeyValuePair <VPoint, List <VPoint> > startPoint in voronoiLeaves)
            {
                foreach (KeyValuePair <VPoint, List <VPoint> > endPoint in voronoiLeaves)
                {
                    if (startPoint.Key == endPoint.Key)
                    {
                        continue;
                    }

                    List <VPoint> leavesPath = GetShortestPath(new List <VPoint>()
                    {
                        startPoint.Key
                    }, endPoint.Key, voronoiGraph);
                    if (leavesPath == null)
                    {
                        continue;
                    }
                    float distanceWithPenalty = GetPathDistance(leavesPath, curvePenalty);
                    if (distanceWithPenalty > longestDistance)
                    {
                        longestDistance = distanceWithPenalty;
                        centerLine      = leavesPath;
                    }

                    float distanceNoPenalty = GetPathDistance(leavesPath, 0f);
                    if (distanceNoPenalty > longestDistanceNoPenalty)
                    {
                        longestDistanceNoPenalty = distanceNoPenalty;
                        centerLineNoPenalty      = leavesPath;
                    }
                }
            }

            // If the straight centerline is too short, take the longer curvy one instead
            if (GetPathDistance(centerLine, 0f) < 0.4f * GetPathDistance(centerLineNoPenalty, 0f))
            {
                centerLine = centerLineNoPenalty;
            }

            // 5. Smoothen the centerline
            int           smoothSteps      = 5;
            List <VPoint> smoothCenterLine = new List <VPoint>();

            smoothCenterLine.AddRange(centerLine);
            for (int i = 0; i < smoothSteps; i++)
            {
                smoothCenterLine = SmoothLine(smoothCenterLine);
            }


            // DEBUG centerline
            //Debug.Log("Longest path without curve penalty: " + GetPathDistance(centerLineNoPenalty, 0f));
            //Debug.Log("Longest path with curve penalty: " + GetPathDistance(centerLine, curvePenalty));
            //for (int i = 1; i < centerLineNoPenalty.Count; i++) Debug.DrawLine(new Vector3((float)centerLineNoPenalty[i - 1].X, 0f, (float)centerLineNoPenalty[i - 1].Y), new Vector3((float)centerLineNoPenalty[i].X, 0f, (float)centerLineNoPenalty[i].Y), Color.blue, 30);
            //for (int i = 1; i < centerLine.Count; i++) Debug.DrawLine(new Vector3((float)centerLine[i - 1].X, 0f, (float)centerLine[i - 1].Y), new Vector3((float)centerLine[i].X, 0f, (float)centerLine[i].Y), Color.red, 30);
            for (int i = 1; i < smoothCenterLine.Count; i++)
            {
                Debug.DrawLine(new Vector3((float)smoothCenterLine[i - 1].X, 0f, (float)smoothCenterLine[i - 1].Y), new Vector3((float)smoothCenterLine[i].X, 0f, (float)smoothCenterLine[i].Y), Color.blue, 30);
            }

            // 6. Make sure the path goes from left to right
            double xChange = 0;

            for (int i = 1; i < smoothCenterLine.Count; i++)
            {
                xChange += smoothCenterLine[i].X - smoothCenterLine[i - 1].X;
            }
            if (xChange < 0)
            {
                smoothCenterLine.Reverse();
            }


            // 7. Place text along centerline
            return(DrawTextAlongPath(label, smoothCenterLine, color));
        }
Beispiel #20
0
        public override void Start()
        {
            // Convert Polygon to physic units.

            var vertices = new List <Vector2>();

            // Get centroid first
            Polygon.ForEach((v) => { vertices.Add(ConvertUnits.ToSimUnits(v)); });
            float area = GeometryFunctions.GetSignedArea(vertices);

            if (area < 0)
            {
                vertices.Reverse();
            }

            Vector2 position = GeometryFunctions.GetCentroid(vertices);

            GameObject.Position = ConvertUnits.ToDisplayUnits(position);

            Polygon = vertices;

            if (IsSensor)
            {
                _physics = new Sensor(GameObject.Scene.WorldInfo, ConvertUnits.ToSimUnits(GameObject.Position), Polygon);
            }
            else
            {
                if (IsStatic)
                {
                    _physics = new StaticObject(GameObject.Scene.WorldInfo, ConvertUnits.ToSimUnits(GameObject.Position), Mass, Friction, Restitution, Polygon);
                }
                else
                {
                    var dynamicObject = new DynamicObject(GameObject.Scene.WorldInfo, ConvertUnits.ToSimUnits(GameObject.Position), Mass, Friction, Restitution, Polygon);
                    dynamicObject.IgnoreGravity = IgnoreGravity;

                    _physics = dynamicObject;
                }
            }

            _physics.IsProjectile = IsProjectile;
            _physics.IsEthereal   = IsEthereal;

            // Hook up collision callbacks
            _physics.OnCollision += (A, B, p) =>
            {
                if (A == _physics)
                {
                    if (OnCollision != null)
                    {
                        OnCollision(B.GameObject);
                    }

                    if (B.GameObject != null)
                    {
                        if (OnCollisionEnter != null && !_collidingGameObjects.ContainsKey(B.GameObject))
                        {
                            OnCollisionEnter(B.GameObject);
                        }

                        if (OnCollisionEnter != null || OnCollisionLeave != null)
                        {
                            _collidingGameObjects[B.GameObject] = true;
                        }
                    }
                }
                else if (B == _physics)
                {
                    if (OnCollision != null)
                    {
                        OnCollision(A.GameObject);
                    }

                    if (A.GameObject != null)
                    {
                        if (OnCollisionEnter != null && !_collidingGameObjects.ContainsKey(A.GameObject))
                        {
                            OnCollisionEnter(A.GameObject);
                        }

                        if (OnCollisionEnter != null || OnCollisionLeave != null)
                        {
                            _collidingGameObjects[A.GameObject] = true;
                        }
                    }
                }

                // If we collide with object subscripe to pre update event.
                if (_preUpdateEventRegistered == false && ((_collidingGameObjects.Count != 0 && (OnCollisionEnter != null || OnCollisionLeave != null)) || StorePreviousVelocity))
                {
                    _preUpdateEventRegistered   = true;
                    GameObject.Scene.PreUpdate += preUpdate;
                }
            };

            // Set reset info.
            if (IsStatic == false && IsProjectile == false)
            {
                _startPosition = GameObject.Position;
                SceneInfo.DynamicPhysicObjects.Add(this);
            }

            if (_pendingGameObject != null)
            {
                _physics.GameObject = _pendingGameObject;
            }
        }
Beispiel #21
0
    public static GameObject CreateSinglePolygonBorder(List <GraphNode> nodes, float width, Color c, float layer, bool clockwise = false)
    {
        List <Vector2> outerVertices = nodes.Select(x => x.Vertex).ToList();
        List <Vector2> innerVertices = new List <Vector2>();

        for (int i = 0; i < outerVertices.Count; i++)
        {
            Vector2 beforeVertex = outerVertices[i == 0 ? outerVertices.Count - 1 : i - 1];
            Vector2 thisVertex   = outerVertices[i];
            Vector2 afterVertex  = outerVertices[i == outerVertices.Count - 1 ? 0 : i + 1];

            Vector2 targetPoint = GeometryFunctions.GetOffsetIntersection(beforeVertex, thisVertex, afterVertex, width, width, clockwise);

            innerVertices.Add(targetPoint);
        }

        // Create full vertex list (outer0, inner0, outer1, inner1, outer2, inner2, ...)
        Vector3[] vertices = new Vector3[outerVertices.Count + innerVertices.Count];
        for (int i = 0; i < outerVertices.Count; i++)
        {
            vertices[2 * i]     = new Vector3(outerVertices[i].x, layer, outerVertices[i].y);
            vertices[2 * i + 1] = new Vector3(innerVertices[i].x, layer, innerVertices[i].y);
        }

        // Create triangles ( 0/2/1, 1/2/3, 2/4/3, 3/4/5, 4/6/5, 5/6/7, ...)
        int[] triangles = new int[vertices.Length * 3];
        for (int i = 0; i < vertices.Length; i++)
        {
            if (clockwise)
            {
                triangles[3 * i]     = i;
                triangles[3 * i + 1] = ((((i + 1) / 2) * 2) + 1) % vertices.Length;
                triangles[3 * i + 2] = (((i / 2) * 2) + 2) % vertices.Length;
            }
            else
            {
                // One column represents one triangle
                triangles[3 * i]     = i;                                             // 0, 1, 2, 3, 4, 5, ...
                triangles[3 * i + 1] = (((i / 2) * 2) + 2) % vertices.Length;         // 2, 2, 4, 4, 6, 6, ...
                triangles[3 * i + 2] = ((((i + 1) / 2) * 2) + 1) % vertices.Length;   // 1, 3, 3, 5, 5, 7, ...
            }
        }

        // Create the mesh
        Mesh msh = new Mesh();

        msh.vertices  = vertices;
        msh.triangles = triangles;
        msh.RecalculateNormals();
        msh.RecalculateBounds();

        GameObject   border   = new GameObject("Border (" + vertices.Length + ")");
        MeshRenderer renderer = border.AddComponent <MeshRenderer>();

        renderer.shadowCastingMode = UnityEngine.Rendering.ShadowCastingMode.Off;
        renderer.receiveShadows    = false;
        renderer.material          = MapDisplayResources.Singleton.DefaultMaterial;
        renderer.material.color    = c;
        MeshFilter filter = border.AddComponent <MeshFilter>();

        filter.mesh = msh;

        return(border);
    }
Beispiel #22
0
        public static River CreateRiverObject(GraphPath riverPath, PolygonMapGenerator PMG)
        {
            //Debug.Log("Creating mesh for river with " + riverPath.Nodes.Count + " points");

            // Calculate vertices of river polygon
            List <Vector2> polygonVerticesHalf1 = new List <Vector2>();
            List <Vector2> polygonVerticesHalf2 = new List <Vector2>();

            for (int i = 1; i < riverPath.Nodes.Count - 1; i++)
            {
                Vector2 startPoint = riverPath.Nodes[i - 1].Vertex;
                Vector2 thisPoint  = riverPath.Nodes[i].Vertex;
                Vector2 nextPoint  = riverPath.Nodes[i + 1].Vertex;

                float startWidth = riverPath.Nodes[i - 1].RiverWidth;
                float endWidth   = riverPath.Nodes[i].RiverWidth;

                //Debug.Log("River point " + i + ": startWidth = " + startWidth + ", endWidth = " + endWidth);

                if (i == 1) // Add two starting points
                {
                    Vector2 rotatedVector = GeometryFunctions.RotateVector((thisPoint - startPoint).normalized * startWidth, 90);
                    polygonVerticesHalf1.Add(startPoint + rotatedVector);
                    polygonVerticesHalf2.Add(startPoint - rotatedVector);
                }

                polygonVerticesHalf1.Add(GeometryFunctions.GetOffsetIntersection(startPoint, thisPoint, nextPoint, startWidth, endWidth, true));
                polygonVerticesHalf2.Add(GeometryFunctions.GetOffsetIntersection(startPoint, thisPoint, nextPoint, startWidth, endWidth, false));

                if (i == riverPath.Nodes.Count - 2) // Add two ending points (calculate river delta by taking intersecion between river and shoreline
                {
                    GraphNode lastNode = riverPath.Nodes.Last();
                    List <GraphConnection> shoreDelta       = lastNode.Connections.Where(x => x.Type == BorderType.Shore).ToList();
                    List <GraphNode>       riverDeltaPoints = new List <GraphNode>();
                    foreach (GraphConnection delta in shoreDelta)
                    {
                        if (delta.StartNode == lastNode)
                        {
                            riverDeltaPoints.Add(delta.EndNode);
                        }
                        else
                        {
                            riverDeltaPoints.Add(delta.StartNode);
                        }
                    }

                    Vector2 endPoint1, endPoint2;

                    // BUG: this method doesn't work 100%
                    GraphPolygon firstPolygon = riverPath.Nodes[i].Polygons.FirstOrDefault(x => GeometryFunctions.IsPointInPolygon4(x.Nodes.Select(x => x.Vertex).ToList(), polygonVerticesHalf1.Last()));
                    if (firstPolygon == null)
                    {
                        throw new Exception("Couldn't find direction of river delta. is river too short? length = " + riverPath.Nodes.Count);
                    }

                    bool addDeltaMidPoint = true;
                    if (riverDeltaPoints[0].Polygons.Contains(firstPolygon))
                    {
                        endPoint1 = GeometryFunctions.GetOffsetIntersection(thisPoint, nextPoint, riverDeltaPoints[0].Vertex, endWidth, 0f, true);
                        endPoint2 = GeometryFunctions.GetOffsetIntersection(thisPoint, nextPoint, riverDeltaPoints[1].Vertex, endWidth, 0f, false);

                        if (!GeometryFunctions.IsPointOnLineSegment(endPoint1, riverDeltaPoints[0].Vertex, lastNode.Vertex))
                        {
                            endPoint1        = lastNode.Vertex;
                            addDeltaMidPoint = false;
                        }
                        if (!GeometryFunctions.IsPointOnLineSegment(endPoint2, riverDeltaPoints[1].Vertex, lastNode.Vertex))
                        {
                            endPoint2        = lastNode.Vertex;
                            addDeltaMidPoint = false;
                        }
                    }
                    else
                    {
                        endPoint1 = GeometryFunctions.GetOffsetIntersection(thisPoint, nextPoint, riverDeltaPoints[1].Vertex, endWidth, 0f, true);
                        endPoint2 = GeometryFunctions.GetOffsetIntersection(thisPoint, nextPoint, riverDeltaPoints[0].Vertex, endWidth, 0f, false);

                        if (!GeometryFunctions.IsPointOnLineSegment(endPoint1, riverDeltaPoints[1].Vertex, lastNode.Vertex))
                        {
                            endPoint1        = lastNode.Vertex;
                            addDeltaMidPoint = false;
                        }
                        if (!GeometryFunctions.IsPointOnLineSegment(endPoint2, riverDeltaPoints[0].Vertex, lastNode.Vertex))
                        {
                            endPoint2        = lastNode.Vertex;
                            addDeltaMidPoint = false;
                        }
                    }

                    polygonVerticesHalf1.Add(endPoint1);
                    if (addDeltaMidPoint)
                    {
                        polygonVerticesHalf1.Add(lastNode.Vertex);
                    }
                    polygonVerticesHalf2.Add(endPoint2);
                }
            }

            polygonVerticesHalf2.Reverse();
            List <Vector2> polygonVertices = polygonVerticesHalf1;

            polygonVertices.AddRange(polygonVerticesHalf2);

            List <Vector2> polygonVerticesList = polygonVertices.ToList();

            if (GeometryFunctions.IsClockwise(polygonVerticesList))
            {
                polygonVerticesList.Reverse();
            }

            // Create object
            GameObject riverObject = MeshGenerator.GeneratePolygon(polygonVerticesList, PMG, layer: PolygonMapGenerator.LAYER_RIVER);

            River river = riverObject.AddComponent <River>();

            river.Init(riverPath.Nodes.Select(x => x.BorderPoint).ToList(), riverPath.Connections.Select(x => x.Border).ToList(), riverPath.Polygons.Select(x => x.Region).ToList());

            riverObject.GetComponent <MeshRenderer>().material.color = Color.red;

            riverObject.name = "River";

            return(river);
        }
Beispiel #23
0
 public void Init()
 {
     this.modelData = GeometryFunctions.Load(this.modelFileName);
 }