Question

Extracting transformation Matrix


Hi,

 

 

Looking to extract the transformation matrix information from an E57 pointcloud file. Is there a way to do this? I know the information can be found in FME Data Inspector.

 

 

 

Thanks

 

 

 

13 replies

Has anyone sorted this out? You can see the information in the inspector but I cannot seem to expose it as an attribute.

 

 

Userlevel 4
Badge +25
Has anyone sorted this out? You can see the information in the inspector but I cannot seem to expose it as an attribute.

 

 

I asked one of our point cloud developers and we'll see what they say.

 

Badge +5

Hi @ryanw

It might be something along the line of forcing the RevIt feature attributes above the meta-attribute line.

 

Please see expose custom attrs from RevIt using the AttributeExposer and i think there is maybe traits you can express using GeomPropertyExposer or to scratch at some of these.

and lastly there alot of clever features hiding in PointCloudExpressionEvaluator / PointCloudPropertyExtractor see if you can force the component into an attribute using one of these .

-S

Userlevel 4
Badge +25
Has anyone sorted this out? You can see the information in the inspector but I cannot seem to expose it as an attribute.

 

 

Looks like the answer is no. Sorry. All I can suggest is that you contact our support team (safe.com/support) and ask them to file an enhancement request. I don't see one already.

 

 

Userlevel 4
Badge +25
Has anyone sorted this out? You can see the information in the inspector but I cannot seem to expose it as an attribute.

 

 

Additionally, please feel free to post this as an idea, to see if other users feel the same need. https://safe.com/ideas

 

 

The more votes your idea gets, the more likely it will be completed. As an alternative we would be more than happy to add this idea to the ideas exchange anonymously on your behalf.

 

 

Additionally, please feel free to post this as an idea, to see if other users feel the same need. https://safe.com/ideas

 

 

The more votes your idea gets, the more likely it will be completed. As an alternative we would be more than happy to add this idea to the ideas exchange anonymously on your behalf.

 

 

Thanks Mark, I've implemented both of your suggestions.

 

 

Userlevel 2
Badge +17

The transformation matrix will be logged by the Logger, so I think you can extract the required information from the feature log if you sneak a peek at log.

0684Q00000ArLdWQAV.png

# PythonCaller Script
import fmeobjects

def collectLog(sevirity, message):
    g_logger.append(message)

class PreProcessor(object):
    def __init__(self):
        fmeobjects.FMELogFile().setCallBack(collectLog)
        
    def input(self,feature):
        global g_logger
        g_logger = []
        self.pyoutput(feature)

# PythonCaller_2 Script
class PostProcessor(object):
    def input(self, feature):
        feature.setAttribute("_log", "\n".join(g_logger))
        self.pyoutput(feature)

The attribute named "_log" stores a text string like this. You can then parse this text to extract the transformation matrix.

