/*
** Call_Qhull.h 
**      Old code calling qhull to find a mixed subdivision 
**
**    copyright (c) 1995  Birk Huber
*/

#include "pelclqhl.h"
#include "pelqhull.h"

/*
** node pcfg_facets(node PC, Imatrix Controll)
**  Return a list of the inner-normals of the facets of a point
**   configuaration PC. Uses Control as input to pcfg_good
**   facets (see bellow) to screen for facets whoose normals
**   obey certain conditions.
*/

#define FORALLfacet_(facetlist) if (facetlist) for(facet=(facetlist);facet && facet->next;facet=facet->next)

node pcfg_facets(node PC, Imatrix Controll)
{
    int curlong, totlong, exitcode, i, j, k;
    int D, N;
    coordT *points, *make_cay(node, boolT *, node **);
    boolT ismalloc;
    facetT *facet;
    vertexT *vertex, **vertexp;
    node NormList = 0, *pt_table;
    Imatrix M, Norm, P0, P1;
    LOCS(2);


    PUSH_LOC(PC);
    PUSH_LOC(NormList);

    N = pcfg_npts(PC);
    D = pcfg_dim(PC);
    M = Imatrix_new(N, D);
    Norm = Ivector_new(D);
    M = pcfg_M(PC, M);


    j = Imatrix_rref(M, &i);

   

    if (j <= D - 1) {
	if (j == D - 1) {
	  /* printf("point config is D-1 dim\n"); */



	    Imatrix_backsolve(M, Norm);
            Imatrix_gcd_reduce(Norm);
	    /* printf("Imatrix norm : ");
	       Imatrix_print(Norm); 
	       printf("\n"); */
	    if (is_normal_good(Norm, Controll) != True) {
		for (i = 1; i <= D; i++)
		    *IVref(Norm, i) *= -1;
	    }
	    if (is_normal_good(Norm, Controll) == True)
		NormList = Cons(atom_new((char *) Norm, IMTX), 0);
	    else
		Imatrix_free(Norm);
	} else {
	    bad_error("point config is low dim in pcfg_facets");
	    printf("point config is low dim \n");
	    Imatrix_free(Norm);
	}
	Imatrix_free(M);
	POP_LOCS();
	/* printf("leaving qhull with low D:");
	node_print(NormList);
	printf("\n"); */
	return NormList;
    }
    qh_meminit(stderr);
    qh_initqhull_start(stdin, stdout, stderr);
    if (!(exitcode = setjmp(qh errexit))) {
	strcpy(qh qhull_command, "qhull i Qs Pg Pp");
	qh_initflags(qh qhull_command);
	points = make_cay(PC, &ismalloc, &pt_table);
	qh_initqhull_globals(points, N, D, ismalloc);
	qh_initqhull_mem();

	/* mem.c and set.c are initialized */
	qh_initqhull_buffers();
	/* setting up treshold to ensure that good facets will be those
	   on the lower hull with respecto to the last coordinate */

	qh_qhull();
	qh_findgood_all(qh facet_list);

	FORALLfacet_(qh facet_list) {
	    if (facet->good) {
		k = 0;
		FOREACHvertex_(facet->vertices) {
		    if (k == 0)
			P0 = pnt_coords(pt_table[qh_pointid(vertex->point)]);
		    else {
			P1 = pnt_coords(pt_table[qh_pointid(vertex->point)]);
			for (i = 1; i <= pcfg_dim(PC); i++) {
			    *IMref(M, k, i) = *IVref(P1, i) - *IVref(P0, i);
			}
		    }
		    k++;

		}
		Imatrix_submat(M, k - 1, pcfg_dim(PC));
		Imatrix_rref(M, &i);


		Imatrix_backsolve(M, Norm);
		for (i = 1; (*IVref(Norm, i) == 0) && i <= IVlength(Norm); i++);
		if ((facet->normal[i - 1] * (*IVref(Norm, i))) > 0.0) {
		    for (i = 1; i <= IVlength(Norm); i++) {
			*(IVref(Norm, i)) = -1 * (*IVref(Norm, i));
		    }
		}
		if (is_normal_good(Norm, Controll) == True) {
		    list_insert(atom_new((char *) Norm, IMTX),
				    &NormList, &(list_Imatrix_comp),FALSE);
		    Norm = Ivector_new(pcfg_dim(PC));
		}
	    }
	}

	exitcode = qh_ERRnone;
    }
    qh NOerrexit = True;	/* no more setjmp */
    qh_freeqhull(False);
    qh_memfreeshort(&curlong, &totlong);
    if (curlong || totlong)
#ifdef LOG_PRINT
	fprintf(stderr,
		"qhull internal warning (main): did not free %d bytes of long memory (%d pieces)\n",
		totlong, curlong)
#endif
;
    mem_free((char *) pt_table);
    Imatrix_free(M);
    Imatrix_free(Norm);
    POP_LOCS();
    return NormList;
}


coordT *make_cay(node PC, boolT * ismalloc, node ** table)
{
    int i, j;
    coordT *points, *coords;
    node ptr = PC, *lptr;

    coords = points = (coordT *) malloc(pcfg_npts(PC) *
					pcfg_dim(PC) * sizeof(coordT));
    *table = lptr = (node *) mem_malloc(pcfg_npts(PC) * sizeof(node));
    if (coords == 0) {
	*ismalloc = False;
	return 0;
    }
    *ismalloc = True;
    for (i = 1; i <= pcfg_npts(PC); i++) {
	ptr = Cdr(ptr);
	*(lptr++) = Car(ptr);
	for (j = 1; j <= pcfg_dim(PC); j++) {
	    *(coords++) = *(IVref(pnt_coords(Car(ptr)), j));
	}
    }
    return points;
}


