ftp.nice.ch/pub/next/graphics/3d/geomview.1.4.1.s.tar.gz#/Geomview/src/bin/geomview/common/space.c

This is space.c in view mode; [Download] [Up]

/* Copyright (c) 1992 The Geometry Center; University of Minnesota
   1300 South Second Street;  Minneapolis, MN  55454, USA;
   
This file is part of geomview/OOGL. geomview/OOGL is free software;
you can redistribute it and/or modify it only under the terms given in
the file COPYING, which you should have received along with this file.
This and other related software may be obtained via anonymous ftp from
geom.umn.edu; email: software@geom.umn.edu. */

/* Authors: Stuart Levy, Tamara Munzner, Mark Phillips */

#include <stdio.h>
#include <math.h>
#include <string.h>
#include "drawer.h"
#include "ui.h"
#include "lang.h"
#include "lisp.h"
#include "mg.h"
#include "geom.h"
#include "vect.h"
#include "color.h"
#include "camera.h"
#include "space.h"


char *
spacename(int space)
{
    switch(space) {
	case TM_SPHERICAL: return "spherical";
	case TM_EUCLIDEAN: return "euclidean";
	case TM_HYPERBOLIC: return "hyperbolic";
	default: return NULL;
    }
}

void
camera_space_relabel(int id)
{
    DView *dv = (DView *)drawer_get_object(id);
    char *extra=NULL;
    char *fmt;
    char label[256];

    if(!ISCAM(id) || dv == NULL || dv->mgctx == NULL)
	return;
    mgctxselect(dv->mgctx);
    extra = keywordname(hmodelkeyword("", dv->hmodel));
    switch(spaceof(WORLDGEOM)) {
    case TM_SPHERICAL: fmt = "%s (spherical %s view)"; break;
    case TM_HYPERBOLIC: fmt = "%s (hyperbolic %s view)"; break;
    case TM_EUCLIDEAN: fmt = "%s (Euclidean%s view)";
      switch (dv->hmodel) {
      case VIRTUAL:
      case PROJECTIVE:
	extra = "";
	break;
      case CONFORMALBALL:
	extra = " inverted";
	break;
      }
      break;
    default: return;
    }
    sprintf(label, fmt, dv->name[1], extra);
    mgctxset(MG_WnSet, WN_NAME, label, WN_END, MG_END);
}

/*
 * Is this a good directory to select in the file browser by default?
 * Say it is if it contains the 3-char prefix of our space name.
 */
int
our_space_dir(char *dirname)
{
    char *sname, sub[4];
    if((sname = spacename(spaceof(WORLDGEOM))) == NULL)
	return 0;
    sprintf(sub, "%.3s", sname);
    return (int)strstr(dirname, sub);
}
    

Geom *unitsphere(int n, ColorA *color);

#define N  50

Geom *
unitsphere(int n, ColorA *color)
{
    register int i, j;
    float si[N+1], ci[N+1], sj[N+1], cj[N+1];
    Point3 verts[(N-2 + N)*N];
    short vcounts[N-2 + N/2];
    short ccounts[N-2 + N/2];
    register Point3 *p;
    register short *vc;
    Geom *g;
    float excess = 1. / cos(M_PI / n);
 
    for(i = 0; i <= n; i++) {
	register float t = i * 2*M_PI / n;
	sj[i] = sin(t) * excess;
	cj[i] = cos(t) * excess;
	t = i * M_PI / n;
	si[i] = sin(t);
	ci[i] = cos(t);
    }

    memset(ccounts, 0, sizeof(ccounts));
    ccounts[0] = color ? 1 : 0;

    /* Construct n-2 parallels */
    p = verts;
    vc = vcounts;
    for(i = 1; i < n-1; i++) {
	register float y = ci[i];
	register float r = si[i];

	*vc++ = -n;		/* Closed line with n vertices */
	for(j = 0; j < n; j++) {
	    p->x = r*cj[j];
	    p->y = y;
	    p->z = r*sj[j];
	    p++;
	}
    }
    /* Construct n/2 meridians, each a full circle */
    for(j = 0; j < n/2; j++) {
	register float s = sj[j];
	register float c = cj[j];

	*vc++ = -2*n;
	for(i = 0; i < n; i++) {
	    p->x = c*si[i];
	    p->y = ci[i];
	    p->z = s*si[i];
	    p++;
	}
	for(i = n; i > 0; i--) {
	    p->x = -c*si[i];
	    p->y = ci[i];
	    p->z = -s*si[i];
	    p++;
	}
    }
    g = GeomCreate("vect",
		   CR_NVECT,	n-2 + n/2,
		   CR_VECTC,	vcounts,
		   CR_COLRC,	ccounts,
		   CR_NVERT,	(n-2 + n) * n,
		   CR_POINT,	verts,
		   CR_NCOLR,	color ? 1 : 0,
		   CR_COLOR,	color,
		   CR_END);
    return g;
}

