示例#1
0
        public virtual void Transform(IUnitTransformation transform, TransformFlags flags)
        {
            foreach (var t in Vertices)
            {
                t.Location = transform.Transform(t.Location);
            }
            Plane  = new Plane(Vertices[0].Location, Vertices[1].Location, Vertices[2].Location);
            Colour = Colour;
            if (flags.HasFlag(TransformFlags.TextureScalingLock) && Texture.Texture != null)
            {
                // Make a best-effort guess of retaining scaling. All bets are off during skew operations.
                // Transform the current texture axes
                var origin = transform.Transform(Coordinate.Zero);
                var ua     = transform.Transform(Texture.UAxis) - origin;
                var va     = transform.Transform(Texture.VAxis) - origin;
                // Multiply the scales by the magnitudes (they were normals before the transform operation)
                Texture.XScale *= ua.VectorMagnitude();
                Texture.YScale *= va.VectorMagnitude();
            }
            {
                // Transform the texture axes and move them back to the origin
                var origin = transform.Transform(Coordinate.Zero);
                var ua     = transform.Transform(Texture.UAxis) - origin;
                var va     = transform.Transform(Texture.VAxis) - origin;

                // Only do the transform if the axes end up being not perpendicular
                // Otherwise just make a best-effort guess, same as the scaling lock
                if (Math.Abs(ua.Dot(va)) < 0.0001m && DMath.Abs(Plane.Normal.Dot(ua.Cross(va).Normalise())) > 0.0001m)
                {
                    Texture.UAxis = ua;
                    Texture.VAxis = va;
                }
                else
                {
                    AlignTextureToFace();
                }

                if (flags.HasFlag(TransformFlags.TextureLock) && Texture.Texture != null)
                {
                    // Check some original reference points to see how the transform mutates them
                    var scaled   = (transform.Transform(Coordinate.One) - transform.Transform(Coordinate.Zero)).VectorMagnitude();
                    var original = (Coordinate.One - Coordinate.Zero).VectorMagnitude();

                    // Ignore texture lock when the transformation contains a scale
                    if (DMath.Abs(scaled - original) <= 0.01m)
                    {
                        // Calculate the new shift values based on the UV values of the vertices
                        var vtx = Vertices[0];
                        Texture.XShift = Texture.Texture.Width * vtx.TextureU - (vtx.Location.Dot(Texture.UAxis)) / Texture.XScale;
                        Texture.YShift = Texture.Texture.Height * vtx.TextureV - (vtx.Location.Dot(Texture.VAxis)) / Texture.YScale;
                    }
                }
            }
            CalculateTextureCoordinates(true);
            UpdateBoundingBox();
        }
示例#2
0
 public bool EquivalentTo(Matrix other, decimal delta = 0.0001m)
 {
     for (var i = 0; i < 16; i++)
     {
         if (DMath.Abs(Values[i] - other.Values[i]) >= delta)
         {
             return(false);
         }
     }
     return(true);
 }
示例#3
0
 public virtual void Evaluate(SplineResult result, double percent)
 {
     if (samples.Length == 0)
     {
         result = new SplineResult();
     }
     else if (samples.Length == 1)
     {
         result.CopyFrom(samples[0]);
     }
     else if (_uniformSample && _uniformPreserveClipRange)
     {
         double num  = 1.0;
         int    num2 = 0;
         for (int i = 0; i < samples.Length; i++)
         {
             double num3 = DMath.Abs(percent - samples[i].percent);
             if (num3 < num)
             {
                 num  = num3;
                 num2 = i;
             }
         }
         if (percent > samples[num2].percent)
         {
             SplineResult.Lerp(samples[num2], samples[num2 + 1], Mathf.InverseLerp((float)samples[num2].percent, (float)samples[num2 + 1].percent, (float)percent), result);
         }
         else if (percent < samples[num2].percent)
         {
             SplineResult.Lerp(samples[num2 - 1], samples[num2], Mathf.InverseLerp((float)samples[num2 - 1].percent, (float)samples[num2].percent, (float)percent), result);
         }
         else
         {
             result.CopyFrom(samples[num2]);
         }
     }
     else
     {
         percent = DMath.Clamp01(percent);
         int    sampleIndex = GetSampleIndex(percent);
         double num4        = (double)(samples.Length - 1) * percent - (double)sampleIndex;
         if (num4 > 0.0 && sampleIndex < samples.Length - 1)
         {
             SplineResult.Lerp(samples[sampleIndex], samples[sampleIndex + 1], num4, result);
         }
         else
         {
             result.CopyFrom(samples[sampleIndex]);
         }
     }
 }
