internal static Polygon Ellipse(Vector mid, double a, double b, double angle, int steps) { var p = new Polygon(); double beta = -angle * Constants.DegToRad; double sinBeta = Math.Sin(beta); double cosBeta = Math.Cos(beta); for (int i = 0; i < steps; i++) { double currentAngle = i * 360.0 / steps; double alpha = currentAngle * Constants.DegToRad; double sinAlpha = Math.Sin(alpha); double cosAlpha = Math.Cos(alpha); p.Add(new Vector(mid.X + a * cosAlpha * cosBeta - b * sinAlpha * sinBeta, mid.Y + a * cosAlpha * sinBeta + b * sinAlpha * cosBeta)); } p.UpdateDecomposition(); return(p); }
internal static void Decompose(List <Polygon> polygons) { for (int i = 0; i < polygons.Count; i++) { Polygon poly = polygons[i]; if (poly.Count <= 3) { continue; } int firstDiagonal = 0; int secondDiagonal = 2; var newPoly = new Polygon(); for (int j = firstDiagonal; j <= secondDiagonal; j++) { newPoly.Add(poly.Vertices[j]); } poly.RemoveRange(firstDiagonal + 1, secondDiagonal - firstDiagonal - 1); polygons.Add(newPoly); i -= 1; } }
private void LoadFromBytes(byte[] level) { Size = level.Length; LevStartMagic = Encoding.UTF8.GetString(level, 0, 5); if (!IsElmaLevel && !IsAcrossLevel && !IsLeb) { throw new LevelException( "Unknown file type. This is neither an Elma level, an Across level nor a LEB file."); } var sp = 7; if (IsAcrossLevel) { sp -= 2; } Identifier = BitConverter.ToInt32(level, sp); sp += 4; for (var i = 0; i <= 3; i++) { Integrity[i] = BitConverter.ToDouble(level, sp); sp += 8; } Title = Utils.ReadNullTerminatedString(level, sp, 60); if (IsAcrossLevel) { sp = 100; } else { sp = 94; LgrFile = Utils.ReadNullTerminatedString(level, sp, 16); sp += 16; GroundTextureName = Utils.ReadNullTerminatedString(level, sp, 12).ToLower(); sp += 10; SkyTextureName = Utils.ReadNullTerminatedString(level, sp, 12).ToLower(); sp += 10; } var polygonCount = (int)Math.Round(BitConverter.ToDouble(level, sp) - MagicDouble); sp += 8; var objectCount = -1; if (IsLeb) { objectCount = (int)Math.Round(BitConverter.ToDouble(level, sp) - MagicDouble); sp += 8; } var isGrassPolygon = false; Polygons = new List <Polygon>(); for (var i = 0; i < polygonCount; i++) { int numVertice; if (IsAcrossLevel) { numVertice = level[sp] + 256 * level[sp + 1]; sp += 4; } else { numVertice = level[sp + 4] + 256 * level[sp + 5]; sp += 8; isGrassPolygon = level[sp - 8] == 1; } var poly = new Polygon(); for (var j = 0; j < numVertice; j++) { var x = BitConverter.ToDouble(level, sp); var y = BitConverter.ToDouble(level, sp + 8); poly.Add(new Vector(x, y)); sp += 16; } poly.IsGrass = isGrassPolygon; Polygons.Add(poly); } if (!IsLeb) { objectCount = (int)Math.Round(BitConverter.ToDouble(level, sp) - MagicDouble); sp += 8; } Apples = new List <LevObject>(); var startFound = false; for (var i = 0; i < objectCount; i++) { var x = BitConverter.ToDouble(level, sp); var y = BitConverter.ToDouble(level, sp + 8); var objectType = (ObjectType)(level[sp + 16]); if (objectType == ObjectType.Start) { startFound = true; } var appleType = AppleType.Normal; var animNum = 0; if (!IsAcrossLevel) { appleType = (AppleType)(BitConverter.ToInt32(level, sp + 20)); animNum = BitConverter.ToInt32(level, sp + 24); sp += 28; } else { sp += 20; } var objectToAdd = new LevObject(new Vector(x, y), objectType, appleType, animNum + 1); Objects.Add(objectToAdd); if (objectType == ObjectType.Apple) { Apples.Add(objectToAdd); } } if (!startFound) { Objects.Add(new LevObject(new Vector(0, 0), ObjectType.Start, AppleType.Normal)); } if (!IsAcrossLevel) { var numberOfPicturesPlusTextures = (int)Math.Round(BitConverter.ToDouble(level, sp) - MagicDouble2); sp += 8; for (var i = 0; i < numberOfPicturesPlusTextures; i++) { if (level[sp] == 0) { _textureData.Add(new LevelFileTexture(Utils.ReadNullTerminatedString(level, sp + 10, 10), Utils.ReadNullTerminatedString(level, sp + 20, 10), new Vector(BitConverter.ToDouble(level, sp + 30), BitConverter.ToDouble(level, sp + 38)), BitConverter.ToInt32(level, sp + 46), ((ClippingType)(BitConverter.ToInt32(level, sp + 50))))); } else { _textureData.Add(new LevelFileTexture(Utils.ReadNullTerminatedString(level, sp, 10), null, new Vector(BitConverter.ToDouble(level, sp + 30), BitConverter.ToDouble(level, sp + 38)), BitConverter.ToInt32(level, sp + 46), ((ClippingType)(BitConverter.ToInt32(level, sp + 50))))); } sp += 54; } } if (sp != level.Length) { sp += 4; //Skip end of data magic number CryptTop10(level, sp); try { Top10.SinglePlayer = ReadTop10Part(level, sp, (a, b, t) => new Top10EntrySingle(a, b, t)); Top10.MultiPlayer = ReadTop10Part(level, sp + 344, (a, b, t) => new Top10EntryMulti(a, b, t)); } catch (IndexOutOfRangeException) { throw new LevelException( "Top 10 list is corrupted. The list will be cleared if you save the level."); } } UpdateBounds(); }
private void LoadFromStream(Stream data) { var lev = new BinaryReader(data, Encoding.ASCII); LevStartMagic = lev.ReadString(5); if (!IsElmaLevel && !IsAcrossLevel && !IsLeb) { throw new BadFileException( "Unknown file type. This is neither an Elma level, an Across level nor a LEB file."); } if (!IsAcrossLevel) { lev.ReadInt16(); } Identifier = lev.ReadInt32(); for (var i = 0; i < 4; i++) { Integrity[i] = lev.ReadDouble(); } Title = lev.ReadNullTerminatedString(IsAcrossLevel ? 59 : 51); if (!IsAcrossLevel) { LgrFile = lev.ReadNullTerminatedString(16); GroundTextureName = lev.ReadNullTerminatedString(10).ToLower(); SkyTextureName = lev.ReadNullTerminatedString(10).ToLower(); } var polygonCount = (int)Math.Round(lev.ReadDouble() - MagicDouble); var objectCount = -1; if (IsLeb) { objectCount = (int)Math.Round(lev.ReadDouble() - MagicDouble); } Polygons = new List <Polygon>(); for (var i = 0; i < polygonCount; i++) { var isGrassPolygon = false; if (!IsAcrossLevel) { isGrassPolygon = lev.ReadInt32() == 1; } var numVertice = lev.ReadInt32(); var poly = new Polygon(); for (var j = 0; j < numVertice; j++) { var x = lev.ReadDouble(); var y = lev.ReadDouble(); poly.Add(new Vector(x, y)); } poly.IsGrass = isGrassPolygon; Polygons.Add(poly); } if (!IsLeb) { objectCount = (int)Math.Round(lev.ReadDouble() - MagicDouble); } var startFound = false; for (var i = 0; i < objectCount; i++) { var x = lev.ReadDouble(); var y = lev.ReadDouble(); var objectType = (ObjectType)lev.ReadInt32(); if (objectType == ObjectType.Start) { startFound = true; } var appleType = AppleType.Normal; var animNum = 0; if (!IsAcrossLevel) { appleType = (AppleType)lev.ReadInt32(); animNum = lev.ReadInt32(); } var objectToAdd = new LevObject(new Vector(x, y), objectType, appleType, animNum + 1); Objects.Add(objectToAdd); } if (!startFound) { Objects.Add(new LevObject(new Vector(0, 0), ObjectType.Start, AppleType.Normal)); } if (!IsAcrossLevel) { var numberOfPicturesPlusTextures = (int)Math.Round(lev.ReadDouble() - MagicDouble2); for (var i = 0; i < numberOfPicturesPlusTextures; i++) { var pictureName = lev.ReadNullTerminatedString(10); var textureName = lev.ReadNullTerminatedString(10); var maskName = lev.ReadNullTerminatedString(10); var x = lev.ReadDouble(); var y = lev.ReadDouble(); var distance = lev.ReadInt32(); var clipping = (ClippingType)lev.ReadInt32(); if (pictureName == "") { _textureData.Add(new LevelFileTexture(textureName, maskName, new Vector(x, y), distance, clipping)); } else { _textureData.Add(new LevelFileTexture(pictureName, null, new Vector(x, y), distance, clipping)); } } } HandleLevEndRead(lev); UpdateBounds(); }
internal static Polygon Connect(Polygon p1, Polygon p2, Vector v1, Vector v2, double connectRadius) { if (p1.IntersectsWith(p2)) { return(null); } bool isContained = p1.AreaHasPoint(p2[0]) || p2.AreaHasPoint(p1[0]); var p1C = new Polygon(p1); var p2C = new Polygon(p2); if (p1C.IsCounterClockwise) { p1C.ChangeOrientation(); } if (p2C.IsCounterClockwise ^ isContained) { p2C.ChangeOrientation(); } int numberOfIntersectionsP1C = 0; int numberOfIntersectionsP2C = 0; Vector p1IsectPoint = null; Vector p2IsectPoint = null; Vector.MarkDefault = VectorMark.Selected; for (int i = 0; i < p1.Vertices.Count; i++) { Vector isectPoint = GetIntersectionPoint(p1[i], p1[i + 1], v1, v2); if ((object)isectPoint != null) { p1IsectPoint = isectPoint; p1C.InsertIntersection(p1IsectPoint, Constants.Tolerance); numberOfIntersectionsP1C++; } } if (numberOfIntersectionsP1C != 1) { return(null); } for (int i = 0; i < p2.Vertices.Count; i++) { Vector isectPoint = GetIntersectionPoint(p2[i], p2[i + 1], v1, v2); if ((object)isectPoint != null) { p2IsectPoint = isectPoint; p2C.InsertIntersection(p2IsectPoint, Constants.Tolerance); numberOfIntersectionsP2C++; } } Vector.MarkDefault = VectorMark.None; if (numberOfIntersectionsP2C != 1) { return(null); } var result = new Polygon(); int p1Index = 0; int p2Index = p2C.IndexOf(p2IsectPoint); bool p1CCurrent = true; Vector p1ConnectVector = null; Vector p2ConnectVector = null; while (!(p1Index == 0 && p1CCurrent && result.Count > 0)) { if (p1CCurrent) { if (p1C[p1Index].Mark != VectorMark.Selected) { result.Add(p1C[p1Index]); } else { p1ConnectVector = p1C[p1Index + 1] - p1C[p1Index - 1]; p1ConnectVector /= p1ConnectVector.Length; var p1AngleAbs = Math.Abs(p1ConnectVector.AngleBetween(v2 - v1)); if (p1AngleAbs < Constants.Tolerance) { return(null); } p1ConnectVector *= connectRadius / Math.Sin(p1AngleAbs * Constants.DegToRad); double distance1 = (p1C[p1Index + 1] - p1C[p1Index]).Length; double distance2 = (p1C[p1Index] - p1C[p1Index - 1]).Length; if (p1ConnectVector.Length > Math.Min(distance1, distance2)) { p1ConnectVector = p1ConnectVector / p1ConnectVector.Length * Math.Min(distance1, distance2) / 2; } result.Add(p1IsectPoint - p1ConnectVector); p2ConnectVector = p2C[p2Index + 1] - p2C[p2Index - 1]; p2ConnectVector /= p2ConnectVector.Length; var p2AngleAbs = Math.Abs(p2ConnectVector.AngleBetween(v2 - v1)); if (p2AngleAbs < Constants.Tolerance) { return(null); } p2ConnectVector *= connectRadius / Math.Sin(p2AngleAbs * Constants.DegToRad); double dist1 = (p2C[p2Index + 1] - p2C[p2Index]).Length; double dist2 = (p2C[p2Index] - p2C[p2Index - 1]).Length; if (p2ConnectVector.Length > Math.Min(dist1, dist2)) { p2ConnectVector = p2ConnectVector / p2ConnectVector.Length * Math.Min(dist1, dist2) / 2; } result.Add(p2IsectPoint + p2ConnectVector); p2Index++; p1CCurrent = false; } p1Index++; p1Index = p1Index % p1C.Count; } else { if (p2C[p2Index].Mark != VectorMark.Selected) { result.Add(p2C[p2Index]); } else { result.Add(p2IsectPoint - p2ConnectVector); result.Add(p1IsectPoint + p1ConnectVector); p1CCurrent = true; } p2Index++; } } result.UpdateDecomposition(); return(result); }
internal static Level LoadLevelFromImage(string imageFileName) { var lev = new Level(); var vr = new VectRast(false, false); byte[,] pixelOn; Bitmap bmp; var transformMatrix = Matrix2D.identityM(); const int numFlowers = 0; try { vr.loadAsBmp(imageFileName, out bmp, out pixelOn, Math.Abs(transformMatrix.elements[0, 0]) + Math.Abs(transformMatrix.elements[1, 1]), 1, numFlowers); } catch (ArgumentException) { throw new VectrastException(string.Format("The image file {0} is invalid.", imageFileName)); } try { vr.collapseVectors(vr.createVectors(pixelOn, bmp)); } catch (Exception e) { throw new VectrastException(e.Message); } transformMatrix = Matrix2D.translationM(-bmp.Width / 2.0, -bmp.Height / 2.0) * transformMatrix; transformMatrix = transformMatrix * Matrix2D.scaleM(0.1, 0.1); bmp.Dispose(); try { vr.transformVectors(transformMatrix); } catch (Exception e) { throw new VectrastException(e.Message); } if (vr.polygons.Count == 0) { throw new VectrastException(string.Format("Failed to vectorize the image file {0}.", imageFileName)); } foreach (ArrayList polygon in vr.polygons) { var elmaPolygon = new Polygon(); foreach (DoubleVector2 vertex in polygon) { elmaPolygon.Add(new Vector(vertex.x, vertex.y)); } lev.Polygons.Add(elmaPolygon); } return(lev); }