Skip to content

Instantly share code, notes, and snippets.

@GeorgCantor
Created March 14, 2021 17:57
Show Gist options
  • Save GeorgCantor/b7aa21080ad97a58540f1de9f4ac3fc8 to your computer and use it in GitHub Desktop.
Save GeorgCantor/b7aa21080ad97a58540f1de9f4ac3fc8 to your computer and use it in GitHub Desktop.
class GraphicOverlay<T : Graphic?>(context: Context?, attrs: AttributeSet?) : View(context, attrs) {
private val mLock = Any()
private var mPreviewWidth = 0
/**
* Returns the horizontal scale factor.
*/
var widthScaleFactor = 1.0f
private set
private var mPreviewHeight = 0
/**
* Returns the vertical scale factor.
*/
var heightScaleFactor = 1.0f
private set
private var mFacing = CameraSource.CAMERA_FACING_BACK
private val mGraphics: MutableSet<T?> = HashSet()
/**
* Base class for a custom graphics object to be rendered within the graphic overlay. Subclass
* this and implement the [Graphic.draw] method to define the
* graphics element. Add instances to the overlay using [GraphicOverlay.add].
*/
abstract class Graphic(private val mOverlay: GraphicOverlay<*>) {
/**
* Draw the graphic on the supplied canvas. Drawing should use the following methods to
* convert to view coordinates for the graphics that are drawn:
*
* 1. [Graphic.scaleX] and [Graphic.scaleY] adjust the size of
* the supplied value from the preview scale to the view scale.
* 1. [Graphic.translateX] and [Graphic.translateY] adjust the
* coordinate from the preview's coordinate system to the view coordinate system.
*
*
* @param canvas drawing canvas
*/
abstract fun draw(canvas: Canvas?)
/**
* Adjusts a horizontal value of the supplied value from the preview scale to the view
* scale.
*/
fun scaleX(horizontal: Float): Float {
return horizontal * mOverlay.widthScaleFactor
}
/**
* Adjusts a vertical value of the supplied value from the preview scale to the view scale.
*/
fun scaleY(vertical: Float): Float {
return vertical * mOverlay.heightScaleFactor
}
/**
* Adjusts the x coordinate from the preview's coordinate system to the view coordinate
* system.
*/
fun translateX(x: Float): Float {
return if (mOverlay.mFacing == CameraSource.CAMERA_FACING_FRONT) {
mOverlay.width - scaleX(x)
} else {
scaleX(x)
}
}
/**
* Adjusts the y coordinate from the preview's coordinate system to the view coordinate
* system.
*/
fun translateY(y: Float): Float {
return scaleY(y)
}
fun postInvalidate() {
mOverlay.postInvalidate()
}
}
/**
* Removes all graphics from the overlay.
*/
fun clear() {
synchronized(mLock) { mGraphics.clear() }
postInvalidate()
}
/**
* Adds a graphic to the overlay.
*/
fun add(graphic: T) {
synchronized(mLock) { mGraphics.add(graphic) }
postInvalidate()
}
/**
* Removes a graphic from the overlay.
*/
fun remove(graphic: T) {
synchronized(mLock) { mGraphics.remove(graphic) }
postInvalidate()
}
/**
* Returns a copy (as a list) of the set of all active graphics.
*
* @return list of all active graphics.
*/
val graphics: Vector<Any?>
get() {
synchronized(mLock) { return Vector<Any?>(mGraphics) }
}
/**
* Sets the camera attributes for size and facing direction, which informs how to transform
* image coordinates later.
*/
fun setCameraInfo(previewWidth: Int, previewHeight: Int, facing: Int) {
synchronized(mLock) {
mPreviewWidth = previewWidth
mPreviewHeight = previewHeight
mFacing = facing
}
postInvalidate()
}
/**
* Draws the overlay with its associated graphic objects.
*/
override fun onDraw(canvas: Canvas) {
super.onDraw(canvas)
synchronized(mLock) {
if (mPreviewWidth != 0 && mPreviewHeight != 0) {
widthScaleFactor = width.toFloat() / mPreviewWidth.toFloat()
heightScaleFactor = height.toFloat() / mPreviewHeight.toFloat()
}
for (graphic in mGraphics) {
graphic!!.draw(canvas)
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment