Modulo 6

Descargar como docx, pdf o txt
Descargar como docx, pdf o txt
Está en la página 1de 73

SIMULACIONES

MÓDULO # 6: OOP -HERENCIA E INTERFACE-


Diego Luis Aristizábal R, Profesor asociado con tenencia del cargo
Escuela de Física
Universidad Nacional de Colombia Sede Medellín
2020-02

Temas
 RECORDANDO
 HERENCIA: UN PRIMER ACERCAMIENTO
 MI NOVENA APP
 HERENCIA: SOBRE-ESCRITURA DE MÉTODO
 MI DECIMA APP
 HERENCIA: CLASE ABSTRACTA
 MI DECIMA PRIMERA APP
 INTERFACE
 MI DECIMO SEGUNDA APP
 TALLER
 REFERENCIAS

RECORDANDO

La programación orientada a objetos (OOP por sus siglas en inglés) es un paradigma de

programación modelada con base en la forma como funciona el mundo real: objetos con

comportamientos específicos que a su vez se conforman de objetos más pequeños. En este

paradigma de programación los programas se organizan como colecciones cooperativas de

objetos, cada uno de los cuales representa una instancia de alguna clase, y cuyas clases son

todos miembros de una jerarquía de clases unidas mediante relaciones.

La programación orientada a objetos está basada en los siguientes conceptos:

 Abstracción: clase y objeto

 Encapsulamiento

 Composición

 Polimorfismo

 Herencia

 Clase abstracta

 Interface
Se dice que, si alguno de estos elementos no existe, entonces el modelo no es orientado a

objetos. En el módulo # 5 se abordaron los conceptos clase, objeto, encapsulamiento,

composición y polimorfismo por sobrecarga de método.

En este módulo se aborda el concepto de herencia. Se comienza dando un primer

acercamiento a este concepto. Luego se ilustra cómo implementar la herencia usando

sobre-esctirtura de métodos, lo que se conoce como polimorfismo por sobre-escritura de

métodos (en el módulo anterior se hizo polimorfismo por sobrecarga de métodos). Se 2


continúa explicando cómo implementar la herencia usando el concepto de clase abstracta.

Por último, se aborda las denominadas interfaces como una forma de reemplazar la

herencia múltiple del C++.

HERENCIA: UN PRIMER ACERCAMIENTO

La herencia es una propiedad esencial de la Programación Orientada a Objetos que consiste

en la creación de nuevas clases a partir de otras ya existentes. Este término ha sido

prestado de la Biología donde se afirma que un niño tiene la cara de su padre, que ha

heredado ciertas facetas físicas o del comportamiento de sus progenitores.

La herencia es la característica fundamental que distingue un lenguaje orientado a objetos,

como el C++ o Java, de otro convencional como C, BASIC, etc. Java permite heredar a una

clase características y conductas de otra clase denominada base. Las clases que heredan

de clases base se denominan derivadas, estas a su vez pueden ser clases bases para otras

clases derivadas. Se establece así una clasificación jerárquica, similar a la existente en

Biología con los animales y las plantas.

La herencia ofrece una ventaja importante, permite la reutilización del código. Una vez que

una clase ha sido depurada y probada, el código fuente de dicha clase no necesita

modificarse. Su funcionalidad se puede cambiar derivando una nueva clase que herede la

funcionalidad de la clase base y le añada otros comportamientos. Reutilizando el código

existente, el programador ahorra tiempo y dinero, ya que solamente tiene que verificar la

nueva conducta que proporciona la clase derivada.


Los programadores crean clases base:

 Cuando se dan cuenta que diversos tipos tienen algo en común, por ejemplo, en el juego

del ajedrez peones, alfiles, rey, reina, caballos y torres, son piezas del juego. Creamos,

por tanto, una clase base y derivamos cada pieza individual a partir de dicha clase base.

 Cuando se precisa ampliar la funcionalidad de un programa sin tener que modificar el

código existente.

3
Por seguridad en el código Java NO permite la herencia múltiple, es decir, que una clase

herede de varias clases (el lenguaje C++ si lo permite). Para resolver las ventajas de la

herencia múltiple Java emplea el concepto de interface el cual se abordará al final de

este módulo.

En este módulo se ilustrará el concepto de herencia aplicándolo al comportamiento

mecánico de diferentes cuerpos rígidos. Para facilitar la comprensión de un primer ejemplo

sólo se considerarán tres de éstos: poleas, bloques recangulares y ruedas. Para simular este

comportamiento se definen cuatro clases: la clase madre (superclase o clase base)

CuerpoRigido y las clases que darán origen a objetos Polea, CuerpoRectangular y

Rueda, las cuales heredan atributos y comportamientos de la clase CuerpoRigido (son

hijas: subclases o clases derivadas).

Para simular el movimiento de los cuerpos rígidos debe pensarse en que todo cuerpo rígido

puede trasladarse y/o rotar alrededor de un eje que pasa por su centro de masa. Todos

tienen el atributo masa y momento de inercia (que no se agregarán en este ejemplo para no

dificultar su comprensión). Para dibujarlos en una representación todos tienen un atributo

como el color, entre otros (grosor de línea, color de los bordes…, que no se agregarán en

este ejemplo para no dificultar su comprensión) y necesitan del método que los dibuje.

Adicionalmente es necesario poderlos posicionar por lo que deben tener el método

respectivo para lograr esto. Con base en este análisis se puede pensar en diseñar una clase

madre que tenga estos atributos y comportamientos comunes a todos los cuerpos rígidos y

ésta será la clase que se denominará en este módulo CuerpoRigido.

Para poderse dibujar los objetos de las clases Polea y Rueda necesitarán adicionalmente

el atributo radio y los ojbetos tipo CuerpoRectangular necesitarán los atributoa largo y
alto. Estas clases heredarán de CuerpoRigido y agregarán o implementarán sus

particularidades. En la Figura 1 se ilustra el árbol de herencia que se implementará.

Figura 1

A continuación, se ilustra el código respectivo de estas clases y que se empleará en la

siguiente app (MiNovenaApp). En el código de la clase CuerpoRigido no se incluirá el

método dibujese( ), éste será incluido en las clases hijas. En las siguientes dos apps se

incluirá en CuerpoRigido y será también heredado en las hijas: en MiDecimaApp se hará

la inclusión a través del concepto sobresescritura y en MiDecimoPrimerApp se hará la

inclusión a través del concepto de clase abstracta. En la última app de este módulo este

método se incluirá en las clases, pero a través del concepto de interface.

Clase CuerpoRigido:

