ChunkyImageOperation.cs 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121
  1. using ChunkyImageLib.DataHolders;
  2. using PixiEditor.DrawingApi.Core.Numerics;
  3. namespace ChunkyImageLib.Operations;
  4. internal class ChunkyImageOperation : IMirroredDrawOperation
  5. {
  6. private readonly ChunkyImage imageToDraw;
  7. private readonly VecI targetPos;
  8. private readonly bool mirrorHorizontal;
  9. private readonly bool mirrorVertical;
  10. public bool IgnoreEmptyChunks => false;
  11. public ChunkyImageOperation(ChunkyImage imageToDraw, VecI targetPos, bool mirrorHorizontal, bool mirrorVertical)
  12. {
  13. this.imageToDraw = imageToDraw;
  14. this.targetPos = targetPos;
  15. this.mirrorHorizontal = mirrorHorizontal;
  16. this.mirrorVertical = mirrorVertical;
  17. }
  18. public void DrawOnChunk(Chunk chunk, VecI chunkPos)
  19. {
  20. chunk.Surface.DrawingSurface.Canvas.Save();
  21. {
  22. VecI pixelPos = chunkPos * ChunkyImage.FullChunkSize;
  23. VecI topLeftImageCorner = GetTopLeft();
  24. RectD clippingRect = RectD.Create(
  25. OperationHelper.ConvertForResolution(topLeftImageCorner - pixelPos, chunk.Resolution),
  26. OperationHelper.ConvertForResolution(imageToDraw.CommittedSize, chunk.Resolution));
  27. chunk.Surface.DrawingSurface.Canvas.ClipRect(clippingRect);
  28. }
  29. VecI chunkPixelCenter = chunkPos * ChunkyImage.FullChunkSize;
  30. chunkPixelCenter.X += ChunkyImage.FullChunkSize / 2;
  31. chunkPixelCenter.Y += ChunkyImage.FullChunkSize / 2;
  32. VecI chunkCenterOnImage = chunkPixelCenter - targetPos;
  33. VecI chunkSize = chunk.PixelSize;
  34. if (mirrorHorizontal)
  35. {
  36. chunk.Surface.DrawingSurface.Canvas.Scale(-1, 1, chunkSize.X / 2f, chunkSize.Y / 2f);
  37. chunkCenterOnImage.X = -chunkCenterOnImage.X;
  38. }
  39. if (mirrorVertical)
  40. {
  41. chunk.Surface.DrawingSurface.Canvas.Scale(1, -1, chunkSize.X / 2f, chunkSize.Y / 2f);
  42. chunkCenterOnImage.Y = -chunkCenterOnImage.Y;
  43. }
  44. VecI halfChunk = new(ChunkyImage.FullChunkSize / 2, ChunkyImage.FullChunkSize / 2);
  45. VecI topLeft = OperationHelper.GetChunkPos(chunkCenterOnImage - halfChunk, ChunkyImage.FullChunkSize);
  46. VecI topRight = OperationHelper.GetChunkPos(
  47. new VecI(chunkCenterOnImage.X + halfChunk.X, chunkCenterOnImage.Y - halfChunk.Y), ChunkyImage.FullChunkSize);
  48. VecI bottomRight = OperationHelper.GetChunkPos(chunkCenterOnImage + halfChunk, ChunkyImage.FullChunkSize);
  49. VecI bottomLeft = OperationHelper.GetChunkPos(
  50. new VecI(chunkCenterOnImage.X - halfChunk.X, chunkCenterOnImage.Y + halfChunk.Y), ChunkyImage.FullChunkSize);
  51. imageToDraw.DrawCommittedChunkOn(
  52. topLeft,
  53. chunk.Resolution,
  54. chunk.Surface.DrawingSurface,
  55. (VecI)((topLeft * ChunkyImage.FullChunkSize - chunkCenterOnImage).Add(ChunkyImage.FullChunkSize / 2) * chunk.Resolution.Multiplier()));
  56. VecI gridShift = targetPos % ChunkyImage.FullChunkSize;
  57. if (gridShift.X != 0)
  58. {
  59. imageToDraw.DrawCommittedChunkOn(
  60. topRight,
  61. chunk.Resolution,
  62. chunk.Surface.DrawingSurface,
  63. (VecI)((topRight * ChunkyImage.FullChunkSize - chunkCenterOnImage).Add(ChunkyImage.FullChunkSize / 2) * chunk.Resolution.Multiplier()));
  64. }
  65. if (gridShift.Y != 0)
  66. {
  67. imageToDraw.DrawCommittedChunkOn(
  68. bottomLeft,
  69. chunk.Resolution,
  70. chunk.Surface.DrawingSurface,
  71. (VecI)((bottomLeft * ChunkyImage.FullChunkSize - chunkCenterOnImage).Add(ChunkyImage.FullChunkSize / 2) * chunk.Resolution.Multiplier()));
  72. }
  73. if (gridShift.X != 0 && gridShift.Y != 0)
  74. {
  75. imageToDraw.DrawCommittedChunkOn(
  76. bottomRight,
  77. chunk.Resolution,
  78. chunk.Surface.DrawingSurface,
  79. (VecI)((bottomRight * ChunkyImage.FullChunkSize - chunkCenterOnImage).Add(ChunkyImage.FullChunkSize / 2) * chunk.Resolution.Multiplier()));
  80. }
  81. chunk.Surface.DrawingSurface.Canvas.Restore();
  82. }
  83. public HashSet<VecI> FindAffectedChunks(VecI imageSize)
  84. {
  85. return OperationHelper.FindChunksTouchingRectangle(new(GetTopLeft(), imageToDraw.CommittedSize), ChunkyImage.FullChunkSize);
  86. }
  87. private VecI GetTopLeft()
  88. {
  89. VecI topLeft = targetPos;
  90. if (mirrorHorizontal)
  91. topLeft.X -= imageToDraw.CommittedSize.X;
  92. if (mirrorVertical)
  93. topLeft.Y -= imageToDraw.CommittedSize.Y;
  94. return topLeft;
  95. }
  96. public IDrawOperation AsMirrored(int? verAxisX, int? horAxisY)
  97. {
  98. var newPos = targetPos;
  99. if (verAxisX is not null)
  100. newPos = newPos.ReflectX((int)verAxisX);
  101. if (horAxisY is not null)
  102. newPos = newPos.ReflectY((int)horAxisY);
  103. return new ChunkyImageOperation(imageToDraw, newPos, mirrorHorizontal ^ (verAxisX is not null), mirrorVertical ^ (horAxisY is not null));
  104. }
  105. public void Dispose() { }
  106. }