Skip to content

Commit

Permalink
Merge pull request #418 from scenerygraphics/boundingBoxBugBrotein
Browse files Browse the repository at this point in the history
Fix BoundingBox Bug for Proteins. Thanks @Domino2357 👍
  • Loading branch information
skalarproduktraum authored Oct 20, 2021
2 parents c9e2d22 + b92891b commit 2cc5a5a
Show file tree
Hide file tree
Showing 5 changed files with 6,652 additions and 30 deletions.
2 changes: 2 additions & 0 deletions src/main/kotlin/graphics/scenery/geometry/Curve.kt
Original file line number Diff line number Diff line change
Expand Up @@ -318,6 +318,8 @@ class Curve(spline: Spline, private val firstPerpendicularVector: Vector3f = Vec
vertices.flip()
texcoords = BufferUtils.allocateFloat(verticesVectors.size * 2)
recalculateNormals()

boundingBox = generateBoundingBox()
}
}
}
Expand Down
6 changes: 3 additions & 3 deletions src/main/kotlin/graphics/scenery/proteins/RibbonDiagram.kt
Original file line number Diff line number Diff line change
Expand Up @@ -516,9 +516,9 @@ class RibbonDiagram(val protein: Protein, private val displaySS: Boolean = false
* and the last residue, hence, this function.
*/
private fun Vector3f.randomFromVector(): Vector3f {
return Vector3f(Random.randomFromRange(this.x() - 1f, this.x() + 1f),
Random.randomFromRange(this.y() - 1f, this.y() + 1f),
Random.randomFromRange(this.z() - 1f, this.z() + 1f))
return Vector3f(Random.randomFromRange(this.x() - 0.1f, this.x() + 0.1f),
Random.randomFromRange(this.y() - 0.1f, this.y() + 0.1f),
Random.randomFromRange(this.z() - 0.1f, this.z() + 0.1f))
}
}

Expand Down
11 changes: 10 additions & 1 deletion src/test/kotlin/graphics/scenery/tests/unit/ProteinTests.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@ package graphics.scenery.tests.unit
import graphics.scenery.proteins.Protein
import graphics.scenery.utils.LazyLogger
import org.junit.Test
import kotlin.test.assertEquals
import kotlin.test.assertFails
import kotlin.test.assertTrue

/**
* Unit test for the Protein class
Expand All @@ -16,12 +18,19 @@ class ProteinTests {
@Test
fun testInvalidPath() {
logger.info("Tests that an invalid path gets caught")
assertFails { Protein.fromFile("LetsGetSchwifty") }
assertFails { Protein.fromFile("LetsGetShwifty") }
}

@Test
fun testInvalidID() {
logger.info("Test if an invalid pdb entry is caught")
assertFails { Protein.fromID("3mbn") }
}

@Test
fun testOpenFromFile() {
logger.info("Test if opening from file works")
assertEquals(Protein.fromFile(
"src/test/resources/graphics/scenery/tests/unit/proteins/2zzw.pdb").structure.pdbCode, "2ZZW")
}
}
91 changes: 65 additions & 26 deletions src/test/kotlin/graphics/scenery/tests/unit/RibbonDiagramTests.kt
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,13 @@ import graphics.scenery.proteins.RibbonDiagram
import graphics.scenery.utils.LazyLogger
import org.biojava.nbio.structure.Group
import org.biojava.nbio.structure.secstruc.SecStrucElement
import org.joml.Vector3f
import org.junit.Test
import kotlin.reflect.full.declaredMemberFunctions
import kotlin.reflect.jvm.isAccessible
import kotlin.test.assertEquals
import kotlin.test.assertNotEquals
import kotlin.test.assertTrue

/**
* This is the test for the RibbonCalculation, i.e. the pdb-support.
Expand All @@ -31,29 +34,31 @@ class RibbonDiagramTests {
val plantChains = plantProtein.getResidues()
var allPlantPoints = 0
plantChains.forEach {
if(dsspPlant is List<*>) {
if (dsspPlant is List<*>) {
@Suppress("UNCHECKED_CAST")
val guides = RibbonDiagram.GuidePointCalculation.calculateGuidePoints(it, dsspPlant as List<SecStrucElement>)
val guides =
RibbonDiagram.GuidePointCalculation.calculateGuidePoints(it, dsspPlant as List<SecStrucElement>)
val spline = plantRibbon.callPrivateFunc("ribbonSpline", guides) as DummySpline
allPlantPoints += spline.splinePoints().size
}
}
assertEquals(allPlantPoints, (46)*(10+1))
assertEquals(allPlantPoints, (46) * (10 + 1))

val saccharomycesCerevisiae = Protein.fromID("6zqd")
val scRibbon = RibbonDiagram(saccharomycesCerevisiae)
val dsspSC = scRibbon.callPrivateFunc("dssp")
val scChains = saccharomycesCerevisiae.getResidues()
var allSCPoints = 0
scChains.forEach {
if(dsspSC is List<*>) {
if (dsspSC is List<*>) {
@Suppress("UNCHECKED_CAST")
val guides = RibbonDiagram.GuidePointCalculation.calculateGuidePoints(it, dsspSC as List<SecStrucElement>)
val guides =
RibbonDiagram.GuidePointCalculation.calculateGuidePoints(it, dsspSC as List<SecStrucElement>)
val spline = scRibbon.callPrivateFunc("ribbonSpline", guides) as DummySpline
allSCPoints += spline.splinePoints().size
}
}
assertEquals(allSCPoints, (23448)*(10+1))
assertEquals(allSCPoints, (23448) * (10 + 1))

}

Expand Down Expand Up @@ -114,39 +119,73 @@ class RibbonDiagramTests {
"4idj", "2vr3", "2win", "6urh", "3ua7", "3mrn", "4z0x", "2rhk",
"6pdx", "6urm", "2x4q", "1r0n", "2ff6", "4i7b", "3bs5", "5chl",
"5f84", "4uuz", "4v98", "4wsi", "4u68", "4aa1", "5jvs", "6hom",
"4xib", "4u0q", "6phf")
"4xib", "4u0q", "6phf"
)

proteins.shuffled().drop(80).forEach { pdbId ->
val protein = Protein.fromID(pdbId)
logger.info("Testing ${protein.structure.name} ...")
RibbonDiagram(protein)
}
}

/**
* Verifies that the boundingbox min and max vector don't become the null vector.
*/
@Test
fun testMaxBoundingBoxNoNullVector() {
//test min max don't become the null vector
val protein = Protein.fromID("2zzw")
val ribbon = RibbonDiagram(protein)
val bb = ribbon.getMaximumBoundingBox()
assertEquals(bb.n, ribbon)
assertNotEquals(bb.min, Vector3f(0f, 0f, 0f))
assertNotEquals(bb.max, Vector3f(0f, 0f, 0f))
}

