Skip to content

Commit

Permalink
Improves ListAttribute by accepting attributes of its element type
Browse files Browse the repository at this point in the history
  • Loading branch information
serivesmejia committed Nov 29, 2024
1 parent 04b8115 commit adcc91f
Show file tree
Hide file tree
Showing 6 changed files with 138 additions and 75 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import io.github.deltacv.papervision.codegen.CodeGen
import io.github.deltacv.papervision.codegen.GenValue
import io.github.deltacv.papervision.util.hexString
import io.github.deltacv.mai18n.tr
import io.github.deltacv.papervision.attribute.misc.ListAttribute
import io.github.deltacv.papervision.engine.client.message.TunerChangeValueMessage
import io.github.deltacv.papervision.engine.client.message.TunerChangeValuesMessage

Expand Down Expand Up @@ -192,7 +193,10 @@ abstract class TypedAttribute(val attributeType: AttributeType) : Attribute() {
}
}

override fun acceptLink(other: Attribute) = this::class == other::class
// acceptLink is overridden to allow for ListAttribute to accept TypedAttribute
override fun acceptLink(other: Attribute) =
(other is TypedAttribute && other.attributeType == attributeType) ||
this::class == other::class || (other is ListAttribute && other.elementAttributeType == attributeType)

protected fun changed() {
if(!isFirstDraw && !isSecondDraw) onChange.run()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ package io.github.deltacv.papervision.attribute.misc
import com.google.gson.JsonObject
import imgui.ImGui
import imgui.flag.ImGuiCol
import io.github.deltacv.papervision.action.editor.CreateLinkAction
import io.github.deltacv.papervision.attribute.Attribute
import io.github.deltacv.papervision.attribute.AttributeMode
import io.github.deltacv.papervision.attribute.AttributeType
Expand All @@ -29,6 +30,7 @@ import io.github.deltacv.papervision.codegen.CodeGen
import io.github.deltacv.papervision.codegen.GenValue
import io.github.deltacv.papervision.gui.FontAwesomeIcons
import io.github.deltacv.papervision.gui.style.rgbaColor
import io.github.deltacv.papervision.node.Link
import io.github.deltacv.papervision.serialization.data.DataSerializable
import io.github.deltacv.papervision.serialization.data.adapter.dataSerializableToJsonObject
import io.github.deltacv.papervision.serialization.data.adapter.jsonObjectToDataSerializable
Expand Down Expand Up @@ -135,8 +137,31 @@ open class ListAttribute(
override fun draw() {
super.draw()

var ignoreNewLink = false

// accepts links of elementAttributeType to redirect them into a list element
if (mode == AttributeMode.INPUT && beforeHasLink != hasLink && hasLink && enabledLinkedAttribute() !is ListAttribute) {
val linkedAttribute = enabledLinkedAttribute()!!

// the user might be crazy and try to link an attribute that is already linked to one of our elements
// this caused a funny bug during testing, so, please don't do that (not that you can do it anymore)
val alreadyLinkedAttribute = listAttributes.find {
it.enabledLinkedAttribute() == linkedAttribute
}
if(alreadyLinkedAttribute == null) {
createElement(linkTo = linkedAttribute)
}

// delete the original link
// this also handles the case in which the user was indeed crazy
// and linked an attribute that was already linked to one of our elements
links.last().delete()

ignoreNewLink = true
}

for ((i, attrib) in listAttributes.withIndex()) {
if (beforeHasLink != hasLink) {
if (beforeHasLink != hasLink && !ignoreNewLink) {
if (hasLink) {
// delete attributes if a link has been created
attrib.delete()
Expand Down Expand Up @@ -166,6 +191,9 @@ open class ListAttribute(

private var isDrawAttributeTextOverriden = false

// accept either another ListAttribute with the same element type or a TypedAttribute with the same type as the element type
override fun acceptLink(other: Attribute) = (other is ListAttribute && other.elementAttributeType == elementAttributeType) || (other is TypedAttribute && other.attributeType == elementAttributeType)

open fun drawAttributeText(index: Int, attrib: Attribute) {
isDrawAttributeTextOverriden = false
}
Expand Down Expand Up @@ -250,8 +278,6 @@ open class ListAttribute(
}
}

override fun acceptLink(other: Attribute) = other is ListAttribute && other.elementAttributeType == elementAttributeType

override fun thisGet(): Array<Any?> {
val list = mutableListOf<Any?>()

Expand All @@ -262,7 +288,7 @@ open class ListAttribute(
return list.toTypedArray()
}

private fun createElement(enable: Boolean = true): TypedAttribute {
private fun createElement(enable: Boolean = true, linkTo: Attribute? = null): TypedAttribute {
val count = listAttributes.size.toString()
val elementName = count + if (count.length == 1) " " else ""

Expand All @@ -275,6 +301,12 @@ open class ListAttribute(

listAttributes.add(element)

if (linkTo != null) {
parentNode.editor.onDraw.doOnce {
CreateLinkAction(Link(linkTo.id, element.id)).enable()
}
}

onElementCreation(element)
return element
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,11 +45,11 @@ import io.github.deltacv.papervision.node.PaperNode
class BoundingRectsNode : DrawNode<BoundingRectsNode.Session>() {

val inputContours = ListAttribute(INPUT, PointsAttribute, "$[att_contours]")
val outputRects = ListAttribute(OUTPUT, RectAttribute, "$[att_boundingrects]")
val outputRects = ListAttribute(OUTPUT, RectAttribute, "$[att_boundingrects]")

override fun onEnable() {
+ inputContours.rebuildOnChange()
+ outputRects.rebuildOnChange()
+inputContours.rebuildOnChange()
+outputRects.rebuildOnChange()
}

override val generators = generatorsBuilder {
Expand All @@ -59,11 +59,11 @@ class BoundingRectsNode : DrawNode<BoundingRectsNode.Session>() {

val input = inputContours.value(current)

if(input !is GenValue.GList.RuntimeListOf<*>) {
raise("") // TODO: Handle non-runtime lists
}
val listName = if (input is GenValue.GList.RuntimeListOf<*>) {
"${input.value}Rects"
} else "rects"

val rectsList = uniqueVariable("${input.value.value}Rects", JavaTypes.ArrayList(JvmOpenCvTypes.Rect).new())
val rectsList = uniqueVariable(listName, JavaTypes.ArrayList(JvmOpenCvTypes.Rect).new())

group {
private(rectsList)
Expand All @@ -72,8 +72,23 @@ class BoundingRectsNode : DrawNode<BoundingRectsNode.Session>() {
current.scope {
rectsList("clear")

foreach(variable(JvmOpenCvTypes.MatOfPoint, "points"), input.value) {
rectsList("add", Imgproc.callValue("boundingRect", JvmOpenCvTypes.Rect, it))
if (input is GenValue.GList.RuntimeListOf<*>) {
foreach(variable(JvmOpenCvTypes.MatOfPoint, "points"), input.value) {
rectsList("add", Imgproc.callValue("boundingRect", JvmOpenCvTypes.Rect, it))
}
} else {
for (points in (input as GenValue.GList.ListOf<*>).elements) {
if (points is GenValue.GPoints.RuntimePoints) {
ifCondition(points.value notEqualsTo language.nullValue) {
rectsList(
"add",
Imgproc.callValue("boundingRect", JvmOpenCvTypes.Rect, points.value)
)
}
} else {
raise("Invalid input type for contours")
}
}
}
}

Expand All @@ -89,17 +104,31 @@ class BoundingRectsNode : DrawNode<BoundingRectsNode.Session>() {

val input = inputContours.value(current)

if(input !is GenValue.GList.RuntimeListOf<*>) {
raise("") // TODO: Handle non-runtime lists
}
val listName = if (input is GenValue.GList.RuntimeListOf<*>) {
"${input.value}_rects"
} else "rects"

val rectsList = uniqueVariable("${input.value.value}_rects", CPythonLanguage.NoType.newArray(0.v))
val rectsList = uniqueVariable(listName, CPythonLanguage.NoType.newArray(0.v))

current.scope {
local(rectsList)

foreach(variable(CPythonLanguage.NoType, "points"), input.value) { points ->
rectsList("append", cv2.callValue("boundingRect", CPythonLanguage.NoType, points))
if (input is GenValue.GList.RuntimeListOf<*>) {
foreach(variable(CPythonLanguage.NoType, "points"), input.value) { points ->
rectsList("append", cv2.callValue("boundingRect", CPythonLanguage.NoType, points))
}
} else {
for (points in (input as GenValue.GList.ListOf<*>).elements) {
if (points is GenValue.GPoints.RuntimePoints) {
ifCondition(points.value notEqualsTo language.nullValue) {
rectsList(
"append",
cv2.callValue("boundingRect", CPythonLanguage.NoType, points.value)
)
}
} else {
raise("Invalid input type for contours")
}
}
}
}

Expand All @@ -113,7 +142,7 @@ class BoundingRectsNode : DrawNode<BoundingRectsNode.Session>() {
override fun getOutputValueOf(current: CodeGen.Current, attrib: Attribute): GenValue {
genCodeIfNecessary(current)

if(attrib == outputRects) {
if (attrib == outputRects) {
return current.sessionOf(this)!!.outputRects
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -101,17 +101,23 @@ open class DrawContoursNode
lineParams.thicknessValue
)
} else {
val list = Variable("contoursList", JavaTypes.List(JvmOpenCvTypes.MatOfPoint).new())
separate()

val list = Variable("contoursList", JavaTypes.ArrayList(JvmOpenCvTypes.MatOfPoint).new())
local(list)

for (contour in (contoursList as GenValue.GList.ListOf<*>).elements) {
if (contour is GenValue.GPoints.RuntimePoints) {
list("add", contour.value)
ifCondition(contour.value notEqualsTo language.nullValue) {
list("add", contour.value)
}
} else {
raise("Invalid contour type")
raise("Points are not supported")
}
}

separate()

Imgproc("drawContours", drawMat, list, (-1).v,
lineParams.colorScalarValue,
lineParams.thicknessValue
Expand Down Expand Up @@ -161,17 +167,23 @@ open class DrawContoursNode
if(contoursList is GenValue.GList.RuntimeListOf<*>) {
cv2("drawContours", target, contoursList.value, (-1).v, colorScalar, thickness.v)
} else {
separate()

val list = uniqueVariable("contoursList", CPythonLanguage.NoType.newArray())
local(list)

for(contour in (contoursList as GenValue.GList.ListOf<*>).elements) {
if(contour is GenValue.GPoints.RuntimePoints) {
list("append", contour.value)
ifCondition(contour.value notEqualsTo CPythonLanguage.nullValue) {
list("append", contour.value)
}
} else {
raise("Invalid contour type")
}
}

separate()

cv2("drawContours", target, list, (-1).v, colorScalar, thickness.v)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import io.github.deltacv.papervision.codegen.CodeGenSession
import io.github.deltacv.papervision.codegen.GenValue
import io.github.deltacv.papervision.codegen.build.Value
import io.github.deltacv.papervision.codegen.build.type.CPythonOpenCvTypes.cv2
import io.github.deltacv.papervision.codegen.build.type.CPythonOpenCvTypes.np
import io.github.deltacv.papervision.codegen.build.type.JavaTypes
import io.github.deltacv.papervision.codegen.build.type.JvmOpenCvTypes
import io.github.deltacv.papervision.codegen.build.type.JvmOpenCvTypes.Imgproc
Expand Down Expand Up @@ -96,23 +97,29 @@ open class DrawRotatedRectanglesNode
}

fun ScopeContext.drawRuntimeRect(rectValue: Value) {
val rectPoints = uniqueVariable("rectPoints", JvmOpenCvTypes.Point.newArray(4.v))
local(rectPoints)
rectValue("points", rectPoints)

val matOfPoint = uniqueVariable("matOfPoint", JvmOpenCvTypes.MatOfPoint.new(rectPoints))
local(matOfPoint)

separate()

// Draw the rectangle using the points
Imgproc(
"polylines", drawMat,
JavaTypes.Collections.callValue("singletonList", JavaTypes.List(JvmOpenCvTypes.MatOfPoint), matOfPoint), // list of points forming the rotated rectangle
trueValue, // closed polygon
lineParams.colorScalarValue,
lineParams.thicknessValue
)
ifCondition(rectValue notEqualsTo language.nullValue) {
val rectPoints = uniqueVariable("rectPoints", JvmOpenCvTypes.Point.newArray(4.v))
local(rectPoints)
rectValue("points", rectPoints)

val matOfPoint = uniqueVariable("matOfPoint", JvmOpenCvTypes.MatOfPoint.new(rectPoints))
local(matOfPoint)

separate()

// Draw the rectangle using the points
Imgproc(
"polylines", drawMat,
JavaTypes.Collections.callValue(
"singletonList",
JavaTypes.List(JvmOpenCvTypes.MatOfPoint),
matOfPoint
), // list of points forming the rotated rectangle
trueValue, // closed polygon
lineParams.colorScalarValue,
lineParams.thicknessValue
)
}
}

if (rectanglesList !is GenValue.GList.RuntimeListOf<*>) {
Expand Down Expand Up @@ -158,7 +165,7 @@ open class DrawRotatedRectanglesNode
input.value
} else {
val output = uniqueVariable(
"${input.value.value}_rects",
"${input.value.value}_rot_rects",
input.value.callValue("copy", CPythonLanguage.NoType)
)
local(output)
Expand All @@ -173,39 +180,18 @@ open class DrawRotatedRectanglesNode
// TODO: Implement rotated rect drawing in python

fun ScopeContext.runtimeRect(rectValue: Value) {
val rectangle = CPythonLanguage.tupleVariables(
rectValue,
"x", "y", "w", "h"
)
local(rectangle)

// cv2.rectangle(mat, (x, y), (x + w, y + h), color, thickness)
// color is a (r, g, b, a) tuple
cv2(
"rectangle", target,
CPythonLanguage.tuple(rectangle.get("x"), rectangle.get("y")),
CPythonLanguage.tuple(
rectangle.get("x") + rectangle.get("w"),
rectangle.get("y") + rectangle.get("h")
),
colorScalar,
thickness.v
)
ifCondition(rectValue notEqualsTo language.nullValue) {
val box = uniqueVariable("box", cv2.callValue("boxPoints", CPythonLanguage.NoType, rectValue))
local(box)
box set np.callValue("int0", CPythonLanguage.NoType, box)
cv2("drawContours", target, box, (0).v, colorScalar, thickness.v)
}
}

if (rectanglesList !is GenValue.GList.RuntimeListOf<*>) {
for (rectangle in (rectanglesList as GenValue.GList.ListOf<*>).elements) {
if (rectangle is GenValue.GRect.Rect) {
cv2(
"rectangle", target,
CPythonLanguage.tuple(rectangle.x.value.v, rectangle.y.value.v),
CPythonLanguage.tuple(
rectangle.x.value.v + rectangle.w.value.v,
rectangle.y.value.v + rectangle.h.value.v
),
colorScalar,
thickness.v
)
if (rectangle is GenValue.GRect.Rotated.RotatedRect) {
raise("RotatedRects are not supported")
} else if (rectangle is GenValue.GRect.RuntimeRect) {
runtimeRect(rectangle.value)
}
Expand Down
4 changes: 2 additions & 2 deletions PaperVision/src/main/resources/lang.csv
Original file line number Diff line number Diff line change
Expand Up @@ -118,8 +118,8 @@ err_musthave_attachedattrib,Must have an attribute attached,Debe tener un atribu
err_attachedattrib_isnot,Attribute attached is not $[0],El atributo conectado no es $[0]
err_valreturned_isnot,Value returned from the node is not $[0],El valor retornado del nodo no es $[0]
err_attrib_nothandledby_this,Attribute $[0] is not an output of this node or not handled by this,El atributo $[0] no es una salida de este nodo o no es manejado por este
err_couldntlink_didntmatch,Couldnt link nodes: Types didnt match,No se completo la conexion: Los tipos son diferentes
err_couldntlink_recursion,Couldnt link nodes: Recursion problem detected,No se completo la conexion: Problema de recursion detectado
err_couldntlink_didntmatch,Couldn't link nodes: Types didn't match,No se completo la conexion: Los tipos son diferentes
err_couldntlink_recursion,Couldn't link nodes: Recursion problem detected,No se completo la conexion: Problema de recursion detectado
mis_input,Input,Entrada
mis_output,Output,Salida
mis_nodeslist_open,Press SPACE to open the nodes list,Presiona ESPACIO para abrir la lista de nodos
Expand Down

0 comments on commit adcc91f

Please sign in to comment.