示例#4
0
        public IEnumerable <Problem> Check(Map map)
        {
            var faces = map.WorldSpawn
                        .Find(x => x is Solid).OfType <Solid>()
                        .SelectMany(x => x.Faces)
                        .ToList();

            foreach (var face in faces)
            {
                var normal = face.Texture.GetNormal();
                if (DMath.Abs(face.Plane.Normal.Dot(normal)) <= 0.0001m)
                {
                    yield return(new Problem(GetType(), map, new [] { face }, Fix, "Texture axis perpendicular to face", "The texture axis of this face is perpendicular to the face plane. This occurs when manipulating objects with texture lock off, as well as various other operations. Re-align the texture to the face to repair. Fixing the problem will reset the textures to the face plane."));
                }
            }
        }
示例#5
0
        public virtual Vector3 EvaluatePosition(double percent, bool overrideUniformClipRange = false)
        {
            if (samples.Length == 0)
            {
                return(Vector3.zero);
            }
            if (samples.Length == 1)
            {
                return(samples[0].position);
            }
            percent = DMath.Clamp01(percent);
            if (_uniformSample && overrideUniformClipRange)
            {
                double num  = 1.0;
                int    num2 = 0;
                for (int i = 0; i < samples.Length; i++)
                {
                    double num3 = DMath.Abs(percent - samples[i].percent);
                    if (num3 < num)
                    {
                        num  = num3;
                        num2 = i;
                    }
                }
                if (percent > samples[num2].percent)
                {
                    return(Vector3.Lerp(samples[num2].position, samples[num2 + 1].position, Mathf.InverseLerp((float)samples[num2].percent, (float)samples[num2 + 1].percent, (float)percent)));
                }
                if (percent < samples[num2].percent)
                {
                    return(Vector3.Lerp(samples[num2 - 1].position, samples[num2].position, Mathf.InverseLerp((float)samples[num2 - 1].percent, (float)samples[num2].percent, (float)percent)));
                }
                return(samples[num2].position);
            }
            int    sampleIndex = GetSampleIndex(percent);
            double num4        = (double)(samples.Length - 1) * percent - (double)sampleIndex;

            if (num4 > 0.0 && sampleIndex < samples.Length - 1)
            {
                return(Vector3.Lerp(samples[sampleIndex].position, samples[sampleIndex + 1].position, (float)num4));
            }
            return(samples[sampleIndex].position);
        }
