
/**********************************************************

    Routines for user-defined primitives (INSTANCE_OF)

 **********************************************************/

#include "qrt.h"

float Get_Next_Num(), IsPos();
char  *Get_Next_Name();

/* #define INSTANCEDEBUG TRUE */

/**********************************************************

     Returns a pointer to the object in the object
     tree with the given name.

 **********************************************************/


OBJ_PTR Name_Find(obj,name)
  OBJ_PTR obj;
  char *name;
{
  OBJ_PTR temp;

  if (obj==NULL) return(NULL);

  if (obj->name!=NULL)
    if (strcmp(name,obj->name)==0) return(obj);

  if (obj->child != NULL)
    if ((temp=Name_Find(obj->child,name))!=NULL)
      return(temp);

  if (obj->nextobj != NULL)
    if ((temp=Name_Find(obj->nextobj,name))!=NULL)
      return(temp);

  return(NULL);
}


/**********************************************************

    Copies a given sub-tree and returns a pointer to
    the copy.    Always pass fflag=TRUE

 **********************************************************/

OBJ_PTR Subtree_Copy(obj, fflag)
  OBJ_PTR obj;
  int fflag;
{
  OBJ_PTR newobj, new_obj();

  if (obj==NULL) return(NULL);

# ifdef INSTANCEDEBUG
    printf("SUBTREECOPY: name = %s\n",obj->name);
# endif

  newobj = new_obj( obj->type,         /* make new obj */
                    &(obj->loc),
                    &(obj->vect1),
                    &(obj->vect2),
                    &(obj->vect3),
                    &(obj->cinfo),
                    obj->pattern,
                    obj->remove,
                    NULL,              /* no name here */
                    &(obj->upper),
                    &(obj->lower),
                    obj->cterm,
                    obj->xmult,
                    obj->ymult );

  newobj->child   = Subtree_Copy(obj->child,FALSE);

  if (!fflag)
    newobj->nextobj = Subtree_Copy(obj->nextobj,FALSE);
  else
    newobj->nextobj = NULL;

  return(newobj);
}

/**********************************************************

          Offsets sub-tree by offset distance units
          ALWAYS pass fflag = TRUE

 **********************************************************/

Subtree_Offset(obj,offset,fflag)
  OBJ_PTR obj;
  VECT_PTR offset;
  int fflag;
{
  if (obj==NULL) return;

# ifdef INSTANCEDEBUG
    printf("SUBTREEOFFSET: type = %d offset = %f %f %f\n",
           obj->type,
           offset->x,
           offset->y,
           offset->z);
# endif

  (*(ObjData[obj->type].Offset))(obj,offset);

  Subtree_Offset(obj->child,offset,FALSE);

  if (!fflag)
    Subtree_Offset(obj->nextobj,offset,FALSE);
}

/**********************************************************

          Scales a sub-tree by mult distance units
          ALWAYS pass fflag = TRUE

 **********************************************************/

Subtree_Scale(obj,mult,fflag)
  OBJ_PTR obj;
  VECT_PTR mult;
  int fflag;
{
  if (obj==NULL) return;

# ifdef INSTANCEDEBUG
    printf("SUBTREESCALE: type = %d mult = %f %f %f\n",
           obj->type,
           mult->x,
           mult->y,
           mult->z);
# endif

  (*(ObjData[obj->type].Resize))(obj,mult);

  Subtree_Scale(obj->child,mult,FALSE);

  if (!fflag)
    Subtree_Scale(obj->nextobj,mult,FALSE);
}

/**********************************************************

  Load an "Instance_of" structure.  This really makes a
  copy of another part of the tree, offsets it, and returns
  a pointer to this copy.  All "name" fields for the copy
  are set to null to avoid duplicate names.  Also, a new
  scale factor can be specified (default 1).

 **********************************************************/

OBJ_PTR Get_Instance_Of()
{
  char str[SLEN], *name;
  int end, f, found;
  VECTOR offset, mult;
  OBJ_PTR source, dest;

  end=f=0;
  mult.x = mult.y = mult.z = 1.00;

  GetLeftParen();

  while (!end && !feof(stdin)) {
    GetToken(str);

    found = FALSE;
    if (strcmp(str,"NAME")==0) {
      name = Get_Next_Name();
      f|=1; found = TRUE;
    }

    if ((strcmp(str,"POS")==0)      ||
        (strcmp(str,"LOC")==0)      ||
        (strcmp(str,"POSITION")==0) ||
        (strcmp(str,"LOCATION")==0)) {

      GetVector(&offset);
      f|=2; found = TRUE;
    }

    if (strcmp(str,"SCALE")==0) {
      GetVector(&mult);
      found = TRUE;
    }

    if (strcmp(str,")")==0) { end=1; found = TRUE; }

    if (!found) Error(UNDEFINED_PARAM,1203);

  }

  if (f!=3) Error(TOO_FEW_PARMS,1204);

# ifdef INSTANCEDEBUG
    printf("GET_INSTANCE: offset = %f %f %f\n",
           offset.x,
           offset.y,
           offset.z);
# endif

  if ((source = Name_Find(THEWORLD.instances,name))==NULL)
    Error(UNDEFINED_NAME,1205);

  if ((dest = Subtree_Copy(source,TRUE))==NULL)
    Error(INTERNAL_ERROR,1206);

  /* scale the subtree */

# ifdef INSTANCEDEBUG
    printf("scaling...\n");
# endif

  Subtree_Scale(dest,&mult,TRUE);

# ifdef INSTANCEDEBUG
    printf("Offsetting...\n");
# endif

  /* move the subtree */

  Subtree_Offset(dest,&offset,TRUE);

# ifdef INSTANCEDEBUG
    printf("returning\n");
# endif

  return(dest);
}


