Skip to content
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

Allow rectangular and box masks to be rotated #845

Merged
merged 10 commits into from Mar 7, 2018

Conversation

@stinebuu
Copy link
Contributor

@stinebuu stinebuu commented Oct 25, 2017

This PR adds the optional parameters azimuth_angle and polar_angle to the rectangular and box mask dictionaries so that the masks can be rotated.

This have led to some changes in the boxMask class, most notably with the inside(..) function and when finding the boundary box. When checking if a point is inside the mask, we have to take rotation into account. If we have rotation, we can no longer use lower_left and upper_right to define the boundary box, so we have to calculate the minimum and maximum values of the mask. This is done in create_min_max_values_().

The functions check to see if we have rotation as much as possible, so that we can use lower_left and upper_right and avoid unnecessary rotation calculations if we do not have rotation.

I have also added a test.

@stinebuu stinebuu changed the title Allow rectangle and box masks to be rotated Allow rectangular and box masks to be rotated Oct 25, 2017
@heplesser heplesser requested review from heplesser and hakonsbm Oct 30, 2017
Copy link
Contributor

@hakonsbm hakonsbm left a comment

Thank you for this, it looks good. As far as I can see, there are just some minor things to fix, see below.

/**
* Calculate the min/max x, y, z values in case of a rotated box.
*/
void create_min_max_values_();

This comment has been minimized.

@hakonsbm

hakonsbm Oct 31, 2017
Contributor

Perhaps rename to calculate_min_max_values_?

return ( lower_left_ <= p ) && ( p <= upper_right_ );
}

// If we have a rotated box, We rotate the point down to the unrotated box,

This comment has been minimized.

@hakonsbm

hakonsbm Oct 31, 2017
Contributor

Small w.

const double cntr_y = ( upper_right_[ 1 ] + lower_left_[ 1 ] ) * 0.5;
const double cntr_z = ( upper_right_[ 2 ] + lower_left_[ 2 ] ) * 0.5;

const double new_x = ( ( p[ 0 ] - cntr_x ) * azimuth_cos_

This comment has been minimized.

@hakonsbm

hakonsbm Oct 31, 2017
Contributor

For efficiency p[ {0|1|2} ] - cntr_{x|y|z} can be precalculated after calculating the centres.


const double new_x = ( ( p[ 0 ] - cntr_x ) * azimuth_cos_
+ ( p[ 1 ] - cntr_y ) * azimuth_sin_ ) * polar_cos_
- ( ( p[ 2 ] - cntr_z ) * polar_sin_ ) + cntr_x;

This comment has been minimized.

@hakonsbm

hakonsbm Oct 31, 2017
Contributor

These lines should have the same indentation.

+ ( p[ 1 ] - cntr_y ) * azimuth_cos_ + cntr_y;
const double new_z = ( ( p[ 0 ] - cntr_x ) * azimuth_cos_
+ ( p[ 1 ] - cntr_y ) * azimuth_sin_ ) * polar_sin_
+ ( ( p[ 2 ] - cntr_z ) * polar_cos_ ) + cntr_z;

This comment has been minimized.

@hakonsbm

hakonsbm Oct 31, 2017
Contributor

Give lines same indentation here too.

def test_RotatedBoxMaskByAzimuthAndPolarAngle(self):
"""Test rotated box mask with azimuth and polar angle."""

pos = [[x*1., y*1., z*1.] for x in range(-2, 3)

This comment has been minimized.

@hakonsbm

hakonsbm Oct 31, 2017
Contributor

Missing whitespace around *-operators.

[38, 39, 44, 58, 59, 64, 69, 70, 84, 89, 90])

def test_RotatedRectangleOutsideOrigo(self):
"""Test rotated rectangle where mask is outside origo."""

This comment has been minimized.

@hakonsbm

hakonsbm Oct 31, 2017
Contributor

As it is the mask that contains things, not origo, perhaps something along the lines of "where origo is not in mask"?

def test_RotatedBoxOutsideOrigo(self):
"""Test rotated box where mask is outside origo."""

pos = [[x*1., y*1., z*1.] for x in range(-2, 3)

This comment has been minimized.

@hakonsbm

hakonsbm Oct 31, 2017
Contributor

Missing whitespace around *-operators.

44
14 -> 40
36

This comment has been minimized.

@hakonsbm

hakonsbm Oct 31, 2017
Contributor

Looks like there's something missing with these example connections.

def suite():
suite = unittest.makeSuite(RotatedRectangularMask, 'test')
return suite

This comment has been minimized.

@hakonsbm

hakonsbm Oct 31, 2017
Contributor

Two blank lines after the function definition.

stinebuu added 2 commits Nov 1, 2017
calculate_min_max_values, precalculation of some of the values,
indentation, changed some comments.
Copy link
Contributor

@hakonsbm hakonsbm left a comment

Great, thank you!

Copy link
Contributor

@heplesser heplesser left a comment

Looks quite fine, but see comments. We should discuss once more about the "eps" that we are adding, just wondering if we are digging some future grave. For 3D, we olny have two angles. Which rotation possibility are we missing?

Position< D > lower_left_;
Position< D > upper_right_;

Position< D > min_values_;

This comment has been minimized.

@heplesser

heplesser Nov 30, 2017
Contributor

Could you add a comment what these are and how they relate to lower_left/upper_right?

This comment has been minimized.

@stinebuu

stinebuu Dec 8, 2017
Author Contributor

@heplesser I have added the comment. The min/max values correspond to the lower_left/upper_right of the boundary box around the rotated box. Should I change the names to something like bbox_lower_left_ and bbox_upper_right_ to make it more clear?

* upper_right - Position of upper right corner (array of doubles)
* lower_left - Position of lower left corner (array of doubles)
* upper_right - Position of upper right corner (array of doubles)
* azimuth_angle - Rotation angle in degrees from x-axis (double), optional

This comment has been minimized.

@heplesser

heplesser Nov 30, 2017
Contributor

Is it documented somewhere that the angles are in degrees? Maybe also add that the polar angle does not apply to 2D.

This comment has been minimized.

@stinebuu

stinebuu Dec 8, 2017
Author Contributor

I have now added a note about the angles in the python documentation for masks.

"polar_angle not defined in 2D." );
}

