Re: DXF format specs

New Message Reply Date view Thread view Subject view Author view

Michael Jones (mtj++at++babar)
Mon, 4 Apr 1994 14:06:40 -0700


The DXF format specs ship with IRIS Performer 1.2.

Here's the simple loader from 1.2 -- you'll want the new pfuBuilder()
from 1.2 to compile this.

Hint: upgrade to SC4-PERF-1.2 (the 1..2 release) right away! If you
have support, ask when you'll get your upgrade.

/*
 * Copyright (c) 1993 Silicon Graphics, Inc.
 *
 * Permission to use, copy, modify, distribute, and sell this software
 * and its documentation for any purpose is hereby granted without
 * fee, provided that (i) the above copyright notices and this
 * permission notice appear in all copies of the software and related
 * documentation, and (ii) the name of Silicon Graphics may not be
 * used in any advertising or publicity relating to the software
 * without the specific, prior written permission of Silicon Graphics.
 *
 * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
 * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
 *
 * IN NO EVENT SHALL SILICON GRAPHICS BE LIABLE FOR ANY SPECIAL,
 * INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY
 * DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
 * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY
 * THEORY OF LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE
 * OR PERFORMANCE OF THIS SOFTWARE.
 *
 */

/*
 * pfdxf.c: $Revision: 1.24 $ $Date: 1994/03/16 11:56:18 $
 */

#include <Performer/pf.h>
#include "pfsgi.h"
#include "pfutil.h"

/*
 * This AutoCAD reader was created almost verbatim from the
 * AutoCAD DXF file to DKB data file converter written and
 * placed in the public domain 8/13/90 by Aaron A. Collins.
 *
 * It parses a limited, but useful, subset of the AutoCAD
 * DXF file format. No effort has been made to handle the
 * complete range of possible DXF opcodes and commands.
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define BUFFER_SIZE 2048

static int groupcode;
static char linbuf[BUFFER_SIZE];
static char curobj[80];
static int curcolor;
static float curr;
static float curg;
static float curb;
static float xcoords[BUFFER_SIZE];
static float ycoords[BUFFER_SIZE];
static float zcoords[BUFFER_SIZE];
static float floats[10];
static float angles[10];
static int ints[10];
static long numTris;
static long numVoid;

/* function type and argument declarations */
static FILE *openFile(char *fileName);
static pfGeoState* defaultGeoState(void);
static int getLine(FILE *fp);
static void addGeometry(pfuBuilder *);
static void getColor(int ndx, float *red, float *green, float *blue);
static int isDegenerate(int a, int b, int c);
static int findEntity(FILE *fp);
static int readEntity(FILE *fp, pfuBuilder *builder);

/*
 * LoadDxf -- load DXF format ".dxf" files into IRIS Performer
 */

extern pfNode *
LoadDxf (char *fileName, pfGeoState *geostate)
{
    int i;

    FILE *dxfFile;

    pfuBuilder *builder = NULL;
    pfList *gsetList = NULL;

    pfGeode *geode = NULL;
    pfNode *node = NULL;
    pfNode *hierarchy = NULL;

    double startTime = pfGetTime();
    double elapsedTime = 0.0;

    /* open DXF file file */
    if ((dxfFile = openFile(fileName)) == NULL)
        return NULL;

    /* give object a default geostate if nothing is passed in */
    if (geostate == NULL)
        geostate = defaultGeoState();

    /* initialize utility library triangle/geoset builder */
    builder = pfuNewBuilder();

    /* initialize current object */
    numTris = 0;
    numVoid = 0;
    curobj[0] = '\0';
    curcolor = 7;
    getColor(curcolor, &curr, &curg, &curb);

    /* read DXF file */
    while (findEntity(dxfFile))
        readEntity(dxfFile, builder);

    /* close DXF file */
    fclose(dxfFile);

    /* signal failure if no geometry loaded */
    if (numTris == 0)
    {
        pfuDelBuilder(builder);
        return NULL;
    }

    /* construct geode */
    geode = pfNewGeode();
    node = (pfNode *)geode;

    /* convert current face list into one or more geosets */
    gsetList = pfuMakeGSets(builder);
    for (i = 0; i < pfGetNum(gsetList); i++)
    {
        pfGeoSet *geoset = (pfGeoSet*)pfGet(gsetList, i);
        pfGSetGState(geoset, geostate);
        pfAddGSet(geode, geoset);
    }
    pfuDelBuilder(builder);

    /* print statistics */
    if(pfGetNotifyLevel() >= PFNFY_INFO)
    {
        elapsedTime = pfGetTime() - startTime;

        fprintf(stderr, "LoadDxf:\n");
        fprintf(stderr, " file name = %s\n", fileName);
        fprintf(stderr, " triangles = %8ld\n", numTris);
        fprintf(stderr, " numVoid = %8ld\n", numVoid);

        if (elapsedTime > 0.0)
        {
            fprintf(stderr, " loading time = %12.3f sec\n",
                elapsedTime);
            fprintf(stderr, " loading rate = %12.3f tri/sec\n",
                numTris/elapsedTime);
        }
    }

/* #define BREAKUP_GEODE */
#ifdef BREAKUP_GEODE
    /* convert geode to recursive spatial hierarchy */
    startTime = pfGetTime();
    hierarchy = pfuBreakup(geode, 10.0f, 24, 8);
    elapsedTime = pfGetTime() - startTime;

    /* replace monolithic geode with recursive spatial hierarchy */
    if (hierarchy != NULL)
    {
        node = hierarchy;
        pfDelete(geode);
    }

    /* print statistics */
    if (pfGetNotifyLevel() >= PFNFY_INFO && elapsedTime > 0.0)
    {
        fprintf(stderr, " breakup time = %12.3f sec\n",
            elapsedTime);
        fprintf(stderr, " breakup rate = %12.3f tri/sec\n",
            numTris/elapsedTime);
    }
#endif

    /* print statistics */
    if (pfGetNotifyLevel() >= PFNFY_INFO)
        fprintf(stderr, "\n");

    return node;
}