Logger: Feature is:
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Feature Type: `Logger_LOGGED'
Attribute(string): `fme_basename' has value `PointCloudCreator'
Attribute(string): `fme_feature_type' has value `PointCloudCreator'
Attribute(string): `fme_geometry' has value `fme_polygon'
Attribute(string): `fme_type' has value `fme_point_cloud'
Coordinate System: `'
Geometry Type: IFMEPointCloud
Transformation Matrix:
   |0.86602540378443904 -0.49999999999999928 0 30|
   |0.49999999999999928 0.86602540378443904  0 50|
   |0                   0                    1 0 |
   |0                   0                    0 1 |
Global Extent Min: (-31.999999999999908,50,0)
Global Extent Max: (137.38715006927043,219.38715006927035,20)
Number of points: 15625
Components: 
   x (Real64)
   y (Real64)
   z (Real64)
===========================================================================

[Update] This script for the PythonCaller_2 extracts individual elements of the transformation matrix from the log and stores them as feature attributes.

# PythonCaller_2 Script [Update]
class PostProcessor(object):
    def input(self, feature):
        # Extract rows containing transformation matrix from the log.
        matrix, flag = [], False
        for r in [s.strip() for s in g_logger]:
            if not flag and r.startswith('Transformation Matrix:'):
                flag = True
            elif flag and len(matrix) < 4:
                matrix.append(r.strip('|'))
                
        # Extract every element of the matrix.
        if len(matrix) == 4:
            r = [s.split() for s in matrix]
            attrs = {
                "_A": r[0][0], "_B": r[0][1], "_C": r[0][2], "_D": r[0][3],
                "_E": r[1][0], "_F": r[1][1], "_G": r[1][2], "_H": r[1][3],
                "_I": r[2][0], "_J": r[2][1], "_K": r[2][2], "_L": r[2][3],
                "_M": r[3][0], "_N": r[3][1], "_O": r[3][2], "_P": r[3][3],
            }
            for k in attrs.keys():
                feature.setAttribute(k, float(attrs[k]))
                
        feature.setAttribute("_log", "\n".join(g_logger)) # Optional
        feature.setAttribute("_matrix{}", matrix) # Optional
        
        self.pyoutput(feature)

The transformation matrix will be logged by the Logger, so I think you can extract the required information from the feature log if you sneak a peek at log.

0684Q00000ArLdWQAV.png

# PythonCaller Script
import fmeobjects

def collectLog(sevirity, message):
    g_logger.append(message)

class PreProcessor(object):
    def __init__(self):
        fmeobjects.FMELogFile().setCallBack(collectLog)
        
    def input(self,feature):
        global g_logger
        g_logger = []
        self.pyoutput(feature)

# PythonCaller_2 Script
class PostProcessor(object):
    def input(self, feature):
        feature.setAttribute("_log", "\n".join(g_logger))
        self.pyoutput(feature)

The attribute named "_log" stores a text string like this. You can then parse this text to extract the transformation matrix.

Logger: Feature is:
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Feature Type: `Logger_LOGGED'
Attribute(string): `fme_basename' has value `PointCloudCreator'
Attribute(string): `fme_feature_type' has value `PointCloudCreator'
Attribute(string): `fme_geometry' has value `fme_polygon'
Attribute(string): `fme_type' has value `fme_point_cloud'
Coordinate System: `'
Geometry Type: IFMEPointCloud
Transformation Matrix:
   |0.86602540378443904 -0.49999999999999928 0 30|
   |0.49999999999999928 0.86602540378443904  0 50|
   |0                   0                    1 0 |
   |0                   0                    0 1 |
Global Extent Min: (-31.999999999999908,50,0)
Global Extent Max: (137.38715006927043,219.38715006927035,20)
Number of points: 15625
Components: 
   x (Real64)
   y (Real64)
   z (Real64)
===========================================================================

[Update] This script for the PythonCaller_2 extracts individual elements of the transformation matrix from the log and stores them as feature attributes.

# PythonCaller_2 Script [Update]
class PostProcessor(object):
    def input(self, feature):
        # Extract rows containing transformation matrix from the log.
        matrix, flag = [], False
        for r in [s.strip() for s in g_logger]:
            if not flag and r.startswith('Transformation Matrix:'):
                flag = True
            elif flag and len(matrix) < 4:
                matrix.append(r.strip('|'))
                
        # Extract every element of the matrix.
        if len(matrix) == 4:
            r = [s.split() for s in matrix]
            attrs = {
                "_A": r[0][0], "_B": r[0][1], "_C": r[0][2], "_D": r[0][3],
                "_E": r[1][0], "_F": r[1][1], "_G": r[1][2], "_H": r[1][3],
                "_I": r[2][0], "_J": r[2][1], "_K": r[2][2], "_L": r[2][3],
                "_M": r[3][0], "_N": r[3][1], "_O": r[3][2], "_P": r[3][3],
            }
            for k in attrs.keys():
                feature.setAttribute(k, float(attrs[k]))
                
        feature.setAttribute("_log", "\n".join(g_logger)) # Optional
        feature.setAttribute("_matrix{}", matrix) # Optional
        
        self.pyoutput(feature)

Thanks @takashi this is a viable workaround. Much appreciated. 

Badge

Hello !

In the log there is also a "Name(UTF-8):" attribute that can be interesting to extract in addition to the transformation matrix values.

log.PNG

I want to adapt your " PythonCaller_2 Script [Update] " to extract the "Name(UTF-8):" line but I don't know how to proceed ... If you eventually know which line(s) I need to add in the python script to extract the "Name(UTF-8):" you will save my week!

Kind regards,

Arnaud

Badge

The transformation matrix will be logged by the Logger, so I think you can extract the required information from the feature log if you sneak a peek at log.

0684Q00000ArLdWQAV.png

# PythonCaller Script
import fmeobjects

def collectLog(sevirity, message):
    g_logger.append(message)

class PreProcessor(object):
    def __init__(self):
        fmeobjects.FMELogFile().setCallBack(collectLog)
        
    def input(self,feature):
        global g_logger
        g_logger = []
        self.pyoutput(feature)

# PythonCaller_2 Script
class PostProcessor(object):
    def input(self, feature):
        feature.setAttribute("_log", "\n".join(g_logger))
        self.pyoutput(feature)

The attribute named "_log" stores a text string like this. You can then parse this text to extract the transformation matrix.

Logger: Feature is:
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Feature Type: `Logger_LOGGED'
Attribute(string): `fme_basename' has value `PointCloudCreator'
Attribute(string): `fme_feature_type' has value `PointCloudCreator'
Attribute(string): `fme_geometry' has value `fme_polygon'
Attribute(string): `fme_type' has value `fme_point_cloud'
Coordinate System: `'
Geometry Type: IFMEPointCloud
Transformation Matrix:
   |0.86602540378443904 -0.49999999999999928 0 30|
   |0.49999999999999928 0.86602540378443904  0 50|
   |0                   0                    1 0 |
   |0                   0                    0 1 |
Global Extent Min: (-31.999999999999908,50,0)
Global Extent Max: (137.38715006927043,219.38715006927035,20)
Number of points: 15625
Components: 
   x (Real64)
   y (Real64)
   z (Real64)
===========================================================================

[Update] This script for the PythonCaller_2 extracts individual elements of the transformation matrix from the log and stores them as feature attributes.

# PythonCaller_2 Script [Update]
class PostProcessor(object):
    def input(self, feature):
        # Extract rows containing transformation matrix from the log.
        matrix, flag = [], False
        for r in [s.strip() for s in g_logger]:
            if not flag and r.startswith('Transformation Matrix:'):
                flag = True
            elif flag and len(matrix) < 4:
                matrix.append(r.strip('|'))
                
        # Extract every element of the matrix.
        if len(matrix) == 4:
            r = [s.split() for s in matrix]
            attrs = {
                "_A": r[0][0], "_B": r[0][1], "_C": r[0][2], "_D": r[0][3],
                "_E": r[1][0], "_F": r[1][1], "_G": r[1][2], "_H": r[1][3],
                "_I": r[2][0], "_J": r[2][1], "_K": r[2][2], "_L": r[2][3],
                "_M": r[3][0], "_N": r[3][1], "_O": r[3][2], "_P": r[3][3],
            }
            for k in attrs.keys():
                feature.setAttribute(k, float(attrs[k]))
                
        feature.setAttribute("_log", "\n".join(g_logger)) # Optional
        feature.setAttribute("_matrix{}", matrix) # Optional
        
        self.pyoutput(feature)

Hello !

In the log there is also a "Name(UTF-8):" attribute that can be interesting to extract in addition to the transformation matrix values.

log.PNG

I want to adapt your " PythonCaller_2 Script [Update] " to extract the "Name(UTF-8):" line but I don't know how to proceed ... If you eventually know which line(s) I need to add in the python script to extract the "Name(UTF-8):" you will save my week!

Kind regards,

Arnaud

Userlevel 2
Badge +17

Hello !

In the log there is also a "Name(UTF-8):" attribute that can be interesting to extract in addition to the transformation matrix values.

log.PNG

I want to adapt your " PythonCaller_2 Script [Update] " to extract the "Name(UTF-8):" line but I don't know how to proceed ... If you eventually know which line(s) I need to add in the python script to extract the "Name(UTF-8):" you will save my week!

Kind regards,

Arnaud

It's the geometry name, and you can extract it as a feature attribute with the GeometryPropertyExtractor transformer. Don't need to use Python.

Badge

Hello !

In the log there is also a "Name(UTF-8):" attribute that can be interesting to extract in addition to the transformation matrix values.

log.PNG

I want to adapt your " PythonCaller_2 Script [Update] " to extract the "Name(UTF-8):" line but I don't know how to proceed ... If you eventually know which line(s) I need to add in the python script to extract the "Name(UTF-8):" you will save my week!

Kind regards,

Arnaud

@takashi Thanks a lot ! It work very well ! :)

Userlevel 4
Badge +26

Just updating this post. I've created a CustomTansformer which can extract the transformation matrix from regular 3D objects (faces). https://hub.safe.com/publishers/vcs/transformers/transformationmatrixextractor

 

Unfortunately it doesn't yet support Point Clouds...so stuck with the logging solution from @Takashi Iijima​ 

 

Related is this one which applies and removes the transformation matrix: https://hub.safe.com/publishers/vcs/transformers/transformationmatrixremover

 

Reply