예제 #1
0
        /**
         * @param T1 the transformation to multiply with
         * @return the product of two transformations, .i.e. the tranformation
         * resulting of the two transformations applied one after the other
         */
        public DX_Transformation prod(DX_Transformation T1)
        {
            Matrix p = _matrix * T1._matrix;

            Matrix  mt = _matrix; mt.Transpose();
            Vector4 v4 = Vector3.Transform(T1._vector, mt);
            Vector3 v3 = new Vector3(v4.X, v4.Y, v4.Z);

            return(new DX_Transformation(p, v3 + _vector));
        }
예제 #2
0
        /* offs=0 */
        /**
         * Creates a new stem
         *
         * @param tr the tree object
         * @param params the general tree parameters
         * @param lparams the parameters for the stem level
         * @param parnt the parent stem, from wich the stems grows out
         * @param stlev the stem level
         * @param trf the base transformation of the stem
         * @param offs the offset of ste stem within the parent stem (0..1)
         */
        public CS_StemImpl(CS_TreeImpl tr, CS_StemImpl growsOutOf, int stlev,
                DX_Transformation trf, float offs)
        {
            tree = tr;
                    stemlevel = stlev;
                    transf = trf;
                    offset = offs;

                    if (growsOutOf != null)
                    {
                        if (growsOutOf.stemlevel < stemlevel)
                            parent = growsOutOf;
                        else
                        {
                            clonedFrom = growsOutOf;
                            parent = growsOutOf.parent;
                        }
                    }

                    par = tree.csparams;
                    lpar = par.getLevelParams(stemlevel);

                    // initialize lists
                    segments = new List<CS_SegmentImpl>(lpar.nCurveRes);

                    if (lpar.nSegSplits > 0 || par._0BaseSplits > 0)
                    {
                        clones = new List<CS_StemImpl>(); // lpar.nSegSplits*lpar.nCurveRes+1);
                    }

                    if (stemlevel < par.Levels - 1)
                    {
                        CS_LevelParams lpar_1 = par.getLevelParams(lpar.level + 1);
                        substems = new List<CS_StemImpl>(lpar_1.nBranches);
                    }

                    if (stemlevel == par.Levels - 1 && par.Leaves != 0)
                    {
                        leaves = new List<CS_LeafImpl>(Math.Abs(par.Leaves));
                    }

                    // inialize other variables
                    leavesPerSegment = 0;
                    splitCorrection = 0;

                    index = 0; // substem number

                    cloneIndex = new List<int>();
                    pruneTest = false; // flag used for pruning

                    //...
                    maxPoint = new Vector3(-float.MaxValue, -float.MaxValue, -float.MaxValue);
                    minPoint = new Vector3(float.MaxValue, float.MaxValue, float.MaxValue);
        }
 public void AddLeaf(DX_Transformation transf)
 {
     if (_leafType == 0) MakeDiscPoints(5, transf);
     else if (_leafType == 1) MakeDiscPoints(3, transf);
     else if (_leafType == 2) MakeDiscPoints(4, transf);
     else if (_leafType == 3) MakeDiscPoints(5, transf);
     else if (_leafType == 4) MakeDiscPoints(6, transf);
     else if (_leafType == 5) MakeDiscPoints(7, transf);
     else if (_leafType == 6) MakeDiscPoints(8, transf);
     else if (_leafType == 7) MakeDiscPoints(9, transf);
     else if (_leafType == 8) MakeDiscPoints(10, transf);
     else if (_leafType == 9) MakeDiscPoints(11, transf);
     else if (_leafType == 10) MakeDiscPoints(4, transf);
     //else if (_leafType == 11) MakeSpherePoints();
 }
예제 #4
0
        public CS_SegmentImpl(/*Params params, LevelParams lparams,*/
            CS_StemImpl stm, int inx, DX_Transformation trf,
            float r1, float r2)
        {
            index = inx;
            transf = trf;
            rad1 = r1;
            rad2 = r2;
            stem = stm;

            par = stem.par;
            lpar = stem.lpar;
            length = stem.segmentLength;

            // FIXME: rad1 and rad2 could be calculated only when output occurs (?)
            // or here in the constructor ?
            // FIXME: inialize subsegs with a better estimation of size
            subsegments = new List<CS_SubsegmentImpl>(10);
        }