static FILE *
openFile (char *fileName)
{
    FILE *file = NULL;
    char filePath[BUFFER_SIZE];

    /* check argument */
    if (fileName == NULL || *fileName == '\0')
        return NULL;

    /* find file in IRIS Performer directory-search path */
    if (!pfFindFile(fileName, filePath, R_OK))
    {
        pfNotify(PFNFY_WARN, PFNFY_RESOURCE,
            "openFile: Could not find file \"%s\"", fileName);
        return NULL;
    }

    /* open file */
    if ((file = fopen(filePath, "r")) == NULL)
    {
        pfNotify(PFNFY_WARN, PFNFY_RESOURCE,
            "openFile: Could not open file \"%s\"", filePath);
        return NULL;
    }

    return file;
}

/*
 * read a group code and the next line from dxfFile
 */
static int
getLine(FILE *fp)
{
    /* get a line from DXF file */
    fgets(linbuf, BUFFER_SIZE, fp);
    if (feof(fp))
        return 1;

    /* scan out group code */
    sscanf(linbuf, "%3d", &groupcode);

    /* get a line from DXF file */
    fgets(linbuf, BUFFER_SIZE, fp);
    if (feof(fp))
        return 1;

    return 0;
}

/*
 * dump out current object we should have all info on
 */
static void
addGeometry(pfuBuilder *builder)
{
    static pfuPoly polygon;
    static int state=0;
    static int nb_points;
    static int nb_cotes;
    static int indice_point;

    /* 2 back-to-back triangles */
    if (strstr(curobj, "TRACE"))
    {
        if (isDegenerate(0, 1, 2))
        {
            numVoid++;
            return;
        }

        polygon.numVerts = 3;
        polygon.tbind = PFGS_OFF;
        polygon.nbind = PFGS_OFF;
        polygon.cbind = PFGS_OVERALL;
        pfSetVec3(polygon.coords[0], xcoords[0], ycoords[0], zcoords[0]);
        pfSetVec3(polygon.coords[1], xcoords[1], ycoords[1], zcoords[1]);
        pfSetVec3(polygon.coords[2], xcoords[2], ycoords[2], zcoords[2]);
        pfSetVec3(polygon.colors[0], curr, curg, curb);
        pfuAddPoly(builder, &polygon);
        numTris += polygon.numVerts - 2;

        if (isDegenerate(0, 3, 2))
        {
            numVoid++;
            return;
        }

        polygon.numVerts = 3;
        polygon.tbind = PFGS_OFF;
        polygon.nbind = PFGS_OFF;
        polygon.cbind = PFGS_OVERALL;
        pfSetVec3(polygon.coords[0], xcoords[0], ycoords[0], zcoords[0]);
        pfSetVec3(polygon.coords[1], xcoords[2], ycoords[2], zcoords[2]);
        pfSetVec3(polygon.coords[2], xcoords[3], ycoords[3], zcoords[3]);
        pfSetVec3(polygon.colors[0], curr, curg, curb);
        pfuAddPoly(builder, &polygon);
        numTris += polygon.numVerts - 2;

        return;
    }
    /* 1 or 2 triangles */
    else if (strstr(curobj, "SOLID"))
    {
        if (isDegenerate(0, 1, 2))
        {
            numVoid++;
            return;
        }

        polygon.numVerts = 3;
        polygon.tbind = PFGS_OFF;
        polygon.nbind = PFGS_OFF;
        polygon.cbind = PFGS_OVERALL;
        pfSetVec3(polygon.coords[0], xcoords[0], ycoords[0], zcoords[0]);
        pfSetVec3(polygon.coords[1], xcoords[1], ycoords[1], zcoords[1]);
        pfSetVec3(polygon.coords[2], xcoords[2], ycoords[2], zcoords[2]);
        pfSetVec3(polygon.colors[0], curr, curg, curb);
        pfuAddPoly(builder, &polygon);
        numTris += polygon.numVerts - 2;

        /* is one triangle enough... */
        if (xcoords[2] == xcoords[3] &&
            ycoords[2] == ycoords[3] &&
            zcoords[2] == zcoords[3])
            return;

        if (isDegenerate(0, 3, 2))
        {
            numVoid++;
            return;
        }

        polygon.numVerts = 3;
        polygon.tbind = PFGS_OFF;
        polygon.nbind = PFGS_OFF;
        polygon.cbind = PFGS_OVERALL;
        pfSetVec3(polygon.coords[0], xcoords[0], ycoords[0], zcoords[0]);
        pfSetVec3(polygon.coords[1], xcoords[2], ycoords[2], zcoords[2]);
        pfSetVec3(polygon.coords[2], xcoords[3], ycoords[3], zcoords[3]);
        pfSetVec3(polygon.colors[0], curr, curg, curb);
        pfuAddPoly(builder, &polygon);
        numTris += polygon.numVerts - 2;

        return;
    }
    /* 1 or 2 triangles */
    else if (strstr(curobj, "3DFACE"))
    {
        if (isDegenerate(0, 1, 2))
        {
            numVoid++;
            return;
        }

        polygon.numVerts = 3;
        polygon.tbind = PFGS_OFF;
        polygon.nbind = PFGS_OFF;
        polygon.cbind = PFGS_OVERALL;
        pfSetVec3(polygon.coords[0], xcoords[0], ycoords[0], zcoords[0]);
        pfSetVec3(polygon.coords[1], xcoords[1], ycoords[1], zcoords[1]);
        pfSetVec3(polygon.coords[2], xcoords[2], ycoords[2], zcoords[2]);
        pfSetVec3(polygon.colors[0], curr, curg, curb);
        pfuAddPoly(builder, &polygon);
        numTris += polygon.numVerts - 2;

        /* is one triangle enough... */
        if (xcoords[2] == xcoords[3] &&
            ycoords[2] == ycoords[3] &&
            zcoords[2] == zcoords[3])
            return;

        if (isDegenerate(0, 3, 2))
        {
            numVoid++;
            return;
        }

        polygon.numVerts = 3;
        polygon.tbind = PFGS_OFF;
        polygon.nbind = PFGS_OFF;
        polygon.cbind = PFGS_OVERALL;
        pfSetVec3(polygon.coords[0], xcoords[0], ycoords[0], zcoords[0]);
        pfSetVec3(polygon.coords[1], xcoords[2], ycoords[2], zcoords[2]);
        pfSetVec3(polygon.coords[2], xcoords[3], ycoords[3], zcoords[3]);
        pfSetVec3(polygon.colors[0], curr, curg, curb);
        pfuAddPoly(builder, &polygon);
        numTris += polygon.numVerts - 2;

        return;
    }
    else if (strstr(curobj, "SEQEND"))
    {
        if (state == 1 && polygon.numVerts > 2)
        {
            pfSetVec3(polygon.colors[0], curr, curg, curb);
            pfuAddPoly(builder, &polygon);
            numTris += polygon.numVerts - 2;
        }
        state = 0; /* end of something */
    }
    else if (strstr(curobj, "POLYLINE"))
    {
        state = 1; /* begin of a polyline */
        indice_point = 1;
        nb_points = ints[1];
        nb_cotes = ints[2];

        if (nb_points >= (BUFFER_SIZE-1))
        {
            state = 0;
            return;
        }

        polygon.numVerts = 0;
        polygon.tbind = PFGS_OFF;
        polygon.nbind = PFGS_OFF;
        polygon.cbind = PFGS_OVERALL;
    }
    /* a new vertex in a polyline */
    else if (strstr(curobj, "VERTEX") && state == 1)
    {
        /* is it a new vertex ? */
        if (indice_point <= nb_points)
        {
            /* copying point */
            xcoords[indice_point] = xcoords[0];
            ycoords[indice_point] = ycoords[0];
            zcoords[indice_point] = zcoords[0];
            indice_point++;
        }
        else
        /* creating edges */
        if (nb_cotes > 0)
        {
            /* closing an older polygon */
            if ((ints[1] > 0) && (polygon.numVerts > 2))
            {
                 pfSetVec3(polygon.colors[0], curr, curg, curb);
                 pfuAddPoly(builder, &polygon);
                 numTris += polygon.numVerts - 2;
            }

            /* creating a new polygon */
            if (ints[1] > 0)
            {
                polygon.numVerts = 0;
                pfSetVec3(polygon.coords[polygon.numVerts++],
                    xcoords[ints[1]], ycoords[ints[1]], zcoords[ints[1]]);
            }
            if (ints[2] > 0)
            {
                pfSetVec3(polygon.coords[polygon.numVerts++],
                    xcoords[ints[2]], ycoords[ints[2]], zcoords[ints[2]]);
            }
            if (ints[3] > 0)
            {
                pfSetVec3(polygon.coords[polygon.numVerts++],
                    xcoords[ints[3]], ycoords[ints[3]], zcoords[ints[3]]);
            }
        }
    }
    /* not implemented */
    else if (
        strstr(curobj, "LINE") || strstr(curobj, "POINT") ||
        strstr(curobj, "CIRCLE") || strstr(curobj, "ARC") ||
        strstr(curobj, "TEXT") || strstr(curobj, "SHAPE") ||
        strstr(curobj, "BLOCK") || strstr(curobj, "ENDBLK") ||
        strstr(curobj, "INSERT") || strstr(curobj, "ATTDEF") ||
        strstr(curobj, "ATTRIB") || strstr(curobj, "3DLINE") ||
        strstr(curobj, "DIMENSION"))
    {
        return;
    }
    /* no current object defined */
    else
        return;
}