/**
* Verifies that a BoundingBox for a ribbon can be created.
*/
@Test
fun testMaxBoundingBox() {
// check if the right BoundingBoc is created
val protein = Protein.fromID("5m9m")
val ribbon = RibbonDiagram(protein)
val bb = ribbon.getMaximumBoundingBox()
print(bb.max)
//We use ranges because the first and last guidePoint are created nondeterministically- but in the guaranteed range
assertTrue { 22.2 < bb.max.x && bb.max.x < 22.6 }
assertTrue { 33.6 < bb.max.y && 34 > bb.max.y }
assertTrue { 37.5 < bb.max.z && 37.9 > bb.max.z }
assertTrue { -31.3 < bb.min.x && -29.9 > bb.min.x }
assertTrue { -28.3 < bb.min.y && -27.9 > bb.min.y }
assertTrue { -36.8 < bb.min.z && -36.4 > bb.min.z }
}

}

//Inline function for the protein to access residues
private fun Protein.getResidues(): ArrayList<ArrayList<Group>> {
val proteins = ArrayList<ArrayList<Group>>(this.structure.chains.size)
this.structure.chains.forEach{ chain ->
if(chain.isProtein) {
val aminoList = ArrayList<Group>(chain.atomGroups.size)
chain.atomGroups.forEach { group ->
if (group.hasAminoAtoms()) {
aminoList.add(group)
//Inline function for the protein to access residues
private fun Protein.getResidues(): ArrayList<ArrayList<Group>> {
val proteins = ArrayList<ArrayList<Group>>(this.structure.chains.size)
this.structure.chains.forEach { chain ->
if (chain.isProtein) {
val aminoList = ArrayList<Group>(chain.atomGroups.size)
chain.atomGroups.forEach { group ->
if (group.hasAminoAtoms()) {
aminoList.add(group)
}
}
proteins.add(aminoList)
}
proteins.add(aminoList)
}
return proteins
}
return proteins
}

//Inline function to access private function in the RibbonDiagram
private inline fun <reified T> T.callPrivateFunc(name: String, vararg args: Any?): Any? =
//Inline function to access private function in the RibbonDiagram
private inline fun <reified T> T.callPrivateFunc(name: String, vararg args: Any?): Any? =
T::class
.declaredMemberFunctions
.firstOrNull { it.name == name }
?.apply { isAccessible = true }
?.call(this, *args)
.declaredMemberFunctions
.firstOrNull { it.name == name }
?.apply { isAccessible = true }
?.call(this, *args)
}

Loading

0 comments on commit 2cc5a5a

Please sign in to comment.