예제 #5
0
        /**
         *	Leaf rotation toward light
         */
        private void setLeafOrientation(CS_Params par)
        {
            if (par.LeafBend == 0) return;

            // FIXME: make this function as fast as possible - a tree has a lot of leafs

            // rotation outside
            Vector3 pos = transf.getT();
            // the z-vector of transf is parallel to the
            // axis of the leaf, the y-vector is the normal
            // (of the upper side) of the leaf
            Vector3 norm = transf.getY3();

            float tpos = (float)(Math.Atan2(pos.Y, pos.X) * 180 / Math.PI);
            float tbend = tpos - (float)(Math.Atan2(norm.Y, norm.X) * 180 / Math.PI); ;
            // if (tbend>180) tbend = 360-tbend;

            float bend_angle = par.LeafBend * tbend;
            // transf = transf.rotz(bend_angle);
            // rotate about global z-axis
            transf = transf.rotaxis(bend_angle, DX_Transformation.Z_AXIS);

            // rotation up
            norm = transf.getY3();
            float fbend = (float)(Math.Atan2((float)Math.Sqrt(norm.X * norm.X + norm.Y * norm.Y), norm.Z) * 180 / Math.PI);

            bend_angle = par.LeafBend * fbend;

            transf = transf.rotx(bend_angle);

            //		this is from the paper, but is equivalent with
            //      local x-rotation (upper code line)
            //
            //		double orientation = Vector.atan2(norm.getY(),norm.getX());
            //		transf = transf
            //			.rotaxis(-orientation,Vector.Z_AXIS)
            //			.rotx(bend_angle)
            //			.rotaxis(orientation,Vector.Z_AXIS);
        }
        private void MakeDiscPoints(int vCount, DX_Transformation transf)
        {
            List<DXBaseArbaroTreeMesh.DXVertex> dxvv = new List<DXBaseArbaroTreeMesh.DXVertex>();

            // Create vertices
            for (int i = 0; i < vCount; i++)
            {
                float a = (float)(i * Math.PI * 2 / vCount);
                Vector4 p = new Vector4((float)Math.Sin(a), 0, (float)Math.Cos(a), 1);

                if (a < Math.PI)
                {
                    p.X -= leaffunc(a);
                }
                else if (a > Math.PI)
                {
                    p.X += leaffunc((float)(2 * Math.PI - a));
                }

                p.X *= _width;
                p.Y *= _width;
                p.Z = (_stemLength + p.Z + 1) * _length;

                p = transf.apply(p);

                DXBaseArbaroTreeMesh.DXVertex dxv = _mesh.Vertices.Add(new DXArbaroVertexTrait(new Vector3(p.X, p.Y, p.Z)));
                dxvv.Add(dxv);
            }

            // create faces
            for (int i = 0; i < vCount - 2; i++)
            {
                //Console.WriteLine(dxvv[0].Index + " " + dxvv[i + 1].Index + " " + dxvv[i + 2].Index);
                _mesh.Faces.Add(dxvv[0], dxvv[i + 1], dxvv[i + 2]);
            }
        }
예제 #7
0
 public CS_LeafImpl(DX_Transformation trf)
 {
     //		par = params;
     transf = trf;
 }
예제 #8
0
 /**
  * For debugging:
  * Prints out the transformation to stderr nicely
  * (only if debugging is enabled)
  *
  * @param where The position in the tree, i.e. wich stem
  *              has this transformation
  * @param trf  The transformation
  */
 void TRF(String where, DX_Transformation trf)
 {
     //DBG(where + ": " + trf.toString());
 }
예제 #9
0
        /**
         * @param T1 the transformation to multiply with
         * @return the product of two transformations, .i.e. the tranformation
         * resulting of the two transformations applied one after the other
         */
        public DX_Transformation prod(DX_Transformation T1)
        {
            Matrix p = _matrix * T1._matrix;

            Matrix mt = _matrix; mt.Transpose();
            Vector4 v4 = Vector3.Transform(T1._vector, mt);
            Vector3 v3 = new Vector3(v4.X, v4.Y, v4.Z);

            return new DX_Transformation(p, v3 + _vector);
        }
