← Back to team overview

kicad-developers team mailing list archive

[PATCH] Fix for 3D model offset

 

Attached is a patch that fixes the problems I found in my 3D model array
investigation. As discussion on that is stalled for now, this patch simply
fixes the model offset issues.

1. Display offset units in 3D preview window

- Offset units are displayed (either inches or mm)

2. Fix offset in 3D rendering

- It appears that the internal units for 3D model offset (mm) were being
multiplied by 25.4 incorrectly
- Fixed rendering in OGL and Raytracing

3. Fix offset in 3D export

- VRML export
- STEP export

Oliver
From 4cfd526944dccf41b89c921ef45f5b6b07a23f35 Mon Sep 17 00:00:00 2001
From: Oliver <oliver.henry.walters@xxxxxxxxx>
Date: Wed, 8 Nov 2017 20:56:57 +1100
Subject: [PATCH] Fixes for 3D model offset

- Display offset units in 3D preview window (inches or mm)
- Fix offset in 3D renderer
- Fix offset in Raytracing renderer
- Fix offset in STEP export
- Fix offset in VRML export
---
 3d-viewer/3d_cache/dialogs/panel_prev_3d_base.cpp  | 15 +++--
 3d-viewer/3d_cache/dialogs/panel_prev_3d_base.fbp  | 16 +++---
 3d-viewer/3d_cache/dialogs/panel_prev_3d_base.h    |  5 +-
 3d-viewer/3d_cache/dialogs/panel_prev_model.cpp    | 67 +++++++++++++++-------
 .../3d_render_ogl_legacy/c3d_render_ogl_legacy.cpp |  4 +-
 .../c3d_render_createscene.cpp                     |  6 +-
 pcbnew/class_module.h                              |  8 +++
 pcbnew/exporters/export_vrml.cpp                   | 10 ++--
 utils/kicad2step/pcb/kicadmodel.cpp                |  5 +-
 utils/kicad2step/pcb/oce_utils.cpp                 |  7 +--
 10 files changed, 89 insertions(+), 54 deletions(-)

diff --git a/3d-viewer/3d_cache/dialogs/panel_prev_3d_base.cpp b/3d-viewer/3d_cache/dialogs/panel_prev_3d_base.cpp
index f7b9fca..826e189 100644
--- a/3d-viewer/3d_cache/dialogs/panel_prev_3d_base.cpp
+++ b/3d-viewer/3d_cache/dialogs/panel_prev_3d_base.cpp
@@ -1,5 +1,5 @@
 ///////////////////////////////////////////////////////////////////////////
-// C++ code generated with wxFormBuilder (version Aug  4 2017)
+// C++ code generated with wxFormBuilder (version Mar 22 2017)
 // http://www.wxformbuilder.org/
 //
 // PLEASE DO "NOT" EDIT THIS FILE!