void
set_hsphere_draw(int id, int draw)
{
  static ColorA color = { .3, .2, .15, .7 };
  static Geom *hsphere = NULL;
  DView *dv;

  if (!ISCAM(id)) return;
  dv = (DView*)drawer_get_object(id);

  if (draw < 0) {
    /* toggle */
    draw = (dv->hsphere == NULL);
  }
  
  if (draw) {
    if (!hsphere) {
	hsphere = unitsphere(16, &color);
    }
    dv->hsphere = hsphere;
  } else {
    dv->hsphere = NULL;
  }
  ui_maybe_refresh(id);
}

NDcam *
NDcluster(char *name)
{
    NDcam *c;

    for(c = drawerstate.NDcams; c != NULL; c = c->next)
	if(strcmp(c->name, name) == 0) return c;
    return NULL;
}

NDcam *
NDnewcluster(char *name)
{
    NDcam *c;

    c = NDcluster(name);
    if(c == NULL) {
	c = OOGLNewE(NDcam, "NDcam cluster");
	c->name = strdup(name);
	c->C2W = TmNIdentity(TmNCreate(drawerstate.NDim,drawerstate.NDim,NULL));
	c->W2C = NULL;
	c->next = drawerstate.NDcams;
	drawerstate.NDcams = c;
    }
    return c;
}

void
NDdeletecluster(NDcam *c)
{	/* Add this someday.  Note that there may be other references to this cluster. XXX */
}




LDEFINE(ND_axes, LLIST,
	"(ND-axes CAMID [CLUSTERNAME [Xindex Yindex Zindex]])\n\
	Sets or reads the set of axes in the space of the N-dimensional virtual\n\
	camera CLUSTERNAME which determine the 3-D subspace seen by camera CAMID.\n\
	Axes are specified by their indices, from 0 to N-1 for an N-dimensional\n\
	space.")
{
  int axes[4];
  char *camname, *clustername = NULL;
  int i, cam;
  DView *dv;

  axes[0] = axes[1] = axes[2] = axes[3] = -1;
  LDECLARE(("ND-axes", LBEGIN,
	LSTRING, &camname,
	LOPTIONAL,
	LSTRING, &clustername,
	LINT, &axes[0],
	LINT, &axes[1],
	LINT, &axes[2],
	LINT, &axes[3],
	LEND));
  if((cam = drawer_idbyname(camname)) == NOID ||
	(dv = (DView *)drawer_get_object(cam)) == NULL || !ISCAM(dv->id)) {
    OOGLError(0, "ND-axes: unknown camera %s", camname);
    return Lnil;
  } else if(axes[0] < 0) {
    LList *l = NULL;
    if(dv->cluster) {
	l = LListAppend(NULL, LNew(LSTRING, &dv->cluster->name));
	for(i = 0; i < 4; i++)
	    l = LListAppend(l, LNew( LINT, &dv->NDPerm[i] ));
    }
    return LNew( LLIST, &l );
  } else {
    NDcam *c = NDnewcluster(clustername);
    NDdeletecluster(dv->cluster);
    dv->cluster = c;
    memcpy(dv->NDPerm, axes, 4*sizeof(int));

    dv->changed |= 1;
    return Lt;
  }
}

static void set_dimension(int d, TransformN **Tp, TransformN **Tinvp)
{
   if(Tinvp) {
	TmNDelete(*Tinvp);
	*Tinvp = NULL;
   }
   if(Tp == NULL)
	return;
   if(d == 0) {
	TmNDelete(*Tp);
	*Tp = NULL;
   } else {
	if(TmNGetSize(*Tp, NULL,NULL) > d) {
	    TmNDelete(*Tp);
	    *Tp = NULL;
	}
	*Tp = TmNPad(*Tp, d, d, *Tp);
   }
}

LDEFINE(dimension, LLIST,
	"(dimension [N])\n\
	Sets or reads the space dimension for N-dimensional viewing.\n\
	(Since calculations are done using homogeneous coordinates,\n\
	this means matrices are (N+1)x(N+1).)\n\
	With no arguments, returns the current dimension, or 0 if\n\
	N-dimensional viewing has not been enabled.")
{
  int i, d = -1;

  LDECLARE(("dimension", LBEGIN,
	LOPTIONAL,
	LINT, &d,
	LEND));

  if(d < 0) {
    d = drawerstate.NDcams ? drawerstate.NDim-1 : 0;
    return LNew(LINT, &d);
  } else {
    NDcam *c;
    if(d == 0) {
	for(i = 0; i < dview_max; i++)
	    if(dview[i] && dview[i]->cluster) {
		NDdeletecluster(dview[i]->cluster);
		dview[i]->cluster = NULL;
	    }
    } else {
	d++;	/* Include homogeneous coordinate drawerstate.NDim */
    }
    if(drawerstate.NDim != d) {
	for(c = drawerstate.NDcams; c != NULL; c = c->next)
	    set_dimension(d, &c->C2W, &c->W2C);
	for(i = 0; i < dgeom_max; i++) {
	    if(dgeom[i])
		set_dimension(d, &dgeom[i]->NDT, &dgeom[i]->NDTinv);
	}
	drawerstate.changed = 1;
	drawerstate.NDim = d;
    }
  }
  return Lt;
}

