public static void Triangulate(ITriangulatable t, TriangulationAlgorithm algorithm = DEFAULT_ALGORITHM) { TriangulationContext tcx = CreateContext(algorithm); tcx.PrepareTriangulation(t); Triangulate(tcx); }
private void Start() { Vector3[] vertices = new Vector3[pointsParent.childCount]; List <int> indices = new List <int>(); for (int i = 0; i < vertices.Length; i++) { vertices[i] = pointsParent.GetChild(i).position; indices.Add(i); } Plane plane = new Plane(Vector3.back, 0); ConvexHullAlgorithm.Execute(ref indices, vertices, plane.normal); indices.Reverse();//反转列表,逆时针变顺时针 /*Vector3[] vertices2=new Vector3[indices.Count]; * for(int i=0;i<indices.Count;i++){ * Vector3 vertex=vertices[indices[i]]; * vertex.z=0; * vertices2[i]=vertex; * } * indices=TriangulationAlgorithm.WidelyTriangleIndex(vertices2);*/ TriangulationAlgorithm.WidelyTriangleIndex(vertices, ref indices, plane); for (int i = 0; i < indices.Count; i++) { int index = indices[i]; s_points.Add(vertices[index]); } }
public static TriangulationContext CreateContext(TriangulationAlgorithm algorithm) { switch (algorithm) { case TriangulationAlgorithm.DTSweep: default: return new DTSweepContext(); } }
public static TriangulationContext CreateContext(TriangulationAlgorithm algorithm) { if (algorithm != TriangulationAlgorithm.DTSweep) { } return new DTSweepContext(); }
public static Shape CreateComplexShape(Image imageBitmap, int timeout, StringBuilder spool, float hullTolerance, byte alphaTolerance, bool multiPartDetection, bool holeDetection = true, bool strict = false, TriangulationAlgorithm algorithm = TriangulationAlgorithm.Bayazit) { Shape shape = null; Action action = () => { try { shape = BuildShape(imageBitmap, spool, hullTolerance, alphaTolerance, multiPartDetection, holeDetection, strict, algorithm); } catch { spool.AppendFormat("Error creating shape for image"); spool.AppendLine(); } }; var result = action.BeginInvoke(null, null); if (!result.AsyncWaitHandle.WaitOne(timeout)) { spool.AppendFormat("Timed out attempting to create shape"); spool.AppendLine(); } return shape; }
public static void Triangulate(TriangulationAlgorithm algorithm, Triangulatable t) { // long time = System.nanoTime(); TriangulationContext tcx = CreateContext(algorithm); tcx.PrepareTriangulation(t); Triangulate(tcx); // logger.info( "Triangulation of {} points [{}ms]", tcx.getPoints().size(), ( System.nanoTime() - time ) / 1e6 ); }
public static void Triangulate(TriangulationAlgorithm algorithm, ITriangulatable t) { TriangulationContext tcx; tcx = CreateContext(algorithm); tcx.PrepareTriangulation(t); Triangulate(tcx); }
public static void Triangulate(TriangulationAlgorithm algorithm, ITriangulatable t) { TriangulationContext tcx; tcx = CreateContext (algorithm); tcx.PrepareTriangulation (t); Triangulate (tcx); }
private static TriangulationContext CreateContext(TriangulationAlgorithm algorithm) { switch (algorithm) { default: return(new DTSweepContext()); } }
public static TriangulationContext CreateContext(TriangulationAlgorithm algorithm) { switch (algorithm) { case TriangulationAlgorithm.DTSweep: default: return(new DTSweepContext()); } }
public static void Triangulate(TriangulationAlgorithm algorithm, ITriangulatable t) { //System.Console.WriteLine("Triangulating " + t.FileName); // long time = System.nanoTime(); var tcx = CreateContext(algorithm); tcx.PrepareTriangulation(t); Triangulate(tcx); //logger.info( "Triangulation of {} points [{}ms]", tcx.getPoints().size(), ( System.nanoTime() - time ) / 1e6 ); }
public static void Triangulate(TriangulationAlgorithm algorithm, Triangulatable t) { TriangulationContext tcx; // long time = System.nanoTime(); tcx = CreateContext(algorithm); tcx.PrepareTriangulation(t); Triangulate(tcx); // logger.info( "Triangulation of {} points [{}ms]", tcx.getPoints().size(), ( System.nanoTime() - time ) / 1e6 ); }
public static void Triangulate(TriangulationAlgorithm algorithm, Triangulatable t) { //long time = System.nanoTime(); TriangulationContext tcx = GetFreeTcxContext(algorithm); tcx.Clear(); //step 1: (3.1) initialization tcx.PrepareTriangulation(t); //step 2: (3.4) sweeping Triangulate(tcx); ReleaseCtxContext(tcx); //logger.info( "Triangulation of {} points [{}ms]", tcx.getPoints().size(), ( System.nanoTime() - time ) / 1e6 ); }
public static void Triangulate(TriangulationAlgorithm algorithm, ITriangulatable t) { TriangulationContext tcx; #if !UNITY_METRO System.Console.WriteLine("Triangulating " + t.FileName); #endif // long time = System.nanoTime(); tcx = CreateContext(algorithm); tcx.PrepareTriangulation(t); Triangulate(tcx); // logger.info( "Triangulation of {} points [{}ms]", tcx.getPoints().size(), ( System.nanoTime() - time ) / 1e6 ); }
/// <summary> /// Creates a list of vertices from a texture. /// </summary> /// <param name="texture">The texture to make a body from</param> /// <param name="scale">The scale of the texture</param> /// <param name="imageSize">The size of each individual image in the hitbox</param> /// <param name="density">The density of the object (Will almost always be one</param> /// <param name="algorithm">The decomposition algorithm to use</param> /// <remarks> Available algorithms to use are Bayazit, Dealuny, Earclip, Flipcode, Seidel, SeidelTrapazoid</remarks> /// @warning In order for this to work the input must have a transparent background. I highly reccomend that you /// only use this with PNGs as that is what I have tested and I know they work. This will only produce a bosy as /// clean as the texture you give it, so avoid partically transparent areas and little edges. private List <Vertices>[] CreateVerticesFromTexture(Texture2D texture, float scale, Point imageSize, float density = 1, TriangulationAlgorithm algorithm = TriangulationAlgorithm.Earclip) { int SpriteSheetSize = texture.Width * texture.Height; int IndividualSize = imageSize.X * imageSize.Y; uint[] TextureData = new uint[SpriteSheetSize]; //Array to copy texture info into texture.GetData(TextureData); //Gets which pixels of the texture are actually filled List <uint[]> IndividualData = new List <uint[]>(); for (int Processed = 0; Processed < SpriteSheetSize; Processed += IndividualSize) { uint[] TempArray = new uint[IndividualSize]; try { Array.Copy(TextureData, Processed, TempArray, 0, IndividualSize); } catch (ArgumentException) { //At the end of textures the amount of data left might be to small Array.Copy(TextureData, Processed, TempArray, 0, TextureData.Length - Processed); } IndividualData.Add(TempArray); } List <Vertices>[] TextureVertices = new List <Vertices> [IndividualData.Count]; for (int count = 0; count < IndividualData.Count; ++count) { uint[] I = IndividualData[count]; Vertices vertices = TextureConverter.DetectVertices(I, texture.Width); List <Vertices> VertexList = Triangulate.ConvexPartition(vertices, algorithm); Vector2 VertScale = new Vector2(ConvertUnits.ToSimUnits(scale)); foreach (Vertices vert in VertexList) { vert.Scale(ref VertScale); //Scales the vertices to match the size we specified } Vector2 Centroid = -vertices.GetCentroid(); vertices.Translate(ref Centroid); //basketOrigin = -centroid; TextureVertices[count] = VertexList; } return(TextureVertices); }
/// <summary> /// Vrátí objekt typu <see cref="Body"/> pro provádění dvourozměrných simulací na základě tvaru nalezeného v /// dané bitmapě. /// </summary> /// <param name="orthographicRender">Bitmapa pro nalezení tvaru tělesa.</param> /// <param name="world">Objekt typu <see cref="World"/> fyzikální knihovny představující dvourozměrný svět, do /// kterého má být vytvořené těleso zařazeno.</param> /// <param name="position">Výchozí pozice tělesa v simulovaném světě.</param> /// <param name="bodyType">Typ simulovaného tělesa (statické, kinematické nebo dynamické).</param> /// <param name="density">Hustota tělesa (počet kilogramů na metr čtvereční).</param> /// <param name="rotation">Výchozí rotace tělesa v simulovaném světě.</param> /// <param name="reduceVerticesDistance">Vzdálenost mezi vrcholy nalezeného tvaru, které mají být sloučeny /// (zjednodušení tvaru).</param> /// <param name="triangulationAlgorithm">Algoritmus pro rozdělení tvaru na množství menších konvexních /// polygonů.</param> /// <param name="graphicsToSimulationRatio">Poměr mezi grafickým zobrazením a simulovaným fyzikálním /// světem.</param> /// <returns>Dvourozměrný simulovatelný objekt.</returns> public static Body CreatePolygonBody( Texture2D orthographicRender, World world, Vector2 position = new Vector2(), BodyType bodyType = DEFAULT_BODY_TYPE, float density = DEFAULT_DENSITY, float rotation = DEFAULT_ROTATION, float reduceVerticesDistance = DEFAULT_REDUCE_VERTICES_DISTANCE, TriangulationAlgorithm triangulationAlgorithm = DEFAULT_TRIANGULATION_ALGORITHM, float graphicsToSimulationRatio = DEFAULT_GRAPHICS_TO_SIMULATION_RATIO) { List <Vertices> verticesList = CreateVerticesForBody(orthographicRender, reduceVerticesDistance, triangulationAlgorithm, graphicsToSimulationRatio); return(world.CreateCompoundPolygon(verticesList, density, position, rotation, bodyType)); }
static TriangulationContext GetFreeTcxContext(TriangulationAlgorithm algorithm) { switch (algorithm) { case TriangulationAlgorithm.DTSweep: default: //return context; if (contextStacks.Count == 0) { return(new DTSweepContext()); } else { return(contextStacks.Pop()); } } }
static TriangulationContext GetFreeTcxContext(TriangulationAlgorithm algorithm) { switch (algorithm) { case TriangulationAlgorithm.DTSweep: default: //return context; if (contextStacks.Count == 0) { return(new DTSweepContext()); } else { int last_index = contextStacks.Count - 1; TriangulationContext result = contextStacks[last_index]; contextStacks.RemoveAt(last_index); return(result); } } }
public WoodBlock( World world, ScreenManager screenManager, Vector2 position, Camera2D camera, string texturePath, TriangulationAlgorithm triangulationAlgorithm, Vector2 scale, float strength, float massKoef) : base( world, screenManager, position, camera, texturePath, triangulationAlgorithm, scale, strength, massKoef) { }
/// <summary> /// Creates a polygon from a texture. This is the important function here. /// </summary> /// <param name="texture">The texture to make a body from</param> /// <param name="density">The density of the object (Will almost always be one</param> /// <param name="position">The position (in meters) of the object in the world</param> /// <param name="scale">The scale of the object (how much to change its size)</param> /// <param name="algorithm">The decomposition algorithm to use</param> /// <remarks> Available algorithms to use are Bayazit, Dealuny, Earclip, Flipcode, Seidel, SeidelTrapazoid</remarks> /// @warning In order for this to work the input must have a transparent background. I highly reccomend that you /// only use this with PNGs as that is what I have tested and I know they work. This will only produce a bosy as /// clean as the texture you give it, so avoid partically transparent areas and little edges. private Body CreatePolygonFromTexture(Texture2D texture, float density, Vector2 position, float scale, TriangulationAlgorithm algorithm = TriangulationAlgorithm.Bayazit) { uint[] TextureData = new uint[texture.Width * texture.Height]; //Array to copy texture info into texture.GetData <uint>(TextureData); //Gets which pixels of the texture are actually filled Vertices vertices = TextureConverter.DetectVertices(TextureData, texture.Width); List <Vertices> vertexList = Triangulate.ConvexPartition(vertices, algorithm); Vector2 vertScale = new Vector2(ConvertUnits.ToSimUnits(scale)); foreach (Vertices vert in vertexList) { vert.Scale(ref vertScale); //Scales the vertices to match the size we specified } Vector2 centroid = -vertices.GetCentroid(); vertices.Translate(ref centroid); //basketOrigin = -centroid; //This actually creates the body return(BodyFactory.CreateCompoundPolygon(LevelWorld, vertexList, density, position)); }
private void DrawPolygon() { mesh = new Mesh(); mesh.name = "Polygon"; mesh.vertices = points.ToArray(); tris = TriangulationAlgorithm.WidelyTriangleIndex(new List <Vector3>(points), indexes).ToArray(); mesh.triangles = tris; normals = new Vector3[mesh.vertices.Length]; for (int i = 0; i < mesh.vertices.Length; ++i) { normals[i] = Vector3.back; } mesh.normals = normals; mesh.RecalculateBounds(); mesh.RecalculateTangents(); targetFilter.mesh = mesh; }
/// <summary> /// Method for creating complex bodies. /// </summary> /// <param name="world">The new object will appear in this world</param> /// <param name="objectTexture">The new object will get this texture</param> /// <param name="Scale">The new object get scaled by this factor</param> /// <param name="Algo">The new object get triangulated by this triangulation algorithm</param> /// <returns>Returns the complex body</returns> public Body CreateComplexBody(World world, Texture2D objectTexture, float Scale, TriangulationAlgorithm Algo = TriangulationAlgorithm.Bayazit) { Body body = null; uint[] data = new uint[objectTexture.Width * objectTexture.Height]; objectTexture.GetData(data); Vertices textureVertices = PolygonTools.CreatePolygon(data, objectTexture.Width, false); Vector2 centroid = -textureVertices.GetCentroid(); textureVertices.Translate(ref centroid); tBodyOrigin = -centroid; textureVertices = SimplifyTools.DouglasPeuckerSimplify(textureVertices, 4f); List <Vertices> list = Triangulate.ConvexPartition(textureVertices, Algo); Vector2 vertScale = new Vector2(ConvertUnits.ToSimUnits(1)) * Scale; foreach (Vertices vertices in list) { vertices.Scale(ref vertScale); } return(body = BodyFactory.CreateCompoundPolygon(world, list, 1f)); }
/// <summary> /// Vrátí objekt typu <see cref="Body3D"/>. Tvar odpovídající dvourozměrné reprezentaci pro fyzikální simulaci /// je nalezen podle ortogonální projekce zadaného trojrozměrného modelu. /// </summary> /// <param name="model">Trojrozměrný model.</param> /// <param name="world2D">Dvourozměrný svět, do kterého má být těleso zařazeno.</param> /// <param name="graphicsDevice">Grafické zařízení.</param> /// <param name="position">Výchozí pozice objektu ve dvojrozměrném světě.</param> /// <param name="bodyType">Typ simulovaného tělesa (statické, kinematické nebo dynamické).</param> /// <param name="orthographicModelSize">Velikost modelu pro renderování. Pokud tento parametr není zadán, /// vypočítá se.</param> /// <param name="triangulationAlgorithm">Algoritmus pro rozdělení tvaru na množství menších konvexních /// polygonů.</param> /// <param name="basicEffectParams">Parametry pro třídu <see cref="BasicEffect"/>.</param> /// <returns>Objekt typu <see cref="Body3D"/>.</returns> public static Body3D CreateBody3D( Model model, World world2D, GraphicsDevice graphicsDevice, Vector2 position = new Vector2(), BodyType bodyType = BodyCreator.DEFAULT_BODY_TYPE, Vector2 orthographicModelSize = new Vector2(), TriangulationAlgorithm triangulationAlgorithm = BodyCreator.DEFAULT_TRIANGULATION_ALGORITHM, BasicEffectParams basicEffectParams = null) { using (Texture2D orthoRender = BitmapRenderer.RenderOrthographic(graphicsDevice, model, BitmapRenderer.DEFAULT_BITMAP_SCALE, orthographicModelSize)) { Body body2D = BodyCreator.CreatePolygonBody(orthoRender, world2D, position, bodyType, 1f, 0f, 1f, triangulationAlgorithm); Body3D body3D = new Body3D(model, body2D) { BasicEffectParams = basicEffectParams }; return(body3D); } }
/// <summary> /// Creates a list of vertices from a texture. /// </summary> /// <param name="texture">The texture to make a body from</param> /// <param name="scale">The scale of the texture</param> /// <param name="algorithm">The decomposition algorithm to use</param> /// <remarks> Available algorithms to use are Bayazit, Dealuny, Earclip, Flipcode, Seidel, SeidelTrapazoid</remarks> /// @warning In order for this to work the input must have a transparent background. I highly reccomend that you /// only use this with PNGs as that is what I have tested and I know they work. This will only produce a bosy as /// clean as the texture you give it, so avoid partically transparent areas and little edges. private List <Vertices> CreateVerticesFromTexture(Texture2D texture, float scale, TriangulationAlgorithm algorithm = TriangulationAlgorithm.Earclip) { int SpriteSheetSize = texture.Width * texture.Height; uint[] TextureData = new uint[SpriteSheetSize]; //Array to copy texture info into texture.GetData(TextureData); //Gets which pixels of the texture are actually filled Vertices vertices = TextureConverter.DetectVertices(TextureData, texture.Width); List <Vertices> VertexList = Triangulate.ConvexPartition(vertices, algorithm); Vector2 VertScale = new Vector2(ConvertUnits.ToSimUnits(scale)); foreach (Vertices vert in VertexList) { vert.Scale(ref VertScale); //Scales the vertices to match the size we specified } Vector2 Centroid = -vertices.GetCentroid(); vertices.Translate(ref Centroid); //basketOrigin = -centroid; return(VertexList); }
public static List <Vertices> ConvexPartition(Vertices vertices, TriangulationAlgorithm algorithm, bool discardAndFixInvalid = true, float tolerance = 0.001f) { if (vertices.Count <= 3) { return new List <Vertices> { vertices } } ; List <Vertices> results = null; switch (algorithm) { case TriangulationAlgorithm.Earclip: #pragma warning disable 162 // ReSharper disable three ConditionIsAlwaysTrueOrFalse if (Settings.SkipSanityChecks) { Debug.Assert(!vertices.IsCounterClockWise(), "The Ear-clip algorithm expects the polygon to be clockwise."); } else { if (vertices.IsCounterClockWise()) { Vertices temp = new Vertices(vertices); temp.Reverse(); results = EarclipDecomposer.ConvexPartition(temp, tolerance); } else { results = EarclipDecomposer.ConvexPartition(vertices, tolerance); } } break; case TriangulationAlgorithm.Bayazit: if (Settings.SkipSanityChecks) { Debug.Assert(vertices.IsCounterClockWise(), "The polygon is not counter clockwise. This is needed for Bayazit to work correctly."); } else { if (!vertices.IsCounterClockWise()) { Vertices temp = new Vertices(vertices); temp.Reverse(); results = BayazitDecomposer.ConvexPartition(temp); } else { results = BayazitDecomposer.ConvexPartition(vertices); } } break; case TriangulationAlgorithm.Flipcode: if (Settings.SkipSanityChecks) { Debug.Assert(vertices.IsCounterClockWise(), "The polygon is not counter clockwise. This is needed for Bayazit to work correctly."); } #pragma warning restore 162 else { if (!vertices.IsCounterClockWise()) { Vertices temp = new Vertices(vertices); temp.Reverse(); results = FlipcodeDecomposer.ConvexPartition(temp); } else { results = FlipcodeDecomposer.ConvexPartition(vertices); } } break; case TriangulationAlgorithm.Seidel: results = SeidelDecomposer.ConvexPartition(vertices, tolerance); break; case TriangulationAlgorithm.SeidelTrapezoids: results = SeidelDecomposer.ConvexPartitionTrapezoid(vertices, tolerance); break; case TriangulationAlgorithm.Delauny: results = CDTDecomposer.ConvexPartition(vertices); break; default: throw new ArgumentOutOfRangeException(nameof(algorithm)); } if (discardAndFixInvalid) { for (int i = results.Count - 1; i >= 0; i--) { Vertices polygon = results[i]; if (!ValidatePolygon(polygon)) { results.RemoveAt(i); } } } return(results); }
/// <summary> /// Triangulate a list of polygons. /// </summary> /// <returns>The triangulation.</returns> /// <param name="polygons">Polygons.</param> /// <param name="algo">Algorithm.</param> public static List <Vertices> Triangulate(List <List <IntPoint> > polygons, TriangulationAlgorithm algo = TriangulationAlgorithm.Earclip) { List <Vertices> result = new List <Vertices>(); polygons.ForEach(p => { result.AddRange(Triangulate(p)); }); return(result); }
private static Shape BuildShape(Image imageBitmap, StringBuilder spool, bool holeDetection, bool strict, TriangulationAlgorithm algorithm) { var data = LoadImageData(imageBitmap); var polygon = PolygonTools.CreatePolygon(data, imageBitmap.Width, holeDetection); var polygons = new List<Vertices> { polygon }; return ScaleConvertAndPartition(spool, strict, imageBitmap, polygons, algorithm); }
private static Shape BuildShape(Image imageBitmap, StringBuilder spool, float hullTolerance, byte alphaTolerance, bool multiPartDetection, bool holeDetection = true, bool strict = false, TriangulationAlgorithm algorithm = TriangulationAlgorithm.Bayazit) { var data = LoadImageData(imageBitmap); var polygons = PolygonTools.CreatePolygon(data, imageBitmap.Width, hullTolerance, alphaTolerance, multiPartDetection, holeDetection); return ScaleConvertAndPartition(spool, strict, imageBitmap, polygons, algorithm); }
/// <summary> /// Triangulate a polygon. /// </summary> /// <returns>The triangulation.</returns> /// <param name="polygon">Polygon.</param> /// <param name="algo">Algorithm.</param> public static List <Vertices> Triangulate(List <IntPoint> polygon, TriangulationAlgorithm algo = TriangulationAlgorithm.Earclip) { return(Physics2D.Common.Decomposition.Triangulate.ConvexPartition(PolygonToVertices(polygon, 1), algo)); }
public static List <Vertices> ConvexPartition(Vertices vertices, TriangulationAlgorithm algorithm, bool discardAndFixInvalid, FP tolerance) { bool flag = vertices.Count <= 3; List <Vertices> result; if (flag) { result = new List <Vertices> { vertices }; } else { List <Vertices> list; switch (algorithm) { case TriangulationAlgorithm.Earclip: { bool flag2 = vertices.IsCounterClockWise(); if (flag2) { Vertices vertices2 = new Vertices(vertices); vertices2.Reverse(); list = EarclipDecomposer.ConvexPartition(vertices2, tolerance); } else { list = EarclipDecomposer.ConvexPartition(vertices, tolerance); } break; } case TriangulationAlgorithm.Bayazit: { bool flag3 = !vertices.IsCounterClockWise(); if (flag3) { Vertices vertices3 = new Vertices(vertices); vertices3.Reverse(); list = BayazitDecomposer.ConvexPartition(vertices3); } else { list = BayazitDecomposer.ConvexPartition(vertices); } break; } case TriangulationAlgorithm.Flipcode: { bool flag4 = !vertices.IsCounterClockWise(); if (flag4) { Vertices vertices4 = new Vertices(vertices); vertices4.Reverse(); list = FlipcodeDecomposer.ConvexPartition(vertices4); } else { list = FlipcodeDecomposer.ConvexPartition(vertices); } break; } case TriangulationAlgorithm.Seidel: list = SeidelDecomposer.ConvexPartition(vertices, tolerance); break; case TriangulationAlgorithm.SeidelTrapezoids: list = SeidelDecomposer.ConvexPartitionTrapezoid(vertices, tolerance); break; case TriangulationAlgorithm.Delauny: list = CDTDecomposer.ConvexPartition(vertices); break; default: throw new ArgumentOutOfRangeException("algorithm"); } if (discardAndFixInvalid) { for (int i = list.Count - 1; i >= 0; i--) { Vertices polygon = list[i]; bool flag5 = !Triangulate.ValidatePolygon(polygon); if (flag5) { list.RemoveAt(i); } } } result = list; } return(result); }
public Body CreatePolygonFromTexture(Texture2D tex, World world, float density, Vector2 position, float scale, TriangulationAlgorithm algorithm = TriangulationAlgorithm.Bayazit) { uint[] texData = new uint[tex.Width * tex.Height]; tex.GetData <uint>(texData); Vertices vertices = TextureConverter.DetectVertices(texData, tex.Width); List <Vertices> vertexList = Triangulate.ConvexPartition(vertices, algorithm); Vector2 vertScale = new Vector2(ConvertUnits.ToSimUnits(scale)); foreach (Vertices vert in vertexList) { vert.Scale(ref vertScale); } Vector2 centroid = vertices.GetCentroid(); vertices.Translate(ref centroid); //basketOrigin = -centroid; return(BodyFactory.CreateCompoundPolygon(world, vertexList, density, position, 100)); }
public static List <Vertices> ConvexPartition(Vertices vertices, TriangulationAlgorithm algorithm, bool discardAndFixInvalid = true, float tolerance = 0.001f) { if (vertices.Count <= 3) { return new List <Vertices> { vertices } } ; List <Vertices> results; switch (algorithm) { case TriangulationAlgorithm.Earclip: if (Settings.SkipSanityChecks) { Debug.Assert(!vertices.IsCounterClockWise(), "The Earclip algorithm expects the polygon to be clockwise."); } else { if (vertices.IsCounterClockWise()) { Vertices temp = new Vertices(vertices); temp.Reverse(); results = EarclipDecomposer.ConvexPartition(temp, tolerance); } else { results = EarclipDecomposer.ConvexPartition(vertices, tolerance); } } break; case TriangulationAlgorithm.Bayazit: if (Settings.SkipSanityChecks) { Debug.Assert(vertices.IsCounterClockWise(), "The polygon is not counter clockwise. This is needed for Bayazit to work correctly."); } else { if (!vertices.IsCounterClockWise()) { Vertices temp = new Vertices(vertices); temp.Reverse(); results = BayazitDecomposer.ConvexPartition(temp); } else { results = BayazitDecomposer.ConvexPartition(vertices); } } break; case TriangulationAlgorithm.Flipcode: if (Settings.SkipSanityChecks) { Debug.Assert(vertices.IsCounterClockWise(), "The polygon is not counter clockwise. This is needed for Bayazit to work correctly."); } else { if (!vertices.IsCounterClockWise()) { Vertices temp = new Vertices(vertices); temp.Reverse(); results = FlipcodeDecomposer.ConvexPartition(temp); } else { results = FlipcodeDecomposer.ConvexPartition(vertices); } } break; case TriangulationAlgorithm.Seidel: results = SeidelDecomposer.ConvexPartition(vertices, tolerance); break; case TriangulationAlgorithm.SeidelTrapezoids: results = SeidelDecomposer.ConvexPartitionTrapezoid(vertices, tolerance); break; case TriangulationAlgorithm.Delauny: results = CDTDecomposer.ConvexPartition(vertices); break; default: throw new ArgumentOutOfRangeException("algorithm"); } if (discardAndFixInvalid) { for (int i = results.Count - 1; i >= 0; i--) { Vertices polygon = results[i]; PolygonError errorCode = polygon.CheckPolygon(); if (errorCode == PolygonError.InvalidAmountOfVertices || errorCode == PolygonError.AreaTooSmall || errorCode == PolygonError.SideTooSmall || errorCode == PolygonError.NotSimple) { results.RemoveAt(i); } else if (errorCode == PolygonError.NotCounterClockWise) { polygon.Reverse(); } else if (errorCode == PolygonError.NotConvex) { results[i] = GiftWrap.GetConvexHull(polygon); } } } return(results); } }
public static List<Vertices> ConvexPartition(Vertices vertices, TriangulationAlgorithm algorithm, bool discardAndFixInvalid = true, float tolerance = 0.001f) { if (vertices.Count <= 3) return new List<Vertices> { vertices }; List<Vertices> results = null; switch (algorithm) { case TriangulationAlgorithm.Earclip: if (Settings.SkipSanityChecks) Debug.Assert(!vertices.IsCounterClockWise(), "The Earclip algorithm expects the polygon to be clockwise."); else { if (vertices.IsCounterClockWise()) { Vertices temp = new Vertices(vertices); temp.Reverse(); results = EarclipDecomposer.ConvexPartition(temp, tolerance); } else results = EarclipDecomposer.ConvexPartition(vertices, tolerance); } break; case TriangulationAlgorithm.Bayazit: if (Settings.SkipSanityChecks) Debug.Assert(vertices.IsCounterClockWise(), "The polygon is not counter clockwise. This is needed for Bayazit to work correctly."); else { if (!vertices.IsCounterClockWise()) { Vertices temp = new Vertices(vertices); temp.Reverse(); results = BayazitDecomposer.ConvexPartition(temp); } else results = BayazitDecomposer.ConvexPartition(vertices); } break; case TriangulationAlgorithm.Flipcode: if (Settings.SkipSanityChecks) Debug.Assert(vertices.IsCounterClockWise(), "The polygon is not counter clockwise. This is needed for Bayazit to work correctly."); else { if (!vertices.IsCounterClockWise()) { Vertices temp = new Vertices(vertices); temp.Reverse(); results = FlipcodeDecomposer.ConvexPartition(temp); } else results = FlipcodeDecomposer.ConvexPartition(vertices); } break; case TriangulationAlgorithm.Seidel: results = SeidelDecomposer.ConvexPartition(vertices, tolerance); break; case TriangulationAlgorithm.SeidelTrapezoids: results = SeidelDecomposer.ConvexPartitionTrapezoid(vertices, tolerance); break; case TriangulationAlgorithm.Delauny: results = CDTDecomposer.ConvexPartition(vertices); break; default: throw new ArgumentOutOfRangeException("algorithm"); } if (discardAndFixInvalid) { for (int i = results.Count - 1; i >= 0; i--) { Vertices polygon = results[i]; if (!ValidatePolygon(polygon)) results.RemoveAt(i); } } return results; }
private static Shape ScaleConvertAndPartition(StringBuilder spool, bool strict, Image image, IEnumerable<Vertices> polygons, TriangulationAlgorithm algorithm) { var scale = ConvertUnits.ToSimUnits(1, 1); var width = ConvertUnits.ToSimUnits(image.Width); var height = ConvertUnits.ToSimUnits(image.Height); var translation = new Vector2(-width, -height)*0.5f; var final = new List<List<Vector2>>(); foreach (var polygon in polygons) { polygon.Scale(scale); polygon.Translate(translation); var thisPolygon = SimplifyTools.CollinearSimplify(polygon); if (strict) { var errors = thisPolygon.CheckPolygon(); if (errors != PolygonError.NoError) { spool.AppendFormat("Invalid shape ({0})", errors); return null; } } try { var partition = Triangulate.ConvexPartition(thisPolygon, algorithm); var vertices = partition.Select(verts => verts.Select(v => new Vector2(v.X, v.Y)).ToList()); final.AddRange(vertices); } catch { spool.AppendFormat("Cannot triangulate polygon"); spool.AppendLine(); } } var shape = new Shape { Vertices = final }; return shape; }
public static List <Vertices> ConvexPartition(Vertices vertices, TriangulationAlgorithm algorithm, bool discardAndFixInvalid = true, float tolerance = 0.001f) { if (vertices.Count <= 3) { return new List <Vertices> { vertices } } ; List <Vertices> results; switch (algorithm) { case TriangulationAlgorithm.Earclip: if (vertices.IsCounterClockWise()) { Vertices temp = new Vertices(vertices); temp.Reverse(); results = EarclipDecomposer.ConvexPartition(temp, tolerance); } else { results = EarclipDecomposer.ConvexPartition(vertices, tolerance); } break; case TriangulationAlgorithm.Bayazit: if (!vertices.IsCounterClockWise()) { Vertices temp = new Vertices(vertices); temp.Reverse(); results = BayazitDecomposer.ConvexPartition(temp); } else { results = BayazitDecomposer.ConvexPartition(vertices); } break; case TriangulationAlgorithm.Flipcode: if (!vertices.IsCounterClockWise()) { Vertices temp = new Vertices(vertices); temp.Reverse(); results = FlipcodeDecomposer.ConvexPartition(temp); } else { results = FlipcodeDecomposer.ConvexPartition(vertices); } break; case TriangulationAlgorithm.Seidel: results = SeidelDecomposer.ConvexPartition(vertices, tolerance); break; case TriangulationAlgorithm.SeidelTrapezoids: results = SeidelDecomposer.ConvexPartitionTrapezoid(vertices, tolerance); break; case TriangulationAlgorithm.Delauny: results = CDTDecomposer.ConvexPartition(vertices); break; default: throw new ArgumentOutOfRangeException("algorithm"); } if (discardAndFixInvalid) { for (int i = results.Count - 1; i >= 0; i--) { Vertices polygon = results[i]; if (!ValidatePolygon(polygon)) { results.RemoveAt(i); } } } return(results); }
/// <param name="skipSanityChecks"> /// Set this to true to skip sanity checks in the engine. This will speed up the /// tools by removing the overhead of the checks, but you will need to handle checks /// yourself where it is needed. /// </param> public static List <Vertices> ConvexPartition(Vertices vertices, TriangulationAlgorithm algorithm, bool discardAndFixInvalid = true, float tolerance = 0.001f, bool skipSanityChecks = false) { if (vertices.Count <= 3) { return new List <Vertices> { vertices } } ; List <Vertices> results; switch (algorithm) { case TriangulationAlgorithm.Earclip: if (skipSanityChecks) { Debug.Assert(!vertices.IsCounterClockWise(), "The Earclip algorithm expects the polygon to be clockwise."); } else if (vertices.IsCounterClockWise()) { Vertices temp = new Vertices(vertices); temp.Reverse(); vertices = temp; } results = EarclipDecomposer.ConvexPartition(vertices, tolerance); break; case TriangulationAlgorithm.Bayazit: if (skipSanityChecks) { Debug.Assert(vertices.IsCounterClockWise(), "The polygon is not counter clockwise. This is needed for Bayazit to work correctly."); } else if (!vertices.IsCounterClockWise()) { Vertices temp = new Vertices(vertices); temp.Reverse(); vertices = temp; } results = BayazitDecomposer.ConvexPartition(vertices); break; case TriangulationAlgorithm.Flipcode: if (skipSanityChecks) { Debug.Assert(vertices.IsCounterClockWise(), "The polygon is not counter clockwise. This is needed for Bayazit to work correctly."); } else if (!vertices.IsCounterClockWise()) { Vertices temp = new Vertices(vertices); temp.Reverse(); vertices = temp; } results = FlipcodeDecomposer.ConvexPartition(vertices); break; case TriangulationAlgorithm.Seidel: results = SeidelDecomposer.ConvexPartition(vertices, tolerance); break; case TriangulationAlgorithm.SeidelTrapezoids: results = SeidelDecomposer.ConvexPartitionTrapezoid(vertices, tolerance); break; case TriangulationAlgorithm.Delauny: results = CDTDecomposer.ConvexPartition(vertices); break; default: throw new ArgumentOutOfRangeException("algorithm"); } if (discardAndFixInvalid) { for (int i = results.Count - 1; i >= 0; i--) { Vertices polygon = results[i]; if (!ValidatePolygon(polygon)) { results.RemoveAt(i); } } } return(results); }
/// <summary> /// Vrátí list vrholů pro sestavení tvaru (složeného mnohoúhelníku) na základě ortogonální projekce /// trojrozměrného modelu. Provedení této metody je relativně paměťově a výpočetně náročné v závislosti na /// velikosti zdrojové bitmapy a zvoleném algoritmu. /// </summary> /// <param name="orthographicRender">Bitmapa pro nalezení vrcholů.</param> /// <param name="reduceVerticesDistance">Vzdálenost mezi vrcholy nalezeného tvaru, které mají být sloučeny /// (zjednodušení tvaru).</param> /// <param name="triangulationAlgorithm">Algoritmus pro rozdělení tvaru na množství menších konvexních /// polygonů.</param> /// <param name="graphicsToSimulationRatio">Poměr mezi grafickým zobrazením a simulovaným fyzikálním /// světem.</param> /// <returns></returns> public static List <Vertices> CreateVerticesForBody( Texture2D orthographicRender, float reduceVerticesDistance = DEFAULT_REDUCE_VERTICES_DISTANCE, TriangulationAlgorithm triangulationAlgorithm = DEFAULT_TRIANGULATION_ALGORITHM, float graphicsToSimulationRatio = DEFAULT_GRAPHICS_TO_SIMULATION_RATIO) { //Pole pro data bitmapové textury uint[] data = new uint[orthographicRender.Width * orthographicRender.Height]; //Přenesení dat textury do pole orthographicRender.GetData(data); //Nalezení vrcholů tvořících obrys tvaru v textuře Vertices textureVertices = PolygonTools.CreatePolygon(data, orthographicRender.Width, false); //Snížení počtu nalezených vrcholů (zjednodušení) if (reduceVerticesDistance > 0) { textureVertices = SimplifyTools.ReduceByDistance(textureVertices, reduceVerticesDistance); } //Střed bitmapy Vector2 center = new Vector2(-orthographicRender.Width / 2, -orthographicRender.Height / 2); //Vystředění nalezených vrcholů textureVertices.Translate(ref center); List <Vertices> verticesList = new List <Vertices>(); if (!textureVertices.IsConvex()) { try { //Konkávní polygon je nutné rozdělit na množství menších konvexních polygonů s využitím //preferovaného algoritmu verticesList = Triangulate.ConvexPartition(textureVertices, triangulationAlgorithm); } catch (Exception ex) { if (ex.Message == "Intersecting Constraints") { throw new ArgumentException( "Tvar se nepodařilo rozdělit na konvexní polygony, zkuste změnit parametr udávající " + "vzdálenost vrcholů pro sloučení nebo použijte jiný algoritmus pro rozdělení.", "reduceVerticesDistance, triangulationAlgorithm", ex); } } } else { verticesList.Add(textureVertices); } //Změna velikost polygonu podle poměru ke grafickému zobrazení Vector2 vertScale = new Vector2(graphicsToSimulationRatio); foreach (Vertices vertices in verticesList) { vertices.Scale(new Vector2(1f, -1f)); vertices.Scale(vertScale); } return(verticesList); }
public BreakableObj1( World world, ScreenManager screenManager, Vector2 position, Camera2D camera, string texturePath, TriangulationAlgorithm triangulationAlgorithm, Vector2 scale, float strength, float massKoef) { _world = world; _screenManager = screenManager; _camera = camera; _texturePath = texturePath; _textureScale = scale; _triangulationAlgorithm = triangulationAlgorithm; #region "Триангуляция текстуры в полигоны" Texture2D alphabet = _screenManager.Content.Load <Texture2D>(_texturePath); uint[] data = new uint[alphabet.Width * alphabet.Height]; alphabet.GetData(data); List <Vertices> list = PolygonTools.CreatePolygon(data, alphabet.Width, 3.5f, 20, true, true); for (int i = 0; i < list.Count; i++) { list[i].Scale(new Vector2(1f, -1f)); // flip Vert } List <Vertices> triangulated = new List <Vertices>(); for (int i = 0; i < list.Count; i++) { polygon = list[i]; centroid = -polygon.GetCentroid(); polygon.Translate(ref centroid); polygon = SimplifyTools.CollinearSimplify(polygon); polygon = SimplifyTools.ReduceByDistance(polygon, 4); triangulated = Triangulate.ConvexPartition(polygon, triangulationAlgorithm); Vector2 vertScale = _textureScale /*new Vector2(0.01f, 0.01f)*//*(new Vector2(13.916667f, 23.25f) / new Vector2(alphabet.Width, alphabet.Height)) * scale*//*0.5f*/; foreach (Vertices vertices in triangulated) { vertices.Scale(ref vertScale); } } _breakableBody = new SegmentableBody(_world, triangulated, 1); _breakableBody.MainBody.Position = position; //_breakableBody.MainBody.Mass = 5f; _breakableBody.MainBody.SetFriction(_breakableBody.MainBody.Mass * 50f); _breakableBody.Strength = /*50*/ strength * massKoef; #endregion #region "Массивы для индексного рассчета вершин под графен" //2.1)лист вершин для каждого полигона List <Vertices> temp = _breakableBody.Parts .Select(a => ((PolygonShape)(a.Shape)).Vertices) .ToList(); //2.2)коллекция для подсчета суммарного количества вершин IEnumerable <VertexPositionTexture> temp2 = new VertexPositionTexture[0]; //2.3)буфер вершин под каждый полигон vertexBuffers = new List <VertexBuffer>(); //2.4)координаты центров полигонов для сортировки вершин этих полигонов относительно их центров centroids = new List <Vector2>(); //2.5)сортированый массив вершин и их цветов полигонов для отрисовки TESTListOfVertices = new List <VertexPositionTexture[]>(); //Поиск размера исходного объекта float mainBodyWidth = 0f; float mainBodyHeight = 0f; //Поиск смещения объекта в отрицательную часть координатной плоскости float leftOffsetFromZero = temp.First().First().X; //для всего объекта, а не отдельных полигонов float downOffsetFromZero = temp.First().First().Y; float rightOffsetFromZero = temp.First().First().X; //для всего объекта, а не отдельных полигонов float upOffsetFromZero = temp.First().First().Y; for (int i = 0; i < temp.Count; i++) { for (int j = 0; j < temp[i].Count; j++) { if (temp[i][j].X <= leftOffsetFromZero) { leftOffsetFromZero = temp[i][j].X; } if (temp[i][j].Y <= downOffsetFromZero) { downOffsetFromZero = temp[i][j].Y; } if (temp[i][j].X >= rightOffsetFromZero) { rightOffsetFromZero = temp[i][j].X; } if (temp[i][j].Y >= upOffsetFromZero) { upOffsetFromZero = temp[i][j].Y; } } } mainBodyWidth = Math.Abs(leftOffsetFromZero - rightOffsetFromZero); mainBodyHeight = Math.Abs(downOffsetFromZero - upOffsetFromZero); leftOffsetFromZero = Math.Abs(leftOffsetFromZero); downOffsetFromZero = Math.Abs(downOffsetFromZero); //rightOffsetFromZero = Math.Abs(rightOffsetFromZero); //upOffsetFromZero = Math.Abs(upOffsetFromZero); for (int i = 0; i < temp.Count; i++) { var tempUnsorted = temp[i] .Select(a => new VertexPositionTexture( new Vector3(a.X, a.Y, 0f), /*Color.Crimson*/ new Vector2(a.X, a.Y))) .ToArray(); temp2 = temp2.Concat(tempUnsorted); var centr = temp[i].GetCentroid(); centroids.Add(centr); var temp3 = VertexClockwiseSort(tempUnsorted, centr); //for (int j = 0; j < temp3.Length; j++) //{ // temp3[j].Position.Z = -10f;///////////////////////////////////////////// //} for (int j = 0; j < temp3.Length; j++) { temp3[j].TextureCoordinate.X = ((temp3[j].TextureCoordinate.X + leftOffsetFromZero) / ((mainBodyWidth /*width*/))); temp3[j].TextureCoordinate.Y = 1f - ((temp3[j].TextureCoordinate.Y + downOffsetFromZero) / ((mainBodyHeight /*height*/))); } TESTListOfVertices.Add(temp3); } triangleVertices = temp2.ToArray(); //(2.2) int verticesCount = 0; foreach (var e in TESTListOfVertices) { verticesCount += e.Length; } //(2.3) foreach (var e in TESTListOfVertices) { var vb = new VertexBuffer( _screenManager.GraphicsDevice, typeof(VertexPositionTexture), e.Length, BufferUsage.None); vb.SetData(e); vertexBuffers.Add(vb); } #endregion effect = new BasicEffect(_screenManager.GraphicsDevice); texture = _screenManager.Content.Load <Texture2D>(/*"wood2"*//*"wood-plank2"*/ texturePath); effect.TextureEnabled = true; effect.Texture = texture; //буферы индексов для полигонов с разным числом вершин indexBuffer3 = new IndexBuffer(_screenManager.GraphicsDevice, typeof(short), 36, BufferUsage.WriteOnly); indexBuffer3.SetData <short>(TriangleCubeIndices.triangleCubeIndices3_1); indexBuffer4 = new IndexBuffer(_screenManager.GraphicsDevice, typeof(short), 36, BufferUsage.WriteOnly); indexBuffer4.SetData <short>(TriangleCubeIndices.triangleCubeIndices4_1); indexBuffer5 = new IndexBuffer(_screenManager.GraphicsDevice, typeof(short), 36, BufferUsage.WriteOnly); indexBuffer5.SetData <short>(TriangleCubeIndices.triangleCubeIndices5_1); indexBuffer6 = new IndexBuffer(_screenManager.GraphicsDevice, typeof(short), 36, BufferUsage.WriteOnly); indexBuffer6.SetData <short>(TriangleCubeIndices.triangleCubeIndices6_1); indexBuffer7 = new IndexBuffer(_screenManager.GraphicsDevice, typeof(short), 36, BufferUsage.WriteOnly); indexBuffer7.SetData <short>(TriangleCubeIndices.triangleCubeIndices7_1); indexBuffer8 = new IndexBuffer(_screenManager.GraphicsDevice, typeof(short), 36, BufferUsage.WriteOnly); indexBuffer8.SetData <short>(TriangleCubeIndices.triangleCubeIndices8_1); //точка для отрисовки центрода(ТЕСТ) TESTCentroid = new Sprite(_screenManager.Assets.CircleTexture(0.1f, MaterialType.Squares, Color.Black, 1f, 24f)); //IsCanDraw = true; }