示例#6
0
        public IEnumerable <MapObject> Create(IDGenerator generator, Box box, ITexture texture, int roundDecimals)
        {
            var numSides = (int)_numSides.GetValue();

            if (numSides < 3)
            {
                yield break;
            }
            var wallWidth = _wallWidth.GetValue();

            if (wallWidth < 1)
            {
                yield break;
            }
            var arc = _arc.GetValue();

            if (arc < 1)
            {
                yield break;
            }
            var startAngle = _startAngle.GetValue();

            if (startAngle < 0 || startAngle > 359)
            {
                yield break;
            }
            var addHeight  = _addHeight.GetValue();
            var curvedRamp = _curvedRamp.GetValue();
            var tiltAngle  = curvedRamp ? _tiltAngle.GetValue() : 0;

            if (DMath.Abs(tiltAngle % 180) == 90)
            {
                yield break;
            }
            var tiltInterp = curvedRamp && _tiltInterp.GetValue();

            // Very similar to the pipe brush, except with options for start angle, arc, height and tilt
            var width  = box.Width;
            var length = box.Length;
            var height = box.Height;

            var majorOut = width / 2;
            var majorIn  = majorOut - wallWidth;
            var minorOut = length / 2;
            var minorIn  = minorOut - wallWidth;

            var start = DMath.DegreesToRadians(startAngle);
            var tilt  = DMath.DegreesToRadians(tiltAngle);
            var angle = DMath.DegreesToRadians(arc) / numSides;

            // Calculate the coordinates of the inner and outer ellipses' points
            var outer = new Coordinate[numSides + 1];
            var inner = new Coordinate[numSides + 1];

            for (var i = 0; i < numSides + 1; i++)
            {
                var a          = start + i * angle;
                var h          = i * addHeight;
                var interp     = tiltInterp ? DMath.Cos(DMath.PI / numSides * (i - numSides / 2M)) : 1;
                var tiltHeight = wallWidth / 2 * interp * DMath.Tan(tilt);

                var xval = box.Center.X + majorOut * DMath.Cos(a);
                var yval = box.Center.Y + minorOut * DMath.Sin(a);
                var zval = box.Start.Z + (curvedRamp ? h + tiltHeight : 0);
                outer[i] = new Coordinate(xval, yval, zval).Round(roundDecimals);

                xval     = box.Center.X + majorIn * DMath.Cos(a);
                yval     = box.Center.Y + minorIn * DMath.Sin(a);
                zval     = box.Start.Z + (curvedRamp ? h - tiltHeight : 0);
                inner[i] = new Coordinate(xval, yval, zval).Round(roundDecimals);
            }

            // Create the solids
            var colour = Colour.GetRandomBrushColour();
            var z      = new Coordinate(0, 0, height).Round(roundDecimals);

            for (var i = 0; i < numSides; i++)
            {
                var faces = new List <Coordinate[]>();

                // Since we are triangulating/splitting each arch segment, we need to generate 2 brushes per side
                if (curvedRamp)
                {
                    // The splitting orientation depends on the curving direction of the arch
                    if (addHeight >= 0)
                    {
                        faces.Add(new[] { outer[i], outer[i] + z, outer[i + 1] + z, outer[i + 1] });
                        faces.Add(new[] { outer[i + 1], outer[i + 1] + z, inner[i] + z, inner[i] });
                        faces.Add(new[] { inner[i], inner[i] + z, outer[i] + z, outer[i] });
                        faces.Add(new[] { outer[i] + z, inner[i] + z, outer[i + 1] + z });
                        faces.Add(new[] { outer[i + 1], inner[i], outer[i] });
                    }
                    else
                    {
                        faces.Add(new[] { inner[i + 1], inner[i + 1] + z, inner[i] + z, inner[i] });
                        faces.Add(new[] { outer[i], outer[i] + z, inner[i + 1] + z, inner[i + 1] });
                        faces.Add(new[] { inner[i], inner[i] + z, outer[i] + z, outer[i] });
                        faces.Add(new[] { inner[i + 1] + z, outer[i] + z, inner[i] + z });
                        faces.Add(new[] { inner[i], outer[i], inner[i + 1] });
                    }
                    yield return(MakeSolid(generator, faces, texture, colour));

                    faces.Clear();

                    if (addHeight >= 0)
                    {
                        faces.Add(new[] { inner[i + 1], inner[i + 1] + z, inner[i] + z, inner[i] });
                        faces.Add(new[] { inner[i], inner[i] + z, outer[i + 1] + z, outer[i + 1] });
                        faces.Add(new[] { outer[i + 1], outer[i + 1] + z, inner[i + 1] + z, inner[i + 1] });
                        faces.Add(new[] { inner[i + 1] + z, outer[i + 1] + z, inner[i] + z });
                        faces.Add(new[] { inner[i], outer[i + 1], inner[i + 1] });
                    }
                    else
                    {
                        faces.Add(new[] { outer[i], outer[i] + z, outer[i + 1] + z, outer[i + 1] });
                        faces.Add(new[] { inner[i + 1], inner[i + 1] + z, outer[i] + z, outer[i] });
                        faces.Add(new[] { outer[i + 1], outer[i + 1] + z, inner[i + 1] + z, inner[i + 1] });
                        faces.Add(new[] { outer[i] + z, inner[i + 1] + z, outer[i + 1] + z });
                        faces.Add(new[] { outer[i + 1], inner[i + 1], outer[i] });
                    }
                    yield return(MakeSolid(generator, faces, texture, colour));
                }
                else
                {
                    var h = i * addHeight * Coordinate.UnitZ;
                    faces.Add(new[] { outer[i], outer[i] + z, outer[i + 1] + z, outer[i + 1] }.Select(x => x + h).ToArray());
                    faces.Add(new[] { inner[i + 1], inner[i + 1] + z, inner[i] + z, inner[i] }.Select(x => x + h).ToArray());
                    faces.Add(new[] { outer[i + 1], outer[i + 1] + z, inner[i + 1] + z, inner[i + 1] }.Select(x => x + h).ToArray());
                    faces.Add(new[] { inner[i], inner[i] + z, outer[i] + z, outer[i] }.Select(x => x + h).ToArray());
                    faces.Add(new[] { inner[i + 1] + z, outer[i + 1] + z, outer[i] + z, inner[i] + z }.Select(x => x + h).ToArray());
                    faces.Add(new[] { inner[i], outer[i], outer[i + 1], inner[i + 1] }.Select(x => x + h).ToArray());
                    yield return(MakeSolid(generator, faces, texture, colour));
                }
            }
        }
