home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Informática Multimedia Fácil 56
/
INF1297.iso
/
SOFCAS
/
EDUCA
/
EVSIM11.ZIP
/
EV.C
< prev
next >
Wrap
C/C++ Source or Header
|
1996-04-27
|
67KB
|
1,839 lines
/*───────────────────────────────────────────────────────────────────\
│ │
│ EV 1.1 │
│ │
│ PROGRAMA DE SIMULACION GRAFICA DE CAMPOS (Borland C++ 2.0+ │
│ Y POTENCIALES ELECTRICOS Y GRAVITATORIOS y Turbo Assembler) │
│ │
│ (C) 1996 José J. Muñoz García (hobster@gui.uva.es) │
│ & Ciriaco G. de Celis (ciri@gui.uva.es) │
│ │
│ Incluir en un fichero de proyecto con EV-SYS.ASM │
│ El modelo de memoria debe ser necesariamente LARGE │
│ │
│ Nota: Puede ser necesario editar Options/Transfer/TurboAssembler │
│ y activar la opción /m5 en la línea de comandos, para │
│ evitar mensajes de error. Alternativamente, se puede │
│ introducir ev-sys.obj en lugar de ev-sys.asm en el fichero │
│ de proyecto, obteniéndolo antes con TASM ev-sys /m5 /mx │
│ │
\───────────────────────────────────────────────────────────────────*/
/* FICHEROS DE CABECERA */
#include <stdlib.h>
#include <stdio.h>
#include <conio.h>
#include <dos.h>
#include <alloc.h>
#include <string.h>
#include <math.h>
unsigned _stklen = 32768;
/* CONSTANTES */
#define PRESERVAR 1
#define RESTAURAR 2
#define MOSTRAR 3
#define MODO80 4
#define RESALTAR 5
#define MAX_E 100
#define CAMPO 0
#define POTENCIAL 1
#define ELECTRICO 1
#define GRAVITATORIO 2
#define M800x600x16 0x102 /* modos VESA de 16c */
#define M800x600x16_S3 0x202
#define M1024x768x16 0x104
#define M1024x768x16_S3 0x204
#define M1280x1024x16 0x106
#define M1280x1024x16_S3 0x208
/* TIPOS */
typedef enum {CONF, EDIT, LINE, CAMP, POT, INFO, SALIR, IDIOMA} Opciones;
typedef struct {
int tipo; /* puede ser ELECTRICO o GRAVITATORIO */
int puntuales; /* número de cargas o masas */
float puntual [MAX_E][3]; /* (X, Y) de las cargas/masas; valor */
float xrango, yrango; /* rango del plano */
float ajuste; /* para representación en 256 colores */
int lineas; /* para representación en 16 colores */
} Sistema;
typedef struct {
char fabricante;
char version;
char compresion;
char bitspixel;
short xmin, ymin, xmax, ymax;
short hdpi, vdpi;
char paleta[48];
char reservado;
char planos;
short byteslinea;
short infopaleta;
short hpantalla;
short vpantalla;
char resto[54];
} CabeceraPCX;
/* PROTOTIPOS */
extern void VGAModeX (int);
extern void setpix (int, int, int);
extern void set16pix (int, int, int);
extern void set4pix (int, int, int);
extern void lineahoriz (int, int, int, int);
extern void recta (int, int, int, int, int, int);
extern void setpage (int);
extern void showpage (int);
extern void Xprcar (int, int, int, int, int, int, int, int);
extern int prcar (int, int, int, int, int);
extern void PintaBitMap (char *, int, int, int, int, int, int, int, int);
extern void MoveVram (void *, void *, int);
extern int getpix (int, int);
extern int NoHayTecla (void);
extern void interrupt NuevaInt24 (void);
extern int segvideo;
extern char far *FuenteInfo;
void main (int *, char **),
Vram (int),
SetMode (unsigned),
PaletaEV (void),
PaletaMenu (void),
PaletaConf (void),
Xprcad (char *, int, int, int, int, int, int, int),
PintaOpcionMenu (Opciones, int),
PintaOpcionConf (int, int),
Configurar (int *, int *, int *, int *),
Ventana (int, int, int, int, int, int),
Cuadro (int),
Puntuales (Sistema *, float, float),
EmulaCursor (int, int, int),
Cursor (int, int),
Editar (Sistema *),
Ayuda (void),
Grafica256 (Sistema *, int, int),
Grafica16 (Sistema *, int, int, int),
Pausa (int, int),
About (void);
int prcad (char *, int, int, int, int),
getpix16 (int, int),
AnimaCursor (int *, int *, float, float),
input (char *, int, int, int, int, int, int, int),
PintaModos (int, int),
SalvaPantalla (int, int),
PintaEoV (Sistema *, int, int),
TrazaCampo (Sistema *datos, int, int, int),
ExisteVGA (void), /* Detectar VGA */
TestVESA (void), /* Detectar soporte VESA */
ExisteModoVESA (unsigned), /* Comprobar si un modo es soportado */
GetBest16 (int *, int *), /* Obtener mejor modo de 16c */
HablaSp (void);
Opciones Menu (void);
/* VARIABLES */
int sp = 1, /* 1 = mensajes en español */
sonido = 1; /* 1 = sonido activo */
/* TOLERANCIA A FALLOS (ESTA FUNCION NO DEBERIA EJECUTARSE NUNCA) */
int matherr (struct exception *a)
{
SetMode (0x12);
prcad ("Error interno de cálculo irrecuperable.", 0, 0, 15, 0);
prcad ("Pulse una tecla para intentar continuar...", 0, 16, 15, 0);
while (kbhit()) getch(); if (!getch()) getch();
a->retval = 0;
main (0, NULL);
exit (129);
return 1;
}
/* PRESERVAR O RESTAURAR LA PANTALLA DE TEXTO */
void Vram (int operacion)
{
static scr_ok, modo, pag, cx, cy, colorbits;
static long tam;
static char *scrbuf;
union REGS regs;
if (operacion==PRESERVAR) {
scr_ok=0;
modo=peekb(0x40, 0x49) & 0x7F;
if (peekb(0x40, 0x84) < 24) pokeb(0x40, 0x84, 24);
pag=peekb(0x40,0x62);
cx=peekb(0x40,0x50+pag*2); cy=peekb(0x40,0x51+pag*2);
colorbits=peek(0x40, 0x10) & 0x30;
tam = 2L * (peekb(0x40, 0x84) + 1) * peek (0x40, 0x4A);
if (tam > 32768L) tam=32768L;
if ((modo<=3)||(modo==7)) {
if ((scrbuf=farmalloc(tam))!=NULL) {
scr_ok=1;
movedata ((modo==7) ? 0xb000: 0xb800,
(modo==7) ? 0 : peek(0x40, 0x4e),
FP_SEG(scrbuf), FP_OFF(scrbuf), tam);
}
}
if ((modo!=3) && (modo!=7)) textmode ((modo!=7) ? C80:MONO);
}
else if ((operacion==RESTAURAR) || (operacion==MOSTRAR)) {
poke (0x40, 0x10, peek(0x40, 0x10) & 0xFFCF | colorbits);
if (modo != (peekb(0x40, 0x49) & 0x7F)) {
regs.x.ax=modo; int86 (0x10, ®s, ®s);
}
else {
regs.x.ax=0x1003; regs.x.bx=1;
int86 (0x10, ®s, ®s);
}
regs.x.ax=0x500+pag; int86 (0x10, ®s, ®s);
regs.x.ax=0x200; regs.x.bx=pag<<8;
regs.h.dh=cy; regs.h.dl=cx; int86 (0x10, ®s, ®s);
if (scr_ok) {
movedata (FP_SEG(scrbuf), FP_OFF(scrbuf),
(modo==7) ? 0xb000 : 0xb800,
(modo==7) ? 0 : peek(0x40, 0x4e), tam);
if (operacion==RESTAURAR) farfree(scrbuf);
}
}
else if ((operacion==MODO80)) {
poke (0x40, 0x10, peek(0x40, 0x10) & 0xFFCF | colorbits);
if (((peekb(0x40, 0x49) & 0x7F) == 0x13) || ((modo!=3) && (modo!=7)))
textmode ((modo!=7) ? C80:MONO);
if ((scr_ok) && ((modo==2) || (modo==3) || (modo==7)))
movedata (FP_SEG(scrbuf), FP_OFF(scrbuf),
(modo==7) ? 0xb000 : 0xb800,
(modo==7) ? 0 : peek(0x40, 0x4e), tam);
}
}
/* COMPROBAR QUE EXISTE VGA */
int ExisteVGA()
{
struct REGPACK r;
r.r_ax=0x1A00; intr (0x10, &r);
return ((r.r_ax & 0xFF)==0x1A);
}
/* COMPROBAR QUE EXISTE SOPORTE VESA */
int TestVESA (void)
{
struct REGPACK r;
char far *mem;
unsigned vesa;
mem = farmalloc (256L);
r.r_es = FP_SEG (mem); r.r_di = FP_OFF (mem);
r.r_ax = 0x4F00; intr (0x10, &r);
mem[4]=0; if (strcmp (mem, "VESA")==0) vesa=1; else vesa=0;
farfree (mem);
return (vesa);
}
/* COMPROBAR LA EXISTENCIA DE UN MODO GRAFICO VESA */
int ExisteModoVESA (unsigned modo)
{
struct REGPACK r;
unsigned far *mem, far *array;
mem = farmalloc (256L);
r.r_es = FP_SEG (mem); r.r_di = FP_OFF (mem);
r.r_ax=0x4F00; intr (0x10, &r);
array = MK_FP (mem[8], mem[7]);
farfree (mem);
while ((*array!=0xFFFF) && (*array!=modo)) array++;
return (*array==modo);
}
/* ESTABLECER UN MODO GRAFICO VESA U ORDINARIO */
void SetMode (unsigned modo)
{
struct REGPACK r;
long far *mem;
if (modo < 0x100) {
r.r_ax=0x0012;
intr (0x10, &r);
}
else {
mem = farmalloc (256L);
r.r_es = FP_SEG (mem); r.r_di = FP_OFF (mem);
r.r_ax = 0x4F01; r.r_cx = modo; intr (0x10, &r);
farfree (mem);
r.r_ax=0x4F02; r.r_bx=modo; intr (0x10, &r);
}
}
/* OBTENER EL VALOR DE UN PIXEL EN UN MODO VESA U ORDINARIO */
int getpix16 (int cx, int cy)
{
union REGS r;
r.x.ax = 0x0D00;
r.x.bx = 0;
r.x.cx = cx;
r.x.dx = cy;
int86 (0x10, &r, &r);
return (r.h.al);
}
/* BUSCAR EL MODO DE 16 COLORES DE MAYOR RESOLUCION (HASTA 1024x768) */
int GetBest16 (int *maxx, int *maxy)
{
if (TestVESA()) {
*maxx=1024; *maxy=768;
if (ExisteModoVESA (M1024x768x16)) return (M1024x768x16);
if (ExisteModoVESA (M1024x768x16_S3)) return (M1024x768x16_S3);
*maxx=800; *maxy=600;
if (ExisteModoVESA (M800x600x16)) return (M800x600x16);
if (ExisteModoVESA (M800x600x16_S3)) return (M800x600x16_S3);
}
*maxx=640; *maxy=480;
return (0x12);
}
/* ESTABLECER LA PALETA PARA EL MODULO DEL CAMPO O EL POTENCIAL */
void PaletaEV()
{
unsigned char dac[256][3];
union REGS r;
struct SREGS s;
register p;
for (p=191; p>127; p--) {
dac[p][0]=0;
dac[p][1]=0;
dac[p][2]=191-p;
}
for (p=192; p<256; p++) {
dac[p][0]=p-192;
dac[p][1]=0;
dac[p][2]=0;
}
r.x.ax=0x1012; r.x.bx=128; r.x.cx=128;
s.es=FP_SEG(dac); r.x.dx=FP_OFF(&dac[r.x.bx]);
int86x (0x10, &r, &r, &s);
}
/* ESTABLECER LA PALETA PARA EL MENU */
void PaletaMenu()
{
unsigned char dac[256][3];
union REGS r;
struct SREGS s;
register i;
for (i=128; i<192; i++) {
dac[i][0]=0;
dac[i][1]=0;
dac[i][2]=i-128;
}
for (i=208; i<256; i++) {
dac[i][0]=255-i+16;
dac[i][1]=0;
dac[i][2]=((255-i+16) >> 1) + 8;
}
for (i=192; i<208; i++) {
dac[i][0]=(208-i) * 3 + 15;
dac[i][1]=(208-i) * 3 + 15;
dac[i][2]=0;
}
for (i=64; i<128; i++) {
dac[i][0]=0;
dac[i][1]=127-i;
dac[i][2]=0;
}
for (i=32; i<64; i++) {
dac[i][0]=0;
dac[i][1]=0;
dac[i][2]=(64-i)*3/2+15;
}
dac[20][0]=0;
dac[20][1]=0;
dac[20][2]=63;
dac[21][0]=8;
dac[21][1]=40;
dac[21][2]=16;
r.x.ax=0x1012; r.x.bx=20; r.x.cx=236;
s.es=FP_SEG(dac); r.x.dx=FP_OFF(&dac[r.x.bx]);
int86x (0x10, &r, &r, &s);
}
/* ESTABLECER LA PALETA PARA LA CONFIGURACION */
void PaletaConf()
{
unsigned char dac[256][3];
union REGS r;
struct SREGS s;
register i;
for (i=128; i<192; i++) {
dac[i][0]=i-128;
dac[i][1]=(i-128) >> 1;
dac[i][2]=0;
}
for (i=200; i<256; i++) {
dac[i][0]=0;
dac[i][1]=(255-i)+8;
dac[i][2]=0;
}
dac[199][0]=dac[199][1]=dac[199][2]=63;
dac[198][0]=dac[198][1]=0; dac[198][2]=63;
dac[197][0]=dac[197][1]=63; dac[197][2]=0;
dac[196][0]=63; dac[196][1]=0; dac[196][2]=63;
r.x.ax=0x1012; r.x.bx=128; r.x.cx=128;
s.es=FP_SEG(dac); r.x.dx=FP_OFF(&dac[r.x.bx]);
int86x (0x10, &r, &r, &s);
}
/* IMPRIMIR CADENA DE CARACTERES EN MODO X */
void Xprcad (char *cad, int x, int y, int largo, int alto,
int tinta, int papel, int escala)
{
while (*cad) {
Xprcar (*cad, x, y, largo, alto, tinta, papel, escala);
x+=largo*8;
cad++;
}
}
/* IMPRIMIR CADENA DE CARACTERES EN MODO GRAFICO DE 16 COLORES */
int prcad (char *cad, int x, int y, int tinta, int papel)
{
static cx=0, cy=0;
if (x!=-1) cx=x, cy=y;
while (*cad) {
cx += prcar (*cad, cx, cy, tinta, papel);
cad++;
if (cx > 632) cx=0, cy+=16;
}
if (y==-1) cy+=16, cx=0;
return (cy*256+cx);
}
/* LEER CADENA DE CARACTERES POR TECLADO EN MODO 640x480x16 */
void EmulaCursor (int x, int y, int insercion)
{
register i;
outport (0x3CE, 0x1803);
for (i = insercion? 13:0; i<15; i++) recta (x, y+i, x+8, y+i, 15, 1);
outport (0x3CE, 0x0003);
}
int input (char *cad, int modo, int maxcar, int x, int y, int tinta, int papel, int papeli)
{
int t, i, px, primeravez=1, cx, xx;
static insercion=1;
char *p, tamcars[80];
px = strlen (cad);
p=cad; cx=x; while (*p) cx += (tamcars[p-cad] = prcar (*p++, cx, y, tinta, papeli));
xx = cx;
for (i=px; i<maxcar; i++) cx += (tamcars[i] = prcar (255, cx, y, tinta, papel));
EmulaCursor (xx, y, insercion);
do {
if (!(t=getch())) t = getch() << 8;
if ((primeravez) && (t!=8) && (t!=13) && (t!=27) && (t<256)) cad[0]=px=0;
primeravez=0;
switch (t) {
case 0x4B00: if (px) px--; break;
case 0x4D00: if (px < strlen(cad)) px++; break;
case 8: if (px)
for (i=--px; i<=strlen(cad); i++) cad[i]=cad[i+1];
break;
case 0x5300: for (i=px; i<=strlen(cad); i++) cad[i]=cad[i+1]; break;
case 0x4700: px=0; break;
case 0x4F00: px = strlen(cad); break;
case 0x5200: EmulaCursor (xx, y, insercion);
insercion ^= 1;
EmulaCursor (xx, y, insercion);
default: if(
(t>=32) && (t<256) && (
(modo==0) ||
((modo==1) && (t>='0') && (t<='9')) ||
((modo==2) && (
((t>='0') && (t<='9')) || /* Modo 0: Asc */
((t>='a') && (t<='f')) || /* Modo 1: Dec */
((t>='A') && (t<='F')) /* Modo 2: Hex */
)
)
)
)
if (!insercion) {
if (px < maxcar) {
cad[strlen(cad)+1]=0;
cad[px++]=t;
}
}
else
if (strlen(cad) < maxcar) {
for (i=strlen(cad); i>=px; i--) cad[i+1]=cad[i];
cad[i+1]=t; px++;
}
break;
}
EmulaCursor (xx, y, insercion);
p=cad; cx=x; while (*p) cx += (tamcars[p-cad] = prcar (*p++, cx, y, tinta, papel));
for (i=strlen(cad); i<maxcar; i++) cx += (tamcars[i] = prcar (255, cx, y, tinta, papel));
for (xx=x, i=1; i<=px; i++) xx += tamcars[i];
EmulaCursor (xx, y, insercion);
} while ((t!=13) && (t!=27));
EmulaCursor (xx, y, insercion);
if ((t==13) && (strlen(cad)==0)) t=27; /* campo vacío -> ESC */
return (t==13);
}
/* Grabar pantalla gráfica en formato PCX. En el caso de las
pantallas 320x400 y 320x480 se dobla imaginariamente la
resolución horizontal (320->640) para mejorar la relación
de aspecto que presentarán por defecto. */
int SalvaPantalla (int maxx, int maxy)
{
CabeceraPCX cab;
FILE *f;
void interrupt (*ViejaInt24) (void);
int cx, cy, pixel, antpixel, pixveces, offset, error,
doblar, i, m320;
static char nombre[13]="EV-CAP00.PCX";
unsigned char buffer [2049];
union REGS r;
struct SREGS s;
if (sonido) for (i=2000; i<2400; i+=40) {
sound (i); delay (10);
sound (i+200); delay (10);
}
nosound();
m320 = (maxx==320);
doblar = (m320 && (maxy>240));
memset (&cab, 0, sizeof(CabeceraPCX)); /* Cabecera estándar PCX */
cab.fabricante = 10;
cab.version = 5;
cab.compresion = 1;
cab.bitspixel = 8;
cab.xmax = maxx-1; if (doblar) cab.xmax = maxx*2 - 1;
cab.ymax = maxy-1;
cab.planos = 1;
cab.byteslinea = cab.xmax+1;
cab.infopaleta = 1;
ViejaInt24=getvect(0x24);
setvect (0x24, NuevaInt24); /* evitar error crítico */
if ((f=fopen(nombre, "wb")) == NULL) return (1);
if (fwrite (&cab, 1, sizeof(CabeceraPCX), f) == 0) {
fclose (f);
return (1);
}
offset = 0;
pixveces = 1;
if (maxx==320)
antpixel = getpix (0, 0);
else
antpixel = getpix16 (0, 0); /* B y N */
cx = 1;
cy = 0;
do {
do {
if (m320)
pixel = getpix (cx, cy);
else
pixel = getpix16 (cx, cy);
if ((pixel == antpixel) && ((pixveces<31) || ((pixveces<63) && !doblar)))
pixveces++;
else {
if ((pixveces==1) && !doblar && (antpixel<0xC0))
buffer[offset++]=antpixel;
else {
if (doblar)
buffer [offset++] = 0xC0 | (pixveces << 1); /* ancho x2 */
else
buffer [offset++] = 0xC0 | pixveces;
buffer [offset++] = antpixel;
}
antpixel = pixel;
pixveces = 1;
}
if (offset >= 2048) {
if (fwrite (buffer, 1, offset, f) != offset) {
fclose (f);
return (1);
}
offset = 0;
}
cx ++;
} while (cx < maxx);
if (m320) lineahoriz (0, cy, 80, 0); else recta (0, cy, maxx, cy, 0, 0);
cx = 0;
cy++;
} while (cy < maxy);
if (fwrite (buffer, 1, offset, f) != offset) {
fclose (f);
return (1);
}
offset = 0;
if (pixveces>1) {
if (doblar)
buffer [offset++] = 0xC0 | (pixveces << 1); /* ancho x2 */
else
buffer [offset++] = 0xC0 | pixveces;
buffer [offset++] = antpixel;
}
buffer [offset++] = 0xC1;
buffer [offset++] = pixel;
buffer [offset++] = 0x0C; /* paleta de 256 colores */
r.x.ax = 0x1017; r.x.bx = 0; r.x.cx = 256;
s.es = FP_SEG (&buffer[offset]); r.x.dx = FP_OFF (&buffer[offset]);
int86x (0x10, &r, &r, &s); /* obtener paleta */
for (cx = 0; cx < 768; cx++)
buffer [offset++] <<= 2; /* 64 -> 256 */
if (fwrite (buffer, 1, offset, f) != offset) {
fclose (f);
return (1);
}
if (sonido) for (i=2400; i>2000; i-=40) {
sound (i); delay (10);
sound (i+200); delay (10);
}
nosound();
nombre[7]++; if (nombre[7] > '9') nombre[7]='0', nombre[6]++;
i = (fclose(f) == EOF);
setvect (0x24, ViejaInt24);
return (i);
}
/* TRAZAR LA GRAFICA DEL MODULO DEL CAMPO O DEL POTENCIAL */
int PintaEoV (Sistema *datos, int ypixels, int EoV)
{
register x, y;
double cx, cy, EV, coc, cx0, cy0, cte;
int xx2, yy2, xinc, punt, tec, xpixels=320;
if (!datos->puntuales) {
Xprcad (sp?"¡No hay datos! ":" No data! ",
44, ypixels/5, 2, ypixels/80, 15, 0xFF, 0);
Xprcad (sp?"Elige primero la opción de Editar":" Select first the Edit option ",
24, ypixels/2, 1, 1, 15, 0xFF, 0);
Xprcad (sp?"Pulsa una tecla...":" Press any key...", 92, ypixels*2/3, 1, 2, 15, 0xFF, 0);
return ('P');
}
if (datos->tipo == ELECTRICO) cte=8.987551e9; else cte=6.67259e-11;
xx2 = xpixels >> 1; yy2 = ypixels >> 1;
/* primera pasada: resolución real
de 80x120, 80x100, 80x60 ó 80x50: 1/16 de los pixels */
for (y=0; (y<ypixels) && NoHayTecla(); y+=4)
for (x=0; (x<xpixels) && NoHayTecla(); x+=4) {
EV = 0.0;
for (punt = 0; punt < datos->puntuales; punt++) {
cx = datos->xrango * (x - xx2) / xpixels;
cy = datos->yrango * (ypixels - 1 - y - yy2) / ypixels;
cx0 = datos->puntual [punt][0] - cx;
cy0 = datos->puntual [punt][1] - cy;
coc = cx0 * cx0 + cy0 * cy0;
if (EoV) coc = sqrt (coc); /* r² -> campo, r -> potencial */
if (coc < 1e-10) coc=1e-10; /* evitar división por cero */
EV += cte * datos->puntual[punt][2] / coc;
}
if (EV>1.0) EV = pow (datos->ajuste, log (EV)); /* reducción logarítmica */
else if (EV<-1.0) EV = - pow (datos->ajuste, log (-EV)); else EV = 0.0;
if (EV > 63.) EV = 63.; else if (EV < -63.) EV = -63.;
set16pix (x, y, (int) EV + 192);
}
/* segunda pasada: resolución real
de 160x240, 160x200, 160x120 ó 160x100: 3/16 de los pixels */
for (y=0; (y<ypixels) && NoHayTecla(); y+=2) {
if (y % 4) { x=0; xinc=2; } else { x=2; xinc=4; }
for (; (x<xpixels) && NoHayTecla(); x+=xinc) {
EV = 0.0;
for (punt = 0; punt < datos->puntuales; punt++) {
cx = datos->xrango * (x - xx2) / xpixels;
cy = datos->yrango * (ypixels - 1 - y - yy2) / ypixels;
cx0 = datos->puntual [punt][0] - cx;
cy0 = datos->puntual [punt][1] - cy;
coc = cx0 * cx0 + cy0 * cy0;
if (EoV) coc = sqrt (coc);
if (coc < 1e-10) coc=1e-10;
EV += cte * datos->puntual[punt][2] / coc;
}
if (EV>1.0) EV = pow (datos->ajuste, log (EV)); /* reducción logarítmica */
else if (EV<-1.0) EV = - pow (datos->ajuste, log (-EV)); else EV = 0.0;
if (EV > 63.) EV = 63.; else if (EV < -63.) EV = -63.;
set4pix (x, y, (int) EV + 192);
}
}
/* última pasada: resolución real
de 320x480, 360x400, 320x240 ó 320x200: 12/16 de los pixels */
for (y=0; (y<ypixels) && NoHayTecla(); y++) {
if (y % 2) { x=0; xinc=1; } else { x=1; xinc=2; }
for (; (x<xpixels) && NoHayTecla(); x+=xinc) {
EV = 0.0;
for (punt = 0; punt < datos->puntuales; punt++) {
cx = datos->xrango * (x - xx2) / xpixels;
cy = datos->yrango * (ypixels - 1 - y - yy2) / ypixels;
cx0 = datos->puntual [punt][0] - cx;
cy0 = datos->puntual [punt][1] - cy;
coc = cx0 * cx0 + cy0 * cy0;
if (EoV) coc = sqrt (coc);
if (coc < 1e-10) coc=1e-10;
EV += cte * datos->puntual[punt][2] / coc;
}
if (EV>1.0) EV = pow (datos->ajuste, log (EV)); /* reducción logarítmica */
else if (EV<-1.0) EV = - pow (datos->ajuste, log (-EV)); else EV = 0.0;
if (EV > 63.) EV = 63.; else if (EV < -63.) EV = -63.;
setpix (x, y, (int) EV + 192);
}
}
if (kbhit()) { tec=getch(); if (!tec) tec=getch() << 8; } else tec=0;
return (tec);
}
/* TRAZAR LA GRAFICA DE LAS LINEAS DE CAMPO */
int TrazaCampo (Sistema *datos, int xpixels, int ypixels, int color)
{
double PI=3.1415926536, angulo, nlin, maxc, Ei, Ex, Ey, absEy, absEx,
xi, yi, xf, yf, ix, iy, coc, xinc, yinc, cte,
alto2pasos, ancho2pasos, pasos2, ancho2, alto2, nancho2, nalto2,
xpixelsancho, ypixelsalto, xpixels2, ypixels2;
int carga, cargas, i, tec, pasos=100, EntraEnOtraCarga,
signo, deveras, x0, y0, x1, y1;
if (!datos->puntuales) {
if (sp)
printf("\n\n\n\n\n\n\n\n\n\n\n\n\t\t\t\t ¡No hay datos!\n\n"
"\t\t\tElige primero la opción de Editar\n\n"
"\t\t\t\tPulsa una tecla...");
else
printf("\n\n\n\n\n\n\n\n\n\n\n\n\t\t\t\t No data! \n\n"
"\t\t\t Select first the Edit option\n\n"
"\t\t\t\t Press any key...");
return (0);
}
if (datos->tipo == ELECTRICO) cte=8.987551e9; else cte=6.67259e-11;
/* valores fijos precalculados para acelerar cálculos */
pasos2 = 2*pasos;
alto2pasos = datos->yrango/2/pasos; ancho2pasos = datos->xrango/2/pasos;
ancho2 = datos->xrango/2; nancho2 = -datos->xrango/2;
alto2 = datos->yrango/2; nalto2 = -datos->yrango/2;
xpixelsancho = xpixels / datos->xrango; xpixels2 = xpixels / 2;
ypixelsalto = ypixels / datos->yrango; ypixels2 = ypixels / 2;
maxc = fabs(datos->puntual[0][2]);
for (carga=1; carga < datos->puntuales; carga++)
if (maxc < fabs(datos->puntual[carga][2]))
maxc = fabs(datos->puntual[carga][2]);
if (maxc > 1e-99) nlin = datos->lineas / maxc; else nlin=0;
for (carga=0; (carga < datos->puntuales) && (!kbhit()); carga++) {
if (datos->puntual[carga][2] == 0.0) signo=1; else
signo = fabs(datos->puntual[carga][2]) / datos->puntual[carga][2];
cargas = fabs(datos->puntual[carga][2]) * nlin;
if (cargas)
for (angulo=0.1; (angulo < 2*PI+0.1) && (!kbhit()); angulo += PI/cargas) {
for (deveras = (signo==-1)?0:1; deveras < 2; deveras++) {
xi = cos (angulo) * datos->xrango/pasos + datos->puntual[carga][0];
yi = sin (angulo) * datos->yrango/pasos + datos->puntual[carga][1]; /* (x, y) iniciales */
EntraEnOtraCarga=0;
while (!EntraEnOtraCarga) {
Ex = Ey = 0.0;
for (i=0; i<datos->puntuales; i++) {
ix = xi - datos->puntual[i][0];
iy = yi - datos->puntual[i][1];
coc = ix * ix + iy * iy; /* r² */
if (coc < 1e-99) coc=1e-99;
Ei = cte * datos->puntual[i][2] / coc;
coc = sqrt (coc);
Ex += Ei * (ix / coc);
Ey += Ei * (iy / coc);
}
absEy = fabs (Ey);
if (absEy < 1e-99) xinc=0.; else xinc = (Ex * datos->yrango) / (absEy * pasos2);
if (fabs(xinc) <= ancho2pasos)
if (Ey >= 0) yinc = alto2pasos; else yinc = -alto2pasos;
else {
absEx = fabs (Ex);
if (absEx < 1e-99) yinc=0.; else yinc = (Ey * datos->xrango) / (absEx * pasos2);
if (fabs(yinc) <= alto2pasos)
if (Ex >= 0) xinc = ancho2pasos; else xinc = -ancho2pasos;
}
xf = xi + xinc * signo;
yf = yi + yinc * signo;
if ((xf < nancho2) ||
(xf > ancho2) ||
(yf < nalto2) ||
(yf > alto2)) break; /* fuera de la pantalla */
if (deveras) recta (xi * xpixelsancho + xpixels2,
ypixels2 - yi * ypixelsalto,
xf * xpixelsancho + xpixels2,
ypixels2 - yf * ypixelsalto,
color, 0);
for (i=0; (i<datos->puntuales) && !EntraEnOtraCarga; i++) {
if ((fabs (xf - datos->puntual[i][0]) < ancho2pasos) &&
(fabs (yf - datos->puntual[i][1]) < alto2pasos)) EntraEnOtraCarga=1;
}
xi = xf; yi = yf;
}
if (EntraEnOtraCarga) break;
}
}
}
if (kbhit()) {
tec=getch(); if (!tec) tec=getch() << 8;
}
else {
tec=0;
for (carga=0; carga < datos->puntuales; carga++)
for (angulo=0.; angulo < PI; angulo += PI/180) {
ix = cos (angulo) * datos->xrango/pasos;
iy = 1.5 * sin (angulo) * datos->yrango/pasos;
x0 = x1 = (datos->puntual[carga][0] + ix) * xpixelsancho + xpixels2;
y0 = ypixels2 - (datos->puntual[carga][1] + iy) * ypixelsalto;
y1 = ypixels2 - (datos->puntual[carga][1] - iy) * ypixelsalto;
if (x0 < 0) x0=0; if (x0>=xpixels) x0=xpixels-1;
if (x1 < 0) x1=0; if (x1>=xpixels) x1=xpixels-1;
if (y0 < 0) y0=0; if (y0>=ypixels) y0=ypixels-1;
if (y1 < 0) y1=0; if (y1>=ypixels) y1=ypixels-1;
recta (x0, y0, x1, y1,
(datos->puntual[carga][2] >= 0)? 12:9, 0);
}
}
return (tec);
}
/* PINTAR OPCION DEL MENU PRINCIPAL */
void PintaOpcionMenu (Opciones opcion, int modo)
{
int a, b, c, cy, co, i;
if (modo==RESALTAR)
a=32, b=21, c=1;
else {
a=64, b=0xFF, c=3;
cy = opcion * 32 + 144;
for (i=cy; i<cy+32; i++) {
if (i < 200) co=i/4+142; else co=(399-i)/4+142;
lineahoriz (3, i, 76, co);
}
}
switch (opcion) {
case CONF: Xprcad (sp?" Configuración ":" Configuration ", 12, 144, 1, 2, a, b, c);
break;
case EDIT: Xprcad (sp?" Editar sistema de cargas o masas ":" Edit a mass or load system ", 12, 176, 1, 2, a, b, c);
break;
case LINE: Xprcad (sp?" Líneas de campo eléct./gravit. ":" Draw elec./grav. field lines ", 12, 208, 1, 2, a, b, c);
break;
case CAMP: Xprcad (sp?" Gráfica del módulo del vector campo ":" Draw field vector length ", 12, 240, 1, 2, a, b, c);
break;
case POT: Xprcad (sp?" Gráfica del potencial ":" Draw potential value ", 12, 272, 1, 2, a, b, c);
break;
case INFO: Xprcad (sp?" Información ":" Information ", 12, 304, 1, 2, a, b, c);
break;
case SALIR: Xprcad (sp?" Salir ":" Exit ", 12, 336, 1, 2, a, b, c);
case IDIOMA: Xprcad (sp?" F9 English ":" F9 Español ", 212, 360, 1, 1, 20, 0xFF, 0);
break;
}
}
/* MENU PRINCIPAL DEL PROGRAMA */
Opciones Menu()
{
register i, j, y;
static Opciones op=IDIOMA, antop=CONF;
int tec;
VGAModeX (400); /* Modo 320x400x256 para el menú principal */
PaletaMenu();
for (i=142, y=0; i<192; i++)
for (j=0; j<4; j++, y++) {
lineahoriz (0, y, 80, i);
lineahoriz (0, 399-y, 80, i);
}
Xprcad ("EV", 12, -4, 5, 10, 196, 0xFF, 1);
Xprcad ("1.1", 92, 68, 2, 4, 196, 0xFF, 2);
Xprcad ("(C) 1996:", 190, 44, 1, 1, 192, 0xFF, 2);
Xprcad ("José J. Muñoz García", 150, 64, 1, 1, 208, 0xFF, -2);
Xprcad ("Ciriaco G. de Celis", 154, 84, 1, 1, 192, 0xFF, 2);
if (op==IDIOMA) op=antop; if (op < 0) op=-op;
for (antop=CONF; antop <= IDIOMA; antop++)
PintaOpcionMenu (antop, RESTAURAR);
do {
while (kbhit()) getch();
PintaOpcionMenu (op, RESALTAR);
tec = getch(); if (!tec) tec = getch() << 8;
antop = op;
switch (tec) {
case 0x3B00: op=INFO; tec=13; break;
case 0x4800: if (op > CONF) op--; else op=SALIR; break;
case 32:
case 0x5000: if (op < SALIR) op++; else op=CONF; break;
case 0x4700:
case 0x4900: op=CONF; break;
case 0x4F00:
case 0x5100: op=SALIR; break;
case 27: if (op!=SALIR) op=SALIR; else tec=13; break;
case 0x2D00: op=SALIR; tec=13; break;
case 0x4300: op=IDIOMA; tec=13; break;
case 0x4400: SalvaPantalla (320, 400); op = -op; tec=13; break;
}
if (op!=antop) PintaOpcionMenu (antop, RESTAURAR);
} while (tec != 13);
return (op);
}
/* PINTAR OPCIONES DE CONFIGURACION */
void PintaOpcionConf (int opcion, int modo)
{
int a, b, c, cx, cy, co, i;
if (modo==RESALTAR)
a=0, b=199, c=0;
else {
a=199, b=0xFF, c=0, cx=8;
if (opcion < 4) cy = opcion * 23 + 79;
else if (opcion < 8) cy = opcion * 23 + 110;
else cy = 306, cx = 16;
for (i=cy; i<cy+24; i++) {
if (i < 200) co=i/4+142; else co=(399-i)/4+142;
lineahoriz (cx, i, 46, co);
}
}
switch (opcion) {
case 0: Xprcad (sp?" 640*480 (VGA normal)":" 640*480 (normal VGA)", 32, 79, 1, 1, a, b, c);
break;
case 1: Xprcad (" 800*600 (VESA)", 32, 102, 1, 1, a, b, c);
break;
case 2: Xprcad (" 1024*768 (VESA)", 32, 125, 1, 1, a, b, c);
break;
case 3: Xprcad (" 1280*1024 (VESA)", 32, 148, 1, 1, a, b, c);
break;
case 4: Xprcad (sp?" 320*200 (VGA normal)":" 320*200 (normal VGA)", 32, 206, 1, 1, a, b, c);
break;
case 5: Xprcad (sp?" 320*240 (VGA normal)":" 320*240 (normal VGA)", 32, 229, 1, 1, a, b, c);
break;
case 6: Xprcad (sp?" 320*400 (VGA normal)":" 320*400 (normal VGA)", 32, 252, 1, 1, a, b, c);
break;
case 7: Xprcad (sp?" 320*480 (VGA normal)":" 320*480 (normal VGA)", 32, 275, 1, 1, a, b, c);
break;
case 8: Xprcad (sonido?(sp?" Activo ":" Enabled "):(sp?" Desactivado ":" Disabled "), 72, 306, 1, 1, a, b, c);
break;
}
}
/* INDICAR MODOS GRAFICOS SELECCIONADOS */
int PintaModos (int modo16, int modo256)
{
int m16, m256, cy, co;
switch (modo16) {
case M800x600x16:
case M800x600x16_S3: m16 = 1; break;
case M1024x768x16:
case M1024x768x16_S3: m16 = 2; break;
case M1280x1024x16:
case M1280x1024x16_S3: m16 = 3; break;
default: m16 = 0; break;
}
switch (modo256) {
case 200: m256 = 0; break;
case 240: m256 = 1; break;
case 400: m256 = 2; break;
case 480: m256 = 3; break;
}
for (cy=79; cy<175; cy++) {
if (cy < 200) co=cy/4+142; else co=(399-cy)/4+142;
lineahoriz (5, cy, 2, co);
}
Xprcar ('√', 20, m16 * 23 + 79, 1, 1, 197, 0xFF, 0);
for (cy=206; cy<302; cy++) {
if (cy < 200) co=cy/4+142; else co=(399-cy)/4+142;
lineahoriz (5, cy, 2, co);
}
Xprcar ('√', 20, m256 * 23 + 206, 1, 1, 197, 0xFF, 0);
return (m16 | (m256 << 8));
}
/* CONFIGURAR */
void Configurar (int *modo16, int *xpix16, int *ypix16, int *modo256)
{
register i, j, y;
static op=-1;
int antop, v1, v2, v3;
int tec;
VGAModeX (400); /* Modo 320x400x256 para el menú principal */
PaletaConf();
for (i=142, y=0; i<192; i++)
for (j=0; j<4; j++, y++) {
lineahoriz (0, y, 80, i);
lineahoriz (0, 399-y, 80, i);
}
Xprcad (sp?"CONFIGURACION":"CONFIGURATION", 108, 6, 1, 3, 192, 0xFF, 3);
Xprcad (sp?"Modo gráfico ( 16 colores)":"Graphics mode ( 16 colors)", 12, 56, 1, 1, 0, 0xFF, 0);
Xprcad (sp?"Modo gráfico (256 colores)":"Graphics mode (256 colors)", 12, 183, 1, 1, 0, 0xFF, 0);
Xprcad (sp?"Soportado":"Supported", 236, 56, 1, 1, 198, 0xFF, 0);
Xprcad (sp?"Soportado":"Supported", 236, 183, 1, 1, 198, 0xFF, 0);
Xprcad (sp?"Sonido:":"Sound: ", 12, 306, 1, 1, 0, 0xFF, 0);
Xprcad (sp?"Cursores \030 \031 Recorrer modos":"Cursors \030 \031 Point modes", 40, 332, 1, 1, 196, 0xFF, 0);
Xprcad (sp?"Espacio Seleccionar modo":"Space Select mode", 40, 352, 1, 1, 196, 0xFF, 0);
Xprcad (sp?"INTRO o ESC Fin configuración":"ENTER or ESC End of configuration", 40, 372, 1, 1, 196, 0xFF, 0);
for (antop=0; antop <= 8; antop++) PintaOpcionConf (antop, RESTAURAR);
i = PintaModos (*modo16, *modo256);
if (op==-1) op = i & 0xFF;
v1 = ExisteModoVESA (M800x600x16) || ExisteModoVESA (M800x600x16_S3);
v2 = ExisteModoVESA (M1024x768x16) || ExisteModoVESA (M1024x768x16_S3);
v3 = ExisteModoVESA (M1280x1024x16) || ExisteModoVESA (M1280x1024x16_S3);
Xprcad (sp?"Sí":"Yes", 264, 79, 1, 1, 198, 0xFF, 0);
Xprcad (v1?(sp?"Sí":"Yes"):"No", 264, 102, 1, 1, 198, 0xFF, 0);
Xprcad (v2?(sp?"Sí":"Yes"):"No", 264, 125, 1, 1, 198, 0xFF, 0);
Xprcad (v3?(sp?"??":"??"):"No", 264, 148, 1, 1, 198, 0xFF, 0);
Xprcad (sp?"Sí":"Yes", 264, 206, 1, 1, 198, 0xFF, 0);
Xprcad (sp?"Sí":"Yes", 264, 229, 1, 1, 198, 0xFF, 0);
Xprcad (sp?"Sí":"Yes", 264, 252, 1, 1, 198, 0xFF, 0);
Xprcad (sp?"Sí":"Yes", 264, 275, 1, 1, 198, 0xFF, 0);
do {
PintaOpcionConf (op, RESALTAR);
tec = getch(); if (!tec) tec = getch() << 8;
antop = op;
switch (tec) {
case 0x4400: SalvaPantalla (320, 400);
tec = 27;
break;
case 0x4800: if (op > 0) op--; else op=8;
if ((op==3) && (!v3)) op--;
if ((op==2) && (!v2)) op--;
if ((op==1) && (!v1)) op--;
break;
case 0x2D00:
case 13: tec=27;
case 32:
switch (op) {
case 0: *xpix16=640; *ypix16=480; *modo16=0x12; break;
case 1: *xpix16=800; *ypix16=600; if (ExisteModoVESA (M800x600x16)) *modo16=M800x600x16; else *modo16=M800x600x16_S3; break;
case 2: *xpix16=1024; *ypix16=768; if (ExisteModoVESA (M1024x768x16)) *modo16=M1024x768x16; else *modo16=M1024x768x16_S3; break;
case 3: *xpix16=1280; *ypix16=1024; if (ExisteModoVESA (M1280x1024x16)) *modo16=M1280x1024x16; else *modo16=M1280x1024x16_S3; break;
case 4: *modo256=200; break;
case 5: *modo256=240; break;
case 6: *modo256=400; break;
case 7: *modo256=480; break;
case 8: sonido ^= 1; break;
}
PintaModos (*modo16, *modo256);
break;
case 0x5000: if (op < 8) op++; else op=0;
if ((op==1) && (!v1)) op++;
if ((op==2) && (!v2)) op++;
if ((op==3) && (!v3)) op++;
break;
case 0x4700:
case 0x4900: op=0; break;
case 0x4F00:
case 0x5100: op=8; break;
}
if (op!=antop) PintaOpcionConf (antop, RESTAURAR);
} while (tec !=27);
}
/* DIBUJAR UNA VENTANA EN MODO 640x480x16 */
void Ventana (int x, int y, int largo, int alto, int fondo, int marco)
{
register i;
for (i=y-9; i < y+alto+9; i++) recta (x-9, i, x+largo+9, i, fondo, 1);
recta (x-5, y-5, x+5+largo, y-5, marco, 1);
recta (x-5, y+alto+4, x+5+largo, y+alto+4, marco, 1);
recta (x-5, y-5, x-5, y+alto+5, marco, 1);
recta (x+5+largo, y-5, x+5+largo, y+alto+5, marco, 1);
}
/* PINTAR RECUADRO INFERIOR Y EJES (EDITOR DE CARGAS O MASAS) */
void Cuadro (int tipo)
{
int i;
prcad ("X Y ", 7, 412, 6, 0);
prcad ("=", 19, 412, 6, 0);
prcad ("=", 140, 412, 6, 0);
if (tipo==ELECTRICO)
prcad (sp?" SISTEMA DE CARGAS":" ELECTRIC LOADS S.", 250, 412, 10, 0);
else
prcad (sp?" SISTEMA DE MASAS ":" GRAV. MASS SYSTEM", 250, 412, 10, 0);
prcad (sp?" Usar ":" Use ", -1, 0, 7, 0);
prcad ("\033", -1, 0, 14, 4); prcad (" ", -1, 0, 10, 0);
prcad ("\030", -1, 0, 14, 4); prcad (" ", -1, 0, 10, 0);
prcad ("\031", -1, 0, 14, 4); prcad (" ", -1, 0, 10, 0);
prcad ("\032", -1, 0, 14, 4); prcad (" ", -1, 0, 10, 0);
prcad (sp?"INTRO":"ENTER", -1, 0, 14, 4);
prcad (" ", -1, 0, 15, 0);
prcad ("ESC", -1, 0, 14, 4);
prcad (sp?" Fin":" End ", -1, 0, 7, 0);
prcad ("F4", 5, 440, 14, 4);
if (tipo==ELECTRICO)
prcad (sp?" Cambiar cargas -> masas ":" Change from load to mass ", -1, 0, 9, 0);
else
prcad (sp?" Cambiar masas -> cargas ":" Change from mass to load ", -1, 0, 9, 0);
prcad ("F5", -1, 0, 14, 4); prcad (sp?" Borrar pantalla (empezar) ":" Clear screen (to begin) ", -1, 0, 9, 0);
prcad ("F6", -1, 0, 14, 4);
if (tipo==ELECTRICO)
prcad (sp?" Editar una carga":" Edit one load ", -1, 0, 9, 0);
else
prcad (sp?" Editar una masa ":" Edit one mass ", -1, 0, 9, 0);
prcad ("F7", 5, 460, 14, 4); prcad (sp?" Acercar ":" Zoom in ", -1, 0, 9, 0);
prcad ("F8", -1, 0, 14, 4); prcad (sp?" Alejar ":" Zoom out ", -1, 0, 9, 0);
prcad ("F9", -1, 0, 14, 4); prcad (sp?" Nuevo rango ":" New range ", -1, 0, 9, 0);
prcad ("F2", -1, 0, 14, 4); prcad (sp?" Grabar a disco ":" Save to disk ", -1, 0, 9, 0);
prcad ("F3", -1, 0, 14, 4); prcad (sp?" Cargar de disco":" Load from disk ", -1, 0, 9, 0);
recta (0, 406, 639, 406, 3, 1);
recta (0, 433, 639, 433, 3, 1);
recta (0, 479, 639, 479, 3, 1);
recta (0, 406, 0, 479, 3, 1);
recta (639, 406, 639, 479, 3, 1);
recta (564, 406, 564, 433, 3, 1);
recta (403, 406, 403, 433, 3, 1);
recta (250, 406, 250, 433, 3, 1);
recta (0, 199, 639, 199, 5, 1);
recta (0, 200, 639, 200, 5, 1);
recta (318, 0, 318, 399, 5, 1);
recta (319, 0, 319, 399, 5, 1);
for (i=638; i>0; i-=32) {
recta (i, 197, i, 203, 5, 1);
recta (i+1, 197, i+1, 203, 5, 1);
}
for (i=7; i<400; i+=32) {
recta (316, i, 322, i, 5, 1);
recta (316, i+1, 322, i+1, 5, 1);
}
}
/* PINTAR CURSOR (EDITOR DE CARGAS O MASAS) */
void Cursor (int x, int y)
{
outport (0x3CE, 0x1803); /* activar modo XOR de escritura en vídeo */
recta (x+3, y+1, x+9, y+1, 15, 1);
recta (x+2, y, x+10, y, 15, 1);
recta (x+3, y-1, x+9, y-1, 15, 1);
recta (x-3, y+1, x-9, y+1, 15, 1);
recta (x-2, y, x-10, y, 15, 1);
recta (x-3, y-1, x-9, y-1, 15, 1);
recta (x-1, y+3, x-1, y+9, 15, 1);
recta (x, y+2, x, y+10, 15, 1);
recta (x+1, y+3, x+1, y+9, 15, 1);
recta (x-1, y-3, x-1, y-9, 15, 1);
recta (x, y-2, x, y-10, 15, 1);
recta (x+1, y-3, x+1, y-9, 15, 1);
outport (0x3CE, 0x0003); /* desactivar modo de escritura XOR */
}
/* MOVER EL CURSOR (EDITOR DE CARGAS O MASAS) */
int AnimaCursor (int *cx, int *cy, float xr, float yr)
{
int tecla, xx, yy, accion=0, salto=1, tm, incr, maxincr, tics, i;
char cad[12];
unsigned long *cbios = MK_FP (0x40, 0x6C),
tiempos[11];
xx = *cx; yy = *cy;
for (i=tm=0; i<11; i++) tiempos[i]=maxincr=18;
Cursor (xx, yy);
while (!accion) {
sprintf (cad, "%.3E", (xx-319)*xr/620);
while (strlen(cad)<11) strcat (cad, "\377");
prcad (cad, 32, 412, 12, 0);
sprintf (cad, "%.3E", (200-yy)*yr/380);
while (strlen(cad)<11) strcat (cad, "\377");
prcad (cad, 153, 412, 12, 0);
tecla = getch(); if (!tecla) tecla = getch() << 8;
tiempos [tm++] = *cbios; if (tm > 10) tm=0;
for (i=1, tics=0; i<11; i++) {
incr=tiempos[i]-tiempos[i-1]; if (incr > maxincr) maxincr=incr;
tics+=incr;
}
if ((tics < 19) && (maxincr < 10)) salto++; else salto=1, maxincr=0;
switch (tecla) {
case 0x4800: if (yy > 9+salto) yy -= salto; else yy=389; break;
case 0x5000: if (yy < 390-salto) yy += salto; else yy=10; break;
case 0x4D00: if (xx < 630-salto) xx += salto; else xx=10; break;
case 0x4B00: if (xx > 9+salto) xx -= salto; else xx=629; break;
case 13:
case 27:
case 0x3B00:
case 0x3C00:
case 0x3D00:
case 0x3E00:
case 0x3F00:
case 0x4000:
case 0x4100:
case 0x4200:
case 0x2D00:
case 0x4300:
case 0x4400: accion=1; break;
}
Cursor (*cx, *cy); /* Borrar cursor previo */
Cursor (xx, yy); /* Pintar el nuevo */
*cx = xx; *cy = yy;
}
Cursor (xx, yy); /* Borrar cursor al salir */
return (tecla);
}
/* PINTAR CARGAS O MASAS PUNTUALES */
void Puntuales (Sistema *datos, float xr, float yr)
{
int i, j, x, y, posit;
char cad[20];
outport (0x3CE, 0x1803); /* activar modo XOR de escritura en vídeo */
for (i=0; i < datos->puntuales; i++) {
x = datos->puntual[i][0] / xr * 620 + 319;
y = 200 - datos->puntual[i][1] / yr * 380;
if ((x < 630) && (x > 8) && (y < 390) && (y > 9)) {
posit = (datos->puntual[i][2] >= 0);
prcar (posit?'+':'-', x-3, y-7, posit?12:9, 0);
for (j = x-5; j < x+6; j++) recta (j, y+5, j, y-6, posit?12:9, 1);
sprintf (cad, "%.3E", datos->puntual[i][2]);
x = x-40; y = y+10; if (x<0) x=0; if (x>556) x=556; if (y>393) y=393;
prcad (cad, x, y, 7, 0);
}
}
outport (0x3CE, 0x0003); /* desactivar modo de escritura XOR */
}
/* AYUDA DEL EDITOR */
void Ayuda()
{
int t=15, p=2;
Ventana (70, 56, 400, 112, p, t);
if (sp) {
prcad ("Utilice los cursores y pulse INTRO para colocar", 80, 64, t, p);
prcad ("las cargas o las masas. Los sistemas de masas", 80, 80, t, p);
prcad ("sólo pueden contener masas, y los sistemas de", 80, 96, t, p);
prcad ("cargas sólo cargas. Consulte el apartado de", 80, 112, t, p);
prcad ("información en el menú principal para recibir", 80, 128, t, p);
prcad ("orientación acerca de los valores recomendados.", 80, 144, t, p);
}
else {
prcad ("Use the cursor keys and press RETURN to set the", 80, 64, t, p);
prcad ("loads and mass. The mass systems can only hold", 80, 80, t, p);
prcad ("mass, and the load systems can only hold loads.", 80, 96, t, p);
prcad ("Select the information option in the main menu", 80, 112, t, p);
prcad ("to read some tips about the recommended values", 80, 128, t, p);
prcad ("for load and mass.", 80, 144, t, p);
}
if (!getch()) getch();
}
/* EDITAR CARGAS O MASAS PUNTUALES */
void Editar (Sistema *datos)
{
void interrupt (*ViejaInt24) (void);
static cx=400, cy=150, primeravez=1, xx, yy;
int tecla, tec, salir=0, i, j, tpok;
static char cadp[20], cadrx[20], cadry[20], tipo[20],
fichero[60]="EV-01.DAT", cadc[20];
char c0, c1, cad[4];
float valor;
FILE *f;
ViejaInt24=getvect(0x24);
setvect (0x24, NuevaInt24); /* evitar error crítico */
SetMode (0x12); /* 640x480x16 */
Cuadro (datos->tipo);
Puntuales (datos, datos->xrango, datos->yrango);
if (primeravez) {
Ayuda();
SetMode (0x12);
Cuadro (datos->tipo);
Puntuales (datos, datos->xrango, datos->yrango);
primeravez = 0;
}
while (!salir)
switch (AnimaCursor (&cx, &cy, datos->xrango, datos->yrango)) {
case 0x3B00: Ayuda();
SetMode (0x12);
Cuadro (datos->tipo);
Puntuales (datos, datos->xrango, datos->yrango);
break;
case 0x3C00: Ventana (80, 80, 428, 56, 1, 15);
prcad (sp?"GRABAR SISTEMA EN DISCO":" SAVE A SYSTEM ON DISK ", 200, 88, 15, 1);
prcad (sp?"Nombre: ":" Name: ", 88, 112, 15, 1);
if (input (fichero, 0, 40, 152, 112, 15, 1, 3)) {
if ((f=fopen(fichero, "wt")) == NULL) {
prcad (sp?" ¡ERROR DE DISCO! ":" DISK ERROR! ", 88, 112, 15, 1);
if (!getch()) getch();
}
else {
fprintf (f, (datos->tipo==1)?"EV10-ELECTRICO\n":"EV10-GRAVITATORIO\n");
fprintf (f, "%d %d %d %.8E\n%.3E %.3E\n%d\n", cx, cy, datos->lineas,
datos->ajuste, datos->xrango, datos->yrango,datos->puntuales);
for (i=0; i < datos->puntuales; i++)
fprintf (f, "%.3E %.3E %.3E\n", datos->puntual[i][0],
datos->puntual[i][1], datos->puntual[i][2]);
fclose (f);
}
}
SetMode (0x12);
Cuadro (datos->tipo);
Puntuales (datos, datos->xrango, datos->yrango);
break;
case 0x3D00: Ventana (80, 80, 428, 56, 1, 15);
prcad (sp?"CARGAR SISTEMA DE DISCO":"LOAD A SYSTEM FROM DISK", 200, 88, 15, 1);
prcad (sp?"Nombre: ":" Name: ", 88, 112, 15, 1);
if (input (fichero, 0, 40, 152, 112, 15, 1, 3)) {
if ((f=fopen(fichero, "rt")) == NULL) {
prcad (sp?" ¡ERROR DE DISCO! ":" DISK ERROR! ", 88, 112, 15, 1);
if (!getch()) getch();
}
else {
fgets (tipo, 19, f); tpok=1;
if (strstr(tipo, "EV10-ELECTRICO")!=NULL) datos->tipo=ELECTRICO;
else if (strstr(tipo, "EV10-GRAVITATORIO")!=NULL) datos->tipo=GRAVITATORIO;
else tpok=0;
if (tpok) {
fscanf (f, "%d %d %d %f\n%f %f\n%d\n", &cx, &cy, &datos->lineas, &datos->ajuste,
&datos->xrango, &datos->yrango, &datos->puntuales);
for (i=0; i < datos->puntuales; i++)
fscanf (f, "%f %f %f\n", &datos->puntual[i][0],
&datos->puntual[i][1], &datos->puntual[i][2]);
fclose (f);
}
else {
prcad (sp?" FORMATO DE FICHERO DESCONOCIDO ":" UNKNOWN FILE FORMAT ", 88, 112, 15, 1);
if (!getch()) getch();
}
}
}
SetMode (0x12);
Cuadro (datos->tipo);
Puntuales (datos, datos->xrango, datos->yrango);
break;
case 0x3E00: Puntuales (datos, datos->xrango, datos->yrango);
if (datos->tipo==ELECTRICO)
datos->tipo=GRAVITATORIO;
else
datos->tipo=ELECTRICO;
Cuadro (datos->tipo);
datos->puntuales = cadp[0] = 0;
break;
case 0x3F00: Puntuales (datos, datos->xrango, datos->yrango);
datos->puntuales = cadp[0] = 0;
datos->xrango = 2.5;
datos->yrango = 2.0;
break;
case 0x4000: for (i=0; i < datos->puntuales; i++) {
xx = datos->puntual[i][0] / datos->xrango * 620 + 319;
yy = 200 - datos->puntual[i][1] / datos->yrango * 380;
c0 = (i+1)/10 + '0'; c1 = ((i+1) % 10) + '0';
if (c0!='0') prcar (c0, xx-11, yy-24, 15, 0);
prcar (c1, xx-3, yy-24, 15, 0);
}
Ventana (170, 430, 300, 16, 1, 15);
if (datos->tipo==ELECTRICO)
prcad (sp?"Carga":" Load", 178, 430, 15, 1);
else
prcad (sp?"Masa":"Mass", 178, 430, 15, 1);
prcad (sp?" a modificar:":" to modify:", -1, 0, 15, 1);
cad[0]=0;
if (input (cad, 1, 3, 330, 430, 15, 1, 3)) {
i = atoi (cad);
if (i && (i <= datos->puntuales)) {
prcad (sp?"Nuevo valor (Q eliminar):":" New value (Q remove it):", 178, 430, 15, 1);
if (input (cadc, 0, 10, 385, 430, 15, 1, 3))
if ((cadc[0]=='q') || (cadc[0]=='Q')) {
while (i <= datos->puntuales)
for (i++, j=0; j<3; j++)
datos->puntual[i][j] = datos->puntual[i+1][j];
datos->puntuales--;
}
else if ((atof(cadc)!=0.0) || (cadc[0]=='0'))
datos->puntual[i-1][2] = atof(cadc);
}
}
SetMode (0x12);
Cuadro (datos->tipo);
Puntuales (datos, datos->xrango, datos->yrango);
break;
case 0x4100: Puntuales (datos, datos->xrango, datos->yrango);
datos->xrango /= 1.1; datos->yrango /= 1.1;
cx = (cx - 319) * 1.1 + 319;
cy = 200 - (200 - cy ) * 1.1;
if (cx>629) cx = 629; if (cx < 10) cx = 10;
if (cy>389) cy = 389; if (cy < 10) cy = 10;
Puntuales (datos, datos->xrango, datos->yrango);
break;
case 0x4200: Puntuales (datos, datos->xrango, datos->yrango);
datos->xrango *= 1.1; datos->yrango *= 1.1;
cx = (cx - 319) / 1.1 + 319;
cy = 200 - (200 - cy ) / 1.1;
Puntuales (datos, datos->xrango, datos->yrango);
break;
case 0x4300: Ventana (150, 152, 340, 90, 1, 15);
prcad (sp?"Nuevo RANGO del plano":" New RANGE of plane ", 230, 160, 15, 1);
prcad (sp?"Anchura del eje X (metros): ":" Width of X axis (meters): ", 158, 192, 15, 1);
if (input (cadrx, 0, 10, 390, 192, 15, 1, 3))
if ((valor = atof (cadrx)) > 0.0) {
cx = (cx - 319) * (datos->xrango / valor) + 319;
if (cx>629) cx = 629; if (cx < 10) cx = 10;
datos->xrango = valor;
prcad (sp?"Anchura del eje Y (metros): ":" Width of Y axis (meters): ", 158, 208, 15, 1);
if (input (cadry, 0, 10, 390, 208, 15, 1, 3))
if ((valor = atof (cadry)) > 0.0) {
cy = 200 - (200 - cy ) * (datos->yrango / valor);
if (cy>389) cy = 389; if (cy < 10) cy = 10;
datos->yrango = valor;
}
}
SetMode (0x12);
Cuadro (datos->tipo);
Puntuales (datos, datos->xrango, datos->yrango);
break;
case 0x4400: Cursor (cx, cy);
SalvaPantalla (640, 480);
Cuadro (datos->tipo);
Puntuales (datos, datos->xrango, datos->yrango);
break;
case 13: xx = cx-150; yy = cy-8;
if (xx>340) xx=340; if (xx<10) xx=10;
if (yy>375) yy=375; if (yy<10) yy=10;
Ventana (xx, yy, 290, 16, 1, 15);
prcad (sp?"Valor de la ":" Value for ", xx, yy, 15, 1);
prcad ((datos->tipo==ELECTRICO)?(sp?"carga (Cul): ":"load (Cul): "):(sp?"masa (Kg): ":"mass (Kg): "), -1, 0, 15, 1);
if (input (cadp, 0, 10, xx+200, yy, 15, 1, 3)) {
valor = atof (cadp);
if ((valor >= 0.0) || ((valor < 0.0) && (datos->tipo==ELECTRICO)))
if ((valor != 0.0) || (cadp[0]=='0')) {
datos->puntual[datos->puntuales][0] = (cx-319) * datos->xrango / 620;
datos->puntual[datos->puntuales][1] = (200-cy) * datos->yrango / 380;
datos->puntual[datos->puntuales][2] = valor;
datos->ajuste=2.71828182;
datos->lineas=50;
datos->puntuales ++;
}
}
SetMode (0x12);
Cuadro (datos->tipo);
Puntuales (datos, datos->xrango, datos->yrango);
break;
case 27:
case 0x2D00: salir=1; break;
}
setvect (0x24, ViejaInt24);
}
/* OPCION DE INFORMACION */
void About()
{
int c1=9, c2=11, c3=12, c4=14;
SetMode (0x12); /* 640x480x16 */
if (sp) {
prcad (" INFORMACION ", 254, 0, 14, 4);
prcad ("", -1, -1, c1, 0);
prcad ("", -1, -1, c1, 0);
prcad (" Este programa traza las líneas de campo (modo 16 colores) de un conjunto de", -1, -1, c1, 0);
prcad ("cargas o masas puntuales introducido en la opción de editar. También puede", -1, -1, c1, 0);
prcad ("dibujar una representación del módulo del vector campo y del potencial (modo", -1, -1, c1, 0);
prcad ("256 colores).\377Se puede utilizar el rango del plano deseado\377(por defecto,\377unos", -1, -1, c1, 0);
prcad ("dos metros de largo y alto) y colocar las cargas o masas en cualquier punto.", -1, -1, c1, 0);
prcad ("", -1, -1, c1, 0);
prcad (" Para esas distancias, son recomendables cargas de nanoculombios (ej. 1e-9)", -1, -1, c2, 0);
prcad ("y, tratándose de masas, alrededor de 100 millones de toneladas (ej. 1e11 Kg),", -1, -1, c2, 0);
prcad ("otra opción sería modificar el rango propuesto por defecto. Se permite la", -1, -1, c2, 0);
prcad ("introducción de datos en notación científica.", -1, -1, c2, 0);
prcad ("", -1, -1, c2, 0);
prcad (" Una vez completado el dibujo, un sonido lo notificará. Se puede pulsar (+)", -1, -1, c2, 0);
prcad ("y (-) para cambiar la intensidad/número de líneas [(*) para restaurar] y F10", -1, -1, c2, 0);
prcad ("para grabar la pantalla en formato PCX, con\377nombre EV-CAP00.PCX y sucesivos", -1, -1, c2, 0);
prcad ("(en los modos 320x400 y 320x480 se\377simula el doble de resolución horizontal", -1, -1, c2, 0);
prcad ("para no deformar la relación de aspecto). La pulsación de cualquier otra", -1, -1, c2, 0);
prcad ("tecla durante o después del proceso de dibujo volverá al menú.", -1, -1, c2, 0);
prcad ("", -1, -1, c2, 0);
prcad (" El programa funciona en cualquier PC con VGA, si bien es muy recomendable", -1, -1, c3, 0);
prcad ("una máquina con coprocesador o un 486-DX o superior. \377Si la tarjeta\377gráfica", -1, -1, c3, 0);
prcad ("cumple el estándar VESA, podría ser posible alcanzar 1280x1024 puntos en la", -1, -1, c3, 0);
prcad ("gráfica de las líneas de campo (si\377el monitor lo soporta). \377La opción de", -1, -1, c3, 0);
prcad ("configuración permite una flexibilidad total.", -1, -1, c3, 0);
prcad ("", -1, -1, c3, 0);
prcad (" EV es un proyecto de software\377científico-educativo desarrollado por José", -1, -1, c4, 0);
prcad ("Javier Muñoz García (Internet E-Mail: hobster@gui.uva.es) y Ciriaco\377García", -1, -1, c4, 0);
prcad ("de Celis (ciri@gui.uva.es). La última versión de este programa normalmente", -1, -1, c4, 0);
prcad ("estará disponible entre otros,\377en ftp://ftp.gui.uva.es/pub/pc/gui/evsim??.zip", -1, -1, c4, 0); }
else {
prcad (" INFORMATION ", 254, 0, 14, 4);
prcad ("", -1, -1, c1, 0);
prcad ("", -1, -1, c1, 0);
prcad (" This program draws the field lines of a set of puntual electric loads or", -1, -1, c1, 0);
prcad ("gravitational mass introduced by the edit option (16 colours mode). It can", -1, -1, c1, 0);
prcad ("also draw a representation of field vector length and the potential (256 col.", -1, -1, c1, 0);
prcad ("mode). It is possible to use the desired range of the plane (by default, near", -1, -1, c1, 0);
prcad ("to 2 meters width) and to place the loads or mass at any coordinates.", -1, -1, c1, 0);
prcad ("", -1, -1, c1, 0);
prcad (" Using such distances, there are recomended nanoculombium loads (vg 1e-9)", -1, -1, c2, 0);
prcad ("and, using mass, close to 100 million of tons\377(for example, 1e11 Kg); other", -1, -1, c2, 0);
prcad ("option would be to modify the proposed range.\377It\377is allowed to introduce data", -1, -1, c2, 0);
prcad ("in scientific notation.", -1, -1, c2, 0);
prcad ("", -1, -1, c2, 0);
prcad (" Once the draw is completed, a sound will notify it. It is possible to press", -1, -1, c2, 0);
prcad ("(+) and (-) to change the intensity/number of lines\377[(*)\377to\377restore defaults]", -1, -1, c2, 0);
prcad ("and F10 to save the screen in a PCX file. The screens are saved starting with", -1, -1, c2, 0);
prcad ("EV-CAP00.PCX and so on. Under the 320x400 and 320x480 graphic\377modes, it\377is", -1, -1, c2, 0);
prcad ("simulated a double horizontal resolution\377(to keep the\377aspect ratio).\377To\377press", -1, -1, c2, 0);
prcad ("any other key while drawing process is in progress would stop it.", -1, -1, c2, 0);
prcad ("", -1, -1, c2, 0);
prcad (" The program works in any PC provided with VGA graphics, but it is a lot of", -1, -1, c3, 0);
prcad ("recommendable a system with mathematic coprocessor or a 486-DX or better. If", -1, -1, c3, 0);
prcad ("the CGA card supports VESA, it would be possible to reach 1280x1024 pixels in", -1, -1, c3, 0);
prcad ("the field lines\377graphic (if the monitor supports\377it). \377The configuration",-1, -1, c3, 0);
prcad ("option allows a total flexibility.", -1, -1, c3, 0);
prcad ("", -1, -1, c3, 0);
prcad (" EV is a scientific-educative software proyect developed by José Javier", -1, -1, c4, 0);
prcad ("Muñoz García (Internet\377E-Mail:\377hobster@gui.uva.es) and by Ciriaco García", -1, -1, c4, 0);
prcad ("de Celis (ciri@gui.uva.es). The latest version of this program should to be", -1, -1, c4, 0);
prcad ("available, among other sites, in ftp://ftp.gui.uva.es/pub/pc/gui/evsim??.zip", -1, -1, c4, 0);
}
Pausa (640, 480);
}
/* PAUSA */
void Pausa (int xpix, int ypix)
{
int tec;
tec=getch(); if (!tec) tec=getch() << 8;
if (tec==0x4400)
SalvaPantalla (xpix, ypix); /* F10 */
}
/* GRAFICA EN 16 COLORES DE LAS LINEAS DE CAMPO */
void Grafica16 (Sistema *datos, int modo16, int xpixels, int ypixels)
{
int i, tecla, color=10,
salir = 0;
while (!salir) {
SetMode (modo16);
tecla = TrazaCampo (datos, xpixels, ypixels, color);
if (!tecla) {
if (sonido) for (i=1500; i<2000; i+=25) {
sound (i); delay (10);
sound (i+200); delay (10);
}
nosound();
tecla=getch(); if (!tecla) tecla=getch() << 8;
}
switch (tecla) {
case 0x4800: color++; if (color>15) color=1; break;
case 0x5000: color--; if (color<1) color=15; break;
case '+': datos->lineas +=5;
if (sonido) { sound ((datos->lineas)*25+750); delay (50); nosound(); }
break;
case '-': datos->lineas -=5; if (datos->lineas < 5) datos->lineas = 5;
if (sonido) { sound ((datos->lineas)*25+750); delay (50); nosound(); }
break;
case '*': datos->lineas = 50;
if (sonido) {
sound (2500); delay (200); nosound(); delay (75);
sound (2500); delay (200); nosound();
}
break;
case 'P':
case 'p': if (!getch()) getch(); salir=1; break;
case 0x4400: SalvaPantalla (xpixels, ypixels);
break;
default: salir++;
}
}
}
/* GRAFICA EN 256 COLORES DEL MODULO DEL CAMPO O DEL POTENCIAL */
void Grafica256 (Sistema *datos, int ypixels, int EoV)
{
int i, tecla,
salir = 0;
VGAModeX (ypixels);
PaletaEV();
while (!salir) {
tecla = PintaEoV (datos, ypixels, EoV);
if (!tecla) {
if (sonido) for (i=1500; i<2000; i+=25) {
sound (i); delay (10);
sound (i+200); delay (10);
}
nosound();
tecla=getch(); if (!tecla) tecla=getch() << 8;
}
switch (tecla) {
case '+': datos->ajuste += 0.05;
if (sonido) { sound (((datos->ajuste)-2.71828182)*749+2000); delay (50); nosound(); }
break;
case '-': datos->ajuste -= 0.05; if (datos->ajuste < 0.05) datos->ajuste = 0.05;
if (sonido) { sound (((datos->ajuste)-2.71828182)*749+2000); delay (50); nosound(); }
break;
case '*': datos->ajuste = 2.71828182;
if (sonido) {
sound (2500); delay (200); nosound(); delay (75);
sound (2500); delay (200); nosound();
}
break;
case 'P':
case 'p': if (!getch()) getch(); salir=1; break;
case 0x4400: SalvaPantalla (320, ypixels);
break;
default: salir++;
}
}
}
/* DEVOLVER 1 SI MENSAJES EN CASTELLANO */
int HablaSp()
{
union REGS r; struct SREGS s;
char info[2048];
int i, idioma, spl[]={54, 591, 57, 506, 56, 593, 503, 34, 63, 502,
504, 212, 52, 505, 507, 595, 51, 80, 508, 598, 58, 3, 0};
idioma=0; /* supuesto el inglés */
if (_osmajor>=3) {
r.x.ax=0x3800; s.ds=FP_SEG(info); r.x.dx=FP_OFF(info);
intdosx (&r, &r, &s);
i=0; while (spl[i++]) if (spl[i-1]==r.x.bx) idioma=1;
}
return (idioma);
}
/* PROGRAMA PRINCIPAL */
void main()
{
int terminar=0, modo16, xpix16, ypix16, modo256=480;
Sistema datos;
sp = HablaSp();
datos.puntuales=0; /* sin datos al principio */
datos.xrango = 2.5;
datos.yrango = 2.0;
datos.tipo=ELECTRICO;
if (!ExisteVGA()) {
if (sp)
fprintf(stderr, "\nError: Necesarios gráficos VGA o superiores.\n");
else
fprintf(stderr, "\nError: Needs VGA graphics or better.\n");
exit (1);
}
modo16 = GetBest16 (&xpix16, &ypix16);
Vram (PRESERVAR); /* preservar pantalla previa al programa */
do switch (Menu()) {
case CONF: Configurar (&modo16, &xpix16, &ypix16, &modo256); break;
case EDIT: Editar (&datos); break;
case LINE: Grafica16 (&datos, modo16, xpix16, ypix16); break;
case CAMP: Grafica256 (&datos, modo256, CAMPO); break;
case POT: Grafica256 (&datos, modo256, POTENCIAL); break;
case INFO: About(); break;
case SALIR: terminar++; break;
case IDIOMA: sp ^= 1; break;
} while (!terminar);
Vram (RESTAURAR); /* restaurar pantalla previa al programa */
}