node aset_cayley(node A,int addlift)
{
    node res = 0, ptr = A, ptp, ptc;
    int r = 0, R, D, i;
    char *lab;
    char *amm_string;
    Imatrix C;
    LOCS(2);
    PUSH_LOC(A);
    PUSH_LOC(res);
    D = aset_dim(A);
    if (addlift==1)addlift=1; else addlift=0;
    R = aset_r(A);
    ptr = aset_start_cfg(A);
    res = pcfg_new();
    while ((ptc = aset_next_cfg(&ptr)) != 0) {
        r++;
        while ((ptp = aset_next_pnt(&ptc)) != 0) {
            C = Ivector_new(D + R - 1 + addlift);
            if(addlift==1) *IVref(C,D+R)=0;
            for (i = 1; i < D; i++)
                *IVref(C, i) = aset_pnt_get(ptp, i);
            for (i = 1; i <= R - 1; i++)
                if (r - 1 == i)                               
                    *IVref(C, D + i-1) = 1;
                else
                    *IVref(C, D + i-1) = 0;
            *IVref(C,D+R-1)=aset_pnt_get(ptp,D);
            lab = (char *)mem_malloc(6 * sizeof(char));
	    amm_string = pnt_label(ptp);
	    /*            strncpy(lab, amm_string,6); - ERROR */
	    /* Therefore I fake it as follows - AMM */
	    for (i = 0; i <= 5; i++)
	      if (i < (int)strlen(amm_string))
		lab[i] = amm_string[i];
	      else
		lab[i] = '\0';
            pcfg_add(pnt_new(lab, C), res);
        }
    }
    POP_LOCS();
    return res;
}

node aset_lower_facets(node A)
{
    node res = 0, cay = 0;
    Imatrix Normfilter;
    int i;
    LOCS(3);
    PUSH_LOC(A);
    PUSH_LOC(res);
    PUSH_LOC(cay);
                                cay = aset_cayley(A,0);
    Normfilter = Ivector_new(aset_dim(A) + aset_r(A)-1);
    for (i = 1; i < aset_dim(A) + aset_r(A)-1; i++)
        *IVref(Normfilter, i) = 0;
    *IVref(Normfilter, aset_r(A)+aset_dim(A)-1) = 2;

    res = pcfg_facets(cay, Normfilter);

    cay = res;
    while (cay != 0) {
      *IVref((Imatrix) Car(Car(cay)),aset_dim(A))
      = *IVref((Imatrix) Car(Car(cay)),
               aset_dim(A)+aset_r(A)-1);
        Imatrix_resize((Imatrix) Car(Car(cay)), 1, aset_dim(A));
        cay = Cdr(cay);
    }
    Imatrix_free(Normfilter);
    POP_LOCS();
    return res;
}
                        
/* #define ACTUALLY_PRINT */
node aset_print_subdiv(node A, node norms, Imatrix T)
{
  //  int i;
    node ptr = 0, ptc = 0, res = 0;
    Imatrix M = 0, Tp = 0;
    int v, mv = 0, t = 0;
    LOCS(5);
    PUSH_LOC(A);
    PUSH_LOC(res);
    PUSH_LOC(ptc);
    PUSH_LOC(ptr);
    PUSH_LOC(norms);

     ptr = norms;
#ifdef ACTUALLY_PRINT
    printf("\n");
#endif
    while (ptr != 0) {
        /*     Imatrix_gcd_reduce((Imatrix)Car((Imatrix)Car(ptr))); */
        ptc = aset_face(A, (Imatrix) Car((node) Car(ptr)));
#ifdef ACTUALLY_PRINT
	aset_print_short(ptc);
        printf("   ");
#endif
	Tp = aset_type(ptc, Tp);
#ifdef ACTUALLY_PRINT
	printf(" < %d",*IVref(Tp,1));
        for(i=2;i<=IVlength(Tp);i++) printf(", %d",*IVref(Tp,i));
        printf(" >  ");
        printf("   ");
#endif
	if (T != 0 && Imatrix_equal(Tp, T) == TRUE) {
            t = 1;
            list_insert(Car(ptr),&res, &(list_Imatrix_comp),FALSE);
        } else
            t = 0;
        M = aset_M(ptc, M);
        if (
               (Imatrix_rref(M, &v) == aset_dim(A) - 1) &&
               (IMrows(M) == aset_dim(A) - 1)
            ) {
#ifdef ACTUALLY_PRINT
   printf("   vol = %d", abs(v));
#endif
  if (t == 1)
                mv += abs(v);
        }
#ifdef ACTUALLY_PRINT
     printf("\n");
#endif
     ptr = Cdr(ptr);
    }
    if (T != 0)
#ifdef ACTUALLY_PRINT
        printf("MV =%d\n", mv);
#endif
   Imatrix_free(Tp);
    Imatrix_free(M);
    POP_LOCS();
    return res;

}



syntax highlighted by Code2HTML, v. 0.9.1