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; }
/// <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); }
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); }
//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); }
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); }
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); }
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); }
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); }
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; }
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]); }
/// <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); }
// 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}"); } } } } }
/// <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)); }
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; } }
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); }
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); }
public void Init() { this.modelData = GeometryFunctions.Load(this.modelFileName); }