-
Notifications
You must be signed in to change notification settings - Fork 26
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
add 'boundingBox' to NmlParser and NmlWriter #2827
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please add some comments, that explain which bounding box takes precendence when & (especially) why. On which layers do we have bounding boxes now?
app/controllers/TaskController.scala
Outdated
@@ -99,13 +99,15 @@ class TaskController @Inject() (val messagesApi: MessagesApi) | |||
} | |||
|
|||
private def buildFullParams(nmlParams: NmlTaskParameters, tracing: SkeletonTracing, fileName: String, description: Option[String]) = { | |||
val parsedTracingBoundingBox = tracing.boundingBox.map(b => BoundingBox(b.topLeft, b.width, b.height, b.depth)) | |||
val bbox = if(nmlParams.boundingBox.isDefined) nmlParams.boundingBox else parsedTracingBoundingBox |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why does it make sense to give the nml bounding box precedence?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nmlParms
are the form-parameter that you specify when you are uploading an nml. There you can specify a bounding box explicitly (this is optional).
The bounding box parsedTracingBoundingBox
is the bounding box which might be stored inside the nml (this is optional as well).
When you are uploading an nml and you are specifying the bounding box in the form-value explicitly then you are aware which bounding box you want. (Therefore this value is used)
When you don't specify a bounding box in the form-value then the bounding box of the parsed nml is used. (In case none of those two are specified, then the bounding box is None
)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@rschwanhold: Thanks for the explanation! I thought the variables are exactly the opposite^^
Therefore I renamed them here to make this more clear.
@@ -56,14 +56,15 @@ object NmlParser extends LazyLogging with ProtoGeometryImplicits { | |||
val editPosition = parseEditPosition(parameters \ "editPosition").getOrElse(SkeletonTracingDefaults.editPosition) | |||
val editRotation = parseEditRotation(parameters \ "editRotation").getOrElse(SkeletonTracingDefaults.editRotation) | |||
val zoomLevel = parseZoomLevel(parameters \ "zoomLevel").getOrElse(SkeletonTracingDefaults.zoomLevel) | |||
val userBoundingBox = parseUserBoundingBox(parameters \ "userBoundingBox") | |||
val userBoundingBox = parseBoundingBox(parameters \ "userBoundingBox") | |||
val boundingBox = parseBoundingBox(parameters \ "boundingBox") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is this simply None
if boundingBox
does not exist?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
boundingBox
is None
if the parsed nml does not contain information about this bounding box
|
||
logger.debug(s"Parsed NML file. Trees: ${trees.size}, Volumes: ${volumes.size}") | ||
|
||
if (volumes.size >= 1) { | ||
(Right(VolumeTracing(None, BoundingBox.empty, time, dataSetName, editPosition, editRotation, ElementClass.uint32, None, 0, 0, zoomLevel), volumes.head.location), description) | ||
} else { | ||
(Left(SkeletonTracing(dataSetName, trees, time, None, activeNodeId, | ||
(Left(SkeletonTracing(dataSetName, trees, time, boundingBox, activeNodeId, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why should the boundingBox be part of the NML? I thought this belongs rather to the dataset than to a tracing?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In
optional BoundingBox boundingBox = 4; |
The reason why we want to write the bounding box to the nml is that after you've downloaded the nml of a SkeletonTracing and then you are uploading it again, you dont't want to lose the bounding box. (see: https://discuss.webknossos.org/t/bounding-box-should-be-persisted-to-parsed-from-nml/966)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, thanks! 👍 I wasn't aware of that layer.
@rschwanhold Two things: Is this your understanding as well? :) |
@daniel-wer
I think renaming |
I don't know how renaming this would affect the already stored proto data and if they need a migration |
nmlParams --> nmlFormParams parsedTracingBoundingBox --> parsedNmlTracingBoundingBox
(1) I'll take care of that as part of this PR :) |
…s/webknossos into make-bbox-persisted
I've implemented the frontend part, updated the nml snapshots and added some more tests for invalid nmls. @philippotto Please have a look at the frontend changes in c7f598a. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice 🎉 Cool that you added more front-end tests, @daniel-wer 👍
topLeftX: bb.min[0], | ||
topLeftY: bb.min[1], | ||
topLeftZ: bb.min[2], | ||
width: bb.max[0] - bb.min[0], |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you use convertFrontendBoundingBoxToServer
from reducer_helpers.js
here like this?
const [topLeft, width, height, depth] = convertFrontendBoundingBoxToServer(bb);
const [topLeftX, topLeftY, topLeftZ] = topLeft;
return serializeTag(name, { topLeftX, topLeftY, topLeftZ, width, height, depth });
Then, we don't duplicate the max - min
logic :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, I see, you moved the code. But maybe it's a good idea, anyway, to reduce the boundingbox-related code a bit.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
backend part LGTM
Mailable description of changes:
Example:
<taskBoundingBox topLeftX="0" topLeftY="0" topLeftZ="0" width="512" height="512" depth="512" />
BoundinBox
:=> the bounding box of the form-value is used
=> the bounding box of the form-value is used
=> the bounding box of the parsed NML is used
=> no bounding box is used
Steps to test:
/api/annotations/:typ/:id/download
boundingBox
if the task has a boundingBox (this is optional)Issues: