Search code examples
pythonpython-3.xstep

pythonOCC set default units to inches


PLEASE SEE EDIT FOR SHORT VERSION

Been hunting through the pythonOCC documentation for this.

I have .step file in inches. Here are the lines in the .step file for confirmation:

#50 =  ( CONVERSION_BASED_UNIT( 'INCH', #122 )LENGTH_UNIT(  )NAMED_UNIT( #125 ) );
#51 =  ( NAMED_UNIT( #127 )PLANE_ANGLE_UNIT(  )SI_UNIT( $, .RADIAN. ) );
#52 =  ( NAMED_UNIT( #127 )SI_UNIT( $, .STERADIAN. )SOLID_ANGLE_UNIT(  ) );
~~~
#122 = LENGTH_MEASURE_WITH_UNIT( LENGTH_MEASURE( 25.4000000000000 ), #267 );

File reads and displays in window: Display window

When I use manual coordinates to make a bounding box, I find my box is wayyyy off:

Tiny Bounding Box!

Position is off because the STEP model is not at 0,0,0.

Turns out pythonOCC automatically converts everything into MM. When I manually enter in box dimensions in INCHES, it reads them as MM. I've tried to deal by converting everything manually too (inches * 25.4) but this is problematic and ugly.

I know pythonOCC uses the STEP file line # 122 as the conversion ratio as I've changed it from above to:

#122 = LENGTH_MEASURE_WITH_UNIT( LENGTH_MEASURE( 1.0 ), #267 );

When I do, my bounding box and step model line up perfectly... But I still know PythonOCC thinks it's converting to MM.

Perfect!... but in MM

Anyone have any experience changing the default units for pythonocc? I've tried to find in the following occ packages: OCC.STEPControl, OCC.Display, OCC.AIS and many others.

EDIT:

When I draw my box using my own coordinates like this:

minPoint = gp_Pnt(minCoords)
maxPoint = gp_Pnt(maxCoords)
my_box = AIS_Shape(BRepPrimAPI_MakeBox(minPoint, maxPoint).Shape())
display.Context.Display(my_box.GetHandle())

My coordinates are in Inches, but pythonOCC reads them as MM. If I can get my own coordinates to be read in Inches, this would be solved. Can't find anything in OCC.Display for how my coordinates are interpreted. Something like "OCC.Display.inputUnitsAre("INCHES")"?

EDIT 2:

Getting closer looking here:

https://dev.opencascade.org/doc/refman/html/class_units_a_p_i.html

Under UnitsAPI_SystemUnits and SetCurrentUnit... Though I'm not sure how to implement in python yet to test. Working on it.


Solution

  • You'll find documentation for the units here

    Take a look at the OCC.Extended.DataExchange module, you'll see the following function:

    def write_step_file(a_shape, filename, application_protocol="AP203"):
        """ exports a shape to a STEP file
        a_shape: the topods_shape to export (a compound, a solid etc.)
        filename: the filename
        application protocol: "AP203" or "AP214"
        """
        # a few checks
        assert not a_shape.IsNull()
        assert application_protocol in ["AP203", "AP214IS"]
        if os.path.isfile(filename):
            print("Warning: %s file already exists and will be replaced" % filename)
        # creates and initialise the step exporter
        step_writer = STEPControl_Writer()
        Interface_Static_SetCVal("write.step.schema", "AP203")
    
        # transfer shapes and write file
        step_writer.Transfer(a_shape, STEPControl_AsIs)
        status = step_writer.Write(filename)
    
        assert status == IFSelect_RetDone
        assert os.path.isfile(filename)
    

    By default, OCC writes units in millimeters, so I'm curious what function / method was used to export your STEP file.

    Interface_Static_SetCVal("Interface_Static_SetCVal("write.step.unit","MM")
    

    The docs though state that this methods Defines a unit in which the STEP file should be written. If set to unit other than MM, the model is converted to these units during the translation., so having to explicitly set this unit is unexpected.