# Plane markup json files - how to create "baseToNode" and "orientation" matrices

**URL:** <https://discourse.slicer.org/t/plane-markup-json-files-how-to-create-basetonode-and-orientation-matrices/31826>\
**Category:** Development\
**Created:** [September 21, 2023, 2:08pm UTC](https://discourse.slicer.org/t/plane-markup-json-files-how-to-create-basetonode-and-orientation-matrices/31826 "2023-09-21T14:08:55Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![drobny](https://avatars.discourse-cdn.com/v4/letter/d/5daacb/32.png) [@drobny](https://discourse.slicer.org/u/drobny)\
**Post date:** [September 21, 2023, 2:08pm UTC](https://discourse.slicer.org/t/plane-markup-json-files-how-to-create-basetonode-and-orientation-matrices/31826/1 "2023-09-21T14:08:55Z")

</div>

Hi,  
I’m looking into using slicer for the visualisation of results from another tool. Therefore, I’d like to import plane definitions to quickly inspect whether they are as expected.  
I use a point and normal vector in world coordinates. I keep the rest of a slicer generated json file as template while replacing “center” and “normal”.  
The “objectToBase” matrix seems straight forward enough the conversion between the image orientation to the default LPS orientation of the markups.  
But it’s not immediately clear how the “baseToNode” and “orientation” matrices are defined and I can’t find a reference. I hoped I could omit those in the definition as the point and normal should be sufficient for defining a plane (to my needs). This does not seem to be the case so I assume I will have to calculate the matrices to make Slicer read my file.

Could someone point me to a resource of how these should behave or how they would be calculated based on the point and normal vector? Much appreciated!

---

<div class="post-metadata">

**Author:** ![lassoan](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.slicer.org/lassoan/32/13_2.png) [@lassoan](https://discourse.slicer.org/u/lassoan)\
**Post date:** [September 22, 2023, 2:58am UTC](https://discourse.slicer.org/t/plane-markup-json-files-how-to-create-basetonode-and-orientation-matrices/31826/2 "2023-09-22T02:58:52Z")

</div>

Definition of these coordinate systems are [here](https://github.com/Slicer/Slicer/blob/main/Modules/Loadable/Markups/MRML/vtkMRMLMarkupsPlaneNode.h).

If you specify a plane by a single point (`"planeType": "pointNormal"`) then you only need to specify:

- plane position: position of the one and only control point
- plane orientation: `baseToNode` matrix. Note that a plane in mathematical sense is specified by a position and a normal, but if you want to display a plane then you need to specify its rotation around that normal. `baseToNode` contains the two axis of the plane and the plane normal. If you don’t care about the rotation then you can choose an arbitrary orientation and use cross product with the normal vector to make it orthogonal to the normal vector. Translation component of `baseToNode` matrix is ignored (because position is set by the control point), so it can be set to `0.0, 0.0, 0.0`.
- plane bounds: specifies how far the plane extends in 4 directions (-x, +x, -y, +y) from the plane position

Example:

```auto
{
    "@schema": "https://raw.githubusercontent.com/slicer/slicer/master/Modules/Loadable/Markups/Resources/Schema/markups-schema-v1.0.3.json#",
    "markups": [
        {
            "type": "Plane", "coordinateSystem": "LPS", "planeType": "pointNormal",
            "baseToNode": [
                -0.7177763971220261, -0.48438183588553957, -0.5001712514716112, 0.0,
                0.3974111999339178, -0.8748566951587867, 0.2769297764830091, 0.0,
                -0.5717179216201003, -1.1102230246251565e-16, 0.820450253274623, 0.0,
                0.0, 0.0, 0.0, 1.0],
            "planeBounds": [-50.0, 50.0, -50.0, 50.0],
            "controlPoints": [{ "position": [60.6068749511193, -26.833897399804197, -175.25000000000006] }],
            "display": { "visibility": true, "opacity": 1.0, "color": [0.4, 1.0, 1.0] }
       }
    ]
}
```

---

<div class="post-metadata">

**Author:** ![angolin22\_fan](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.slicer.org/angolin22_fan/32/67798_2.png) [@angolin22\_fan](https://discourse.slicer.org/u/angolin22_fan)\
**Post date:** [January 31, 2024, 11:44am UTC](https://discourse.slicer.org/t/plane-markup-json-files-how-to-create-basetonode-and-orientation-matrices/31826/3 "2024-01-31T11:44:51Z")

</div>

Dear teacher,  
Hello, Thanks for your excellent work!  
I have a question, If I know the plane center(c1,c2,c3) and normal(n1,n2,n3), How can I calculate the ‘baseToNode’?

---

<div class="post-metadata">

**Author:** ![phiro753](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.slicer.org/phiro753/32/68721_2.png) [@phiro753](https://discourse.slicer.org/u/phiro753)\
**Post date:** [May 2, 2024, 5:56am UTC](https://discourse.slicer.org/t/plane-markup-json-files-how-to-create-basetonode-and-orientation-matrices/31826/4 "2024-05-02T05:56:19Z")

</div>

Hi team,

I seem to be struggling with the same issue coming to the end of my PhD on Sarcoma. (I have worked across disciplines to propose a method for bone histology registration because bone can be a little tricky… We are aiming to enable similar correlation to prostate research, [Mirabela and PIMed](https://github.com/pimed/Slicer-RadPathFusion)).

I can get the planes for histology initalisaiton in python working, but these are only specified by a centre and normal… The baseToNode seems to be giving similar issues to this thread when I try import jsons to Slicer… Mind expanding on your comments about circumventing baseToNormal above Andras?

 ![image](https://us1.discourse-cdn.com/flex002/uploads/slicer/original/3X/e/2/e20ddae7c399a1b95e135ced722a693fad3131ab.png)

---

<div class="post-metadata">

**Author:** ![phiro753](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.slicer.org/phiro753/32/68721_2.png) [@phiro753](https://discourse.slicer.org/u/phiro753)\
**Post date:** [May 29, 2024, 3:13am UTC](https://discourse.slicer.org/t/plane-markup-json-files-how-to-create-basetonode-and-orientation-matrices/31826/5 "2024-05-29T03:13:15Z")

</div>

I missed posting this a little while ago. To wrap my problem up I managed to cobble something together that seemed to work for my issue… A wee function for calculating the baseToNode array:

```auto
def CalcBase2Node(self):
    '''Calculating the baseToNode matrix for .JSON import into Slicer'''
    # Normalize the plane normal vector
    self.normal /= np.linalg.norm(self.normal)

    # Choose an arbitrary vector not parallel to the self.normal (e.g., x-axis)
    arbitrary_vector = np.array([1, 0, 0])

    # Calculate a third axis of the plane coordinate system
    third_axis = np.cross(self.normal, arbitrary_vector)
    third_axis /= np.linalg.norm(third_axis)

    # Calculate the second axis of the plane coordinate system
    second_axis = np.cross(self.normal, third_axis)
    second_axis /= np.linalg.norm(second_axis)

    # Construct the rotation-translation matrix baseToNode
    base_to_node_matrix = np.eye(4)
    base_to_node_matrix[:3, 0] = third_axis
    base_to_node_matrix[:3, 1] = second_axis
    base_to_node_matrix[:3, 2] = self.normal
    base_to_node_matrix[:3, 3] = self.centre

    return base_to_node_matrix

```

This feeds a seraliser and produces .json files which import well into Slicer now.

 ![image](https://us1.discourse-cdn.com/flex002/uploads/slicer/original/3X/7/c/7ccc1333e200f714da319b608e0f9625b8e29bb1.png)