public class CuerpoRigido {

protected float posicionCentroMasaX, posicionCentroMasaY;


protected float posicionEjeRotacionX, posicionEjeRotacionY;
protected float posicionAngularRotacionEjeXY;
protected int color = Color.RED;

/**
* Constructor por defecto del cuerpo rígido.
* Su centro de masa está ubicado en la
* posición (0,0). La posición angular es cero
* y su color es rojo
*/
public CuerpoRigido() {

/**
* Constructor de CuerpoRigido
* cuyo centro de masa está
* ubicado en (posicionInicialX,posicionInicialX)
*/

public CuerpoRigido(float posicionInicialX, float


posicionInicialY) {
this.posicionCentroMasaX = posicionInicialX;
this.posicionCentroMasaY = posicionInicialY;
}

/**
* Modifica el color del cuerpo rígido
*
* @param color
*/ 5
public void setColor(int color) {
this.color = color;
}

/**
* Devuelve el color del cuerpo rígido
*
* @return
*/
public int getColor() {
return color;
}

/*
Se podría hacer un método setPosicion(x,y)
para cambiar la posición del centro de masa, pero más adelante
esta el método mover(x,y) que hace esto
*/

/**
* Retorna la posicion en X
* del centro de masa
*
* @return
*/

public float getPosicionX() {

return posicionCentroMasaX;
}

/**
* Retorna posicion en Y
* del centro de masa
*
* @return
*/
public float getPosicionY() {

return posicionCentroMasaY;
}

/**
* Modifica la posición (posicionCentroMasaX,posicionCentroMasaY)
* del centro de masa del cuerpo rígido
*
* @param posicionCentroMasaX
* @param posicionCentroMasaY
*/
public void mover(float posicionCentroMasaX, float
posicionCentroMasaY) {
this.posicionCentroMasaX = posicionCentroMasaX;
this.posicionCentroMasaY = posicionCentroMasaY;

/** 6
* Modifica la posición angular del cuerpo rígido
* alrededor de une eje uqe pasa por su centro
* de masa
*
* @param posicionAngular
*/
public void mover(float posicionAngular) {
// this.posicionAngularRotacionCentroMasa = posicionAngular;
this.posicionEjeRotacionX = posicionCentroMasaX;
this.posicionEjeRotacionY = posicionCentroMasaY;

this.posicionAngularRotacionEjeXY=posicionAngular;
}

/**
* Modifica la posición (posicionCentroMasaX,posicionCentroMasaY)
* del centro de masa del cuerpo rígido y genera una rotación
* alrededor del eje que pasa por éste
* @param posicionCentroMasaX
* @param posicionCentroMasaY
* @param posicionAngular
*/

public void mover(float posicionCentroMasaX, float


posicionCentroMasaY, float posicionAngular){
this.posicionCentroMasaX=posicionCentroMasaX;
this.posicionCentroMasaY=posicionCentroMasaY;

this.posicionEjeRotacionX = posicionCentroMasaX;
this.posicionEjeRotacionY = posicionCentroMasaY;

this.posicionAngularRotacionEjeXY=posicionAngular;
}

/**
* Genera rotación del cuerpo rígido a la
* posición angular posicionAngularRotacionEjeXY
* alrededor de eje que pasa por
* (posicionEjeRotacionX,posicionEjeRotacionY)
* @param posicionEjeRotacionX
* @param posicionEjeRotacionY
* @param posicionAngular
*/

public void rotar(float posicionEjeRotacionX, float


posicionEjeRotacionY, float posicionAngular){
this.posicionEjeRotacionX=posicionEjeRotacionX;
this.posicionEjeRotacionY=posicionEjeRotacionY;

this.posicionAngularRotacionEjeXY=posicionAngular;

7
Clase Polea:

public class Polea extends CuerpoRigido {

protected float radio;

/**
* Constructor por defecto
* Polea centrada en (0,0)
* y de radio 50f
*/
public Polea() {
super();
this.radio = 50f;
}

/**
* Constructor de Polea centrada
* en (posicionX,posicionY)
* y diámetro igual a 2*radio
*/

public Polea(float posicionCentroMasaX, float


posicionCentroMasaY, float radio) {
super(posicionCentroMasaX, posicionCentroMasaY);
this.radio = radio;
}

/**
* Modifica el valor del radio de la polea
*
* @param radio
*/
public void setRadio(float radio) {
this.radio = radio;
}

/**
* Devuelve el valor del radio de la polea
*
* @return
*/
public float getRadio() {
return radio;
}

public void dibujese(Canvas canvas, Paint pincel) {

//estilo del pindel


pincel.setStyle(Paint.Style.STROKE);
//grosor del pincel
pincel.setStrokeWidth(2f);
//color del pincel 8
pincel.setColor(color);

canvas.save();
//rotar

canvas.rotate(posicionAngularRotacionEjeXY,posicionEjeRotacionX,posic
ionEjeRotacionY);
//dibujar circunferencia de la polea
canvas.drawCircle(posicionCentroMasaX, posicionCentroMasaY,
radio, pincel);
//dibujar las líenas radiales de la polea
for (int i = 0; i < 12; i = i + 1) {
//rotar de a 36 grados
canvas.rotate(i * 36f, posicionCentroMasaX,
posicionCentroMasaY);
canvas.drawLine(posicionCentroMasaX, posicionCentroMasaY,
posicionCentroMasaX, posicionCentroMasaY - radio, pincel);
//retroceder la rotación
canvas.rotate(-i * 36f, posicionCentroMasaX,
posicionCentroMasaY);
}//fin for

//regresar la rotación
canvas.restore();
}

Clase Rueda:

public class Rueda extends CuerpoRigido {

protected float radio;

/**
* Constructor por defecto
* Rueda centrada en (0,0)
* y de radio 50f
*/
public Rueda() {
super();
this.radio = 50f;
}

/**
* Constructor de Rueda centrada
* en (posicionCentroMasaX,posicionCentroMasaY)
* y diámetro igual a 2*radio 9
*/

public Rueda(float posicionCentroMasaX, float


posicionCentroMasaY, float radio) {
super(posicionCentroMasaX, posicionCentroMasaY);
this.radio = radio;

/**
* Modifica el valor del radio de la rueda
*
* @param radio
*/
public void setRadio(float radio) {
this.radio = radio;
}

/**
* Devuelve el valor del radio de la rueda
*
* @return
*/
public float getRadio() {
return radio;
}

public void dibujese(Canvas canvas, Paint pincel) {

//estilo del pindel


pincel.setStyle(Paint.Style.STROKE);
//grosor del pincel
pincel.setStrokeWidth(2f);
//color del pincel
pincel.setColor(color);

canvas.save();
//rotar

canvas.rotate(posicionAngularRotacionEjeXY,posicionEjeRotacionX,posic
ionEjeRotacionY);
//dibujar círculo de la rueda
pincel.setStyle(Paint.Style.FILL);
canvas.drawCircle(posicionCentroMasaX, posicionCentroMasaY,
radio, pincel);
pincel.setColor(Color.BLACK);
//dibujar punticos negro para poder bservar la rotación de la
rueda

for (int i = 0; i < 6; i = i + 1) {


//rotar de a 36 grados
canvas.rotate(i * 60f, posicionCentroMasaX,
posicionCentroMasaY);
canvas.drawCircle(posicionCentroMasaX - 0.2f * radio,
posicionCentroMasaY - 0.3f * radio, 0.1f * radio, pincel);
canvas.rotate(-i * 60f, posicionCentroMasaX,
posicionCentroMasaY); 10
}

//dibujar circunferencia de la rueda


pincel.setStyle(Paint.Style.STROKE);
canvas.drawCircle(posicionCentroMasaX, posicionCentroMasaY,
radio, pincel);

//regresa la rotación
canvas.restore();

Clase CuerpoRectangular:

public class CuerpoRectangular extends CuerpoRigido {

private float largo, alto;

/**
* Constructor por defecto
* Bloque centrado en (0,0)
* de largo 150f y de alto 100f
*/
public CuerpoRectangular() {
this.largo = 150f;
this.alto = 100f;
}

/**
* Constructor de cuerpo rectangular
* centrado en (posicionCentroMasaX,posicionCentroMasaY)
* de dimensiones largoxalto
*/

public CuerpoRectangular(float posicionCentroMasaX, float


posicionCentroMasaY, float largo, float alto) {
super(posicionCentroMasaX, posicionCentroMasaY);
this.largo = largo;
this.alto=alto;
}

/**
* Modifica el valor del largo del cuerpo
* rectangular *
* @param largo
*/
public void setLargo(float largo) {
this.largo = largo;
} 11

/**
* Devuelve el valor del largo del cuerpo
* rectangular
*
* @return
*/
public float getLargo() {
return largo;
}

/**
* Modifica el valor del ancho del cuerpo
* rectangular
*
* @param alto
*/
public void setAlto(float alto) {
this.alto = alto;
}

/**
* Devuelve el valor del alto del cuerpo
* rectangular
*
* @return
*/
public float getAlto() {
return alto;
}

public void dibujese(Canvas canvas, Paint pincel) {

//estilo del pindel


pincel.setStyle(Paint.Style.STROKE);
//grosor del pincel
pincel.setStrokeWidth(2f);
//color del pincel
pincel.setColor(color);

canvas.save();
//rotar
canvas.rotate(posicionAngularRotacionEjeXY,posicionEjeRotacionX,posic
ionEjeRotacionY);
//dibujar el relleno del bloque
pincel.setStyle(Paint.Style.FILL);
canvas.drawRect(posicionCentroMasaX-0.5f*largo,
posicionCentroMasaY-0.5f*alto,posicionCentroMasaX+0.5f*largo,
posicionCentroMasaY+0.5f*alto, pincel);
//dibujar el perímetro del bloque
pincel.setColor(Color.BLACK);
pincel.setStyle(Paint.Style.STROKE);
canvas.drawRect(posicionCentroMasaX-0.5f*largo,
posicionCentroMasaY-0.5f*alto,posicionCentroMasaX+0.5f*largo,
posicionCentroMasaY+0.5f*alto, pincel);
//regresar la rotación 12
canvas.restore();

MI NOVENA APP

Paso 1:

Con Android Studio craer un proyecto denominado MiNovenaApp (recordar que el proyecto

se debe crear tal cual se ha venido desarrollando los proyectos en el curso) y crear las

clases y paquetes que den la estructura de la Figura 2. A las clases del paquete

elementos_laboratorio agregar los códigos fuente dados atrás.


Figura 2

Paso 2: Código de Pizarra

Agregar el código siguiente a la clase Pizarra.

13

public class Pizarra extends View {

private Polea poleas[];


private Rueda ruedas[];
private CuerpoRectangular cuerposRect[];

/**
* Constructor
*
* @param context
*/
public Pizarra(Context context) {
super(context);

public void setEstadoEscena(Polea[] poleas, Rueda ruedas[],


CuerpoRectangular cuerposRect[]) {

this.poleas = poleas;
this.ruedas = ruedas;
this.cuerposRect = cuerposRect;

//Método para dibujar la escena


private void dibujarEscena(Canvas canvas, Paint pincel) {

//dibujar las poleas


for (int i = 0; i < poleas.length; i++) {
if (poleas[i] != null) {
poleas[i].dibujese(canvas, pincel);
}
}

//dibujar las ruedas


for (int i = 0; i < ruedas.length; i++) {
if (ruedas[i] != null && ruedas.length > 0) {
ruedas[i].dibujese(canvas, pincel);
}
}

//dibujar los cuerpos rectangularespoleas


for (int i = 0; i < cuerposRect.length; i++) {
if (cuerposRect[i] != null && cuerposRect.length > 0) {
cuerposRect[i].dibujese(canvas, pincel);
}

} 14

//método para dibujar


protected void onDraw(Canvas canvas) {
super.onDraw(canvas);

Paint pincel = new Paint();


//evita efecto sierra
pincel.setAntiAlias(true);

if (poleas != null)
dibujarEscena(canvas, pincel);

//necesario para actualizar los dibujos en animaciones


invalidate();

Paso 3: Código de HiloAnimacion

Agregar el código siguiente a la clase HiloAnimación.

public class HiloAnimacion extends Thread{

private boolean corriendo;


private long periodo_muestreo=50;//en milisegundos
public float tiempo;
//pizarra que contiene la escena física
private Pizarra pizarra;
//objetos cuerpos rígidos
private Polea[] poleas;
private Rueda[] ruedas;
private CuerpoRectangular[] cuerposRect;
/*
Este método construtor para un hilo que
maneja la animación de la pizarra
*/
public HiloAnimacion(Pizarra pizarra, Polea[] poleas, Rueda[]
ruedas, CuerpoRectangular[] cuerposRect ){
this.pizarra=pizarra;
this.poleas=poleas;
this.ruedas=ruedas;
this. cuerposRect=cuerposRect;
}

@Override 15
public void run(){

corriendo = true;

while (corriendo==true){

try {
Thread.sleep(periodo_muestreo);//esto en milisegundos
} catch (InterruptedException e) {
e.printStackTrace();
}

tiempo=tiempo+0.01f;
//cambio de estado de la escena física en la pizarra
cambiarEstadosEscenaPizarra(tiempo);

/*Cambia el esatado de los objetos caricatura y lo comunica a


pizarra*/
private void cambiarEstadosEscenaPizarra(float tiempo){

//polea_1
/*La polea 1 arranca de la posición x=100 y=100
Se traslada con velocidad constante en x Vx=200; Vy=0;
No rota alrededor de su eje, W=0
*/
float x_1= 100 + 200*tiempo;
float y_1=100;

//polea_2
/*La polea 2 se arranca de la posición x=100 y=250
No se traslada Vx=0; Vy=0;
Rota alrededor de su eje, W=100
*/
float x_2= 100;
float y_2=250;
float teta_2=100*tiempo;
//polea3
/*La polea 3 se arranca de la posición x=100 y=450
Se traslada Vx=200; Vy=0;
Rota alrededor de su eje, W=100
*/
float x_3= 100 + 200*tiempo;
float y_3=450;
float teta_3=100*tiempo;

//mover las poleas


poleas[0].mover(x_1,y_1);
poleas[1].mover(teta_2);
poleas[2].mover(x_3,y_3,teta_3); 16

/*
Rueda rotando alrededor de eje que pasa por
su centro de masa
*/
float teta_rueda=200*tiempo;
ruedas[0].mover(teta_rueda);

/*
La regla oscila armónicamente con frecuencia
igual a 2 Hz y amplitud 0.2 rad
y fase inicial cero
*/
float frecuencia= 2;
float teta_regla_radianes=(float)
(0.2*(Math.sin(2*Math.PI*frecuencia*tiempo)));
float teta_regla_grados= (float)
(Math.toDegrees(teta_regla_radianes));
cuerposRect[1].rotar(700,320,teta_regla_grados);

//actualizar escena
pizarra.setEstadoEscena(poleas, ruedas, cuerposRect);

}//fin Hilo

Paso 4: Código de la clase AcividadPrincipalMiNovenaApp

Agregar el código siguiente a la clase ActividadPrincipalMiNovenaApp.


public class ActividadPrincipalMiNovenaApp extends Activity {

//Pizarra para dibujar


Pizarra pizarra;
//objetos dibujables para Pizarra
private Polea polea_1,polea_2,polea_3;
private Rueda rueda_1;
private CuerpoRectangular bloque_1, regla_1;
public Polea[] poleas= new Polea[10];
public Rueda[] ruedas= new Rueda[10];
public CuerpoRectangular cuerposRect[]= new
CuerpoRectangular[10];

17
/*Hilo responsable de la animación
El trabajo de animación es mejor manejarlo en hilo
para evitar bloqueos de la aplicación
debido al manejo simultáneo de la GUI con la Acivity
*/
private HiloAnimacion hilo;

protected void onCreate(Bundle savedInstanceState) {


super.onCreate(savedInstanceState);

/*llamada al método para crear los elementos de la interfaz


gráfica de usuario (GUI)*/
crearElementosGui();

/*para informar cómo se debe adaptar la GUI a la pantalla del


dispositivo*/
ViewGroup.LayoutParams parametro_layout_principal = new
ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT);

/*pegar al contenedor la GUI: en el argumento se está


llamando al método crearGui()*/
this.setContentView(crearGui(), parametro_layout_principal);

//crear objetos de laboratorio


crearObjetosLaboratorio( );

//creación del hilo


hilo= new HiloAnimacion(pizarra,poleas, ruedas, cuerposRect);
//empezar la ejecución del hilo
hilo.start();

//crear los objetos de la interfaz gráfica de usuario (GUI)


private void crearElementosGui(){
pizarra=new Pizarra(this);
pizarra.setBackgroundColor(Color.WHITE);
}
//organizar la distribución de los objetos de de la GUI usando
administradores de diseño
private LinearLayout crearGui(){

//administrador de diseño
LinearLayout linear_principal = new LinearLayout(this);
linear_principal.setOrientation(LinearLayout.VERTICAL);
linear_principal.setGravity(Gravity.CENTER_HORIZONTAL);
linear_principal.setGravity(Gravity.FILL);
linear_principal.setBackgroundColor(Color.rgb(250, 150, 50));

18
/*pegar el objeto tipo PizarraDibujo)*/
//parámetro de pegada
LinearLayout.LayoutParams parametrosPegada= new
LinearLayout.LayoutParams(android.view.ViewGroup.LayoutParams.MATCH_P
ARENT,0);
parametrosPegada.setMargins(50, 50, 50, 50);
parametrosPegada.weight = 1.0f;
//pegar
linear_principal.addView(pizarra, parametrosPegada);

return linear_principal;

/*Crea los objetos cuerpo rígido con su estado inicial*/


private void crearObjetosLaboratorio( ) {

//trea poleas
//polea ubicada inicialmente en (10,10) y de radio 50
polea_1=new Polea(100,100,50);
poleas[0]=polea_1;

//polea ubicada inicialmente en (100,250) y de radio 100


polea_2=new Polea(100,250,100);
polea_2.setColor(Color.BLACK);
poleas[1]=polea_2;

//polea ubicada incialmente en (100,450) y de radio 50


polea_3= new Polea(100,450,50);
polea_3.setColor(Color.MAGENTA);
poleas[2]=polea_3;

//dibujar las ruedas


rueda_1=new Rueda(700,400,100);
rueda_1.setColor(Color.rgb(0,128,0));
ruedas[0]=rueda_1;

//dos cuerpos rectangulares


//bloque ubicado su centro de masa inicialmente
//en (500,450) de largo 50 y alto 20
bloque_1= new CuerpoRectangular(500,450,50,20);
bloque_1.setColor(Color.argb(100,250,250,100));
cuerposRect[0]=bloque_1;

//regla ubicado su centro de masa inicialmente


//en 700,450) de largo 20 y alto 300
regla_1=new CuerpoRectangular(700,450,20,300);
cuerposRect[1]=regla_1;

}
}

19

Paso 5: Archivo manifiesto

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.curso_simulaciones.minovenaapp">

<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme" >

<activity
android:name="com.curso_simulaciones.minovenaapp.controlador.Activida
dPrincipalMiNovenaApp"
android:screenOrientation="landscape">

<intent-filter>
<action android:name="android.intent.action.MAIN" />

<category
android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>

Paso 6: Compilar y ejecutar

Al compilar y ejecutar se debe desplegar la GUI de la Figura 3.


20

Figura 3

HERENCIA: SOBRE-ESCRITURA DE MÉTODO

Para implementar MiDecimaApp se agregará el método dibujese a la clase CuerpoRigido.

Este método para esta clase dibujará un círculo sencillo con la letra R en su interior.

public void dibujese(Canvas canvas, Paint pincel) {

canvas.save();
//rotar

canvas.rotate(posicionAngularRotacionEjeXY,posicionEjeRotacionX,posic
ionEjeRotacionY);

//dibujar un circulo de radio 40


pincel.setColor(color);
canvas.drawCircle(posicionCentroMasaX, posicionCentroMasaY, 40,
pincel);
pincel.setColor(Color.BLACK);
pincel.setTextSize(40);
canvas.drawText("R",posicionCentroMasaX-10,
posicionCentroMasaY+15,pincel);

//regresar la rotación
canvas.restore();

}
Las clases Polea, CuerpoRectangular y Rueda que heredan de CuerpoRigido tendrán

este método, el cual heredarán también, pero con el mismo código que tenían en

MiNovenaApp. Esto significa que, aunque en este caso están heredando el método de

CuerpoRigido, éste tiene instrucciones diferentes en las hijas. A esto se le denomina

sobreescritura de método.

MI DECIMA APP
21
Crear un proyecto denominado MiDecimaApp con la misma estructura de MiNovenaApp,

Figura 4 (cambia el nombre de la actividad principal a

ActividadPrincipalMiDecimaApp).

Figura 4

Los códigos de las clases Polea, CuerpoRectangular y Rueda siguen iguales a los de
MiNovenaApp: agregarlos. Los códigos de la clase CuerpoRigido, Pizarra e HiloAnimacion
tienen algunos cambios (marcadosen amarillo). Estos códigos son los siguientes
(agregarlos).

Clase CuerpoRigido

public class CuerpoRigido {


protected float posicionCentroMasaX, posicionCentroMasaY;
protected float posicionEjeRotacionX, posicionEjeRotacionY;
protected float posicionAngularRotacionEjeXY;
protected int color = Color.RED;

/**
* Constructor por defecto del cuerpo rígido.
* Su centro de masa está ubicado en la
* posición (0,0). La posición angular es cero
* y su color es rojo
*/
public CuerpoRigido() {
22
}

/**
* Constructor de CuerpoRigido
* cuyo centro de masa está
* ubicado en (posicionInicialX,posicionInicialX)
*/

public CuerpoRigido(float posicionInicialX, float


posicionInicialY) {
this.posicionCentroMasaX = posicionInicialX;
this.posicionCentroMasaY = posicionInicialY;
}

/**
* Modifica el color del cuerpo rígido
*
* @param color
*/
public void setColor(int color) {
this.color = color;
}

/**
* Devuelve el color del cuerpo rígido
*
* @return
*/
public int getColor() {
return color;
}

/*
Se podría hacer un método setPosicion(x,y)
para cambiar la posición del centro de masa, pero más adelante
esta el método mover(x,y) que hace esto
*/

/**
* Retorna la posicion en X
* del centro de masa
*
* @return
*/
public float getPosicionX() {

return posicionCentroMasaX;
}

/**
* Retorna posicion en Y
* del centro de masa
*
* @return
*/
public float getPosicionY() {
23
return posicionCentroMasaY;
}

/**
* Modifica la posición (posicionCentroMasaX,posicionCentroMasaY)
* del centro de masa del cuerpo rígido
*
* @param posicionCentroMasaX
* @param posicionCentroMasaY
*/
public void mover(float posicionCentroMasaX, float
posicionCentroMasaY) {
this.posicionCentroMasaX = posicionCentroMasaX;
this.posicionCentroMasaY = posicionCentroMasaY;

/**
* Modifica la posición angular del cuerpo rígido
* alrededor de une eje uqe pasa por su centro
* de masa
*
* @param posicionAngular
*/
public void mover(float posicionAngular) {
// this.posicionAngularRotacionCentroMasa = posicionAngular;
this.posicionEjeRotacionX = posicionCentroMasaX;
this.posicionEjeRotacionY = posicionCentroMasaY;

this.posicionAngularRotacionEjeXY=posicionAngular;
}

/**
* Modifica la posición (posicionCentroMasaX,posicionCentroMasaY)
* del centro de masa del cuerpo rígido y genera una rotación
* alrededor del eje que pasa por éste
* @param posicionCentroMasaX
* @param posicionCentroMasaY
* @param posicionAngular
*/

public void mover(float posicionCentroMasaX, float


posicionCentroMasaY, float posicionAngular){
this.posicionCentroMasaX=posicionCentroMasaX;
this.posicionCentroMasaY=posicionCentroMasaY;
this.posicionEjeRotacionX = posicionCentroMasaX;
this.posicionEjeRotacionY = posicionCentroMasaY;

this.posicionAngularRotacionEjeXY=posicionAngular;
}

/**
* Genera rotación del cuerpo rígido a la
* posición angular posicionAngularRotacionEjeXY
* alrededor de eje que pasa por
* (posicionEjeRotacionX,posicionEjeRotacionY)
* @param posicionEjeRotacionX 24
* @param posicionEjeRotacionY
* @param posicionAngular
*/

public void rotar(float posicionEjeRotacionX, float


posicionEjeRotacionY, float posicionAngular){

this.posicionEjeRotacionX=posicionEjeRotacionX;
this.posicionEjeRotacionY=posicionEjeRotacionY;

this.posicionAngularRotacionEjeXY=posicionAngular;

public void dibujese(Canvas canvas, Paint pincel) {

canvas.save();
//rotar

canvas.rotate(posicionAngularRotacionEjeXY,posicionEjeRotacionX,posic
ionEjeRotacionY);

//dibujar un circulo de radio 40


pincel.setColor(color);
canvas.drawCircle(posicionCentroMasaX, posicionCentroMasaY,
40, pincel);
pincel.setColor(Color.BLACK);
pincel.setTextSize(40);
canvas.drawText("R",posicionCentroMasaX-10,
posicionCentroMasaY+15,pincel);

//regresar la rotación
canvas.restore();

Código de la clase Pizarra


public class Pizarra extends View {

private CuerpoRigido cuerpos[];

/**
* Constructor
*
* @param context
*/
public Pizarra(Context context) {
super(context); 25
}

public void setEstadoEscena(CuerpoRigido[] cuerpos) {

this.cuerpos = cuerpos;

//Método para dibujar la escena


private void dibujarEscena(Canvas canvas, Paint pincel) {

//dibujar las poleas


for (int i = 0; i < cuerpos.length; i++) {
if (cuerpos[i] != null) {
cuerpos[i].dibujese(canvas, pincel);
}
}

//método para dibujar


protected void onDraw(Canvas canvas) {
super.onDraw(canvas);

Paint pincel = new Paint();


//evita efecto sierra
pincel.setAntiAlias(true);

if (cuerpos != null)
dibujarEscena(canvas, pincel);

//necesario para actualizar los dibujos en animaciones


invalidate();

}
Código de HiloAnimacion

26
public class HiloAnimacion extends Thread{

private boolean corriendo;


private long periodo_muestreo=50;//en milisegundos
public float tiempo;
//pizarra que contiene la escena física
private Pizarra pizarra;
//objetos cuerpos rígidos
private CuerpoRigido[] cuerpos;

/*
Este método construtor para un hilo que
maneja la animación de la pizarra
*/
public HiloAnimacion(Pizarra pizarra, CuerpoRigido[] cuerpos ){
this.pizarra=pizarra;
this.cuerpos=cuerpos;
}

@Override
public void run(){

corriendo = true;

while (corriendo==true){

try {
Thread.sleep(periodo_muestreo);//esto en milisegundos
} catch (InterruptedException e) {
e.printStackTrace();
}

//estaba a 0.1 f
tiempo=tiempo+0.01f;
//cambio de estado de la escena física en la pizarra
cambiarEstadosEscenaPizarra(tiempo);

/*Cambia el esatado de los objetos caricatura y lo comunica a


pizarra*/
private void cambiarEstadosEscenaPizarra(float tiempo){

/*
Rota el rígido sencillo alrededor de su centro de masa
*/

float teta_rigido=200*tiempo;
//mover las poleas
cuerpos[0].mover(teta_rigido);

//polea_1
/*La polea 1 arranca de la posición x=100 y=100 27
Se traslada con velocidad constante en x Vx=200; Vy=0;
No rota alrededor de su eje, W=0
*/
float x_1= 100 + 200*tiempo;
float y_1=100;

//polea_2
/*La polea 2 se arranca de la posición x=100 y=250
No se traslada Vx=0; Vy=0;
Rota alrededor de su eje, W=100
*/
float x_2= 100;
float y_2=250;
float teta_2=100*tiempo;

//polea3
/*La polea 3 se arranca de la posición x=100 y=450
Se traslada Vx=200; Vy=0;
Rota alrededor de su eje, W=100
*/
float x_3= 100 + 200*tiempo;
float y_3=450;
float teta_3=100*tiempo;

//mover las poleas


cuerpos[1].mover(x_1,y_1);
cuerpos[2].mover(teta_2);
cuerpos[3].mover(x_3,y_3,teta_3);

/*
Rueda rotando alrededor de eje que pasa por
su centro de masa
*/
float teta_rueda=200*tiempo;
cuerpos[4].mover(teta_rueda);

/*
La regla oscila armónicamente con frecuencia
igual a 2 Hz y amplitud 0.2 rad
y fase inicial cero
*/
float frecuencia= 2;
float teta_regla_radianes=(float)
(0.2*(Math.sin(2*Math.PI*frecuencia*tiempo)));
float teta_regla_grados= (float)
(Math.toDegrees(teta_regla_radianes));
cuerpos[6].rotar(700,320,teta_regla_grados);

//actualizar escena
pizarra.setEstadoEscena(cuerpos);

}//fin Hilo
28

Agregar los códigos de las clases Polea, CuerpoRectangular y Rueda. Sonlos mimsode

MiNovenaApp.

Ahora agrgarel código de ActividadPrincipalMiDecimaApp.

Código de ActividadPrincipalMiDecimaApp

public class ActividadPrincipalMiDecimaApp extends Activity {

//Pizarra para dibujar


Pizarra pizarra;
//objetos dibujables para Pizarra
private CuerpoRigido rigido_1;
private Polea polea_1,polea_2,polea_3;
private Rueda rueda_1;
private CuerpoRectangular bloque_1, regla_1;
public CuerpoRigido[] cuerpos= new CuerpoRigido[10];

/*Hilo responsable de la animación


El trabajo de animación es mejor manejarlo en hilo
para evitar bloqueos de la aplicación
debido al manejo simultáneo de la GUI con la Acivity
*/
private HiloAnimacion hilo;

protected void onCreate(Bundle savedInstanceState) {


super.onCreate(savedInstanceState);

/*llamada al método para crear los elementos de la interfaz


gráfica de usuario (GUI)*/
crearElementosGui();

/*para informar cómo se debe adaptar la GUI a la pantalla del


dispositivo*/
ViewGroup.LayoutParams parametro_layout_principal = new
ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT);

/*pegar al contenedor la GUI: en el argumento se está


llamando al método crearGui()*/
this.setContentView(crearGui(), parametro_layout_principal);
29

//crear objetos de laboratorio


crearObjetosLaboratorio( );

//creación del hilo


hilo= new HiloAnimacion(pizarra,cuerpos);
//empezar la ejecución del hilo
hilo.start();

//crear los objetos de la interfaz gráfica de usuario (GUI)


private void crearElementosGui(){
pizarra=new Pizarra(this);
pizarra.setBackgroundColor(Color.WHITE);
}

//organizar la distribución de los objetos de de la GUI usando


administradores de diseño
private LinearLayout crearGui(){

//administrador de diseño
LinearLayout linear_principal = new LinearLayout(this);
linear_principal.setOrientation(LinearLayout.VERTICAL);
linear_principal.setGravity(Gravity.CENTER_HORIZONTAL);
linear_principal.setGravity(Gravity.FILL);
linear_principal.setBackgroundColor(Color.rgb(250, 150, 50));

/*pegar el objeto tipo PizarraDibujo)*/


//parámetro de pegada
LinearLayout.LayoutParams parametrosPegada= new
LinearLayout.LayoutParams(android.view.ViewGroup.LayoutParams.MATCH_P
ARENT,0);
parametrosPegada.setMargins(50, 50, 50, 50);
parametrosPegada.weight = 1.0f;
//pegar
linear_principal.addView(pizarra, parametrosPegada);

return linear_principal;
}

/*Crea los objetos cuerpo rígido con su estado inicial*/


private void crearObjetosLaboratorio( ) {

//un rígido sencillo ubicado en (100,100)


rigido_1=new CuerpoRigido(100,100);
rigido_1.setColor(Color.YELLOW);
cuerpos[0]=rigido_1;

//trea poleas
//polea ubicada inicialmente en (10,10) y de radio 50
polea_1=new Polea(100,100,50); 30
cuerpos[1]=polea_1;

//polea ubicada inicialmente en (100,250) y de radio 100


polea_2=new Polea(100,250,100);
polea_2.setColor(Color.BLACK);
cuerpos[2]=polea_2;

//polea ubicada incialmente en (100,450) y de radio 50


polea_3= new Polea(100,450,50);
polea_3.setColor(Color.MAGENTA);
cuerpos[3]=polea_3;

//dibujar las ruedas


rueda_1=new Rueda(700,400,100);
rueda_1.setColor(Color.rgb(0,128,0));
cuerpos[4]=rueda_1;

//dos cuerpos rectangulares


//bloque ubicado su centro de masa inicialmente
//en (500,450) de largo 50 y alto 20
bloque_1= new CuerpoRectangular(500,450,50,20);
bloque_1.setColor(Color.argb(100,250,250,100));
cuerpos[5]=bloque_1;

//regla ubicado su centro de masa inicialmente


//en 700,450) de largo 20 y alto 300
regla_1=new CuerpoRectangular(700,450,20,300);
cuerpos[6]=regla_1;

}
}

Declarar la actividad principal en el archivo manifiesto (exigir que la pantalla quede siempre

en posición horizontal. Compilar y ejecutar. El resultado es’el de la Figura 5. Tratar de


asimilar las diferencias en los códigos entre estás dos apps (MiNovenaApp y

MidecimaApp). En ambos se implementó la herencia, pero en MiNovenaApp no hubo

sobrescritura de método.

31

Figura 5

HERENCIA: CLASE ABSTRACTA

Un método sin implementar se deb declarar abstracto. Sólo está el nombre de éste y sin

llaves { }. Si tuviera llaves el método, así estuvieran vacías, el método estaría

implementado auqnue no haría nada. Un método sin implementar es abstracto y se debe

declarar expresamente con la palabra clave abstract. En el ejemplo que se trabajará, la

clase CuerpoRigido tendrá el método dibujese abstracto:

//Método abstracto
public abstract void dibujese(Canvas canvas, Paint pincel) ;

Una clase que al menos tenga un método abstracto se debe declarar también abstracta. Por

lo tanto, la clase CuerpoRigido que se usará en MiDecimaPriemraApp se debe declarar

abstracta.
public abstract class CuerpoRigido {

Algo más sobre clases abstractas

¡Con las clases abstractas no se pueden crear objetos!


32
En inglés abstract significa “resumen”, por eso en algunos textos en castellano a las clases

abstractas se les llama resúmenes. Una clase abstracta para Java es una clase de la que

nunca se van a crear instancias: simplemente va a servir como superclase a otras clases. No

se puede usar la palabra clave new aplicada a clases abstractas: las clases abstractas no se

pueden instanciar, es decir con ellas no se pueden crear objetos.

La declaración de que una clase es abstracta se hace con la sintaxis,

public abstract class NombreDeLaClase { … }

Una clase abstracta tiene como intención única la de unificar atributos y métodos de las

subclases. No tiene como fin crear objetos.

A su vez, las clases abstractas contienen métodos abstractos: la situación es la misma. Para

que un método se considere abstracto ha de incluir en su signatura la palabra clave

abstract. Además, un método abstracto tiene estas peculiaridades:

 No tiene cuerpo (llaves): sólo consta de signatura con paréntesis.

 Su signatura termina con un punto y coma.

 Sólo puede existir dentro de una clase abstracta. De esta forma se evita que haya

métodos que no se puedan ejecutar dentro de clases concretas. Visto de otra manera,
si una clase incluye un método abstracto, forzosamente la clase será una clase

abstracta.

 Los métodos abstractos forzosamente habrán de estar sobre-escritos en las

subclases. Si una subclase no implementa un método abstracto de la superclase tiene

un método no ejecutable, lo que la obliga a ser una subclase abstracta. Para que la

subclase sea concreta habrá de implementar métodos sobre-escritos para todos los

métodos abstractos de sus superclases.

33
Un método abstracto para Java es un método que nunca va a ser ejecutado porque no tiene

cuerpo. Simplemente, un método abstracto referencia a otros métodos de las subclases.

¿Qué utilidad tiene un método abstracto? Se puede ver un método abstracto como una

palanca que tiene dos efectos: el primero, que no se puedan crear objetos de una clase. El

segundo, que todas las subclases sobre-escriban el método declarado como abstracto.

Que un método sea abstracto tiene otra implicación adicional: que se pueda invocar el

método abstracto sobre una variable de la superclase que apunta a un objeto de una

subclase de modo que el método que se ejecute sea el correspondiente al tipo dinámico de

la variable. En cierta manera, podría verse como un método sobre-escrito para que Java

comprenda que debe buscar dinámicamente el método adecuado según la subclase a la que

apunte la variable.

¿Es necesario que una clase que tiene uno o más métodos abstractos se defina como

abstracta? Sí, si se declara un método abstracto el compilador obliga a declarar la clase

como abstracta porque si no se hace así se tendría un método de una clase concreta no

ejecutable, y eso no es admitido por Java.

¿Una clase se puede declarar como abstracta y no contener métodos abstractos? Sí,

una clase puede ser declarada como abstracta y no contener métodos abstractos. En

algunos casos la clase abstracta simplemente sirve para efectuar operaciones comunes a

subclases sin necesidad de métodos abstractos.

¿Una clase que hereda de una clase abstracta puede ser no abstracta? Sí, de hecho,

esta es una de las razones de ser de las clases abstractas. Una clase abstracta no puede

ser instanciada, pero pueden crearse subclases concretas sobre la base de una clase

abstracta, y crear instancias de estas subclases. Para ello hay que heredar de la clase

abstracta y anular los métodos abstractos, es decir, implementarlos.


MI DECIMO PRIMERA APP

Con Android Studio crear un proyecto denominado MiDecimoPrimaraApp con la misma

estryctura de las apps que se han ido desarrollando en este módulo, Figura 6 (la actividad

principal cambia su nombre a ActividadPrincipalmiDecimoPrimeraApp).

34

Figura 6

En la clase CuerpoRigido el método dibujese se hace abstracto. El código es el siguiente

(agregarlo)

public abstract class CuerpoRigido {

protected float posicionCentroMasaX, posicionCentroMasaY;


protected float posicionEjeRotacionX, posicionEjeRotacionY;
protected float posicionAngularRotacionEjeXY;
protected int color = Color.RED;

/**
* Constructor por defecto del cuerpo rígido.
* Su centro de masa está ubicado en la
* posición (0,0). La posición angular es cero
* y su color es rojo
*/
public CuerpoRigido() {

}
/**
* Constructor de CuerpoRigido
* cuyo centro de masa está
* ubicado en (posicionInicialX,posicionInicialX)
*/

public CuerpoRigido(float posicionInicialX, float


posicionInicialY) {
this.posicionCentroMasaX = posicionInicialX;
this.posicionCentroMasaY = posicionInicialY;
}

35
/**
* Modifica el color del cuerpo rígido
*
* @param color
*/
public void setColor(int color) {
this.color = color;
}

/**
* Devuelve el color del cuerpo rígido
*
* @return
*/
public int getColor() {
return color;
}

/*
Se podría hacer un método setPosicion(x,y)
para cambiar la posición del centro de masa, pero más adelante
esta el método mover(x,y) que hace esto
*/

/**
* Retorna la posicion en X
* del centro de masa
*
* @return
*/

public float getPosicionX() {

return posicionCentroMasaX;
}

/**
* Retorna posicion en Y
* del centro de masa
*
* @return
*/
public float getPosicionY() {

return posicionCentroMasaY;
}

/**
* Modifica la posición (posicionCentroMasaX,posicionCentroMasaY)
* del centro de masa del cuerpo rígido
*
* @param posicionCentroMasaX
* @param posicionCentroMasaY
*/
public void mover(float posicionCentroMasaX, float
posicionCentroMasaY) {
this.posicionCentroMasaX = posicionCentroMasaX;
this.posicionCentroMasaY = posicionCentroMasaY; 36
}

/**
* Modifica la posición angular del cuerpo rígido
* alrededor de une eje uqe pasa por su centro
* de masa
*
* @param posicionAngular
*/
public void mover(float posicionAngular) {
// this.posicionAngularRotacionCentroMasa = posicionAngular;
this.posicionEjeRotacionX = posicionCentroMasaX;
this.posicionEjeRotacionY = posicionCentroMasaY;

this.posicionAngularRotacionEjeXY=posicionAngular;
}

/**
* Modifica la posición (posicionCentroMasaX,posicionCentroMasaY)
* del centro de masa del cuerpo rígido y genera una rotación
* alrededor del eje que pasa por éste
* @param posicionCentroMasaX
* @param posicionCentroMasaY
* @param posicionAngular
*/

public void mover(float posicionCentroMasaX, float


posicionCentroMasaY, float posicionAngular){
this.posicionCentroMasaX=posicionCentroMasaX;
this.posicionCentroMasaY=posicionCentroMasaY;

this.posicionEjeRotacionX = posicionCentroMasaX;
this.posicionEjeRotacionY = posicionCentroMasaY;

this.posicionAngularRotacionEjeXY=posicionAngular;
}

/**
* Genera rotación del cuerpo rígido a la
* posición angular posicionAngularRotacionEjeXY
* alrededor de eje que pasa por
* (posicionEjeRotacionX,posicionEjeRotacionY)
* @param posicionEjeRotacionX
* @param posicionEjeRotacionY
* @param posicionAngular
*/

public void rotar(float posicionEjeRotacionX, float


posicionEjeRotacionY, float posicionAngular){

this.posicionEjeRotacionX=posicionEjeRotacionX;
this.posicionEjeRotacionY=posicionEjeRotacionY;

this.posicionAngularRotacionEjeXY=posicionAngular;

//Método abstracto 37
public abstract void dibujese(Canvas canvas, Paint pincel) ;

Los códigos de Polea, CuerpoRectangular y Rueda son los mismos de las dos apps que se

han desarrolllado en este módulo. Agregarlo. Estas clases heredan de la clase abstracta

CuerpoRigido y tienen implementado el método dibujese (de no hacerlo deben

declararse también como clases abstractas).

El código de la clase Pizarra es el mismo de MiDecimaApp (agregarlo).

Los códigos de las otras clases ya no instancian la clase CuerpoRigido. Los códigos son

los siguientes (agregarlos).

El código de la clase HiloAnimacion es el siguiente (agregarlo).

public class HiloAnimacion extends Thread{

private boolean corriendo;


private long periodo_muestreo=50;//en milisegundos
public float tiempo;
//pizarra que contiene la escena física
private Pizarra pizarra;
//objetos cuerpos rígidos
private CuerpoRigido[] cuerpos;

/*
Este método construtor para un hilo que
maneja la animación de la pizarra
*/
public HiloAnimacion(Pizarra pizarra, CuerpoRigido[] cuerpos ){
this.pizarra=pizarra;
this.cuerpos=cuerpos;
}

@Override
public void run(){

corriendo = true;

while (corriendo==true){

try {
Thread.sleep(periodo_muestreo);//esto en milisegundos
} catch (InterruptedException e) { 38
e.printStackTrace();
}

//estaba a 0.1 f
tiempo=tiempo+0.01f;
//cambio de estado de la escena física en la pizarra
cambiarEstadosEscenaPizarra(tiempo);

/*Cambia el esatado de los objetos caricatura y lo comunica a


pizarra*/
private void cambiarEstadosEscenaPizarra(float tiempo){

//polea_1
/*La polea 1 arranca de la posición x=100 y=100
Se traslada con velocidad constante en x Vx=200; Vy=0;
No rota alrededor de su eje, W=0
*/
float x_1= 100 + 200*tiempo;
float y_1=100;

//polea_2
/*La polea 2 se arranca de la posición x=100 y=250
No se traslada Vx=0; Vy=0;
Rota alrededor de su eje, W=100
*/
float x_2= 100;
float y_2=250;
float teta_2=100*tiempo;

//polea3
/*La polea 3 se arranca de la posición x=100 y=450
Se traslada Vx=200; Vy=0;
Rota alrededor de su eje, W=100
*/
float x_3= 100 + 200*tiempo;
float y_3=450;
float teta_3=100*tiempo;

//mover las poleas


cuerpos[0].mover(x_1,y_1);
cuerpos[1].mover(teta_2);
cuerpos[2].mover(x_3,y_3,teta_3);

/*
Rueda rotando alrededor de eje que pasa por
su centro de masa
*/
float teta_rueda=200*tiempo;
cuerpos[3].mover(teta_rueda); 39

/*
La regla oscila armónicamente con frecuencia
igual a 2 Hz y amplitud 0.2 rad
y fase inicial cero
*/
float frecuencia= 2;
float teta_regla_radianes=(float)
(0.2*(Math.sin(2*Math.PI*frecuencia*tiempo)));
float teta_regla_grados= (float)
(Math.toDegrees(teta_regla_radianes));
cuerpos[5].rotar(700,320,teta_regla_grados);

//actualizar escena
pizarra.setEstadoEscena(cuerpos);

}//fin Hilo

Código de la clase ActividadPrincipalMiDecimoPrimeraApp es el siguiente


(agregarlo).

public class ActividadPrincipalMiDecimoPrimeraApp extends Activity {

//Pizarra para dibujar


Pizarra pizarra;
//objetos dibujables para Pizarra
private CuerpoRigido rigido_1;
private Polea polea_1,polea_2,polea_3;
private Rueda rueda_1;
private CuerpoRectangular bloque_1, regla_1;
public CuerpoRigido[] cuerpos= new CuerpoRigido[10];
/*Hilo responsable de la animación
El trabajo de animación es mejor manejarlo en hilo
para evitar bloqueos de la aplicación
debido al manejo simultáneo de la GUI con la Acivity
*/
private HiloAnimacion hilo;

protected void onCreate(Bundle savedInstanceState) {


super.onCreate(savedInstanceState);

/*llamada al método para crear los elementos de la interfaz


gráfica de usuario (GUI)*/ 40
crearElementosGui();

/*para informar cómo se debe adaptar la GUI a la pantalla del


dispositivo*/
ViewGroup.LayoutParams parametro_layout_principal = new
ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT);

/*pegar al contenedor la GUI: en el argumento se está


llamando al método crearGui()*/
this.setContentView(crearGui(), parametro_layout_principal);

//crear objetos de laboratorio


crearObjetosLaboratorio( );

//creación del hilo


hilo= new HiloAnimacion(pizarra,cuerpos);
//empezar la ejecución del hilo
hilo.start();

//crear los objetos de la interfaz gráfica de usuario (GUI)


private void crearElementosGui(){
pizarra=new Pizarra(this);
pizarra.setBackgroundColor(Color.WHITE);
}

//organizar la distribución de los objetos de de la GUI usando


administradores de diseño
private LinearLayout crearGui(){

//administrador de diseño
LinearLayout linear_principal = new LinearLayout(this);
linear_principal.setOrientation(LinearLayout.VERTICAL);
linear_principal.setGravity(Gravity.CENTER_HORIZONTAL);
linear_principal.setGravity(Gravity.FILL);
linear_principal.setBackgroundColor(Color.rgb(250, 150, 50));
/*pegar el objeto tipo PizarraDibujo)*/
//parámetro de pegada
LinearLayout.LayoutParams parametrosPegada= new
LinearLayout.LayoutParams(android.view.ViewGroup.LayoutParams.MATCH_P
ARENT,0);
parametrosPegada.setMargins(50, 50, 50, 50);
parametrosPegada.weight = 1.0f;
//pegar
linear_principal.addView(pizarra, parametrosPegada);

return linear_principal;

} 41

/*Crea los objetos cuerpo rígido con su estado inicial*/


private void crearObjetosLaboratorio( ) {

/* En MiDecimaApp estaban estas líneas de código,


pero aquí no es posible obtener objetos directamente
de CuerpoRigido ya que es una clase abstracta

//un rígido sencillo ubicado en (100,100)


rigido_1=new CuerpoRigido(100,100);// NO SE PUEDE
rigido_1.setColor(Color.YELLOW);
cuerpos[0]=rigido_1;
*/

//trea poleas
//polea ubicada inicialmente en (10,10) y de radio 50
polea_1=new Polea(100,100,50);
cuerpos[0]=polea_1;

//polea ubicada inicialmente en (100,250) y de radio 100


polea_2=new Polea(100,250,100);
polea_2.setColor(Color.BLACK);
cuerpos[1]=polea_2;

//polea ubicada incialmente en (100,450) y de radio 50


polea_3= new Polea(100,450,50);
polea_3.setColor(Color.MAGENTA);
cuerpos[2]=polea_3;

//dibujar las ruedas


rueda_1=new Rueda(700,400,100);
rueda_1.setColor(Color.rgb(0,128,0));
cuerpos[3]=rueda_1;

//dos cuerpos rectangulares


//bloque ubicado su centro de masa inicialmente
//en (500,450) de largo 50 y alto 20
bloque_1= new CuerpoRectangular(500,450,50,20);
bloque_1.setColor(Color.argb(100,250,250,100));
cuerpos[4]=bloque_1;

//regla ubicado su centro de masa inicialmente


//en 700,450) de largo 20 y alto 300
regla_1=new CuerpoRectangular(700,450,20,300);
cuerpos[5]=regla_1;

}
}

42

Declararar la activiadad principal en el archivo manifiesto. Obligar a que la pantalla se

despliegue horizontal.

Compilar y ejecutar. El resultado es idéntico al de MiNovenaApp.

INTERFACE

¿Qué es una Interface?

Java no permite la denominada herencia múltiple, es decir una clase sólo puede derivarse

de una sola madre y no de varias. Para lograr algo parecido usa las denominadas

"interfaces". Éstas pueden verse simplemente como una forma, es como un molde,

solamente permite declarar nombres de métodos, listas de argumentos, tipos de retorno y

adicionalmente miembros datos (los cuales podrán ser únicamente tipos básicos y serán

tomados como constantes en tiempo de compilación, es decir, static y final). Las Interfaces

son implementadas por clases las cuales deben definir todos sus métodos. Una interfaz no

tiene constructores y no es instanciable Una clase puede implementar varias interfaces.

En resumen, una interface es una construcción similar a una clase abstracta en Java, pero

con las siguientes diferencias:

 En el encabezado se usa la palabra clave interface en lugar de class o abstract class.

Por ejemplo,

public interface NombreDelInterface {…}


 Todo método es abstracto y público sin necesidad de declararlo, es decir, no hace falta

poner abstract public porque por defecto todos los métodos son abstract

public. Por lo tanto, un interface en Java no implementa ninguno de los métodos que

declara: ninguno de sus métodos tiene cuerpo.

 Las interfaces no tienen ningún constructor.

 Una interface solo admite campos de tipo “public static final”, es decir, campos

de clase, públicos y constantes. No hace falta incluir las palabras public static

final porque todos los campos serán tratados como si llevaran estas palabras. 43
Recordar que static equivale a “de clase” y final a “constante”. Las interfaces

pueden ser un lugar interesante para declarar constantes que van a ser usadas por

diferentes clases en nuestros programas.

 Una clase puede “derivar” de una interface de la misma manera en que puede derivar de
otra clase. No obstante, se dice que la interface se implementa (implements), no se

extiende (extends) por sus subclases. Por tanto, para declarar la “herencia” de un

interface se usa la palabra clave implements en lugar de extends.

Una clase puede implementar uno o varios interfaces en Java (se indica con

implements NombreInterface1, NombreInterface2, …etc.), pero sólo puede

extender una clase. Implementar varios interfaces en una sola clase es lo más parecido

que tiene Java a la herencia múltiple.

En la app que se implementará a continuación se incluirán dos objetos de laboratorio

adicionales: resortes y flechas (para representar vectores). Para esto se diseñarán la clase

Resorte y la clase Flecha. Como éstas no tienen el comportamiento de un cuerpo rígido no

es recomendable ponerlas a heredar de éste (se podría hacer a la fuerza, pero no es

elegante a nivel de programación ni de lógica). Como los objetos de estas clases también

deben poderse dibujar deberán incluir el método dibujese( ) que se ha diseñado para

que se puedan dibujar los objetos de laboratorio en objetos de la clase Pizarra. Para esto

lo mejor será diseñar una interface que se denominará Dibujable que posee el método

dibujese() sin implementar, la cual (la interface) la implementarán todos las clases cuyos

objetos se quieran dibujar en objetos tipo Pizarra. En la Figura 7 se ilustra la nueva


herencia en donde la clase madre (la super madre) es ObjetoLaboratorio que

implementará la interface Dibujable y por lo tanto todas sus hijas que pretendan no

ser abstractas deben implementar este método. Por ejemplo, CuerpoRigido no

implementa ese método por lo tanto debe ser también una clase abstracta (no se pueden

hacer objetos con ella). Esta clase tiene las hijas Polea, CuerpoRectangular y Rueda

que si implementan el método dibujese() y por lo tanto no serán abstractas.

44

Figura 7

MI DECIMO SEGUNDA APP

Crear un proyecto denominado MiDecimoSegundaApp con la estructura de la Figura 8

(cambia el nombre de la actividad principal a

ActividadPrincipalMiDecimoSegundaApp). Observar que en el paquete

objetos_laboratorio aparece la interface Dibujable. Esta se crea como las clases, pero

en el proceso de creación en el cuadro se hace doble clic en Interface, Figura 9.


.

45

Figura 8

Figura 9

El código de la interface Dibujable es el siguiente (agregarlo).

public interface Dibujable {

/**
* método que deben implementar las clases cuyos objetos
* serán dibujables en Pizarra que herede de View.
* @param canvas
* @param pincel
*/
public void dibujese(Canvas canvas, Paint pincel);

El código de ObjetoLaboratorio es el siguiente (agregarlo).


46

public abstract class ObjetoLaboratorio implements Dibujable{

/**
* Método para que se dibujen los objetos Dibujables,
* es decir, los objetos que implementanla interface Dibujable
* @param canvas
* @param pincel
*/
public abstract void dibujese(Canvas canvas, Paint pincel);

CuerpoRigido ya hereda de ObjetoLaboratorio. El código es el siguiente (agregarlo).

public abstract class CuerpoRigido extends ObjetoLaboratorio {

protected float posicionCentroMasaX, posicionCentroMasaY;


protected float posicionEjeRotacionX, posicionEjeRotacionY;
protected float posicionAngularRotacionEjeXY;
protected int color = Color.RED;

/**
* Constructor por defecto del cuerpo rígido.
* Su centro de masa está ubicado en la
* posición (0,0). La posición angular es cero
* y su color es rojo
*/
public CuerpoRigido() {

/**
* Constructor de CuerpoRigido
* cuyo centro de masa está
* ubicado en (posicionInicialX,posicionInicialX)
*/

public CuerpoRigido(float posicionInicialX, float


posicionInicialY) {
this.posicionCentroMasaX = posicionInicialX;
this.posicionCentroMasaY = posicionInicialY;
}

/**
* Modifica el color del cuerpo rígido
*
* @param color 47
*/
public void setColor(int color) {
this.color = color;
}

/**
* Devuelve el color del cuerpo rígido
*
* @return
*/
public int getColor() {
return color;
}

/*
Se podría hacer un método setPosicion(x,y)
para cambiar la posición del centro de masa, pero más adelante
esta el método mover(x,y) que hace esto
*/

/**
* Retorna la posicion en X
* del centro de masa
*
* @return
*/

public float getPosicionX() {

return posicionCentroMasaX;
}

/**
* Retorna posicion en Y
* del centro de masa
*
* @return
*/
public float getPosicionY() {

return posicionCentroMasaY;
}

/**
* Modifica la posición (posicionCentroMasaX,posicionCentroMasaY)
* del centro de masa del cuerpo rígido
*
* @param posicionCentroMasaX
* @param posicionCentroMasaY
*/
public void mover(float posicionCentroMasaX, float
posicionCentroMasaY) {
this.posicionCentroMasaX = posicionCentroMasaX;
this.posicionCentroMasaY = posicionCentroMasaY;

48
/**
* Modifica la posición angular del cuerpo rígido
* alrededor de une eje uqe pasa por su centro
* de masa
*
* @param posicionAngular
*/
public void mover(float posicionAngular) {
// this.posicionAngularRotacionCentroMasa = posicionAngular;
this.posicionEjeRotacionX = posicionCentroMasaX;
this.posicionEjeRotacionY = posicionCentroMasaY;

this.posicionAngularRotacionEjeXY=posicionAngular;
}

/**
* Modifica la posición (posicionCentroMasaX,posicionCentroMasaY)
* del centro de masa del cuerpo rígido y genera una rotación
* alrededor del eje que pasa por éste
* @param posicionCentroMasaX
* @param posicionCentroMasaY
* @param posicionAngular
*/

public void mover(float posicionCentroMasaX, float


posicionCentroMasaY, float posicionAngular){
this.posicionCentroMasaX=posicionCentroMasaX;
this.posicionCentroMasaY=posicionCentroMasaY;

this.posicionEjeRotacionX = posicionCentroMasaX;
this.posicionEjeRotacionY = posicionCentroMasaY;

this.posicionAngularRotacionEjeXY=posicionAngular;
}

/**
* Genera rotación del cuerpo rígido a la
* posición angular posicionAngularRotacionEjeXY
* alrededor de eje que pasa por
* (posicionEjeRotacionX,posicionEjeRotacionY)
* @param posicionEjeRotacionX
* @param posicionEjeRotacionY
* @param posicionAngular
*/

public void rotar(float posicionEjeRotacionX, float


posicionEjeRotacionY, float posicionAngular){

this.posicionEjeRotacionX=posicionEjeRotacionX;
this.posicionEjeRotacionY=posicionEjeRotacionY;

this.posicionAngularRotacionEjeXY=posicionAngular;

//Método abstracto que viene de la Interface Dibujable


public abstract void dibujese(Canvas canvas, Paint pincel) ;

}
49

El código de la clase Resorte es el siguiente (agregarlo).

public class Resorte extends ObjetoLaboratorio {

private float posicionX, posicionY;


private float posicionAngular;
private float longitudNatural, longitud;
private float ancho;
private float grosorLinea = 5f;
private int color = Color.BLACK;

/**
* Resorte de longitud 10f
* ancho 20f y horizontal y
* origen en (0,0)
*/

public Resorte() {

this.longitudNatural = 10f;
this.longitud = longitudNatural;
this.ancho = 20f;
}

/**
* Modifica la longitud del objeto de laboratorio Resorte
*
* @param longitud
*/
public void setLongitud(float longitud) {

this.longitud = longitud;

/**
* Devuelve la longitud del objeto de laboratorio Resorte
*
* @return longitud
*/
public float getLongitud() {

return longitud;
}

/**
* Modifica la longitud natural del objeto de laboratorio Resorte
*
* @param longitudNatural
*/ 50
public void setLongitudNatural(float longitudNatural) {

this.longitudNatural = longitudNatural;
this.longitud = longitudNatural;

/**
* Devuelve la longitud natural del objeto de laboratorio Resorte
*
* @return longitudNatural
*/

public float getLongitudNatural() {

return longitudNatural;
}

/**
* Modifica la posicion del objeto de laboratorio
*
* @param posicionX
* @param posicionY
*/

public void setPosicion(float posicionX, float posicionY) {

this.posicionX = posicionX;
this.posicionY = posicionY;

/**
* Regresa la posición del laboratorio
*
* @return
*/

public float[] getPosicion() {

float[] coordenadas = new float[2];


coordenadas[0] = posicionX;
coordenadas[1] = posicionY;

return coordenadas;

/**
* Modifica el grosor de la línea con la que se dibujará
*
* @param grosorLinea
*/ 51
public void setGrosorLinea(float grosorLinea) {

this.grosorLinea = grosorLinea;

/**
* Devuelve el grosor de la línea con la que se dibuja
*
* @return
*/
public float getGrosorLinea() {

return grosorLinea;
}

/**
* Modifica el color del objeto de laboratorio
*
* @param color
*/

public void setColor(int color) {

this.color = color;

/**
* Devuelve el color del objeto de laboratorio
*
* @return
*/
public int getColor() {

return color;
}

/**
* Modifica el ancho del objeto de laboratorio Resorte2D
*
* @param ancho
*/
public void setAncho(float ancho) {
this.ancho = ancho;

/**
* Devuelve el ancho del objeto de laboratorio Resorte2D
*
* @return
*/
52
public float getAncho() {

return ancho;
}

/**
* Genera rotación del resorte a la
* posición angular posicionAngular
* alrededor de eje que pasa por
* (posicionX,posicionY)
* @param posicionAngular
*/

public void rotar(float posicionAngular){

this.posicionAngular=posicionAngular;

public void dibujese(Canvas canvas, Paint pincel) {

//valores del pincel para luego restaurarlo como estaba


float grosorInicialLinea = pincel.getStrokeWidth();

//estado del canvas para luego restaurarlo a como estaba


canvas.save();

pincel.setStrokeWidth(grosorLinea);
pincel.setColor(color);

//traslada la resorte a la posición (posicionX, posicionY)


canvas.translate(posicionX, posicionY);
//rota la resorte alrededor de eje que pasa por (posicionX,
posicionY)
canvas.rotate(posicionAngular,posicionX,posicionY);

float paso = longitud / 24f;

pincel.setStyle(Paint.Style.STROKE);

Path path = new Path();


path.moveTo(0, 0);
path.lineTo(0, 0);

for (int i = 1; i < 24; i = i + 1) {

path.lineTo(i * paso, (float) Math.pow(-1, i) * ancho);


}

path.lineTo(24 * paso, 0);


canvas.drawPath(path, pincel);

//restaurar pincel 53
pincel.setStrokeWidth(grosorInicialLinea);
pincel.setStyle(Paint.Style.FILL);

//restaurar el canvas
canvas.restore();

El código de la clase Flecha es el siguiente (agregarlo).

public class Flecha extends ObjetoLaboratorio {

private float longitud;


private float posicionX, posicionY;
private float posicionAngular;
private float grosorLinea=5f;
private int color= Color.BLACK;

/**
* Constructor por defecto
* Fecha con origen en (0,0),
* longitud 20f, horizontal y
* sentido + X
*/

public Flecha() {

this.posicionX = 0;
this.posicionY = 0;
this.longitud = 20f;

/**
* Modifica la longitud del objeto de laboratorio Flecha
*
* @param longitud
*/

public void setLongitud(float longitud) {

this.longitud = longitud;
}

public float getLongitud() {

return longitud;

}
54
/**
* Modifica la posicion del objeto de laboratorio
* @param posicionX
* @param posicionY
*/

public void setPosicion(float posicionX,float posicionY){

this.posicionX=posicionX;
this.posicionY=posicionY;

/**
* Regresa la posición del laboratorio
* @return
*/

public float[] getPosicion(){

float[] coordenadas = new float[2];

coordenadas[0]=posicionX;
coordenadas[1]=posicionY;

return coordenadas;

/**
* Modifica el grosor de la línea con la que se dibujará
* @param grosorLinea
*/

public void setGrosorLinea(float grosorLinea){

this.grosorLinea=grosorLinea;

}
/**
* Devuelve el grosor de la línea con la que se dibuja
* @return
*/
public float getGrosorLinea(){

return grosorLinea;
}

/**
* Modifica el color del objeto de laboratorio
* @param color
*/
55
public void setColor(int color){

this.color=color;

/**
* Devuelve el color del objeto de laboratorio
* @return
*/
public int getColor(){

return color;
}

/**
* Genera rotación de la flecha a la
* posición angular posicionAngular
* alrededor de eje que pasa por
* (posicionX,posicionY)
* @param posicionAngular
*/

public void rotar(float posicionAngular){

this.posicionAngular=posicionAngular;

//implementa el método de la Interface Dibujable


public void dibujese(Canvas canvas, Paint pincel) {

//valores del pincel para luego restaurarlo como estaba


float grosorInicialLinea = pincel.getStrokeWidth();

//estado del canvas para luego restaurarlo a como estaba


canvas.save();

pincel.setStrokeWidth(grosorLinea);
pincel.setColor(color);

//traslada la flecha a la posición (posicionX, posicionY)


canvas.translate(posicionX, posicionY);
//rota la flecha alrededor de eje que pasa por (posicionX,
posicionY)
canvas.rotate(posicionAngular,posicionX,posicionY);

float cabeza = 0.1f * longitud;


Path path = new Path();
path.moveTo(0, 0);
path.lineTo(longitud - cabeza, 0);
path.lineTo(longitud - cabeza, -0.5f * cabeza); 56
path.lineTo(longitud, 0);
path.lineTo(longitud - cabeza, 0.5f * cabeza);
path.lineTo(longitud - cabeza, 0);
pincel.setStyle(Paint.Style.STROKE);
canvas.drawPath(path, pincel);

//restaurar pincel
pincel.setStrokeWidth(grosorInicialLinea);
pincel.setStyle(Paint.Style.FILL);

//restaurar el canvas
canvas.restore();

}
}

El código de las clases Polea, CuerpoRectangular y Rueda sigue siendo igual al de las

apps desarrolladas en este módulo. Agregarlo.

El código de la clase Pizarra es el siguiente (agregarlo).

public class Pizarra extends View {

private ObjetoLaboratorio objetosLab[];

/**
* Constructor
*
* @param context
*/
public Pizarra(Context context) {
super(context);
}

public void setEstadoEscena(ObjetoLaboratorio[] cuerpos) {

this.objetosLab = cuerpos;

//Método para dibujar la escena


private void dibujarEscena(Canvas canvas, Paint pincel) {

//dibujar las poleas 57


for (int i = 0; i < objetosLab.length; i++) {
if (objetosLab[i] != null) {
objetosLab[i].dibujese(canvas, pincel);
}
}

//método para dibujar


protected void onDraw(Canvas canvas) {
super.onDraw(canvas);

Paint pincel = new Paint();


//evita efecto sierra
pincel.setAntiAlias(true);

if (objetosLab != null)
dibujarEscena(canvas, pincel);

//necesario para actualizar los dibujos en animaciones


invalidate();

El código de la clase HiloAnimacion es el siguiente (agregarlo).

public class HiloAnimacion extends Thread{

private boolean corriendo;


private long periodo_muestreo=50;//en milisegundos
public float tiempo;
//pizarra que contiene la escena física
private Pizarra pizarra;
//objetos cuerpos rígidos
private ObjetoLaboratorio[] objetosLab;

/*
Este método construtor para un hilo que
maneja la animación de la pizarra
*/
public HiloAnimacion(Pizarra pizarra, ObjetoLaboratorio[] cuerpos
){
this.pizarra=pizarra; 58
this.objetosLab=cuerpos;
}

@Override
public void run(){

corriendo = true;

while (corriendo==true){

try {
Thread.sleep(periodo_muestreo);//esto en milisegundos
} catch (InterruptedException e) {
e.printStackTrace();
}

//estaba a 0.1 f
tiempo=tiempo+0.01f;
//cambio de estado de la escena física en la pizarra
cambiarEstadosEscenaPizarra(tiempo);

/*Cambia el esatado de los objetos caricatura y lo comunica a


pizarra*/
private void cambiarEstadosEscenaPizarra(float tiempo){

//polea_1
/*La polea 1 arranca de la posición x=100 y=100
Se traslada con velocidad constante en x Vx=200; Vy=0;
No rota alrededor de su eje, W=0
*/
float x_1= 100 + 200*tiempo;
float y_1=100;

//polea_2
/*La polea 2 se arranca de la posición x=100 y=250
No se traslada Vx=0; Vy=0;
Rota alrededor de su eje, W=100
*/
float x_2= 100;
float y_2=250;
float teta_2=100*tiempo;

//polea3
/*La polea 3 se arranca de la posición x=100 y=450
Se traslada Vx=200; Vy=0;
Rota alrededor de su eje, W=100
*/
float x_3= 100 + 200*tiempo;
float y_3=450;
float teta_3=100*tiempo; 59

//mover las poleas


((CuerpoRigido)objetosLab[0]).mover(x_1,y_1);//casting
((CuerpoRigido)objetosLab[1]).mover(teta_2);//casting
((CuerpoRigido)objetosLab[2]).mover(x_3,y_3,teta_3);//casting

/*
Rueda rotando alrededor de eje que pasa por
su centro de masa
*/
float teta_rueda=200*tiempo;
((CuerpoRigido)objetosLab[3]).mover(teta_rueda);//casting

/*
La regla oscila armónicamente con frecuencia
igual a 2 Hz y amplitud 0.2 rad
y fase inicial cero
*/
float frecuencia= 2;
float teta_regla_radianes=(float)
(0.2*(Math.sin(2*Math.PI*frecuencia*tiempo)));
float teta_regla_grados= (float)
(Math.toDegrees(teta_regla_radianes));

((CuerpoRigido)objetosLab[5]).rotar(700,320,teta_regla_grados);//cast
ing

//flecha_2 rotada 60 grados


((Flecha)objetosLab[7]).rotar(60);//casting

//resorte_1 oscilando con amplitud 50 y frecuencia 2 Hz


float y_resorte_1= (float)
(50*(Math.sin(2*Math.PI*frecuencia*tiempo)));
float
longitudNatural=((Resorte)objetosLab[8]).getLongitudNatural();//casti
ng

((Resorte)objetosLab[8]).setLongitud(longitudNatural+y_resorte_1);//c
asting

//actualizar escena
pizarra.setEstadoEscena(objetosLab);
}

El código de la clase AcividadPrincipalMiDecimoSegundaApp es el siguiente

(agregarlo).

60

public class ActividadPrincipalMiDecimoSegundaApp extends Activity {

//Pizarra para dibujar


Pizarra pizarra;
//objetos dibujables para Pizarra
private Polea polea_1,polea_2,polea_3;
private Rueda rueda_1;
private CuerpoRectangular bloque_1, regla_1;
private Flecha flecha_1, flecha_2;
private Resorte resorte_1;
public ObjetoLaboratorio[] objetoLab= new ObjetoLaboratorio[10];

/*Hilo responsable de la animación


El trabajo de animación es mejor manejarlo en hilo
para evitar bloqueos de la aplicación
debido al manejo simultáneo de la GUI con la Acivity
*/
private HiloAnimacion hilo;

protected void onCreate(Bundle savedInstanceState) {


super.onCreate(savedInstanceState);

/*llamada al método para crear los elementos de la interfaz


gráfica de usuario (GUI)*/
crearElementosGui();

/*para informar cómo se debe adaptar la GUI a la pantalla del


dispositivo*/
ViewGroup.LayoutParams parametro_layout_principal = new
ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT);

/*pegar al contenedor la GUI: en el argumento se está


llamando al método crearGui()*/
this.setContentView(crearGui(), parametro_layout_principal);

//crear objetos de laboratorio


crearObjetosLaboratorio( );
//creación del hilo
hilo= new HiloAnimacion(pizarra,objetoLab);
//empezar la ejecución del hilo
hilo.start();

//crear los objetos de la interfaz gráfica de usuario (GUI)


private void crearElementosGui(){
pizarra=new Pizarra(this);
pizarra.setBackgroundColor(Color.WHITE); 61
}

//organizar la distribución de los objetos de de la GUI usando


administradores de diseño
private LinearLayout crearGui(){

//administrador de diseño
LinearLayout linear_principal = new LinearLayout(this);
linear_principal.setOrientation(LinearLayout.VERTICAL);
linear_principal.setGravity(Gravity.CENTER_HORIZONTAL);
linear_principal.setGravity(Gravity.FILL);
linear_principal.setBackgroundColor(Color.rgb(250, 150, 50));

/*pegar el objeto tipo PizarraDibujo)*/


//parámetro de pegada
LinearLayout.LayoutParams parametrosPegada= new
LinearLayout.LayoutParams(android.view.ViewGroup.LayoutParams.MATCH_P
ARENT,0);
parametrosPegada.setMargins(50, 50, 50, 50);
parametrosPegada.weight = 1.0f;
//pegar
linear_principal.addView(pizarra, parametrosPegada);

return linear_principal;

/*Crea los objetos cuerpo rígido con su estado inicial*/


private void crearObjetosLaboratorio( ) {

//trea poleas
//polea ubicada inicialmente en (10,10) y de radio 50
polea_1=new Polea(100,100,50);
objetoLab[0]=polea_1;

//polea ubicada inicialmente en (100,250) y de radio 100


polea_2=new Polea(100,250,100);
polea_2.setColor(Color.BLACK);
objetoLab[1]=polea_2;

//polea ubicada incialmente en (100,450) y de radio 50


polea_3= new Polea(100,450,50);
polea_3.setColor(Color.MAGENTA);
objetoLab[2]=polea_3;

//dibujar las ruedas


rueda_1=new Rueda(700,400,100);
rueda_1.setColor(Color.rgb(0,128,0));
objetoLab[3]=rueda_1;

//dos cuerpos rectangulares


//bloque ubicado su centro de masa inicialmente
//en (500,450) de largo 50 y alto 20 62
bloque_1= new CuerpoRectangular(500,450,50,20);
bloque_1.setColor(Color.argb(100,250,250,100));
objetoLab[4]=bloque_1;

//regla ubicado su centro de masa inicialmente


//en 700,450) de largo 20 y alto 300
regla_1=new CuerpoRectangular(700,450,20,300);
objetoLab[5]=regla_1;

//flecha_1 de longitud 150 y ubicada en (200,200)


flecha_1=new Flecha();
flecha_1.setLongitud(150);
flecha_1.setPosicion(200,200);
objetoLab[6]=flecha_1;

//flecha_2 de longitud 150 y ubicada en (400,200)


flecha_2=new Flecha();
flecha_2.setLongitud(150);
flecha_2.setPosicion(200,200);
flecha_2.setColor(Color.RED);
objetoLab[7]=flecha_2;

//resorte_1
resorte_1=new Resorte();
resorte_1.setLongitudNatural(300);
resorte_1.setPosicion(100,100);
resorte_1.setColor(Color.BLUE);
resorte_1.rotar(90);
objetoLab[8]=resorte_1;

}
}

Declarar la actividad principal en el archivo manifiesto (obligar a que la pantalla se

despliegue horizontalmente). Compilar y ejecutar. Se despliga la GUI de la Figura 10.


63

Figura 10

TALLER

1. Estudiar con el debido detalle las aplicaciones expuestas en este módulo (ESTO ES

MUY IMPORTNTE por lo que se debe hacer con Responsabilidad y Honestidad).

2. Hacer una aplicación denominada MiDecimoTerceraApp que tenga la estructura de la

Figura 11.
Figura 11

Los requisitos son similares a los de la app MiDecimoSegundaApp y son los siguientes

(apoyarse en la jerarquía de clases de la Figura 12):

 La interface Dibujable debe tener el método dibujese( ) que le darán la

capacidad a las clases que la implementen que sus objetos se puiedan dibujar en un

objeto tipo Pizarra.


64

 La clase ObjetoEspacial debe ser abstracta e implementar la interface

Dibujable. No implementar su método dibujese().

Adicionalmente esta clase tendrá un método setMagnificarCaricatura(float

m) que permite cambiar proporcionalmente (es una transformación afin) el tamaño

del objeto espacial.

protected float m=1;

public void setMagnificarCaricatura(float m){

this.m=m;

 Las clases Extraterrestre y Estrella heredan de la clase ObjetoEspacial.

Extraterrestre continuará siendo abstracta ya que no implementará todavía el

método dibujese(). La clase Estrella si lo implementará.

 La clase Extraterrestre es similar en su código interno a la clase

CuerpoRigido de MiDecimoSegundaApp. En la ayuda de esta tarea se da un

código de esta clase (puede ser usado).


 Las clase Marciano, Venusiano y Selenita heredan de la clase

Extraterrestre e implementarán el método dibujese( ).

 Cuando las clases implementan el método dibujese(), deben en él introducir el

código que dibuje la caricatura correspondiente al objeto espacial según la Tabla 1.

Para los objetos tipo Extraterrestre, el punto negro corresponde al centroide de

la figura principal de la caricatura que lo representa (se tomará como el “centroide”

de la caricatura). En la ayuda de esta tarea se da un código de la clase Marciano 65


(puede ser usado).

 La app debe desplegar simultáneamente en un objeto tipo Pizarra los siguientes

objetos:

o 5 objetos tipo Estrella en diferentes posiciones, de diferentes tamaños y

colores.

o Un objeto tipo Marciano moviéndose parabólicamente y a la vez

oscilando con MAS alrededor del “centroide”. También debe ir

cambiando de tamaño y cambiar en algún instante de color. En la ayuda

se da un código ejemplo el cual puede ser usado.

o Un objeto tipo Selenita desplazándose horizontalmente con velocidad

constante y rotando con velocidad angular constante alrededor de eje que

pasa por su “centroide”. Debe cambiar su color tres veces en su recoorido.

o Un objeto tipo Venusiano desplazándose horizontalmente con velocidad

constante y oscilando su “centroide” con MAS en dirección vertical.


Figura 12 66

Tabla 1

Clase Caricatura

Estrella Fija

Marciano

Selenita

Venusiano

Ayuda:
Un posible código para la clase Extraterrestre (se puede usar para la tarea) es el

siguiente:

public abstract class Extraterrestre extends ObjetoEspacial{

protected float posicionCentroideX, posicionCentroideY;


protected float posicionEjeRotacionX, posicionEjeRotacionY;
protected float posicionAngularRotacionEjeXY;
protected int color = Color.RED;

/**
* Constructor por defecto del extraterrestre.
* Su "centroide" está ubicado en la
* posición (0,0). La posición angular es cero
* y su color es rojo
*/
public Extraterrestre() {

}
67
/**
* Constructor de CuerpoRigido
* cuyo "centroide" está
* ubicado en (posicionCentroideX,posicionCentroideY)
*/

public Extraterrestre(float posicionCentroideX , float


posicionCentroideY) {
this.posicionCentroideX = posicionCentroideX ;
this.posicionCentroideY = posicionCentroideY;
}

/**
* Modifica el color del extraterrestre
*
* @param color
*/
public void setColor(int color) {
this.color = color;
}

/**
* Devuelve el color del extraterrestre
*
* @return
*/
public int getColor() {
return color;
}

/**
* Retorna la posicion en X
* del "centroide" del extraterrestre
*
* @return
*/

public float getPosicionX() {

return posicionCentroideX;
}

/**
* Retorna posicion en Y
* del "centroide" del extraterrestre
*
* @return
*/
public float getPosicionY() {

return posicionCentroideY;
}

/** 68
* Modifica la posición (posicionCentroideX,posicionCentroideY)
* del "centroide" del extraterrestre
*
* @param posicionCentroideX
* @param posicionCentroideY
*/
public void mover(float posicionCentroideX, float
posicionCentroideY) {
this.posicionCentroideX = posicionCentroideX;
this.posicionCentroideY = posicionCentroideY;

/**
* Modifica la posición angular del extraterrestre
* alrededor de une eje que pasa por su "centroide"
*
*
* @param posicionAngular
*/
public void mover(float posicionAngular) {
// this.posicionAngularRotacionCentroMasa = posicionAngular;
this.posicionEjeRotacionX = posicionCentroideX;
this.posicionEjeRotacionY = posicionCentroideY;

this.posicionAngularRotacionEjeXY=posicionAngular;
}

/**
* Modifica la posición (posicionCentroide,posicionCentroideY)
* del "centroide" del extraterrestre y genera una rotación
* alrededor del eje que pasa por éste
* @param posicionCentroideX
* @param posicionCentroideY
* @param posicionAngular
*/

public void mover(float posicionCentroideX, float


posicionCentroideY, float posicionAngular){
this.posicionCentroideX=posicionCentroideX;
this.posicionCentroideY=posicionCentroideY;

this.posicionEjeRotacionX = posicionCentroideX;
this.posicionEjeRotacionY = posicionCentroideY;

this.posicionAngularRotacionEjeXY=posicionAngular;
}

//Método abstracto que viene de la Interface Dibujable


public abstract void dibujese(Canvas canvas, Paint pincel) ;
}

Un posible código para la clase Marciano (se puede usar para la tarea) es el siguiente:

public class Marciano extends Extraterrestre { 69

/**
* Constructor por defecto
* del marciano con "centroide" en (0,0)
* y de radio 50f
*/
public Marciano() {
super();

/**
* Constructor del marciano con "centroide"
* en (posicionCentroideX,posicionCentroideY)
* y diámetro igual a 2*radio
*/

public Marciano(float posicionCentroideX, float


posicionCentroideY) {
super(posicionCentroideX, posicionCentroideY);

//se implementó este método dque en su clase madre es abstracto


public void dibujese(Canvas canvas, Paint pincel) {

//estilo del pindel


pincel.setStyle(Paint.Style.STROKE);
//grosor del pincel
pincel.setStrokeWidth(2f);
//color del pincel
pincel.setColor(color);

canvas.save();

//magnificar
canvas.scale(m,m,posicionCentroideX,posicionCentroideY);
//rotar

canvas.rotate(posicionAngularRotacionEjeXY,posicionEjeRotacionX,posici
onEjeRotacionY);
//dibujar círculo de la cara del marciano
float radio=50f;
pincel.setStyle(Paint.Style.FILL);
canvas.drawCircle(posicionCentroideX, posicionCentroideY,
radio, pincel);
pincel.setColor(Color.BLACK);
//dibujar circunferencia de la cara del marciano
pincel.setStyle(Paint.Style.STROKE);
canvas.drawCircle(posicionCentroideX, posicionCentroideY,
radio, pincel);

//dibujar los ojitos del marcianito 70


float separacion=0.3f*radio;
float posicionOjoCentroIzquierdoX=posicionCentroideX-
separacion;
float posicionOjoCentroIzquierdoY=posicionCentroideY-
separacion;
float posicionOjoCentroDerechoX=posicionCentroideX+separacion;
float posicionOjoCentroDerechoY=posicionCentroideY-separacion;
pincel.setStyle(Paint.Style.FILL);
pincel.setColor(Color.WHITE);
canvas.drawCircle(posicionOjoCentroIzquierdoX,
posicionOjoCentroIzquierdoY, 0.2f*radio, pincel);
canvas.drawCircle(posicionOjoCentroDerechoX,
posicionOjoCentroDerechoY, 0.2f*radio, pincel);
//dibujar la pupila de los ojitos
pincel.setColor(color);
canvas.drawCircle(posicionOjoCentroIzquierdoX,
posicionOjoCentroIzquierdoY, 0.1f*radio, pincel);
canvas.drawCircle(posicionOjoCentroDerechoX,
posicionOjoCentroDerechoY, 0.1f*radio, pincel);

//dibujar la boquita del marcianito


float altoBoca= 0.2f*radio;
float anchoBoca=0.5f*radio;
pincel.setColor(Color.WHITE);
float descenso=0.3f*radio;
float posicionBocaCentroX=posicionCentroideX;
float posicionBocaCentroY=posicionCentroideY+descenso;
float xs_izquierda=posicionBocaCentroX-0.5f*anchoBoca;
float ys_izquierda=posicionBocaCentroY-0.5f*altoBoca;
float xi_derecha=posicionBocaCentroX+0.5f*anchoBoca;
float yi_derecha=posicionBocaCentroY+0.5f*altoBoca;

canvas.drawRect(xs_izquierda,ys_izquierda,xi_derecha,yi_derecha,pincel
);

//dibujar las orejitas del marcianito


//orejita derecha
float x_i_oreja_derecha=posicionOjoCentroDerechoX+0.1f*radio;
float y_i_oreja_derecha=posicionOjoCentroDerechoY-0.2f*radio;
float x_s_oreja_derecha=posicionCentroideX+radio;
float y_s_oreja_derecha=posicionCentroideY-2f*radio;
//orejita izaquierda
float x_i_oreja_izquierda=posicionOjoCentroIzquierdoX-
0.1f*radio;
float y_i_oreja_izquierda=posicionOjoCentroIzquierdoY-
0.2f*radio;
float x_s_oreja_izquierda=posicionCentroideX-radio;
float y_s_oreja_izquierda=posicionCentroideY-2f*radio;

pincel.setColor(color);
pincel.setStrokeWidth(20f);

canvas.drawLine(x_i_oreja_derecha,y_i_oreja_derecha,x_s_oreja_derecha,
y_s_oreja_derecha,pincel);

canvas.drawLine(x_i_oreja_izquierda,y_i_oreja_izquierda,x_s_oreja_izqu
ierda,y_s_oreja_izquierda,pincel);

71
//regresa la rotación
canvas.restore();

Un código inicial para la clase HiloAnimación (se puede usar para la tarea) es el

siguiente:

public class HiloAnimacion extends Thread {

private boolean corriendo;


private long periodo_muestreo = 50;//en milisegundos
public float tiempo;
//pizarra que contiene la escena física
private Pizarra pizarra;
//objetos espaciales
private ObjetoEspacial[] objetosEspacio;

/*
Este método construtor para un hilo que
maneja la animación de la pizarra
*/
public HiloAnimacion(Pizarra pizarra, ObjetoEspacial[] cuerpos) {
this.pizarra = pizarra;
this.objetosEspacio = cuerpos;
}

@Override
public void run() {

corriendo = true;

while (corriendo == true&&tiempo<6) {


try {
Thread.sleep(periodo_muestreo);//esto en milisegundos
} catch (InterruptedException e) {
e.printStackTrace();
}

//estaba a 0.1 f
tiempo = tiempo + 0.01f;
//cambio de estado de la escena física en la pizarra
cambiarEstadosEscenaPizarra(tiempo);

72
}

/*Cambia el esatado de los objetos caricatura y lo comunica a


pizarra*/
private void cambiarEstadosEscenaPizarra(float tiempo) {

/*El marciano ... polea 3 se arranca de la posición x=100


y=450
Se traslada Vx=200; Vy=0;
Rota alrededor de su eje, W=100
*/
//movimiento parabólico del centroide
float velocidad_inicial_marciano_x=100f;
float posicion_inicial_marciano_x=100f;
float posicion_marciano_x = posicion_inicial_marciano_x +
velocidad_inicial_marciano_x* tiempo;
float aceleracion_marciano_y = 100f;
float velocidad_inicial_marciano_y = 300;
float posicion_inicial_marciano_y=450;
float posicion_marciano_y = posicion_inicial_marciano_y-
velocidad_inicial_marciano_y * tiempo + 0.5f * aceleracion_marciano_y
* tiempo * tiempo;
//oscilación armónica alrededor de eje que pas por el
centroide
float frecuencia = 2;
float teta_radianes = (float) (0.2 * (Math.sin(2 * Math.PI *
frecuencia * tiempo)));
float teta_grados = (float) (Math.toDegrees(teta_radianes));

//mover marciano
((Extraterrestre)
objetosEspacio[0]).mover(posicion_marciano_x,
posicion_marciano_y);//casting
objetosEspacio[0].setMagnificarCaricatura(1 + 0.2f * tiempo);
((Extraterrestre)
objetosEspacio[0]).mover(teta_grados);//casting
//cambiar color
if(posicion_marciano_x>600){

((Extraterrestre)objetosEspacio[0]).setColor(Color.GREEN);//casting
}
//actualizar escena
pizarra.setEstadoEscena(objetosEspacio);

73

REFERENCIAS

 Franco G. A (2000)., Curso de Lenguaje Java,  Universidad del País Vasco.

http://www.sc.ehu.es/sbweb/fisica/curso.htm. Consultada [Julio de 2020].

 Moya R. C. Herencia en Java con ejemplos. https://jarroba.com/herencia-en-la-

programacion-orientada-a-objetos-ejemplo-en-java/. Consultada [Julio de 2020].

También podría gustarte

pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy