Esempio n. 1
0
        public void PaintBackground(IGraphicsContext3D g, IPlotArea layer)
        {
            if (null == _background)
            {
                return;
            }

            var cs = layer.CoordinateSystem;

            if (layer.CoordinateSystem is CS.G3DCartesicCoordinateSystem)
            {
                var p = new PointD3D[4];
                p[0] = cs.GetPointOnPlane(_planeID, 0, 0);
                p[1] = cs.GetPointOnPlane(_planeID, 0, 1);
                p[2] = cs.GetPointOnPlane(_planeID, 1, 0);
                p[3] = cs.GetPointOnPlane(_planeID, 1, 1);

                var normal = VectorD3D.CrossProduct(p[1] - p[0], p[2] - p[0]).Normalized;

                var buffer = g.GetPositionNormalIndexedTriangleBuffer(_background);

                if (null != buffer.PositionNormalIndexedTriangleBuffer)
                {
                    // front faces
                    var offs = buffer.IndexedTriangleBuffer.VertexCount;
                    for (int i = 0; i < 4; ++i)
                    {
                        buffer.PositionNormalIndexedTriangleBuffer.AddTriangleVertex(p[i].X, p[i].Y, p[i].Z, normal.X, normal.Y, normal.Z);
                    }

                    buffer.IndexedTriangleBuffer.AddTriangleIndices(0 + offs, 1 + offs, 3 + offs);
                    buffer.IndexedTriangleBuffer.AddTriangleIndices(2 + offs, 0 + offs, 3 + offs);

                    // back faces
                    offs = buffer.IndexedTriangleBuffer.VertexCount;
                    for (int i = 0; i < 4; ++i)
                    {
                        buffer.PositionNormalIndexedTriangleBuffer.AddTriangleVertex(p[i].X, p[i].Y, p[i].Z, -normal.X, -normal.Y, -normal.Z);
                    }

                    buffer.IndexedTriangleBuffer.AddTriangleIndices(0 + offs, 3 + offs, 1 + offs);
                    buffer.IndexedTriangleBuffer.AddTriangleIndices(2 + offs, 3 + offs, 0 + offs);
                }
                else
                {
                    throw new NotImplementedException();
                }
            }
            else
            {
                throw new NotImplementedException();
            }
        }
Esempio n. 2
0
        /// <summary>
        /// Gets the hit point on that plane of the active layer rectangle, that is facing the camera.
        /// </summary>
        /// <param name="doc">The graph document containing the active layer.</param>
        /// <param name="activeLayer">The active layer of the graph document.</param>
        /// <param name="hitposition">Hit point in relative screen coordinates. The z-component is the aspect ratio of the screen (y/x).</param>
        /// <param name="hitPointOnPlaneInActiveLayerCoordinates">Output: The hit point on the plane of the active layer that faces the camera. The hit point is returned in active layer coordinates.</param>
        /// <param name="rotationsRadian">The rotation angles that can be used e.g. to orient text so that the text is most readable from the current camera setting. Rotation angle around x is the x-component of the returned vector, and so on.</param>
        /// <exception cref="InvalidProgramException">There should always be a plane of a rectangle that can be hit!</exception>
        public static void GetHitPointOnActiveLayerPlaneFacingTheCamera(GraphDocument doc, HostLayer activeLayer, PointD3D hitposition, out PointD3D hitPointOnPlaneInActiveLayerCoordinates, out VectorD3D rotationsRadian)
        {
            var activeLayerTransformation = activeLayer.TransformationFromRootToHere();
            var camera  = doc.Camera;
            var hitData = new HitTestPointData(camera.GetHitRayMatrix(hitposition));

            hitData = hitData.NewFromAdditionalTransformation(activeLayerTransformation);                               // now hitdata are in layer cos

            var targetToEye = hitData.WorldTransformation.Transform(camera.TargetToEyeVectorNormalized);                // targetToEye in layer coordinates
            var upEye       = hitData.WorldTransformation.Transform(camera.UpVectorPerpendicularToEyeVectorNormalized); // camera up vector in layer coordinates

            // get the face which has the best dot product between the eye vector of the camera and the plane's normal
            var      layerRect = new RectangleD3D(PointD3D.Empty, activeLayer.Size);
            double   maxval    = double.MinValue;
            PlaneD3D maxPlane  = PlaneD3D.Empty;

            foreach (var plane in layerRect.Planes)
            {
                double val = VectorD3D.DotProduct(plane.Normal, targetToEye);
                if (val > maxval)
                {
                    maxval   = val;
                    maxPlane = plane;
                }
            }

            bool isHit = hitData.IsPlaneHitByRay(maxPlane, out hitPointOnPlaneInActiveLayerCoordinates); // hitPointOnPlane is in layer coordinates too

            if (!isHit)
            {
                throw new InvalidProgramException("There should always be a plane of a rectangle that can be hit!");
            }

            VectorD3D zaxis = maxPlane.Normal;
            VectorD3D yaxis = upEye;

            // Find y axis perpendicular to zaxis
            maxval = double.MinValue;
            foreach (var plane in layerRect.Planes)
            {
                double val = VectorD3D.DotProduct(plane.Normal, upEye);
                if (val > maxval && 0 == VectorD3D.DotProduct(plane.Normal, zaxis))
                {
                    maxval = val;
                    yaxis  = plane.Normal;
                }
            }
            var xaxis = VectorD3D.CrossProduct(yaxis, zaxis);

            // now we have all information about the spatial position and orientation of the text:
            // hitPointOnPlane is the position of the text
            // maxPlane.Normal is the face orientation of the text
            // maxUpVector is the up orientation of the text

            double cx, sx, cy, sy, cz, sz;

            sy = xaxis.Z;
            if (1 != Math.Abs(sy))
            {
                cy = Math.Sqrt(1 - sy * sy);
                cz = xaxis.X / cy;
                sz = xaxis.Y / cy;
                sx = yaxis.Z / cy;
                cx = zaxis.Z / cy;
            }
            else // sy is +1, thus cy is zero
            {
                // we set x-rotation to zero, i.e. cx==1 and sx==0
                cy = 0;
                cx = 1;
                sx = 0;
                cz = yaxis.Y;
                sz = -yaxis.X;
            }

            rotationsRadian = new VectorD3D(Math.Atan2(sx, cx), Math.Atan2(sy, cy), Math.Atan2(sz, cz));
        }