is_rotated_ = azimuth_angle_ or polar_angle_;

This comment has been minimized.

@heplesser

heplesser Nov 30, 2017
Contributor

Make explicit comparisons to 0!

// We need to add a small epsilon in case of rounding errors.
const double x_length = upper_right_[ 0 ] - lower_left_[ 0 ];
const double y_length = upper_right_[ 1 ] - lower_left_[ 1 ];
const Position< 2 > eps( x_length * 1e-12, y_length * 1e-12 );

This comment has been minimized.

@heplesser

heplesser Nov 30, 2017
Contributor

We can use the cntr_* values to determine eps, saving some operations.


// See https://en.wikipedia.org/wiki/Rotation_matrix for more.

const double cntr_x = ( upper_right_[ 0 ] + lower_left_[ 0 ] ) * 0.5;

This comment has been minimized.

@heplesser

heplesser Nov 30, 2017
Contributor

If I am not entirely off, we need to check quite often if a point is inside a (fixed) box. Wouldn't it make more sense to precompute all values that do not depend on p in the box constructor?


// See https://en.wikipedia.org/wiki/Rotation_matrix for more.

const double cntr_x = ( upper_right_[ 0 ] + lower_left_[ 0 ] ) * 0.5;

This comment has been minimized.

@heplesser

heplesser Nov 30, 2017
Contributor

Same comments apply as for 2D.

Position< 2 > upper_right_cos = ( upper_right_ - cntr ) * azimuth_cos_;
Position< 2 > upper_right_sin = ( upper_right_ - cntr ) * azimuth_sin_;

double rotatedLLx = lower_left_cos[ 0 ] - lower_left_sin[ 1 ] + cntr_x;

This comment has been minimized.

@heplesser

heplesser Nov 30, 2017
Contributor

I suppose these can call be const?

double rotatedLLLx =
( lower_left_cos[ 0 ] - lower_left_sin[ 1 ] ) * polar_cos_
- lower_left_polar_sin + cntr_x;
double rotatedLLLy = lower_left_sin[ 0 ] + lower_left_cos[ 1 ] + cntr_y;

This comment has been minimized.

@heplesser

heplesser Nov 30, 2017
Contributor

Can't these all be const?

position is pre-calculated in constructor, added some const, eps no
longer calculated from length, but just a constant, small number.
@stinebuu
Copy link
Contributor Author

@stinebuu stinebuu commented Dec 8, 2017

@heplesser thank you for your review! I have tried to address your comments, please take a look.

I changed the "eps" to be constant 1e-12 for x, y and z. Having it depend on the center of the box will fail when the center is in the origin, as eps then will be zero.

When it comes to the rotation angles, we are missing rotation from the y-axis to the z-axis (the γ here ). Do you want me to add it? We do not have it for the elliptical mask, but I could add it there as well and make a PR of course.

@terhorstd terhorstd added this to the NEST 2.16 milestone Mar 5, 2018
@heplesser
Copy link
Contributor

@heplesser heplesser commented Mar 7, 2018

@stinebuu Thanks for addressing the issues. I think this ready to merge now. Would you create a follow-up issue to add rotation about the third Euler angle?

@heplesser heplesser merged commit c11bb2c into nest:master Mar 7, 2018
1 check passed
1 check passed
continuous-integration/travis-ci/pr The Travis CI build passed
Details
@stinebuu stinebuu deleted the stinebuu:tilted_rectangle_mask branch Mar 7, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Linked issues

Successfully merging this pull request may close these issues.

None yet

4 participants
You can’t perform that action at this time.