5.3. Selección de la Cara.

La primera operación a implementar será la selección de la cara al pulsar el botón Selección Cara (cmdSeleccionar). La selección deberá utilizar el módulo de clase que desarrollamos en el ejercicio 4.2. Selección Interactiva. Para ello podemos simplemente exportar el módulo de clase desde aquél proyecto e importarlo en el nuevo proyecto (ver Figura 3).


Figura 3. Exportación del módulo de clase.
Una vez disponible este módulo en nuestro proyecto implementaremos el procedimiento de respuesta al evento Click del botón cmdSeleccionar.
La selección implica la creación de una nueva instancia de la clase, establecer los valores de sus propiedades Filtro y Mensaje e invocar a continuación el método Designa, que devolverá el objeto Face seleccionado por el usuario. Para permitir la selección el formulario, en este caso definido como modal, se ocultará.

Private Sub cmdSeleccionar_Click()
    Dim oSelecc As New clsSeleccionar

    oSelecc.Filtro = kPartFaceFilter
    oSelecc.Mensaje = "seleccione una cara"
    Me.Hide
    Set oCara = oSelecc.Designa(1)

Una vez devuelta la selección se deberá comprobar que se trate de una cara plana circular, según se explica más arriba. Ya con esto bastaría, pero haremos algo más, que será calcular una serie de valores predefinidos de acuerdo con las dimensiones de la cara que sirvan de orientación al usuario.
Estas opciones serán las siguientes:

 Número de agujeros:  6 agujeros
 Radio de la matriz (a centros de agujero):
 2/3 del radio de la cara.
 Diámetro del agujero:
 1/12 de la circunferencia
 Profundidad del agujero:
 el doble del diámetro

Una vez hecha la selección y comprobado que se trate de una cara circular, se calculan los valores por defecto según los criterios expuestos:

If oCara.Edges.Count = 1 And oCara.Edges.Item(1).CurveType = kCircleCurve Then
    Dim dblRadio As Double

    Dim dblRadMat As Double
    Dim dblDiam As Double

 ' se calculan valores por defecto a partir de las dimensiones de la cara.
  ' el número de agujeros predeterminado será 6

    dblRadio = oCara.Edges.Item(1).Geometry.Radius   ' radio de la cara
    dblRadMat = dblRadio * 2 / 3                     ' radio de la matriz
    dblDiam = 3.1416 * dblRadMat / 6                 ' diámetro del agujero
    If dblDiam > 1 Then
          dblDiam = Fix(dblDiam)                     ' diámetro a entero
    End If

Ahora, para pasar los valores a los cuadros de texto será necesario convertirlos a las unidades del documento recurriendo al objeto UnitsOfMeasure (ver lo explicado en el ejercicio 2.4. Expresión de las unidades en los valores predeterminados del dibujo). El objeto UnitsOfMeasure estará referenciado por la variable oUOM, declarada como global y a la que se puede asignar su valor en el evento Initialize del formulario. Antes de actualizar los datos debemos aactivar las casillas de texto y sus etiquetas identificadoras:

txtCant.Enabled = True
lblCant.Enabled = True
txtRad.Enabled = True
lblRad.Enabled = True
txtDiam.Enabled = True
lblDiam.Enabled = True
txtProf.Enabled = True
lblProf.Enabled = True

txtCant.Value = 6     
txtRadio.Text = oUOM.GetStringFromValue(dblRadMat, kDefaultDisplayLengthUnits)
txtDiam.Text = oUOM.GetStringFromValue(dblDiam, kDefaultDisplayLengthUnits)
txtProf.Text = oUOM.GetStringFromValue(dblDiam * 2, kDefaultDisplayLengthUnits)

Y se presentarán los datos de la cara seleccionada en la etiqueta lblInfo. EStos datos serán el radio y las coordenadas del centro de la cara.

Dim dblCentroX As Double
Dim dblCentroY As Double

dblCentroX = oCara.Edges.Item(1).Geometry.Center.X
dblCentroY = oCara.Edges.Item(1).Geometry.Center.Y

lblInfo.Caption = "Radio de la cara seleccionada: " & _
   oUOM.GetStringFromValue(dblRadio, kDefaultDisplayLengthUnits) & _
   vbCrLf & "Coordenadas locales del centro: (" & _
   oUOM.GetValueFromExpression(dblCentroX, kDefaultDisplayLengthUnits) & "," & _
   oUOM.GetValueFromExpression(dblCentroY, kDefaultDisplayLengthUnits) & ")"

En caso de que la selección no sea de una cara plana circular se deberá advertir de ello al usuario mediante un mensaje en la etiqueta lblInfo. Para llamar la atención se podrá colorear de rojo el texto, lo que habrá que tener en cuenta posteriormente para restituir el color original.

Else
         lblInfo.ForeColor = vbRed
         lblInfo.Caption = "ERROR: Debe seleccionar una cara plana circular"
End If
Me.Show
End Sub

Habrá que tener en cuenta la diferencia entre las unidades visualizadas en los cuadros de texto y las internas del sistema para cuando se realicen cambios en dichas casillas. Para ello será necesario tener en cuenta la sucesión de eventos que se producen al entrar a editar uno de los cuadros, al cambiar los valores y al salir para editar otro cuadro o pulsar algún botón.

Como ejemplo indicaremos los procedimientos de respuesta a dichos eventos para el botón cmdRadio.

Evento Enter.

Al entrar a editar la casilla de texto eliminaremos los caracteres " mm" del texto:

Private Sub txtRadio_Enter()
   txtRadio.Text = Left(txtRadio.Text, Len(txtRadio.Text) - 3)
End Sub

Evento Change.

Este evento se dispara cada vez que se hace un cambio en el texto de la casilla, carácter a carácter. Lo aprovechamos para advertir si se introduce algún valor ilegal (letras o números negativos). Observe que en caso de error se escribe un mensaje en color rojo en la etiqueta lblInfo.

Private Sub txtRadio_Change()
    If IsNumeric(txtRadio.Value) Then
        txtRadio.ForeColor = vbBlack
        If txtRadio.Value <= 0 Then
            lblInfo.Caption = "El valor debe ser mayor que cero"
            txtRadio.ForeColor = vbRed
        End If
    Else
        lblInfo.Caption = "El valor debe ser numérico"
        txtRadio.ForeColor = vbRed
    End If
End Sub

Evento BeforeUpdate.

Recurrimos al evento BeforeUpdate para evitar que se salga de la casilla habiendo insertado un valor erróneo. En este caso se recurre a detectar el error que se produciría en caso de que la expresión no fuera válida para detectar valores no numéricos. Establecer el argumento Cancel en True impide salir del cuadro que se está editando.

Private Sub txtRadio_BeforeUpdate(ByVal Cancel As MSForms.ReturnBoolean)
    Err.Clear
    On Error Resume Next
    If (oUOM.GetValueFromExpression(txtRadio, kDefaultDisplayLengthUnits) _
        < 0 Or Err.Number <> 0) Then

        txtRadio.ForeColor = vbRed
        lblInfo.Caption = "El valor debe ser un número mayor que cero"
        Cancel = True
    Else
        txtRadio.ForeColor = vbBlack
        lblInfo.Caption = ""
        Cancel = False
    End If
End Sub

Evento Exit.

Este evento se produce al cambiar el foco a otro control del formulario. Este procedimiento actualiza la cadena de caracteres en el cuadro de texto y elimina cualquier mensaje de error en lblInfo.

Private Sub txtRadio_Exit(ByVal Cancel As MSForms.ReturnBoolean)
    txtRadio.Text = _
    oUOM.GetStringFromValue(oUOM.GetValueFromExpression(txtRadio.Text,                kDefaultDisplayLengthUnits), kDefaultDisplayLengthUnits)

    txtRadio.ForeColor = vbBlack
    lblInfo.Caption = ""
End Sub

Comprobar Datos.

Las dimensiones que introduzca el usuario pueden hacer que los agujeros queden situados total o parcialmente fuera de la cara, o que se solapen entre ellos. Aunque casi nunca esto provocaría un error de la aplicación, los resultados no serían los que se pretende alcanzar con la herramienta. Para evitar esto se ha incluído en el formulario un botón para comprobar la coherencia de los datos. Solo cuando se comprueben los mismos se activará el botón Aplicar.
Los datos a comprobar serán:
  • que el diámetro de la matriz no sea mayor que el diámetro de la cara,
  • que la suma de los diámetros de los agujeros sea menor que la circunferencia donde se ubican los centros de los agujeros.
Si las condiciones se cumplen se activará el botón Aplicar. En caso contrario este botón permanecerá desactivado y se presentará un mensaje en la etiqueta lblInfo indicando los errores detectados. Esto se hará dentro del procedimiento de respuesta al evento Clic del botón cmdConfirmar.

Private Sub cmdConfirmar_Click()
    Dim strMsj As String
    strMsj = ""

    Dim dblDiaTotal As Double
    dblDiaTotal = _
        oUOM.GetValueFromExpression _
        (frmMatrizAg.txtDiam.Text, kDefaultDisplayLengthUnits) + _

        (2 * oUOM.GetValueFromExpression _
        (frmMatrizAg.txtRadio.Text, kDefaultDisplayLengthUnits))


    Dim dblDistCtr As Double
    dblDistCtr = 2 * (oUOM.GetValueFromExpression _
                (frmMatrizAg.txtRadio.Text, kDefaultDisplayLengthUnits) * _

                Sin(3.1416 / frmMatrizAg.txtCant.Value))
    Dim dblDiaAgujero As Double
    dblDiaAgujero = oUOM.GetValueFromExpression _
                    (frmMatrizAg.txtDiam.Text, kDefaultDisplayLengthUnits)


    If (dblDiaTotal > oCara.Edges.Item(1).Geometry.Radius * 2) Then
            strMsj = "Los agujeros se saldrán de la pieza," & vbCrLf & _
            "Datos;" & vbCrLf & _

            "Diámetro externo de la matriz propuesta:" & _
            oUOM.GetStringFromValue(dblDiaTotal, kDefaultDisplayLengthUnits) _
            & vbCrLf &
"Diámetro de la Pieza: " & _
            oUOM.GetStringFromValue(oCara.Edges.Item(1).Geometry.Radius _
            * 2, kDefaultDisplayLengthUnits)

    End If

    If dblDistCtr <= dblDiaAgujero Then
            strMsj = strMsj & vbCrLf & _
            "Los agujeros se solaparán." & vbCrLf & "Datos:" & vbCrLf & _
            "Distancia entre agujeros:" & dblDistCtr & vbCrLf & _
            "Diámetro de los agujeros: " & frmMatrizAg.txtDiam.Text
    End If

    If strMsj = "" Then
        cmdAceptar.Enabled = True
    Else
        cmdAceptar.Enabled = False
    End If

    lblInfo.Caption = strMsj
End Sub