Esempio n. 3
0
        private void BuildImageWithUColor(
            IGraphicsContext3D g,
            IPlotArea gl,
            IReadOnlyList <double> lx,
            IReadOnlyList <double> ly,
            IROMatrix <double> matrix)
        {
            IPositionNormalUIndexedTriangleBuffer buffers;

            if (gl.ClipDataToFrame == LayerDataClipping.None && !_clipToLayer)
            {
                buffers = g.GetPositionNormalUIndexedTriangleBuffer(_material, null, _colorProvider);
            }
            else
            {
                var clipPlanes = new PlaneD3D[6];
                clipPlanes[0] = new PlaneD3D(1, 0, 0, 0);
                clipPlanes[1] = new PlaneD3D(-1, 0, 0, -gl.Size.X);
                clipPlanes[2] = new PlaneD3D(0, 1, 0, 0);
                clipPlanes[3] = new PlaneD3D(0, -1, 0, -gl.Size.Y);
                clipPlanes[4] = new PlaneD3D(0, 0, 1, 0);
                clipPlanes[5] = new PlaneD3D(0, 0, -1, -gl.Size.Z);

                buffers = g.GetPositionNormalUIndexedTriangleBuffer(_material, clipPlanes, _colorProvider);
            }

            var buf  = buffers;
            var offs = buf.VertexCount;

            int lxl   = lx.Count;
            int lyl   = ly.Count;
            int lxlm1 = lx.Count - 1;
            int lylm1 = ly.Count - 1;

            var vertexPoints = new PointD3D[lxl, lyl];
            var isValid      = new bool[lxl, lyl]; // array which stores for every point[i, j], if it is valid, to speed up calculations

            var zScale = gl.ZAxis;

            for (int i = 0; i < lx.Count; ++i)
            {
                for (int j = 0; j < ly.Count; ++j)
                {
                    double lz = zScale.PhysicalVariantToNormal(matrix[i, j]);
                    gl.CoordinateSystem.LogicalToLayerCoordinates(new Logical3D(lx[i], ly[j], lz), out var pt);

                    isValid[i, j]      = !pt.IsNaN;
                    vertexPoints[i, j] = pt;
                }
            }

            // ------------------------------------------------------------------
            // ------------------ Calculation of normals ------------------------
            // (this can be laborious, if both neighboring points are invalid)
            // ------------------------------------------------------------------
            for (int i = 0; i < lxl; ++i)
            {
                for (int j = 0; j < lyl; ++j)
                {
                    if (isValid[i, j])
                    {
                        var pm = vertexPoints[i, j];

                        // Strategy here: we calculate the vectors (right-left) and (upper-lower) and calculate the cross product. This is our normal vector.

                        // right - left
                        var vec1 = vertexPoints[(i < lxlm1 && isValid[i + 1, j]) ? i + 1 : i, j] -     // right side
                                   vertexPoints[(i > 0 && isValid[i - 1, j]) ? i - 1 : i, j];          // left side

                        if (vec1.IsEmpty)                                                              // if vector 1 is empty (because both the right _and_ the left neighbor points are invalid), then we have to try the diagonals
                        {
                            bool rightup = (i < lxlm1 && j < lylm1 && isValid[i + 1, j + 1]);          // right-up neighbor valid?
                            bool leftlow = (i > 0 && j > 0 && isValid[i - 1, j - 1]);                  // left-lower neighbor valid?
                            var  vec1a   = vertexPoints[rightup ? i + 1 : i, rightup ? j + 1 : j] -    // right / upper side
                                           vertexPoints[leftlow ? i - 1 : i, leftlow ? j - 1 : j];     // left / lower side

                            bool rightlow = (i < lxlm1 && j > 0 && isValid[i + 1, j - 1]);             // right-lower neighbor valid?
                            bool leftup   = (i > 0 && j < lylm1 && isValid[i - 1, j + 1]);             // left-upper neighbor valid?
                            var  vec1b    = vertexPoints[rightlow ? i + 1 : i, rightlow ? j - 1 : j] - // right / lower side
                                            vertexPoints[leftup ? i - 1 : i, leftup ? j + 1 : j];      // left / upper side

                            vec1 = vec1a + vec1b;                                                      // if one of these two vectors is empty, it doesn't matter for the addition
                        }

                        // upper - lower
                        var vec2 = vertexPoints[i, (j < lylm1 && isValid[i, j + 1]) ? j + 1 : j] -    // upper side
                                   vertexPoints[i, (j > 0 && isValid[i, j - 1]) ? j - 1 : j];         // lower side

                        if (vec2.IsEmpty)                                                             // if vector 2 is empty (because both the upper _and_ the lower neighbor points are invalid, then we have to try the diagonals
                        {
                            bool rightup = (i < lxlm1 && j < lylm1 && isValid[i + 1, j + 1]);         // right-up neighbor valid?
                            bool leftlow = (i > 0 && j > 0 && isValid[i - 1, j - 1]);                 // left-lower neighbor valid?
                            var  vec2a   = vertexPoints[rightup ? i + 1 : i, rightup ? j + 1 : j] -   // upper side / right
                                           vertexPoints[leftlow ? i - 1 : i, leftlow ? j - 1 : j];    // lower side / left

                            bool leftup   = (i > 0 && j < lylm1 && isValid[i - 1, j + 1]);            // left-upper neighbor valid?
                            bool rightlow = (i < lxlm1 && j > 0 && isValid[i + 1, j - 1]);            // right-lower neighbor valid?
                            var  vec2b    = vertexPoints[leftup ? i - 1 : i, leftup ? j + 1 : j] -    // upper side / left
                                            vertexPoints[rightlow ? i + 1 : i, rightlow ? j - 1 : j]; // lower side / right

                            vec2 = vec2a + vec2b;                                                     // if one of these two vectors is empty, it doesn't matter for the addition
                        }

                        var    normal = VectorD3D.CrossProduct(vec1, vec2).Normalized;
                        double lz     = null != _colorScale?_colorScale.PhysicalVariantToNormal(matrix[i, j]) : zScale.PhysicalVariantToNormal(matrix[i, j]);

                        buf.AddTriangleVertex(pm.X, pm.Y, pm.Z, normal.X, normal.Y, normal.Z, lz);
                        buf.AddTriangleVertex(pm.X, pm.Y, pm.Z, -normal.X, -normal.Y, -normal.Z, lz);
                    }
                    else // if this point is not valid, we still add triangle vertices to keep the order of points
                    {
                        buf.AddTriangleVertex(double.NaN, double.NaN, double.NaN, double.NaN, double.NaN, double.NaN, double.NaN);
                        buf.AddTriangleVertex(double.NaN, double.NaN, double.NaN, double.NaN, double.NaN, double.NaN, double.NaN);
                    }
                }
            }

            // now add the triangle indices
            // we don't make the effort to sort out the invalid point, because they are suppressed anyways
            for (int i = 0; i < lxlm1; ++i)
            {
                for (int j = 0; j < lylm1; ++j)
                {
                    // upper side
                    buf.AddTriangleIndices(offs + 0, offs + 2 * lyl, offs + 2);
                    buf.AddTriangleIndices(offs + 2, offs + 2 * lyl, offs + 2 * lyl + 2);

                    // from below
                    buf.AddTriangleIndices(offs + 0 + 1, offs + 2 + 1, offs + 2 * lyl + 1);
                    buf.AddTriangleIndices(offs + 2 + 1, offs + 2 * lyl + 2 + 1, offs + 2 * lyl + 1);

                    offs += 2;
                }
                offs += 2; // one extra increment because inner loop ends at one less than array size
            }
        }