예제 #10
0
        /**
         * @param T1 the transformation to multiply with
         * @return the product of two transformations, .i.e. the tranformation
         * resulting of the two transformations applied one after the other
         */
        public DX_Transformation prod(DX_Transformation T1)
        {
            Vector4 t = Vector3.Transform(T1.vector(), _matrix);

            return(new DX_Transformation(T1.matrix() * _matrix, new Vector3(t.X, t.Y, t.Z) + _vector));
        }
예제 #11
0
        /**
         * Calcs a new direction for the current segment
         *
         * @param trf The transformation of the previous segment
         * @param nsegm The number of the segment ( for testing, if it's the
         *              first stem segment
         * @return The new transformation of the current segment
         */
        DX_Transformation newDirection(DX_Transformation trf, int nsegm)
        {
            // next segments direction

            // The first segment shouldn't get another direction
            // down and rotation angle shouldn't be falsified
            if (nsegm == 0) return trf;

            /*
            if (Console.debug())
                TRF("Stem.new_direction() before curving",trf);
            */

            // get curving angle
            double delta;
            if (lpar.nCurveBack == 0)
            {
                delta = lpar.nCurve / lpar.nCurveRes;

            }
            else
            {
                if (nsegm < (lpar.nCurveRes + 1) / 2)
                {
                    delta = lpar.nCurve * 2 / lpar.nCurveRes;
                }
                else
                {
                    delta = lpar.nCurveBack * 2 / lpar.nCurveRes;
                }
            }
            delta += splitCorrection;

            /*
            if (Console.debug())
                DBG("Stem.new_direction(): delta: "+delta);
            */

            trf = trf.rotx(delta);

            // With Weber/Penn the orientation of the x- and y-axis
            // shouldn't be disturbed (maybe, because proper curving relies on this)
            // so may be such random rotations shouldn't be used, instead nCurveV should
            // add random rotation to rotx, and rotate nCurveV about the tree's z-axis too?

            // add random rotation about z-axis
            if (lpar.nCurveV > 0)
            {
                //    		if (nsegm==0 && stemlevel==0) { // first_trunk_segment
                //    			// random rotation more moderate
                //    			delta = (Math.abs(lpar.var(lpar.nCurveV)) -
                //    					Math.abs(lpar.var(lpar.nCurveV)))
                //						/ lpar.nCurveRes;
                //    		}	else {
                // full random rotation
                delta = lpar.var(lpar.nCurveV) / lpar.nCurveRes;
                //    		}
                // self.DBG("curvV (delta): %s\n" % str(delta))
                double rho = 180 + lpar.var(180);
                trf = trf.rotaxisz(delta, rho);
            }
            //TRF("Stem.new_direction() after curving",trf);

            // attraction up/down
            if (par.AttractionUp != 0 && stemlevel >= 2)
            {

                double declination = Math.Acos(trf.getZ3().Z);

                // 			I don't see, why we need orientation here, may be this avoids
                //          attraction of branches with the x-Axis up and thus avoids
                //			twisting (see below), but why branches in one direction should
                //			be attracted, those with another direction not, this is unnaturally:
                //    		double orient = Math.acos(trf.getY().getZ());
                //    		double curve_up_orig = par.AttractionUp * declination * Math.cos(orient)/lpar.nCurveRes;

                // FIXME: devide by (lpar.nCurveRes-nsegm) if last segment
                // should actually be vertical
                double curve_up = par.AttractionUp *
                Math.Abs(declination * Math.Sin(declination)) / lpar.nCurveRes;

                Vector3 z = trf.getZ3();
                // FIXME: the mesh is twisted for high values of AttractionUp
                trf = trf.rotaxis(-curve_up * 180 / Math.PI, new Vector3(-z.Y, z.X, 0));
                // trf = trf.rotx(curve_up*180/Math.PI);
            }
            return trf;
        }
 /**
  * @param T1 the transformation to multiply with
  * @return the product of two transformations, .i.e. the tranformation
  * resulting of the two transformations applied one after the other
  */
 public DX_Transformation prod(DX_Transformation T1)
 {
     Vector4 t = Vector3.Transform(T1.vector(), _matrix);
     return new DX_Transformation(T1.matrix() * _matrix, new Vector3(t.X, t.Y, t.Z) + _vector);
 }