示例#7
0
        protected Coordinate SnapToSelection(Coordinate c, Viewport2D vp)
        {
            if (!Document.Map.SnapToGrid)
            {
                return(c);
            }

            var snap = (Select.SnapStyle == SnapStyle.SnapOnAlt && KeyboardState.Alt) ||
                       (Select.SnapStyle == SnapStyle.SnapOffAlt && !KeyboardState.Alt);

            if (!snap)
            {
                return(c);
            }

            var snapped = c.Snap(Document.Map.GridSpacing);

            if (Document.Selection.InFaceSelection || Document.Selection.IsEmpty())
            {
                return(snapped);
            }

            // Try and snap the the selection box center
            var selBox    = Document.Selection.GetSelectionBoundingBox();
            var selCenter = vp.Flatten(selBox.Center);

            if (DMath.Abs(selCenter.X - c.X) < selBox.Width / 10 && DMath.Abs(selCenter.Y - c.Y) < selBox.Height / 10)
            {
                return(selCenter);
            }

            var objects = Document.Selection.GetSelectedObjects().ToList();

            // Try and snap to an object center
            foreach (var mo in objects)
            {
                if (!(mo is Entity) && !(mo is Solid))
                {
                    continue;
                }
                var center = vp.Flatten(mo.BoundingBox.Center);
                if (DMath.Abs(center.X - c.X) >= mo.BoundingBox.Width / 10)
                {
                    continue;
                }
                if (DMath.Abs(center.Y - c.Y) >= mo.BoundingBox.Height / 10)
                {
                    continue;
                }
                return(center);
            }

            // Get all the edges of the selected objects
            var lines = objects.SelectMany(x =>
            {
                if (x is Entity)
                {
                    return(x.BoundingBox.GetBoxLines());
                }
                if (x is Solid)
                {
                    return(((Solid)x).Faces.SelectMany(f => f.GetLines()));
                }
                return(new Line[0]);
            }).Select(x => new Line(vp.Flatten(x.Start), vp.Flatten(x.End))).ToList();

            // Try and snap to an edge
            var closest = snapped;

            foreach (var line in lines)
            {
                // if the line and the grid are in the same spot, return the snapped point
                if (line.ClosestPoint(snapped).EquivalentTo(snapped))
                {
                    return(snapped);
                }

                // Test for corners and midpoints within a 10% tolerance
                var pointTolerance = (line.End - line.Start).VectorMagnitude() / 10;
                if ((line.Start - c).VectorMagnitude() < pointTolerance)
                {
                    return(line.Start);
                }
                if ((line.End - c).VectorMagnitude() < pointTolerance)
                {
                    return(line.End);
                }

                var center = (line.Start + line.End) / 2;
                if ((center - c).VectorMagnitude() < pointTolerance)
                {
                    return(center);
                }

                // If the line is closer to the grid point, return the line
                var lineSnap = line.ClosestPoint(c);
                if ((closest - c).VectorMagnitude() > (lineSnap - c).VectorMagnitude())
                {
                    closest = lineSnap;
                }
            }
            return(closest);
        }