LDEFINE(ND_xform, LSTRING,
	"(ND-xform OBJID [ntransform { idim odim  ... }])\n\
	Sets or returns the N-D transform of the given object.\n")
{
  int id;
  LObject *objname = NULL;
  DObject *obj;
  TmNStruct *ts;
  TransformN *T = NULL;
  NDcam *cl = NULL;
  int c;

  LDECLARE(("ND-xform", LBEGIN,
	LID, &id,
	LOPTIONAL,
	LTRANSFORMN, &ts,
	LEND));

  if((obj = drawer_get_object(id)) == NULL)
    return Lnil;
  if(ISGEOM(obj->id)) {
    T = ((DGeom *)obj)->NDT;
  } else if(ISCAM(obj->id) && (cl = ((DView *)obj)->cluster)) {
    T = cl->C2W;
  }

  if(ts == NULL) {
    /* (ND-xform id) -> print transform */
    if(T) {
	TmNPrint(lake->streamout, T);
    } else {
	fprintf(lake->streamout, "transformn {}\n");
    }
  } else {
    /* (ND-xform id transformn { ... }) -> set transform */
    TmNDelete(T);
    if(ISGEOM(obj->id)) {
	((DGeom *)obj)->NDT = REFINCR(TransformN, ts->tm);
	obj->changed |= 1;
    } else if(cl != NULL) {
	cl->C2W = REFINCR(TransformN, ts->tm);
	drawerstate.changed = 1;
    }
  }
  return Lt;
}

LDEFINE(ND_color, LLIST,
	"(ND-color CAM-ID [ (((x0 x1 x2 ... xn) v r g b a   v r g b a  ... )\n\
	((x0 ... xn)  v r g b a  v r g b a ...) ...)] )")
{
  int i, j, id;
  DView *dv;
  LList *l = NULL, *ents;
  cmap *cm;
  cent *ce;
  char *err;
  int nents, nfields, ncolors;

  LDECLARE(("ND-color", LBEGIN,
	LID, &id,
	LOPTIONAL,
	LLITERAL,
	LLIST, &l,
	LEND));

  if((dv = (DView *)drawer_get_object(id)) == NULL || !ISCAM(dv->id)) {
    OOGLError(0, "ND-color: expected camera name");
    return Lnil;
  }

  ents = l;

  nents = LListLength(ents);
  if(nents > MAXCMAP) {
	OOGLError(0, "Only %d colormaps allowed per camera; using first %d of %d",
		MAXCMAP, MAXCMAP, nents);
	nents = MAXCMAP;
  }

  cm = dv->NDcmap;
  for(i = 1; i <= nents; i++, cm++) {

    LObject *ent = LListEntry(ents, i);
    LList *entlist, *axis;
    int dim;
    /*
     * Each component of the 'ents' list looks like:
     *  LLIST         ---  v0,r0,g0,b0,a0, v1,r1,g1,b1,a1, ...
     *    x0,x1,x2,...
     */
    if(! LFROMOBJ(LLIST)(ent, &entlist) ||
       ! LFROMOBJ(LLIST)(entlist->car, &axis)) {
	err = "First component of each colormap should be the N-D projection axis";
	goto no;
    }

    dim = LListLength(axis);
    cm->axis = cm->axis ? HPtNPad(cm->axis, dim + 1, cm->axis)
		: HPtNCreate(dim+1, NULL);
    /* The projection axis is a vector, so its homogeneous component is zero */
    cm->axis->v[dim] = 0;
    /* Extract the real components */
    for(j = 0; j < dim; j++) {
	if(!LFROMOBJ(LFLOAT)(LListEntry(axis, j+1), &cm->axis->v[j])) {
	   err = "Non-numeric entry in projection axis?";
	   goto no;
	}
    }

    entlist = entlist->cdr;	/* Look at the remainder of the list */
    nfields = LListLength(entlist);
    ncolors = nfields / 5;
    if(nfields % 5 != 0 || nfields == 0) {
	err = "Each colormap should contain a multiple of 5 numbers: v0 r0 g0 b0 a0  v1 r1 g1 b1 a1 ...";
	goto no;
    }

    vvneeds(&cm->cents, ncolors);
    ce = VVEC(cm->cents, cent);


    for(j = 1; j <= nfields; j += 5, ce++) {
	ce->interp = 1;
	if(!LFROMOBJ(LFLOAT)(LListEntry(entlist, j), &ce->v) ||
	   !LFROMOBJ(LFLOAT)(LListEntry(entlist, j+1), &ce->c.r) ||
	   !LFROMOBJ(LFLOAT)(LListEntry(entlist, j+2), &ce->c.g) ||
	   !LFROMOBJ(LFLOAT)(LListEntry(entlist, j+3), &ce->c.b) ||
	   !LFROMOBJ(LFLOAT)(LListEntry(entlist, j+4), &ce->c.a) ) {
	    err = "Non-numeric entry in colormap?";
	    goto no;
	}
    }
    VVCOUNT(cm->cents) = ncolors;
  }
  dv->nNDcmap = nents;
  dv->changed |= 1;
  return Lt;

 no:
  OOGLError(0, err);
  return Lnil;
}

These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.