/*
 * colors defined by basic AutoCAD color table
 */
static void
getColor (int ndx, float *red, float *green, float *blue)
{
    /* AutoCAD color table */
    static float colors[][3] =
    {
       {0.0f, 0.0f, 0.0f}, /* 0 == black */
       {1.0f, 0.0f, 0.0f}, /* 1 == red */
       {1.0f, 1.0f, 0.0f}, /* 2 == yellow */
       {0.0f, 1.0f, 0.0f}, /* 3 == green */
       {0.0f, 1.0f, 1.0f}, /* 4 == cyan */
       {0.0f, 0.0f, 1.0f}, /* 5 == blue */
       {1.0f, 0.0f, 1.0f}, /* 6 == magenta */
       {1.0f, 1.0f, 1.0f}, /* 7 == white */
       {0.5f, 0.5f, 0.5f}, /* 8 == dk grey */
       {0.75f, 0.75f, 0.75f} /* 9 == lt grey */
    };

    /* use white (color 7) as default color */
    if (ndx < 0 || ndx > 9)
        ndx = 7;

    /* set colors in reference arguments */
    *red = colors[ndx][0];
    *green = colors[ndx][1];
    *blue = colors[ndx][2];

    return;
}

/*
 * check for degenerate triangle structure
 */
static int
isDegenerate(int a, int b, int c)
{
    if ((xcoords[a] == xcoords[b] &&
         ycoords[a] == ycoords[b] &&
         zcoords[a] == zcoords[b]) ||
        (xcoords[b] == xcoords[c] &&
         ycoords[b] == ycoords[c] &&
         zcoords[b] == zcoords[c]) ||
        (xcoords[a] == xcoords[c] &&
         ycoords[a] == ycoords[c] &&
         zcoords[a] == zcoords[c]))
        return 1;
    else
        return 0;
}

