public static TAMImageDiagram Combine(TAMImageDiagram first, TAMImageDiagram second) { return(new TAMImageDiagram() { _strokes = new List <TAMStroke>(first.Strokes).Union(second.Strokes).ToList() }); }
public TAMImageDiagram Generate(TAMImageDiagram baseDiagram, TAMTone tone, TAMMipmapLevel mipmapLevel, int seed) { _strokesGenerator.ResetSeed(seed); _random = new System.Random(seed); var diagram = baseDiagram.Copy(); float currentCoverage = ComputeCoverage(diagram, mipmapLevel); float targetCoverage = _generationConfiguration.TargetCoverages[tone]; while (targetCoverage > currentCoverage) { List <RankedPossibleStroke> possibleStrokes = new List <RankedPossibleStroke>(); for (int i = 0; i < _generationConfiguration.TriesCount[mipmapLevel]; i++) { TAMStroke newStroke = _strokesGenerator.CreateRandomStroke(new Vector2(_random.Next(), _random.Next()), tone); RankedPossibleStroke rankedNewStroke = RankStroke(newStroke, diagram); possibleStrokes.Add(rankedNewStroke); } var bestStroke = possibleStrokes.OrderBy(p => p.Rank).First(); diagram.AddStroke(bestStroke.Stroke); currentCoverage = ComputeCoverage(diagram, mipmapLevel); } return(diagram); }
public TAMImageDiagram Generate(TAMImageDiagram diagram, TAMTone tone, TAMMipmapLevel mipmapLevel, int seed) { List <Vector2> currentPoints = diagram.Strokes.Select(c => c.Center).ToList(); var newPoints = _sampler.Generate(_configuration.GenerationCount, _configuration.ExclusionZoneValues[tone][mipmapLevel], seed, currentPoints); return(new TAMImageDiagram(diagram.Strokes.Union(newPoints.Select(c => _strokesGenerator.CreateRandomStroke(c, tone))).ToList())); }
private TAMImageDiagram GetPreviousToneImageDiagram(TAMTone tone, TAMMipmapLevel mipmapLevel) { if (tone.IsLowestTone) { return(TAMImageDiagram.CreateEmpty()); } else { return(_columns[tone.LowerTone][mipmapLevel]); } }
private Image CreateSoleImage(TAMImageDiagram diagram, TAMMipmapLevel level) { var margin = _configuration.Margin; var soleImageResolution = _configuration.SoleImagesResolutionPerLevel[level].ToFloatVec(); var soleImageResolutionWithMargins = soleImageResolution * (1 + margin * 2); using (ImageFactory imageFactory = new ImageFactory(preserveExifData: true)) { var factory = imageFactory.Load(_blankImage) .Resize(new Size((int)soleImageResolutionWithMargins.x, (int)soleImageResolutionWithMargins.y)); foreach (var stroke in diagram.Strokes) { using (ImageFactory strokeFactory = new ImageFactory(true)) { var strokeSizeInPixels = VectorUtils.MemberwiseMultiply( new Vector2(stroke.Length, stroke.Height * _configuration.StrokeHeightMultiplierPerLevel[level]), soleImageResolution).ToIntVector2(); var rotation = Mathf.Rad2Deg * stroke.Rotation; var rotatedStrokeImageFactory = strokeFactory.Load(_strokeImage) .Resize(new ResizeLayer(new Size(strokeSizeInPixels.X, strokeSizeInPixels.Y), ResizeMode.Stretch)) .Rotate(rotation); //if (stroke.Id == 1) //{ // rotatedStrokeImageFactory = rotatedStrokeImageFactory.ReplaceColor(Color.Black, Color.Blue); //} var rotatedStrokeImage = rotatedStrokeImageFactory.Image; var position = VectorUtils.MemberwiseMultiply(UvToMarginUv(stroke.Center), soleImageResolutionWithMargins).ToIntVector2(); //todo przelicz tu aby brac pod uwage multiplier position -= new IntVector2(rotatedStrokeImage.Width / 2, rotatedStrokeImage.Height / 2); factory = factory.Overlay(new ImageLayer() { Image = rotatedStrokeImage, Opacity = 100, Position = new Point(position.X, position.Y) }); } } using (Stream stream = new MemoryStream()) { factory.Save(stream); return(Image.FromStream(stream)); } } }
private float ComputeCoverage(TAMImageDiagram diagram, TAMMipmapLevel mipmapLevel) { var areaSum = 0.0; for (int i = 0; i < diagram.Strokes.Count; i++) { var currentStroke = diagram.Strokes[i]; var baseArea = Mathf.PI * Mathf.Pow(currentStroke.Length, 2) * 0.2; //todo for (int k = 0; k < i; k++) { var otherStroke = diagram.Strokes[k]; var intersectionArea = MyMathUtils.IntersectionAreaOfTwoCircles(currentStroke.Length, currentStroke.Center, otherStroke.Length, otherStroke.Center); baseArea -= intersectionArea; } areaSum += Math.Max(0.001f, baseArea); //todo what to do with other mipmapLevels } return((float)areaSum); }
private RankedPossibleStroke RankStroke(TAMStroke newStroke, TAMImageDiagram diagram) { // rank the bigger, the better var distanceSum = 0f; var intersectionArea = 0f; foreach (var stroke in diagram.Strokes) { var intersection = MyMathUtils.IntersectionAreaOfTwoCircles(newStroke.Length, newStroke.Center, stroke.Length, stroke.Center); intersectionArea += intersection; distanceSum += Vector2.Distance(newStroke.Center, stroke.Center); } var intersectionPercent = intersectionArea / (Math.PI * Math.Pow(newStroke.Length, 2)); var rank = Mathf.Pow(distanceSum, (float)(2 - intersectionPercent)); return(new RankedPossibleStroke() { Rank = rank, Stroke = newStroke }); }
public TAMTemplate Generate(TAMTemplateSpecification specification) { _specification = specification; _columns = new Dictionary <TAMTone, Dictionary <TAMMipmapLevel, TAMImageDiagram> >(); var seed = 0; //TODO foreach (var tone in _specification.Tones) { _columns[tone] = new Dictionary <TAMMipmapLevel, TAMImageDiagram>(); foreach (var mipmapLevel in _specification.MipmapLevels) { var previousToneImageDiagram = GetPreviousToneImageDiagram(tone, mipmapLevel); var previousLevelImageDiagram = GetPreviousLevelImageDiagram(tone, mipmapLevel); var sumImageDiagram = TAMImageDiagram.Combine(previousLevelImageDiagram, previousToneImageDiagram); var newImageDiagram = GenerateNewImageDiagram(sumImageDiagram, tone, mipmapLevel, seed); AddNewImageDiagram(newImageDiagram, tone, mipmapLevel); seed++; } } UpdatePerMipmapLevelStrokeParameters(); return(new TAMTemplate(_columns)); }
public TAMImageDiagram UpdatePerMipmapLevelStrokeParameters(TAMImageDiagram diagram, TAMMipmapLevel level) { return(new TAMImageDiagram(diagram.Strokes.Select(c => _strokesGenerator.UpdatePerMipmapLevelStrokeParameters(c, level)).ToList())); }
private void AddNewImageDiagram(TAMImageDiagram template, TAMTone tone, TAMMipmapLevel mipmapLevel) { _columns[tone][mipmapLevel] = template; }
private TAMImageDiagram GenerateNewImageDiagram(TAMImageDiagram baseImageDiagram, TAMTone tone, TAMMipmapLevel mipmapLevel, int seed) { return(_imageDiagramGenerator.Generate(baseImageDiagram, tone, mipmapLevel, seed)); }
private List <Image> CreateSoleLayerImages(TAMImageDiagram diagram, TAMMipmapLevel level) { var margin = _configuration.Margin; var soleImageResolution = _configuration.SoleImagesResolutionPerLevel[level]; var soleImageResolutionWithMargins = (soleImageResolution * (1 + margin * 2)).ToIntVector2(); var marginLength = (soleImageResolutionWithMargins - soleImageResolution) / 2; var outImages = Enumerable.Range(0, _layersCount) .Select(c => new Bitmap((int)soleImageResolutionWithMargins.X, (int)soleImageResolutionWithMargins.Y, PixelFormat.Format32bppPArgb)) .ToList(); var occupancyArray = new int[(int)soleImageResolutionWithMargins.X, (int)soleImageResolutionWithMargins.Y]; //Debug.Log($"OutiMages: {outImages[0].Size} || SoleImageResolution {soleImageResolution} Sole with margins {soleImageResolutionWithMargins}"); foreach (var stroke in diagram.Strokes) { using (ImageFactory strokeFactory = new ImageFactory(true)) { var strokeSizeInPixels = VectorUtils.MemberwiseMultiply( new Vector2(stroke.Length, stroke.Height * _configuration.StrokeHeightMultiplierPerLevel[level]), soleImageResolution.ToFloatVec()).ToIntVector2(); var rotation = Mathf.Rad2Deg * stroke.Rotation; var rotatedStrokeImage = strokeFactory.Load(_strokeImage) .Resize(new ResizeLayer(new Size(strokeSizeInPixels.X, strokeSizeInPixels.Y), ResizeMode.Stretch)) .Rotate(rotation).Image; var imageWithId = AddIdToStrokeImage(rotatedStrokeImage, (uint)stroke.Id); var position = VectorUtils.MemberwiseMultiply(UvToMarginUv(stroke.Center), soleImageResolutionWithMargins.ToFloatVec()).ToIntVector2(); position -= new IntVector2(rotatedStrokeImage.Width / 2, rotatedStrokeImage.Height / 2); for (int x = 0; x < imageWithId.Size.Width; x++) { for (int y = 0; y < imageWithId.Size.Height; y++) { var inImagePosition = position + new IntVector2(x, y); uint offsetBitX = 0; uint offsetBitY = 0; if (inImagePosition.X - marginLength.X / 2 >= soleImageResolution.X || inImagePosition.X - marginLength.X * 1.5 < 0) { offsetBitX = 1; } if (inImagePosition.Y - marginLength.Y / 2 >= soleImageResolution.Y || inImagePosition.Y - marginLength.Y * 1.5 < 0) { offsetBitY = 1; } inImagePosition.X = inImagePosition.X % soleImageResolutionWithMargins.X; //probably not needed inImagePosition.Y = inImagePosition.Y % soleImageResolutionWithMargins.Y; var strokePixel = imageWithId.GetPixel(x, y); byte newGColor = (byte)((strokePixel.G | (offsetBitX << 6)) | offsetBitY << 7); strokePixel = Color.FromArgb(strokePixel.A, strokePixel.R, newGColor, strokePixel.B); if (strokePixel.A > 0) { var layerIndex = 0; var occupancy = occupancyArray[inImagePosition.X, inImagePosition.Y]; if (occupancy != 0) { layerIndex = (occupancy) % _layersCount; } occupancyArray[inImagePosition.X, inImagePosition.Y]++; if (!_configuration.UseSmoothAlpha) { var a = strokePixel.A; if (a > 0) { a = 255; } strokePixel = Color.FromArgb(a, strokePixel.R, strokePixel.G, strokePixel.B); } if (!_configuration.UseDithering) { outImages[layerIndex].SetPixel(inImagePosition.X, inImagePosition.Y, strokePixel); } else { var oldPixel = outImages[layerIndex].GetPixel(inImagePosition.X, inImagePosition.Y); if (_configuration.UseSmoothAlpha) { var oldAlpha = oldPixel.A; var maxAlpha = Mathf.Max(oldAlpha, strokePixel.A); strokePixel = Color.FromArgb(maxAlpha, strokePixel.R, strokePixel.G, strokePixel.B); if (layerIndex != 0) { var layer0Pixel = outImages[0].GetPixel(inImagePosition.X, inImagePosition.Y); var layer0OldAlpha = layer0Pixel.A; if (layer0OldAlpha < strokePixel.A) { var newLayer0Pixel = Color.FromArgb(strokePixel.A, layer0Pixel.R, layer0Pixel.G, layer0Pixel.B); outImages[0].SetPixel(inImagePosition.X, inImagePosition.Y, newLayer0Pixel); } } } var ditheringModuler = Mathf.CeilToInt((float)occupancy / _layersCount) + 1; bool ditherPixelActive = (inImagePosition.X + inImagePosition.Y) % ditheringModuler == 0; if (ditherPixelActive) { outImages[layerIndex].SetPixel(inImagePosition.X, inImagePosition.Y, strokePixel); } else { var updatedOldPixel = Color.FromArgb(strokePixel.A, oldPixel.R, oldPixel.G, oldPixel.B); outImages[layerIndex].SetPixel(inImagePosition.X, inImagePosition.Y, updatedOldPixel); } } } } } } } return(outImages.Cast <Image>().ToList()); }