Io scene hgpl

From The Foundry MODO SDK wiki
Revision as of 21:34, 10 September 2013 by Adissid (Talk | contribs)

Jump to: navigation, search

Io_scene_hgpl is a basic example plugin. This wiki page is intended as a walkthrough of the code in order to help you better understand the SDK.

When installed this plugin adds a saver/loader that loads/saves HPGL Plotter files.

HGPL SHOT.png

The saver option highlighted above.

Class Declarations

The HGPL format derives from a default line format(CLxLineFormat) with no delimiters.

class CHPGLFormat : public CLxLineFormat
{
   public:
       virtual const char *	 lf_Separator  ()		{ return ""; }

       int			 Coord    (float);
       void			 outInit  ();
       void			 outPen   (int);
       void			 outPoint (float, float);
       void			 outBreak ();
       void			 outDone  ();

       bool			 pen_down;
       int			 cur_pen;
       int			 next_pen;
};

A polygon edge consists of two point IDs. To rank them we first sort the IDs within each edge and then compare the similar ones.

class CEdge {
   public:
       LXtPointID		 v[2];

       bool operator< (const CEdge &x) const
       {
               int		 ti, xi;

               ti = (  v[0] <   v[1]);
               xi = (x.v[0] < x.v[1]);
               return (v[ti] < x.v[xi] || v[ti] == x.v[xi] && v[!ti] < x.v[!xi]);
       }
};

The HPGL saver needs to be able to save a scene of the HPGL format, so we need to inherit from the CLxSceneSaver and CHGPLFormat classes.

class CHPGLSaver : public CLxSceneSaver, public CHPGLFormat
{
    public:
        virtual CLxFileFormat *	 ss_Format    ()	{ return this; }

        virtual LxResult	 ss_Save      ();
        virtual void		 ss_Polygon   ();

        void			 GetOptions   ();
        void			 PlotPoint    (LXtPointID);

        int			 opt_proj;
        double			 opt_scale;

        int			 idx_x, idx_y;
        float			 max_x, min_y;
        map<CEdge,int>		 edge_map;

        static LXtTagInfoDesc	 descInfo[];
};

These tags define the Saver class above as saving SCENE files with the extension .plt and the identity HGPL Plotter File.

Server tags

LXtTagInfoDesc	 CHPGLSaver::descInfo[] = {
       { LXsSAV_OUTCLASS,	LXa_SCENE		},
       { LXsSAV_DOSTYPE,	"plt"			},
       { LXsSRV_USERNAME,	"HPGL Plotter File"	},
       { LXsSRV_LOGSUBSYSTEM,	LOG_NAME		},
#ifdef LICENSE
       { LXsSRV_LICENSE,	LICENSE			},
#endif
       { 0 }
};

Intialize

This method indicates that we will be adding one server to modo of type saver that will depend upon the CHPGLSaver.

       void
initialize ()
{
       LXx_ADD_SERVER (Saver, CHPGLSaver, SAVER_NAME);
}

Implementations

These are utilities that keep track of the pen state and perform scaling from meters to plotter units.

        int
CHPGLFormat::Coord (
        float			 m)
{
        m /= 0.000025f;		// 25 microns per unit
        if (m > 0)
                return (int) (m + 0.5);
        else
                return (int) (m - 0.5);
}

        void
CHPGLFormat::outInit ()
{
        lf_Output (";IN;PA;");
        lf_Break ();
        lf_Output ("PU;");
        lf_Break ();

        pen_down = false;
        cur_pen  = 0;
        next_pen = 1;
}

        void
CHPGLFormat::outPen (
        int			 pen)
{
        next_pen = pen;
}

        void
CHPGLFormat::outPoint (
        float			 x,
        float			 y)
{
        char			 buf[32];
        int			 ix, iy;

        ix = Coord (x);
        iy = Coord (y);

        if (!pen_down) {
                if (cur_pen != next_pen) {
                        sprintf (buf, "SP%d;", next_pen);
                        lf_Output (buf);
                        lf_Break  ();
                        cur_pen = next_pen;
                }

                sprintf (buf, "PA%d,%d;", ix, iy);
                lf_Output (buf);
                lf_Break  ();
                lf_Output ("PD");
                pen_down = true;
        } else
                lf_Output (",");

        sprintf (buf, "%d,%d", ix, iy);
        lf_Output (buf);
}

        void
CHPGLFormat::outBreak ()
{
        if (!pen_down)
                return;

        lf_Output (";");
        lf_Break ();
        lf_Output ("PU;");
        lf_Break ();
        pen_down = false;
}

        void
CHPGLFormat::outDone ()
{
        outBreak ();
        lf_Output ("SP0;");
        lf_Break ();
}