示例#8
0
        public Matrix Inverse()
        {
            int[] colIdx   = { 0, 0, 0, 0 };
            int[] rowIdx   = { 0, 0, 0, 0 };
            int[] pivotIdx = { -1, -1, -1, -1 };

            // convert the matrix to an array for easy looping
            var inverse = new[, ]
            {
                { Values[0], Values[1], Values[2], Values[3] },
                { Values[4], Values[5], Values[6], Values[7] },
                { Values[8], Values[9], Values[10], Values[11] },
                { Values[12], Values[13], Values[14], Values[15] }
            };
            var icol = 0;
            var irow = 0;

            for (var i = 0; i < 4; i++)
            {
                // Find the largest pivot value
                var maxPivot = 0m;
                for (var j = 0; j < 4; j++)
                {
                    if (pivotIdx[j] != 0)
                    {
                        for (var k = 0; k < 4; ++k)
                        {
                            if (pivotIdx[k] == -1)
                            {
                                var absVal = DMath.Abs(inverse[j, k]);
                                if (absVal > maxPivot)
                                {
                                    maxPivot = absVal;
                                    irow     = j;
                                    icol     = k;
                                }
                            }
                            else if (pivotIdx[k] > 0)
                            {
                                return(this);
                            }
                        }
                    }
                }

                ++(pivotIdx[icol]);

                // Swap rows over so pivot is on diagonal
                if (irow != icol)
                {
                    for (var k = 0; k < 4; ++k)
                    {
                        var f = inverse[irow, k];
                        inverse[irow, k] = inverse[icol, k];
                        inverse[icol, k] = f;
                    }
                }

                rowIdx[i] = irow;
                colIdx[i] = icol;

                var pivot = inverse[icol, icol];
                // check for singular matrix
                if (pivot == 0)
                {
                    throw new InvalidOperationException("Matrix is singular and cannot be inverted.");
                }

                // Scale row so it has a unit diagonal
                var oneOverPivot = 1m / pivot;
                inverse[icol, icol] = 1;
                for (var k = 0; k < 4; ++k)
                {
                    inverse[icol, k] *= oneOverPivot;
                }

                // Do elimination of non-diagonal elements
                for (var j = 0; j < 4; ++j)
                {
                    // check this isn't on the diagonal
                    if (icol != j)
                    {
                        var f = inverse[j, icol];
                        inverse[j, icol] = 0;
                        for (var k = 0; k < 4; ++k)
                        {
                            inverse[j, k] -= inverse[icol, k] * f;
                        }
                    }
                }
            }

            for (var j = 3; j >= 0; --j)
            {
                var ir = rowIdx[j];
                var ic = colIdx[j];
                for (var k = 0; k < 4; ++k)
                {
                    var f = inverse[k, ir];
                    inverse[k, ir] = inverse[k, ic];
                    inverse[k, ic] = f;
                }
            }

            return(new Matrix(
                       inverse[0, 0], inverse[0, 1], inverse[0, 2], inverse[0, 3],
                       inverse[1, 0], inverse[1, 1], inverse[1, 2], inverse[1, 3],
                       inverse[2, 0], inverse[2, 1], inverse[2, 2], inverse[2, 3],
                       inverse[3, 0], inverse[3, 1], inverse[3, 2], inverse[3, 3]));
        }