/*
 * move forward to ENTITIES section
 */
static int
findEntity(FILE *fp)
{
    while (1)
    {
        /* is there more to read */
        if (feof(fp))
            return 0;

        /* get a group code and a line */
        if (getLine(fp))
            return 0;

        /* file section mark */
        if (groupcode == 0)
        {
            if (strstr(linbuf, "EOF"))
                return 0;

            if (strstr(linbuf, "SECTION"))
            {
                if (getLine(fp))
                    return 0;
                if (groupcode != 2)
                    continue;
                if (strstr(linbuf, "ENTITIES"))
                    break;
            }
        }
    }

    return 1;
}

/*
 * read objects from ENTITIES section
 */
static int
readEntity(FILE *fp, pfuBuilder *builder)
{
    while (1)
    {
        /* is there more to read */
        if (feof(fp))
            break;

        /* get a group code and a line */
        if (getLine(fp))
            break;

        /* cardinal group codes */
        if (groupcode < 10)
        {
            switch(groupcode)
            {
            /* start of entity, table, file sep */
            case 0:
                /* add object's polygons to builder */
                addGeometry(builder);

                if (strstr(linbuf, "EOF"))
                    return 0;
                if (strstr(linbuf, "ENDSEC"))
                    continue;

                /* reset object */
                curobj[0] = '\0';
                curcolor = 7;
                getColor(curcolor, &curr, &curg, &curb);

                /* get new */
                strcpy(curobj, linbuf);
                break;

            /* primary text value for entity (?) */
            case 1:
                break;

            /* block name, attribute tag, etc */
            case 2:
            case 3:
            case 4:
                break;

            /* entity handle (hex string) */
            case 5:
                break;

            /* line type name */
            case 6:
                break;

            /* text style name */
            case 7:
                break;

            /* layer name */
            case 8:
                break;

            /* variable name ID (only in header) */
            case 9:
                break;
            }
        }
        /* some X coord */
        else if (groupcode >= 10 && groupcode < 19)
            sscanf(linbuf, "%f", &(xcoords[groupcode-10]));
        /* some Y coord */
        else if (groupcode >= 20 && groupcode < 29)
            sscanf(linbuf, "%f", &(ycoords[groupcode-20]));
        /* some Z coord */
        else if (groupcode >= 30 && groupcode < 38)
            sscanf(linbuf, "%f", &(zcoords[groupcode-30]));
        /* entity elevation if nonzero */
        else if (groupcode == 38)
        {
        }
        /* entity thickness if nonzero */
        else if (groupcode == 39)
        {
        }
        /* misc floats */
        else if (groupcode >= 40 && groupcode < 49)
            sscanf(linbuf, "%f", &(floats[groupcode-40]));
        /* repeated value groups */
        else if (groupcode == 49)
        {
        }
        /* misc angles */
        else if (groupcode >= 50 && groupcode < 59)
            sscanf(linbuf, "%f", &(angles[groupcode-50]));
        /* color number */
        else if (groupcode == 62)
        {
            sscanf(linbuf, "%6d", &curcolor);
            getColor(curcolor, &curr, &curg, &curb);
        }
        /* "entities follow" flag */
        else if (groupcode == 66)
        {
        }
        /* misc ints */
        else if (groupcode >= 70 && groupcode < 79)
            sscanf(linbuf, "%d", &(ints[groupcode-70]));
        /* X, Y, Z components of extrusion direction */
        else if (groupcode == 210 || groupcode == 220 || groupcode == 230)
        {
        }
    }
    return 0;
}