@@ -40,7 +40,7 @@ PANEL_PREV_3D_BASE::PANEL_PREV_3D_BASE( wxWindow* parent, wxWindowID id, const w
 	fgSizerScale->Add( m_staticText2, 0, wxALIGN_CENTER_VERTICAL|wxLEFT, 5 );
 	
 	yscale = new wxTextCtrl( vbScale->GetStaticBox(), wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
-	fgSizerScale->Add( yscale, 0, wxALIGN_CENTER_VERTICAL|wxLEFT, 5 );
+	fgSizerScale->Add( yscale, 0, wxALIGN_CENTER_VERTICAL|wxBOTTOM|wxLEFT|wxTOP, 5 );
 	
 	m_spinYscale = new wxSpinButton( vbScale->GetStaticBox(), wxID_ANY, wxDefaultPosition, wxDefaultSize, wxSP_ARROW_KEYS|wxSP_VERTICAL );
 	fgSizerScale->Add( m_spinYscale, 0, wxALIGN_CENTER_VERTICAL, 5 );
@@ -53,7 +53,7 @@ PANEL_PREV_3D_BASE::PANEL_PREV_3D_BASE( wxWindow* parent, wxWindowID id, const w
 	fgSizerScale->Add( zscale, 0, wxALIGN_CENTER_VERTICAL|wxBOTTOM|wxLEFT, 5 );
 	
 	m_spinZscale = new wxSpinButton( vbScale->GetStaticBox(), wxID_ANY, wxDefaultPosition, wxDefaultSize, wxSP_ARROW_KEYS|wxSP_VERTICAL );
-	fgSizerScale->Add( m_spinZscale, 0, wxALIGN_CENTER_VERTICAL, 5 );
+	fgSizerScale->Add( m_spinZscale, 0, wxALIGN_CENTER_VERTICAL|wxBOTTOM, 5 );
 	
 	
 	vbScale->Add( fgSizerScale, 1, wxEXPAND, 5 );
@@ -100,7 +100,7 @@ PANEL_PREV_3D_BASE::PANEL_PREV_3D_BASE( wxWindow* parent, wxWindowID id, const w
 	#else
 	yrot->SetMaxLength( 9 );
 	#endif
-	fgSizerRotate->Add( yrot, 0, wxALIGN_CENTER_VERTICAL|wxLEFT, 5 );
+	fgSizerRotate->Add( yrot, 0, wxALIGN_CENTER_VERTICAL|wxBOTTOM|wxLEFT|wxTOP, 5 );
 	
 	m_spinYrot = new wxSpinButton( vbRotate->GetStaticBox(), wxID_ANY, wxDefaultPosition, wxDefaultSize, wxSP_ARROW_KEYS|wxSP_VERTICAL );
 	fgSizerRotate->Add( m_spinYrot, 0, wxALIGN_CENTER_VERTICAL, 5 );
@@ -121,7 +121,7 @@ PANEL_PREV_3D_BASE::PANEL_PREV_3D_BASE( wxWindow* parent, wxWindowID id, const w
 	fgSizerRotate->Add( zrot, 0, wxALIGN_CENTER_VERTICAL|wxBOTTOM|wxLEFT, 5 );
 	
 	m_spinZrot = new wxSpinButton( vbRotate->GetStaticBox(), wxID_ANY, wxDefaultPosition, wxDefaultSize, wxSP_ARROW_KEYS|wxSP_VERTICAL );
-	fgSizerRotate->Add( m_spinZrot, 0, wxALIGN_CENTER_VERTICAL, 5 );
+	fgSizerRotate->Add( m_spinZrot, 0, wxALIGN_CENTER_VERTICAL|wxBOTTOM, 5 );
 	
 	
 	vbRotate->Add( fgSizerRotate, 1, wxEXPAND, 5 );
@@ -129,7 +129,6 @@ PANEL_PREV_3D_BASE::PANEL_PREV_3D_BASE( wxWindow* parent, wxWindowID id, const w
 	
 	bSizerLeft->Add( vbRotate, 0, wxEXPAND, 5 );
 	
-	wxStaticBoxSizer* vbOffset;
 	vbOffset = new wxStaticBoxSizer( new wxStaticBox( this, wxID_ANY, _("Offset") ), wxVERTICAL );
 	
 	wxFlexGridSizer* fgSizerOffset;
@@ -152,7 +151,7 @@ PANEL_PREV_3D_BASE::PANEL_PREV_3D_BASE( wxWindow* parent, wxWindowID id, const w
 	fgSizerOffset->Add( m_staticText22, 0, wxALIGN_CENTER_VERTICAL|wxLEFT, 5 );
 	
 	yoff = new wxTextCtrl( vbOffset->GetStaticBox(), wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
-	fgSizerOffset->Add( yoff, 0, wxALIGN_CENTER_VERTICAL|wxLEFT, 5 );
+	fgSizerOffset->Add( yoff, 0, wxALIGN_CENTER_VERTICAL|wxBOTTOM|wxLEFT|wxTOP, 5 );
 	
 	m_spinYoffset = new wxSpinButton( vbOffset->GetStaticBox(), wxID_ANY, wxDefaultPosition, wxDefaultSize, wxSP_ARROW_KEYS|wxSP_VERTICAL );
 	fgSizerOffset->Add( m_spinYoffset, 0, wxALIGN_CENTER_VERTICAL, 5 );
@@ -165,7 +164,7 @@ PANEL_PREV_3D_BASE::PANEL_PREV_3D_BASE( wxWindow* parent, wxWindowID id, const w
 	fgSizerOffset->Add( zoff, 0, wxALIGN_CENTER_VERTICAL|wxBOTTOM|wxLEFT, 5 );
 	
 	m_spinZoffset = new wxSpinButton( vbOffset->GetStaticBox(), wxID_ANY, wxDefaultPosition, wxDefaultSize, wxSP_ARROW_KEYS|wxSP_VERTICAL );
-	fgSizerOffset->Add( m_spinZoffset, 0, wxALIGN_CENTER_VERTICAL, 5 );
+	fgSizerOffset->Add( m_spinZoffset, 0, wxALIGN_CENTER_VERTICAL|wxBOTTOM, 5 );
 	
 	
 	vbOffset->Add( fgSizerOffset, 1, wxEXPAND, 5 );
diff --git a/3d-viewer/3d_cache/dialogs/panel_prev_3d_base.fbp b/3d-viewer/3d_cache/dialogs/panel_prev_3d_base.fbp
index 772d9b8..045f1cc 100644
--- a/3d-viewer/3d_cache/dialogs/panel_prev_3d_base.fbp
+++ b/3d-viewer/3d_cache/dialogs/panel_prev_3d_base.fbp
@@ -464,7 +464,7 @@
                                         </object>
                                         <object class="sizeritem" expanded="1">
                                             <property name="border">5</property>
-                                            <property name="flag">wxALIGN_CENTER_VERTICAL|wxLEFT</property>
+                                            <property name="flag">wxALIGN_CENTER_VERTICAL|wxBOTTOM|wxLEFT|wxTOP</property>
                                             <property name="proportion">0</property>
                                             <object class="wxTextCtrl" expanded="1">
                                                 <property name="BottomDockable">1</property>
@@ -813,7 +813,7 @@
                                         </object>
                                         <object class="sizeritem" expanded="1">
                                             <property name="border">5</property>
-                                            <property name="flag">wxALIGN_CENTER_VERTICAL</property>
+                                            <property name="flag">wxALIGN_CENTER_VERTICAL|wxBOTTOM</property>
                                             <property name="proportion">0</property>
                                             <object class="wxSpinButton" expanded="1">
                                                 <property name="BottomDockable">1</property>
@@ -1271,7 +1271,7 @@
                                         </object>
                                         <object class="sizeritem" expanded="1">
                                             <property name="border">5</property>
-                                            <property name="flag">wxALIGN_CENTER_VERTICAL|wxLEFT</property>
+                                            <property name="flag">wxALIGN_CENTER_VERTICAL|wxBOTTOM|wxLEFT|wxTOP</property>
                                             <property name="proportion">0</property>
                                             <object class="wxTextCtrl" expanded="1">
                                                 <property name="BottomDockable">1</property>
@@ -1620,7 +1620,7 @@
                                         </object>
                                         <object class="sizeritem" expanded="1">
                                             <property name="border">5</property>
-                                            <property name="flag">wxALIGN_CENTER_VERTICAL</property>
+                                            <property name="flag">wxALIGN_CENTER_VERTICAL|wxBOTTOM</property>
                                             <property name="proportion">0</property>
                                             <object class="wxSpinButton" expanded="1">
                                                 <property name="BottomDockable">1</property>
@@ -1717,7 +1717,7 @@
                                 <property name="name">vbOffset</property>
                                 <property name="orient">wxVERTICAL</property>
                                 <property name="parent">1</property>
-                                <property name="permission">none</property>
+                                <property name="permission">protected</property>
                                 <event name="OnUpdateUI"></event>
                                 <object class="sizeritem" expanded="1">
                                     <property name="border">5</property>
@@ -2078,7 +2078,7 @@
                                         </object>
                                         <object class="sizeritem" expanded="1">
                                             <property name="border">5</property>
-                                            <property name="flag">wxALIGN_CENTER_VERTICAL|wxLEFT</property>
+                                            <property name="flag">wxALIGN_CENTER_VERTICAL|wxBOTTOM|wxLEFT|wxTOP</property>
                                             <property name="proportion">0</property>
                                             <object class="wxTextCtrl" expanded="1">
                                                 <property name="BottomDockable">1</property>
@@ -2120,7 +2120,7 @@
                                                 <property name="pane_border">1</property>
                                                 <property name="pane_position"></property>
                                                 <property name="pane_size"></property>
-                                                <property name="permission">protected</property>
+                                                <property name="permission">public</property>
                                                 <property name="pin_button">1</property>
                                                 <property name="pos"></property>
                                                 <property name="resize">Resizable</property>
@@ -2427,7 +2427,7 @@
                                         </object>
                                         <object class="sizeritem" expanded="1">
                                             <property name="border">5</property>
-                                            <property name="flag">wxALIGN_CENTER_VERTICAL</property>
+                                            <property name="flag">wxALIGN_CENTER_VERTICAL|wxBOTTOM</property>
                                             <property name="proportion">0</property>
                                             <object class="wxSpinButton" expanded="1">
                                                 <property name="BottomDockable">1</property>
diff --git a/3d-viewer/3d_cache/dialogs/panel_prev_3d_base.h b/3d-viewer/3d_cache/dialogs/panel_prev_3d_base.h
index d1a497e..b3232ec 100644
--- a/3d-viewer/3d_cache/dialogs/panel_prev_3d_base.h
+++ b/3d-viewer/3d_cache/dialogs/panel_prev_3d_base.h
@@ -1,5 +1,5 @@
 ///////////////////////////////////////////////////////////////////////////
-// C++ code generated with wxFormBuilder (version Aug  4 2017)
+// C++ code generated with wxFormBuilder (version Mar 22 2017)
 // http://www.wxformbuilder.org/
 //
 // PLEASE DO "NOT" EDIT THIS FILE!
@@ -57,11 +57,11 @@ class PANEL_PREV_3D_BASE : public wxPanel
 		wxStaticText* m_staticText31;
 		wxTextCtrl* zrot;
 		wxSpinButton* m_spinZrot;
+		wxStaticBoxSizer* vbOffset;
 		wxStaticText* m_staticText12;
 		wxTextCtrl* xoff;
 		wxSpinButton* m_spinXoffset;
 		wxStaticText* m_staticText22;
-		wxTextCtrl* yoff;
 		wxSpinButton* m_spinYoffset;
 		wxStaticText* m_staticText32;
 		wxTextCtrl* zoff;
@@ -99,6 +99,7 @@ class PANEL_PREV_3D_BASE : public wxPanel
 		
 	
 	public:
+		wxTextCtrl* yoff;
 		
 		PANEL_PREV_3D_BASE( wxWindow* parent, wxWindowID id = wxID_ANY, const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( 503,371 ), long style = wxTAB_TRAVERSAL ); 
 		~PANEL_PREV_3D_BASE();
diff --git a/3d-viewer/3d_cache/dialogs/panel_prev_model.cpp b/3d-viewer/3d_cache/dialogs/panel_prev_model.cpp
index 3cc07b5..4656e1e 100644
--- a/3d-viewer/3d_cache/dialogs/panel_prev_model.cpp
+++ b/3d-viewer/3d_cache/dialogs/panel_prev_model.cpp
@@ -125,7 +125,29 @@ void PANEL_PREV_3D::initPanel()
     };
 
     for( int ii = 0; ii < 9; ii++ )
+    {
         spinButtonList[ii]->SetRange( INT_MIN, INT_MAX );
+    }
+
+    wxString units;
+
+    switch( g_UserUnit )
+    {
+    case INCHES:
+        units = _( "inches" );
+        break;
+    case MILLIMETRES:
+        units = _( "mm" );
+        break;
+    default:
+        break;
+    }
+
+    if( !units.IsEmpty() )
+    {
+        units = wxString::Format( _( "Offset (%s)" ), units );
+        vbOffset->GetStaticBox()->SetLabel( units );
+    }
 }
 
 
@@ -214,26 +236,26 @@ void PANEL_PREV_3D::SetModelDataIdx( int idx, bool aReloadPreviewModule )
             yrot->SetValue( wxString::Format( "%.2f", aModel->m_Rotation.y ) );
             zrot->SetValue( wxString::Format( "%.2f", aModel->m_Rotation.z ) );
 
+            // Convert from internal units (mm) to user units
+
+            double scaler = 1;
+
             switch( g_UserUnit )
             {
             case MILLIMETRES:
-                xoff->SetValue( wxString::Format( "%.4f", aModel->m_Offset.x * 25.4 ) );
-                yoff->SetValue( wxString::Format( "%.4f", aModel->m_Offset.y * 25.4 ) );
-                zoff->SetValue( wxString::Format( "%.4f", aModel->m_Offset.z * 25.4 ) );
+                scaler = 1.0f;
                 break;
-
             case INCHES:
-                xoff->SetValue( wxString::Format( "%.4f", aModel->m_Offset.x ) );
-                yoff->SetValue( wxString::Format( "%.4f", aModel->m_Offset.y ) );
-                zoff->SetValue( wxString::Format( "%.4f", aModel->m_Offset.z ) );
+                scaler = 25.4f;
                 break;
-
-            case DEGREES:
-            case UNSCALED_UNITS:
             default:
-                wxASSERT(0);
+                wxASSERT( 0 );
             }
 
+            xoff->SetValue( wxString::Format( "%.4f", aModel->m_Offset.x / scaler ) );
+            yoff->SetValue( wxString::Format( "%.4f", aModel->m_Offset.y / scaler ) );
+            zoff->SetValue( wxString::Format( "%.4f", aModel->m_Offset.z / scaler ) );
+
             UpdateModelName( aModel->m_Filename );
 
             if( aReloadPreviewModule && m_previewPane )
@@ -249,7 +271,9 @@ void PANEL_PREV_3D::SetModelDataIdx( int idx, bool aReloadPreviewModule )
     }
 
     if( m_previewPane )
+    {
         m_previewPane->SetFocus();
+    }
 
     return;
 }
@@ -565,25 +589,26 @@ void PANEL_PREV_3D::getOrientationVars( SGPOINT& aScale, SGPOINT& aRotation, SGP
     yoff->GetValue().ToDouble( &aOffset.y );
     zoff->GetValue().ToDouble( &aOffset.z );
 
+    // Convert from user units to internal units (mm)
+
+    double scaler = 1.0f;
+
     switch( g_UserUnit )
     {
     case MILLIMETRES:
-        // Convert to Inches. Offset is stored in inches.
-        aOffset.x = aOffset.x / 25.4;
-        aOffset.y = aOffset.y / 25.4;
-        aOffset.z = aOffset.z / 25.4;
+        scaler = 1.0f;
         break;
-
     case INCHES:
-        // It is already in Inches
+        scaler = 25.4f;
         break;
-
-    case DEGREES:
-    case UNSCALED_UNITS:
     default:
-        wxASSERT(0);
+        wxASSERT( 0 );
     }
 
+    aOffset.x *= scaler;
+    aOffset.y *= scaler;
+    aOffset.z *= scaler;
+
     return;
 }
 
diff --git a/3d-viewer/3d_rendering/3d_render_ogl_legacy/c3d_render_ogl_legacy.cpp b/3d-viewer/3d_rendering/3d_render_ogl_legacy/c3d_render_ogl_legacy.cpp
index 19b4616..72f36a6 100644
--- a/3d-viewer/3d_rendering/3d_render_ogl_legacy/c3d_render_ogl_legacy.cpp
+++ b/3d-viewer/3d_rendering/3d_render_ogl_legacy/c3d_render_ogl_legacy.cpp
@@ -1046,9 +1046,7 @@ void C3D_RENDER_OGL_LEGACY::render_3D_module( const MODULE* module,
                         {
                             glPushMatrix();
 
-                            glTranslatef( sM->m_Offset.x * 25.4f,
-                                          sM->m_Offset.y * 25.4f,
-                                          sM->m_Offset.z * 25.4f );
+                            glTranslatef( sM->m_Offset.x, sM->m_Offset.y, sM->m_Offset.z );
 
                             glRotatef( -sM->m_Rotation.z, 0.0f, 0.0f, 1.0f );
                             glRotatef( -sM->m_Rotation.y, 0.0f, 1.0f, 0.0f );
diff --git a/3d-viewer/3d_rendering/3d_render_raytracing/c3d_render_createscene.cpp b/3d-viewer/3d_rendering/3d_render_raytracing/c3d_render_createscene.cpp
index 592d141..85e81cb 100644
--- a/3d-viewer/3d_rendering/3d_render_raytracing/c3d_render_createscene.cpp
+++ b/3d-viewer/3d_rendering/3d_render_raytracing/c3d_render_createscene.cpp
@@ -1263,9 +1263,9 @@ void C3D_RENDER_RAYTRACING::load_3D_models()
                     glm::mat4 modelMatrix = moduleMatrix;
 
                     modelMatrix = glm::translate( modelMatrix,
-                                                  SFVEC3F( sM->m_Offset.x * 25.4f,
-                                                           sM->m_Offset.y * 25.4f,
-                                                           sM->m_Offset.z * 25.4f ) );
+                                                  SFVEC3F( sM->m_Offset.x,
+                                                           sM->m_Offset.y,
+                                                           sM->m_Offset.z ) );
 
                     modelMatrix = glm::rotate( modelMatrix,
                                                (float)-( sM->m_Rotation.z / 180.0f ) *
diff --git a/pcbnew/class_module.h b/pcbnew/class_module.h
index f8f74a6..d45caa0 100644
--- a/pcbnew/class_module.h
+++ b/pcbnew/class_module.h
@@ -82,6 +82,14 @@ enum MODULE_ATTR_T
 class MODULE_3D_SETTINGS
 {
     public:
+        MODULE_3D_SETTINGS() :
+            // Initialize with sensible values
+            m_Scale { 1, 1, 1 },
+            m_Rotation { 0, 0, 0 },
+            m_Offset { 0, 0, 0 }
+        {
+        }
+
         struct VECTOR3D
         {
             double x, y, z;
diff --git a/pcbnew/exporters/export_vrml.cpp b/pcbnew/exporters/export_vrml.cpp
index 66dda6b..8197d58 100644
--- a/pcbnew/exporters/export_vrml.cpp
+++ b/pcbnew/exporters/export_vrml.cpp
@@ -1349,11 +1349,13 @@ static void export_vrml_module( MODEL_VRML& aModel, BOARD* aPcb,
         compose_quat( q1, q2, q1 );
         from_quat( q1, rot );
 
+        double offsetFactor = 1000.0f * IU_PER_MILS / 25.4f;
+
         // adjust 3D shape local offset position
-        // they are given in inch, so they are converted in board IU.
-        double offsetx = sM->m_Offset.x * IU_PER_MILS * 1000.0;
-        double offsety = sM->m_Offset.y * IU_PER_MILS * 1000.0;
-        double offsetz = sM->m_Offset.z * IU_PER_MILS * 1000.0;
+        // they are given in mm, so they are converted in board IU.
+        double offsetx = sM->m_Offset.x * offsetFactor;
+        double offsety = sM->m_Offset.y * offsetFactor;
+        double offsetz = sM->m_Offset.z * offsetFactor;
 
         if( isFlipped )
             offsetz = -offsetz;
diff --git a/utils/kicad2step/pcb/kicadmodel.cpp b/utils/kicad2step/pcb/kicadmodel.cpp
index 6c4c033..6f680e0 100644
--- a/utils/kicad2step/pcb/kicadmodel.cpp
+++ b/utils/kicad2step/pcb/kicadmodel.cpp
@@ -28,7 +28,10 @@
 #include "kicadmodel.h"
 
 
-KICADMODEL::KICADMODEL() : m_scale( 1.0, 1.0, 1.0 )
+KICADMODEL::KICADMODEL() :
+    m_scale( 1.0, 1.0, 1.0 ),
+    m_offset( 0.0, 0.0, 0.0 ),
+    m_rotation( 0.0, 0.0, 0.0 )
 {
     return;
 }
diff --git a/utils/kicad2step/pcb/oce_utils.cpp b/utils/kicad2step/pcb/oce_utils.cpp
index dcf9825..dccd5c6 100644
--- a/utils/kicad2step/pcb/oce_utils.cpp
+++ b/utils/kicad2step/pcb/oce_utils.cpp
@@ -996,10 +996,9 @@ bool PCBMODEL::getModelLocation( bool aBottom, DOUBLET aPosition, double aRotati
     gp_Trsf lPos;
     lPos.SetTranslation( gp_Vec( aPosition.x, -aPosition.y, 0.0 ) );
 
-    // offset (inches)
-    aOffset.x *= 25.4;
-    aOffset.y *= 25.4;
-    aOffset.z *= 25.4 + BOARD_OFFSET;
+    // Offset board thickness
+    aOffset.z += BOARD_OFFSET;
+
     gp_Trsf lRot;
 
     if( aBottom )
-- 
2.7.4


Follow ups