示例#9
0
文件: Face.cs 项目: NCC-Lykos/Chisel
        public virtual void Transform(IUnitTransformation transform, TransformFlags flags)
        {
            foreach (var t in Vertices)
            {
                t.Location = transform.Transform(t.Location);
            }
            Plane  = new Plane(Vertices[0].Location, Vertices[1].Location, Vertices[2].Location);
            Colour = Colour;

            var origin = transform.Transform(Coordinate.Zero);
            var ua     = transform.Transform(Texture.UAxis) - origin;
            var va     = transform.Transform(Texture.VAxis) - origin;

            if (flags.HasFlag(TransformFlags.TextureScalingLock) && Texture.Texture != null)
            {
                // Make a best-effort guess of retaining scaling. All bets are off during skew operations.
                // Transform the current texture axes
                // Multiply the scales by the magnitudes (they were normals before the transform operation)
                Texture.XScale *= ua.VectorMagnitude();
                Texture.YScale *= va.VectorMagnitude();
            }
            {
                //NOTE(SVK):Only edit solids not entities. //do entities have faces??
                if (this.Parent.Parent.GetType().Name == "World" && this.Parent.GetType().Name == "Solid")
                {
                    if (Texture.Flags.HasFlag(FaceFlags.TextureLocked))
                    {
                        Coordinate     Center = this.Parent.Parent.SelCenter;
                        Matrix         Xfrm   = transform.GetMatrix();
                        TransformFlags f      = (TransformFlags)0;
                        if (Xfrm != Matrix.Zero)
                        {
                            f = GetTransformFlags(Xfrm);
                        }
                        else
                        {
                            f = flags;
                        }


                        if (f.HasFlag(TransformFlags.Translate))
                        {
                            Texture.PositionRF = transform.Transform(Texture.PositionRF);
                        }

                        if (f.HasFlag(TransformFlags.Rotation))
                        {
                            Xfrm = ToRF(Xfrm);

                            Texture.TransformAngleRF = Xfrm * Texture.TransformAngleRF;
                            Texture.PositionRF       = Texture.PositionRF - Center;
                            Texture.PositionRF       = RotateRF(Xfrm, ToRF(Texture.PositionRF));
                            Texture.PositionRF       = ToChisel(Texture.PositionRF);
                            Texture.PositionRF       = Texture.PositionRF + Center;
                        }
                    }
                }
                else //entities etc...
                {
                    // Transform the texture axes and move them back to the origin
                    // Only do the transform if the axes end up being not perpendicular
                    // Otherwise just make a best-effort guess, same as the scaling lock

                    if (Math.Abs(ua.Dot(va)) < 0.0001m && DMath.Abs(Plane.Normal.Dot(ua.Cross(va).Normalise())) > 0.0001m)
                    {
                        Texture.UAxis = ua;
                        Texture.VAxis = va;
                    }
                    else
                    {
                        AlignTextureToWorld();
                    }
                    if (flags.HasFlag(TransformFlags.TextureLock) && Texture.Texture != null)
                    {
                        // Check some original reference points to see how the transform mutates them
                        var scaled   = (transform.Transform(Coordinate.One) - transform.Transform(Coordinate.Zero)).VectorMagnitude();
                        var original = (Coordinate.One - Coordinate.Zero).VectorMagnitude();
                        // Ignore texture lock when the transformation contains a scale
                        if (DMath.Abs(scaled - original) <= 0.01m)
                        {
                            // Calculate the new shift values based on the UV values of the vertices
                            var vtx = Vertices[0];
                            Texture.XShift = Texture.Texture.Width * vtx.TextureU - (vtx.Location.Dot(Texture.UAxis)) / Texture.XScale;
                            Texture.YShift = Texture.Texture.Height * vtx.TextureV - (vtx.Location.Dot(Texture.VAxis)) / Texture.YScale;
                        }
                    }
                }
            }

            AlignTexture();
            UpdateBoundingBox();
        }