예제 #13
0
        /**
         * Generates the tree. The following collaboration diagram
         * shows the recursion trough the make process:
         * <p>
         * <img src="doc-files/Tree-2.png" />
         * <p>
         *
         * @throws Exception
         */
        public void make(Object progress)
        {
            this.progress = progress;

            setupGenProgress();
            csparams.prepare(seed);
            maxPoint = new Vector3(-float.MaxValue, -float.MaxValue, -float.MaxValue);
            minPoint = new Vector3(float.MaxValue, float.MaxValue, float.MaxValue);

            Console.WriteLine("Tree species: " + csparams.Species + ", Seed: " + seed);
            Console.WriteLine("making " + csparams.Species + "(" + seed + ") ");

            // create the trunk and all its stems and leaves
            DX_Transformation transf = new DX_Transformation();
            DX_Transformation trf;
            float angle;
            float dist;
            CS_LevelParams lpar = csparams.getLevelParams(0);
            for (int i = 0; i < lpar.nBranches; i++)
            {
                trf = trunkDirection(transf, lpar);
                angle = lpar.var(360);
                dist = lpar.var(lpar.nBranchDist);
                trf = trf.translate(new Vector3(dist * (float)Math.Sin(angle), dist * (float)Math.Cos(angle), 0));
                CS_StemImpl trunk = new CS_StemImpl(this, null, 0, trf, 0);
                trunks.Add(trunk);
                trunk.index = 0;
                trunk.make();
            }

            // set leafCount and stemCount for the tree
            if (csparams.Leaves == 0) setLeafCount(0);
            else
            {
                CS_LeafCounter leafCounter = new CS_LeafCounter();
                traverseTree(leafCounter);
                setLeafCount(leafCounter.getLeafCount());
            }
            CS_StemCounter stemCounter = new CS_StemCounter();
            traverseTree(stemCounter);
            setStemCount(stemCounter.getStemCount());

            // making finished
            Console.WriteLine("making " + csparams.Species + " Done.   ");

            // TODO
            //progress.endPhase();
        }
예제 #14
0
        /**
         * Make a clone of the stem at this position
         *
         * @param trf The base transformation for the clone
         * @param start_segm Start segment number, i.e. the height, where
         *        the clone spreads out
         * @return The clone stem object
         */
        CS_StemImpl make_clone(DX_Transformation trf, int start_segm)
        {
            // creates a clone stem with same atributes as this stem
            CS_StemImpl clone = new CS_StemImpl(tree, this, stemlevel, trf, offset);
            clone.segmentLength = segmentLength;
            clone.segmentCount = segmentCount;
            clone.length = length;
            clone.baseRadius = baseRadius;
            clone.splitCorrection = splitCorrection;
            clone.pruneTest = pruneTest;
            clone.index = index;

            //DBG("Stem.clone(): clone_index "+clone_index);
            clone.cloneIndex.AddRange(cloneIndex);

            //DBG("Stem.clone(): level: "+stemlevel+" clones "+clones);
            clone.cloneIndex.Add(clones.Count);
            if (!pruneTest)
            {
                clone.lengthChildMax = lengthChildMax;
                //clone.substem_cnt = substem_cnt;
                clone.substemsPerSegment = substemsPerSegment;
                //clone.substemdist = substemdist;
                //clone.substemdistv = substemdistv;
                //clone.seg_splits = self.seg_splits
                // FIXME: for more then one clone this angle should somehow
                // correspond to the rotation angle of the clone
                clone.substemRotangle = substemRotangle + 180;
                clone.leavesPerSegment = leavesPerSegment;
            }
            return clone;
        }