GetOptions retrieves certain parameters with which to save your file. ss_Save performs the meat of the saving work.

        void
CHPGLSaver::GetOptions ()
{
        CLxReadUserValue	 ruv;

        if (ruv.Query ("hpgl.projection"))
                opt_proj = ruv.GetInt ();
        else
                opt_proj = 3;

        if (ruv.Query ("hpgl.scale"))
                opt_scale = ruv.GetFloat ();
        else
                opt_scale = 1.0;
}

        LxResult
CHPGLSaver::ss_Save ()
{
        CLxUser_Log		 log (LOG_NAME);
        bool			 mesh, first;
        LXtBBox			 box, total;
        int			 axis;

        GetOptions ();

        StartScan ();
        first = 1;
        LXx_VSET (total.min, 0);
        LXx_VSET (total.max, 0);

        while (mesh = NextMesh ())
                if (ChanInt (LXsICHAN_UISTATE_VISIBLE) != 2) {
                        MeshBounds (box);
                        if (first) {
                                total = box;
                                first = 0;
                        } else {
                                LXx_V3MIN (total.min, box.min);
                                LXx_V3MAX (total.max, box.max);
                        }
                }

        if (opt_proj == 3) {
                LXx_VSUB3 (total.extent, total.max, total.min);

                if (total.extent[0] < total.extent[1]) {
                        if (total.extent[0] < total.extent[2])
                                axis = 0;
                        else
                                axis = 2;
                } else if (total.extent[1] < total.extent[2])
                        axis = 1;
                else
                        axis = 2;
        } else {
                axis = opt_proj;
        }

        if (axis == 0) {
                idx_x = 1;
                idx_y = 2;
        } else if (axis == 1) {
                idx_x = 0;
                idx_y = 2;
        } else if (axis == 2) {
                idx_x = 0;
                idx_y = 1;
        }
        max_x = total.max[idx_x];
        min_y = total.min[idx_y];

        if (ReallySaving () && log.test ()) {
                log.Info ("Writing HPGL");
                log.Message (LXe_INFO, "axis %d, %f x %f", axis, total.extent[idx_x], total.extent[idx_y]);

 #ifdef LICENSE
                CLxUser_HostService	 svc;
                CLxUser_Factory		 fac;
                const char		*who, *ser;

                if (    svc.Lookup (fac, LXa_SAVER, SAVER_NAME)
                     && LXx_OK (fac.InfoTag (LXsSRV_OWNER,  &who))
                     && LXx_OK (fac.InfoTag (LXsSRV_SERIAL, &ser))   )
                {
                        log.Message (LXe_INFO, "Registered to %s, serial %s", who, ser);
                } else
                        log.Warn ("Can't find my own factory!");
 #endif
        }

        outInit ();

        StartScan ();
        while (mesh = NextMesh ())
                if (ChanInt (LXsICHAN_UISTATE_VISIBLE) != 2)
                        WritePolys ();

        outDone ();
        return LXe_OK;
}

Plotting polygons we want to draw only the contour edges, not edges that connect to holes. Thus we count the number of times an edge occurs in the polygon and only draw those that happen exactly once.

        void
CHPGLSaver::ss_Polygon ()
{
        map<CEdge,int>::iterator it;
        CEdge			 edge;
        LXtPointID		 last;
        unsigned		 i, n;

        edge_map.clear ();
        n = PolyNumVerts ();

        for (i = 0; i < n; i++) {
                edge.v[0] = PolyVertex ( i      % n);
                edge.v[1] = PolyVertex ((i + 1) % n);

                it = edge_map.find (edge);
                if (it == edge_map.end ())
                        edge_map[edge] = 1;
                else
                        it->second += 1;
        }

        do {
                last = 0;

                for (i = 0; i < n; i++) {
                        edge.v[0] = PolyVertex ( i      % n);
                        edge.v[1] = PolyVertex ((i + 1) % n);
                        if (edge_map[edge] != 1)
                                continue;

                        if (!last) {
                                PlotPoint (edge.v[0]);
                                PlotPoint (edge.v[1]);

                        } else if (edge.v[0] == last) {
                                PlotPoint (edge.v[1]);

                        } else
                                continue;

                        edge_map[edge] = 0;
                        last = edge.v[1];
                }

                outBreak ();
        } while (last);
}

        void
CHPGLSaver::PlotPoint (
        LXtPointID		 pnt)
{
        float			 vec[3];

        PntSet (pnt);
        PntPosition (vec);
        outPoint ((max_x - vec[idx_x]) * opt_scale,
                  (vec[idx_y] - min_y) * opt_scale);
}