override fun buildIntern()

in plot-base/src/commonMain/kotlin/org/jetbrains/letsPlot/core/plot/base/geom/RasterGeom.kt [31:115]


    override fun buildIntern(
        root: SvgRoot,
        aesthetics: Aesthetics,
        pos: PositionAdjustment,
        coord: CoordinateSystem,
        ctx: GeomContext
    ) {
        val iter = with_X_Y(aesthetics.dataPoints()).iterator()
        if (!iter.hasNext()) {
            return
        }
        val randomP = iter.next()
        val helper = GeomHelper(pos, coord, ctx)

        // Find size of image (row x col)
        val boundsXY = layerAesBounds(aesthetics)
        val stepX = ctx.getResolution(Aes.X)
        val stepY = ctx.getResolution(Aes.Y)
        require(stepX > SeriesUtil.TINY) { "x-step is too small: $stepX" }
        require(stepY > SeriesUtil.TINY) { "y-step is too small: $stepY" }
        val width = (round(boundsXY.dimension.x / stepX) + 1)
        val height = (round(boundsXY.dimension.y / stepY) + 1)

        if (width * height > 5000000) {
            val center = boundsXY.center
            val text = "Raster image size\n[$width X $height]\nexceeds capability\nof\nyour imaging device"
            val label = Label(text)
            label.textColor().set(Color.DARK_MAGENTA)
            label.setTextOpacity(0.5)
            label.setFontSize(12.0)
            label.setLineHeight(16.0)
            label.setFontWeight("bold")
            label.setHorizontalAnchor(HorizontalAnchor.MIDDLE)
            label.setVerticalAnchor(VerticalAnchor.CENTER)
            val loc = helper.toClient(center.x, center.y, randomP)!!
            label.moveTo(loc)
            root.add(label.rootGroup)

            return
        }

        val cols = round(width).toInt()
        val rows = round(height).toInt()

        // translate to client coordinates
        // expand bounds by 1/2 step before the translation to adjust for the size of 'image pixel'
        val halfStep = DoubleVector(stepX * 0.5, stepY * 0.5)
        val corner0 = helper.toClient(boundsXY.origin.subtract(halfStep), randomP)!!
        val corner2 = helper.toClient(boundsXY.origin.add(boundsXY.dimension).add(halfStep), randomP)!!
        val invertedX = corner2.x < corner0.x
        val invertedY = corner2.y < corner0.y

        // Fill image data array with RGB values
        val x0 = boundsXY.origin.x
        val y0 = boundsXY.origin.y

        val argbValues = IntArray(cols * rows)
        for (p in with_X_Y(aesthetics.dataPoints())) {
            val x = p.x()
            val y = p.y()
            val alpha = p.alpha()
            val color = p.fill()

            var col = round((x!! - x0) / stepX).toInt()
            var row = round((y!! - y0) / stepY).toInt()

            if (invertedX) {
                col = cols - (col + 1)
            }

            if (invertedY) {
                row = rows - (row + 1)
            }

            argbValues[row * cols + col] = SvgUtils.toARGB(color!!, alpha!!)
        }

        val bitmap = Bitmap(cols, rows, argbValues)
        val svgImageElement = SvgImageElementEx(
            min(corner0.x, corner2.x), min(corner0.y, corner2.y),
            abs(corner0.x - corner2.x), abs(corner0.y - corner2.y),
            bitmap
        )
        root.add(svgImageElement)
    }