예제 #15
0
        /**
         * Make clones of the current stem at the current segment
         *
         * @param trf The current segments's direction
         * @param nseg The number of the current segment
         * @return Segments outside the pruning envelope, -1
         *         if stem clone is completely inside the envelope
         */
        int makeClones(DX_Transformation trf, int nseg)
        {
            // splitting
            // FIXME: maybe move this calculation to LevelParams
            // but pay attention to saving errorValues and restoring when making prune tests
            int seg_splits_eff;
            if (stemlevel == 0 && nseg == 0 && par._0BaseSplits > 0)
            {
                seg_splits_eff = par._0BaseSplits;
            }
            else
            {
                // how many clones?
                float seg_splits = lpar.nSegSplits;
                seg_splits_eff = (int)(seg_splits + lpar.splitErrorValue + 0.5);

                // adapt error value
                lpar.splitErrorValue -= (seg_splits_eff - seg_splits);
            }

            if (seg_splits_eff < 1) return -1;

            float s_angle = 360 / (seg_splits_eff + 1);

            // make clones
            // if seg_splits_eff > 0:
            for (int i = 0; i < seg_splits_eff; i++)
            {

                // copy params
                CS_StemImpl clone = make_clone(trf, nseg + 1);

                // NOTE: its a little bit problematic here
                // when the clone is given as a parent to
                // the substems, it should have the same
                // params for length and segment_cnt like
                // the original stem, but this could be
                // somewhat confusing(?)
                // clone.segment_cnt = remaining_segs;
                // clone.length = remaining_segs * self.segment_len

                // change the direction for the clone
                //if self.debug: sys.stderr.write("-SPLIT_CORE_BEFOR: %s, dir: %s\n" % \
                //	(str(clone.split_corr),str(clone.direction)))

                clone.transf = clone.split(trf, s_angle * (1 + i), nseg, seg_splits_eff);

                //if self.debug: sys.stderr.write("-SPLIT_CORE_AFTER: %s, dir: %s\n" %
                //	(str(clone.split_corr),str(clone.direction)))

                // make segments etc. for the clone
                int segm = clone.makeSegments(nseg + 1, clone.segmentCount);
                if (segm >= 0)
                { // prune test - clone not inside envelope
                    return segm;
                }
                // add clone to the list
                clones.Add(clone);
            }
            // get another direction for the original stem too
            trf = split(trf, 0, nseg, seg_splits_eff);
            return -1;
        }
예제 #16
0
 /**
  * Calcs the position of a substem in the segment given
  * a relativ position where in 0..1 - needed esp. for helical stems,
  * because the substems doesn't grow from the axis of the segement
  *
  * @param trf the transformation of the substem
  * @param where the offset, where the substem spreads out
  * @return the new transformation of the substem (shifted from
  *        the axis of the segment to the axis of the subsegment)
  */
 public DX_Transformation substemPosition(DX_Transformation trf, float where)
 {
     if (lpar.nCurveV>=0) { // normal segment
     return trf.translate(transf.getZ3() * (where*length));
     } else { // helix
     // get index of the subsegment
     int i = (int)(where*(subsegments.Count-1));
     // interpolate position
     Vector3 p1 = ((CS_SubsegmentImpl)subsegments[i]).pos;
     Vector3 p2 = ((CS_SubsegmentImpl)subsegments[i + 1]).pos;
     Vector3 pos = p1 + (p2 -p1)*(where - i / (subsegments.Count - 1));
     return trf.translate(pos - getLowerPosition());
     }
 }
예제 #17
0
        /**
         * Calcs the direction of a substem from the parameters
         *
         * @param trf The transformation of the current stem segment
         * @param offset The offset of the substem from the base of the currents stem
         * @return The direction of the substem
         */
        DX_Transformation substemDirection(DX_Transformation trf, float offset)
        {
            CS_LevelParams lpar_1 = par.getLevelParams(stemlevel + 1);
            //lev = min(level+1,3);

            // get rotation angle
            float rotangle;
            if (lpar_1.nRotate >= 0)
            { // rotating substems
                substemRotangle = (substemRotangle + lpar_1.nRotate + lpar_1.var(lpar_1.nRotateV) + 360) % 360;
                rotangle = substemRotangle;
            }
            else
            { // alternating substems
                if (Math.Abs(substemRotangle) != 1) substemRotangle = 1;
                substemRotangle = -substemRotangle;
                rotangle = substemRotangle * (180 + lpar_1.nRotate + lpar_1.var(lpar_1.nRotateV));
            }

            // get downangle
            float downangle;
            if (lpar_1.nDownAngleV >= 0)
            {
                downangle = lpar_1.nDownAngle + lpar_1.var(lpar_1.nDownAngleV);
            }
            else
            {
                float len = (stemlevel == 0) ? length * (1 - par.BaseSize) : length;
                downangle = lpar_1.nDownAngle +
                lpar_1.nDownAngleV * (1 - 2 * par.getShapeRatio((length - offset) / len, 0));
            }
            /*
            if (Console.debug())
                DBG("Stem.substem_direction(): down: "+downangle+" rot: "+rotangle);
            */
            return trf.rotxz(downangle, rotangle);
        }
예제 #18
0
        /**
         * Gives a clone a new direction (splitting)
         *
         * @param trf The base transformation of the clone
         * @param s_angle The splitting angle
         * @param nseg The segment number, where the clone begins
         * @param nsplits The number of clones
         * @return The new direction for the clone
         */
        DX_Transformation split(DX_Transformation trf,
                float s_angle, int nseg, int nsplits)
        {
            // applies a split angle to the stem - the Weber/Penn method
            int remaining_seg = segmentCount - nseg - 1;

            // the splitangle
            // FIXME: don't know if it should be nSplitAngle or nSplitAngle/2
            float declination = (float)(Math.Acos(trf.getZ3().Z) * 180 / Math.PI);
            float split_angle = Math.Max(0, (lpar.nSplitAngle
                    + lpar.var(lpar.nSplitAngleV) - declination));

            // FIXME: first works better for level 0, second for further levels
            // transf = transf.rotxz(split_angle,s_angle)
            trf = trf.rotx(split_angle);

            // adapt split correction
            splitCorrection -= split_angle / remaining_seg;
            //t_corr = Transformation().rotx(-split_angle/remaining_seg)

            float split_diverge;
            if (s_angle > 0)
            { // original stem has s_angle==0
                if (par._0BaseSplits > 0 && stemlevel == 0 && nseg == 0)
                {
                    split_diverge = s_angle + lpar.var(lpar.nSplitAngleV);
                }
                else
                {
                    split_diverge = (float)(20 + 0.75 * (30 + Math.Abs(declination - 90))
                    * Math.Pow((lpar.var(1) + 1) / 2.0, 2));
                    if (lpar.var(1) >= 0) split_diverge = -split_diverge;
                }

                trf = trf.rotaxis(split_diverge, DX_Transformation.Z_AXIS);

            }
            else split_diverge = 0; // for debugging only

            // adjust some parameters
            //split_cnt = split_cnt+1;

            // lower substem prospensity
            if (!pruneTest)
            {
                substemsPerSegment /= (float)(nsplits + 1);
                // FIXME: same reduction for leaves_per_segment?
            }
            return trf;
        }
예제 #19
0
        /* (non-Javadoc)
         * @see net.sourceforge.arbaro.tree.TraversableTree#traverseTree(net.sourceforge.arbaro.tree.TreeTraversal)
         */
        DX_Transformation trunkDirection(DX_Transformation trf, CS_LevelParams lpar)
        {
            // get rotation angle
            double rotangle;
            if (lpar.nRotate >= 0)
            { // rotating trunk
                trunk_rotangle = (trunk_rotangle + lpar.nRotate + lpar.var(lpar.nRotateV) + 360) % 360;
                rotangle = trunk_rotangle;
            }
            else
            { // alternating trunks
                if (Math.Abs(trunk_rotangle) != 1) trunk_rotangle = 1;
                trunk_rotangle = -trunk_rotangle;
                rotangle = trunk_rotangle * (180 + lpar.nRotate + lpar.var(lpar.nRotateV));
            }

            // get downangle
            double downangle;
            downangle = lpar.nDownAngle + lpar.var(lpar.nDownAngleV);

            return trf.rotxz(downangle, rotangle);
        }