/*
 * make a reasonable default geostate
 */
static pfGeoState*
defaultGeoState (void)
{
    static void *arena = NULL;
    static pfMaterial *material = NULL;
    static pfGeoState *geostate = NULL;

    if (geostate == NULL)
    {
        arena = pfGetSharedArena();

        material = pfNewMtl(arena);
        pfMtlColor(material, PFMTL_AMBIENT, 0.1, 0.1, 0.1);
        pfMtlColor(material, PFMTL_SPECULAR, 0.8, 0.8, 0.8);
        pfMtlShininess(material, 10.0);
        pfMtlColorMode(material, PFMTL_FRONT, LMC_AD);

        geostate = pfNewGState(arena);
        pfGStateAttr(geostate, PFSTATE_FRONTMTL, material);
    }

    return geostate;
}

-- 

Be seeing you, mtj++at++sgi.com 415.390.1455 M/S 7L-590 Michael Jones Silicon Graphics, Advanced Graphics Division 2011 N. Shoreline Blvd., Mtn. View, CA 94039-7311


New Message Reply Date view Thread view Subject view Author view

This archive was generated by hypermail 2.0b2 on Mon Aug 10 1998 - 17:50:14 PDT

This message has been cleansed for anti-spam protection. Replace '++at++' in any mail addresses with the '@' symbol.