/// <summary>
        /// The parabolic mirror is one of the key elements of the SunCycle concentrator
        /// When light is directed onto a parabolic mirror in the right direction the
        /// lightrays will reflect towards a single point, hence it can be used as a concentrator.
        /// </summary>
        /// <param name="parent">
        /// A <see cref="Scientrace.Object3dCollection"/> in which the physicalobject "parabolicmirror" is placed.
        /// </param>
        /// <param name="mprops">
        /// A <see cref="Scientrace.MaterialProperties"/> instance defines the properties of the mirror.
        /// </param>
        /// <param name="loc">
        /// A <see cref="Scientrace.Location"/> defines the location which has to be shifted to 0,0,0 to make z = x^2 + y^2 = 0
        /// </param>
        /// <param name="zaxis">
        /// A <see cref="Scientrace.UnitVector"/> pointing the direction of the norm at the "bottom" of the mirror pointing "up"
        /// </param>
        /// <param name="c">
        /// A <see cref="System.Double"/>, the value c for which z = c(x^2+y^2) after a location shift.
        /// </param>
        /// <param name="cborder">
        /// A <see cref="CylindricalBorder"/> the mirror only exists between these borders.
        /// </param>
        public ParabolicMirror(Scientrace.Object3dCollection parent, Scientrace.MaterialProperties mprops,
                               Scientrace.Location loc, Scientrace.UnitVector zaxis, double c,
                               AbstractGridBorder cborder) : base(parent, mprops)
        {
            /* Console.WriteLine("Mirror props: loc:"+
             *                        loc.trico()+" zax:"+zaxis.trico()+ " c:"+c +" border: "+cborder.ToString()); */
            this.c       = c;
            this.loc     = loc;
            this.zaxis   = zaxis;
            this.cborder = cborder;


            Scientrace.UnitVector basevec1 = new Scientrace.UnitVector(1, 0, 0);
            if (Math.Abs(zaxis.dotProduct(basevec1)) > 0.8)
            {
                basevec1 = new Scientrace.UnitVector(0, 1, 0);
            }
            Scientrace.UnitVector v = basevec1.crossProduct(zaxis).tryToUnitVector();
            trf = new VectorTransformOrthonormal(zaxis, v, VectorTransform.SWAP_U_WITH_W);

            //Console.WriteLine("V transform: "+trf.transform(v).trico()+ " z: "+zaxis+" transform(Z):"+trf.transform(zaxis).trico());
        }
        public override string exportX3D(Scientrace.Object3dEnvironment env)
        {
            int steps = this.exportX3Dgridsteps;

            Scientrace.AbstractGridBorder cborder = this.cborder;
//		Scientrace.VectorTransform cbordertrf = cborder.getTransform();
            //Generate a rotating grid!
            Scientrace.VectorTransform cbordertrf = cborder.getGridTransform(this.zaxis);
            //Console.WriteLine("CBTRFcp: "+cbordertrf.ToCompactString());

            /*
             * stloc: starting location actually representing the center of the border,
             * from there in the orthonormal direction of this border the collision points with
             * the parabolic mirror will be found (from -radius to +radius in both transform-directions
             */
            Scientrace.Location            stloc = cborder.getOrthoStartCenterLoc();// - cborder.getOthoDirection();
            Scientrace.IntersectionPoint[] iparr, iparre, iparrs;
            Scientrace.Intersection        cintr, eintr, sintr;

            /*
             * eloc is the location "east" of the current node, sloc "south" for drawing a grid
             * of course are terms east and south symbolic
             */
            Scientrace.Location eloc, sloc;
            Scientrace.Line     cline, eline, sline;
            //double r = cborder.getRadius();
            double r1 = cborder.getURadius();
            double r2 = cborder.getVRadius();

            Scientrace.Vector v1     = cbordertrf.u.tryToUnitVector().toVector();
            Scientrace.Vector v2     = cbordertrf.v.tryToUnitVector().toVector();;
            string            retstr = "";

            Scientrace.X3DGridPoint concentrationpoint = new Scientrace.X3DGridPoint(env, this.getConcentrationPoint(), null, null);
            retstr  = concentrationpoint.x3DSphere(env.radius / 1000, "1 0 1", 0.5);
            retstr += concentrationpoint.x3DLineTo(this.loc, "1 0 1 1");
            for (double ix = 0.5; ix < steps; ix++)
            {
                for (double iy = 0.5; iy <= steps; iy++)
                {
                    /* Drawing a grid of lines in direction "border.orthodirection" to ParabolicMirror,
                     * at every intersection a gridpoint is located. "cline" are those ortho-dir lines */
                    cline = new Scientrace.Line(((stloc - (v1 * r1) - (v2 * r2)) + (v1 * (r1 * 2 * (ix / steps))) + (v2 * (r2 * 2 * (iy / steps)))).toLocation(),
                                                cborder.getOrthoDirection());
//											cborder.directionlength.toUnitVector());

                    /* USE THE "checkborder = false" function below to always
                     * show the grid-points, also outside borders
                     * iparr is the IntersectionPoint at the Parabolic Mirror for the current ix/iy iteration */
                    iparr = this.realIntersections(cline, true);

/* DEBUG INFO	foreach (IntersectionPoint ip in iparr) {
 *                                      if (ip!=null) {
 *                                              Console.WriteLine("IP AT: "+ip.ToString());
 *                                              } else {
 *                                              Console.WriteLine("NO IP FROM: "+((stloc-(v1*r)-(v2*r))+(v1*(r*2*(ix/steps)))+(v2*(r*2*(iy/steps))))
 +" AND "+cborder.getOrthoDirection());
 *                                              }
 *                                      }*/
                    eline = new Scientrace.Line(((stloc - (v1 * r1) - (v2 * r2)) + (v1 * (r1 * 2 * ((ix + 1) / steps))) + (v2 * (r2 * 2 * (iy / steps)))).toLocation(),
                                                cborder.getOrthoDirection());
//											cborder.directionlength.toUnitVector());
                    iparre = this.realIntersections(eline, true);
                    //defining "east" neighbour
                    eintr = new Intersection(eline, iparre, this);
                    if (eintr.intersects)
                    {
                        eloc = eintr.enter.loc;
                    }
                    else
                    {
                        eloc = null;
                    }
                    sline = new Scientrace.Line(((stloc - (v1 * r1) - (v2 * r2)) + (v1 * (r1 * 2 * ((ix) / steps))) + (v2 * (r2 * 2 * ((iy + 1) / steps)))).toLocation(),
                                                cborder.getOrthoDirection());
//											cborder.directionlength.toUnitVector());
                    iparrs = this.realIntersections(sline, true);
                    //defining "south" neighbour
                    sintr = new Intersection(sline, iparrs, this);
                    if (sintr.intersects)
                    {
                        sloc = sintr.enter.loc;
                    }
                    else
                    {
                        sloc = null;
                    }

                    /* "central" point
                     * where does line "cline" with intersections "iparr" intersect this object?
                     */
                    cintr = new Intersection(cline, iparr, this, true);
                    if (cintr.intersects)               //add existing gridpoints
                    {
                        if (this.x3dgridspheres)
                        {
                            retstr = retstr + new X3DGridPoint(env, cintr.enter.loc, eloc, sloc).exportX3D();
                        }
                        else
                        {
                            retstr = retstr + new X3DGridPoint(env, cintr.enter.loc, eloc, sloc).exportX3DnosphereRGBA("0 0 1 1");
                        }
                    }
                }
            }
            //Console.WriteLine("!!!"+retstr);
            return(retstr + cborder.exportX3D(env));
        }