All Downloads are FREE. Search and download functionalities are using the official Maven repository.

doodle.algebra.generic.GenericLayout.scala Maven / Gradle / Ivy

The newest version!
/*
 * Copyright 2015 Creative Scala
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package doodle
package algebra
package generic

import cats.*
import cats.implicits.*
import doodle.core.BoundingBox
import doodle.core.Landmark
import doodle.core.Transform

trait GenericLayout[G[_]] extends Layout {
  self: GivenApply[G] with Algebra { type Drawing[A] = Finalized[G, A] } =>
  import Renderable.*

  def on[A](top: Finalized[G, A], bottom: Finalized[G, A])(implicit
      s: Semigroup[A]
  ): Finalized[G, A] =
    Finalized { ctxTxs =>
      val t = top.run(ctxTxs)
      val b = bottom.run(ctxTxs)

      (t, b).mapN { (t, b) =>
        val (bbT, rdrT) = t
        val (bbB, rdrB) = b
        ((bbT.on(bbB)), rdrB |+| rdrT)
      }
    }

  def beside[A](left: Finalized[G, A], right: Finalized[G, A])(implicit
      s: Semigroup[A]
  ): Finalized[G, A] =
    Finalized { ctxTxs =>
      val l = left.run(ctxTxs)
      val r = right.run(ctxTxs)

      (l, r).mapN { (l, r) =>
        val (bbL, rdrL) = l
        val (bbR, rdrR) = r
        val bb = bbL.beside(bbR)

        val txLeft = Transform.translate(bb.left - bbL.left, 0)
        val txRight = Transform.translate(bb.right - bbR.right, 0)
        val rdr = Renderable.parallel(txLeft, txRight)(rdrL)(rdrR)

        (bb, rdr)
      }
    }

  def above[A](top: Finalized[G, A], bottom: Finalized[G, A])(implicit
      s: Semigroup[A]
  ): Finalized[G, A] =
    Finalized { ctxTxs =>
      val t = top.run(ctxTxs)
      val b = bottom.run(ctxTxs)

      (t, b).mapN { (t, b) =>
        val (bbT, rdrT) = t
        val (bbB, rdrB) = b
        val bb = bbT.above(bbB)

        val txTop = Transform.translate(0, bb.top - bbT.top)
        val txBottom = Transform.translate(0, bb.bottom - bbB.bottom)
        val rdr = Renderable.parallel(txTop, txBottom)(rdrT)(rdrB)

        (bb, rdr)
      }
    }

  def at[A](img: Finalized[G, A], landmark: Landmark): Finalized[G, A] =
    img.map { case (bb, rdr) =>
      val point = bb.eval(landmark)
      (
        bb.at(point),
        Renderable.transform(Transform.translate(point.x, point.y))(rdr)
      )
    }

  def originAt[A](img: Finalized[G, A], landmark: Landmark): Finalized[G, A] =
    img.map { case (bb, rdr) =>
      val point = bb.eval(landmark)
      // Moving the origin to point p is equivalent to translating the image to -p
      (
        bb.originAt(landmark),
        Renderable.transform(Transform.translate(-point.x, -point.y))(rdr)
      )
    }

  def margin[A](
      img: Finalized[G, A],
      top: Double,
      right: Double,
      bottom: Double,
      left: Double
  ): Finalized[G, A] =
    img.map { case (bb, rdr) =>
      val newBb = BoundingBox(
        left = bb.left - left,
        top = bb.top + top,
        right = bb.right + right,
        bottom = bb.bottom - bottom
      )
      (newBb, rdr)
    }

  def size[A](
      img: Finalized[G, A],
      width: Double,
      height: Double
  ): Finalized[G, A] = {
    assert(
      width >= 0,
      s"Called `size` with a width of ${width}. The bounding box's width must be non-negative."
    )
    assert(
      height >= 0,
      s"Called `size` with a height of ${height}. The bounding box's height must be non-negative."
    )
    val w = width / 2.0
    val h = height / 2.0

    img.map { case (bb, rdr) =>
      val newBb = BoundingBox(
        left = -w,
        top = h,
        right = w,
        bottom = -h
      )

      (newBb, rdr)
    }
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy