Exemple #1
0
        /// <summary>
        /// Creates a polygon-based shape around a single point of a
        /// random size. The radiusMultiplier is used to increase the
        /// size to ensure that it connects to another shape (if that
        /// is the requirement).
        /// </summary>
        public static IPoly CreateShape(
			Junction parent,
			PointF point,
			float radius)
        {
            // Figure out the size of the square, as a radius. On each
            // retry, we make it a bit bigger.
            radius *= parent.Random.NextSingle(0.5f, 1.5f);

            // Get a random angle
            int count = parent.Random.Next(3, 7);
            float angle = parent.Random.NextSingle(0, Constants.PI2);

            // Create the square we are mapping
            PolyDefault poly = new PolyDefault();

            for (int i = 0; i < count; i++)
            {
                poly.Add(new PointF(
                        point.X + (float) Math.Cos(angle) * radius,
                        point.Y + (float) Math.Sin(angle) * radius));
                angle += Constants.PI2 / count;
            }

            // Return the results
            return poly;
        }
        /// <summary>
        /// Constructs the junction node's shape and sets internal
        /// structures to match the new shape.
        /// </summary>
        public void Create(Junction junction)
        {
            // Figure out the basic points by creating an array
            // radials, which is determined by the random number generator.
            int radialCount = junction.Random.Next(8, 32);
            LinkedList<PointF> internalPoints = new LinkedList<PointF>();

            // Populate the radial points
            for (int i = 0; i < radialCount; i++)
            {
                // Create the length from a random number in meters.
                float length = junction.Random.NextSingle(50, 250);

                // Figure out the angle we are calculating for the
                // internal shape, then use that to calculate the
                // internal point. These points are relative to (0,0).
                float angle = (float) Math.PI * 2 * i / radialCount;
                float px = (float) Math.Cos(angle) * length;
                float py = (float) Math.Sin(angle) * length;

                internalPoints.Add(new PointF(px, py));
            }

            // TODO: Do some fractal generation

            // TODO add solid clutter

            // Create a polygon from the two results. The external
            // then has the internal taken out of the middle to
            // represent the "hollow" space of the polygon.
            IPoly internalPolygon = CreatePolygon(internalPoints);

            // Set the polygons in the junction
            junction.InternalShape = internalPolygon;
        }
        public GtkTunnelerCanvas()
        {
            // Connect the events
            Events |=
                Gdk.EventMask.Button1MotionMask |
                Gdk.EventMask.Button2MotionMask |
                Gdk.EventMask.ButtonPressMask |
                Gdk.EventMask.ButtonReleaseMask |
                Gdk.EventMask.VisibilityNotifyMask |
                Gdk.EventMask.PointerMotionMask |
                Gdk.EventMask.PointerMotionHintMask;
            ExposeEvent += OnExpose;
            ConfigureEvent += OnConfigure;
            ButtonReleaseEvent += OnButtonRelease;
            MotionNotifyEvent += OnMotionNotify;

            // Create the root node with a random seed. We also set
            // the JunctionManage which triggers the update threads
            // and set it for the user.
            rootJunction = new Junction();
            junctionManager.Junction = rootJunction;
        }
        /// <summary>
        /// Selects a random segment factory. For a given seed, this
        /// will always return the same segment.
        /// </summary>
        public static ISegmentFactory ChooseSegmentFactory(
			Junction childJunction)
        {
            return new SimpleSegmentFactory();
        }
        /// <summary>
        /// Creates a segment from a child junction to its parent.
        /// </summary>
        public Segment Create(
			Junction child, PointF childPoint, double distance)
        {
            // Sanity checking
            if (child.ParentJunction == null)
                throw new Exception("Cannot generate with a null parent");

            // Get the distance between the two points
            Segment segment = new Segment();
            Junction parent = child.ParentJunction;

            // Add the two end points
            CenterPointList points = new CenterPointList();
            points.Add(new CenterPoint(0, 0));
            points.Add(new CenterPoint(childPoint));

            // Split apart the line
            #if DEBUG
            Stopwatch stopwatch = Stopwatch.StartNew();
            #endif

            // Stagger (fractalize) the points
            Geometry.StaggerPoints(points, parent.Random,
                Constants.MinimumSegmentDistance,
                Constants.StaggerSegmentPasses);

            #if DEBUG
            // Show timing information
            stopwatch.Stop();
            Log.Debug("Fractal Time: {0}", stopwatch.Elapsed);
            stopwatch.Reset();
            stopwatch.Start();
            #endif

            // Once we generated a set of center points, we go through
            // and add a randomly-sized and angled square to each
            // point, unioning the results to get the shape of the
            // entire segment.
            IPoly shape = null;
            float log = 0;

            if (distance > 0)
                log = (float) Math.Log(distance) * 10;

            foreach (CenterPoint point in points)
            {
                // Keep track of our retries
                int retry = 1;

                while (true)
                {
                    // Create a shape
                    IPoly p = Geometry.CreateShape(parent, point.Point,
                        retry * (Constants.SegmentAverageWidth - log));

                    // If we have no shape, this is automatically
                    // included.
                    if (shape == null)
                    {
                        shape = p;
                        break;
                    }

                    // We have another shape, so we want to build up
                    // an intersection to make sure they are touching.
                    if (!shape.HasIntersection(p))
                    {
                        // If there is no intersection, then we need
                        // to try again and make the radius range larger.
                        retry++;
                        continue;
                    }

                    // Make a union of the two shapes
                    IPoly union = shape.Union(p);

                    // See if we have two shapes
                    if (union.InnerPolygonCount > 1)
                    {
                        // We didn't quite reach each other
                        retry++;
                        continue;
                    }

                    // Set the new shape
                    shape = union;
                    break;
                }
            }

            // Remove both junction shapes from this
            //shape = shape.Difference(parent.InternalShape);
            //shape = shape.Difference(child.InternalShape);

            #if DEBUG
            // Show timing information
            stopwatch.Stop();
            Log.Debug("  Shape Time: {0}", stopwatch.Elapsed);
            stopwatch.Reset();
            stopwatch.Start();
            #endif

            // Add the shape to the list
            segment.InternalShape = shape;

            // Set up the center line and optimize it
            segment.CenterPoints.AddAll(points);
            segment.CenterPoints.Optimize();

            #if DEBUG
            // Show timing information
            stopwatch.Stop();
            Log.Debug("Optimze Time: {0}", stopwatch.Elapsed);
            #endif

            // Return the results
            return segment;
        }
        /// <summary>
        /// Swaps the contents of one junction with another, moving as
        /// appropriate.
        /// </summary>
        private void SwitchJunctionContents(
			Junction oldJunction, Junction newJunction)
        {
            // Get our segment
            Segment s = oldJunction.GetSegment(newJunction);

            if (s == null)
            {
                throw new Exception(
                    "Cannot handle switching to non-continous segments");
            }

            PointF translate = s.ChildJunctionPoint;

            // Get a list of mobiles, including the player, around the
            // player.
            JunctionManagerPreload oldPreload = preloadedJunctions[oldJunction];
            JunctionManagerPreload newPreload = preloadedJunctions[newJunction];

            if (oldPreload == null)
                throw new Exception("oldPreload is null");

            if (newPreload == null)
                throw new Exception("newPreload is null");

            IList<Mobile> list = oldPreload.Physics.GetMobiles(
                State.Player.Point, Constants.OverlapConnectionDistance);

            foreach (Mobile m in list)
            {
                // Kill them in the current engine
                m.PhysicsBody.Lifetime.IsExpired = true;
                oldPreload.Physics.Remove(m);

                // Keep the old body and force the mobile to recreate
                // it by getting the new one and then setting the
                // internal state.
                Body oldBody = m.PhysicsBody;
                m.ClearPhysicsBody();

                Body newBody = m.PhysicsBody;
                newBody.State.Position.Linear.X =
                    oldBody.State.Position.Linear.X - translate.X;
                newBody.State.Position.Linear.Y =
                    oldBody.State.Position.Linear.Y - translate.Y;
                newBody.State.Position.Angular =
                    oldBody.State.Position.Angular;
                newBody.State.Velocity.Linear.X =
                    oldBody.State.Velocity.Linear.X;
                newBody.State.Velocity.Linear.Y =
                    oldBody.State.Velocity.Linear.Y;
                newBody.State.Velocity.Angular =
                    oldBody.State.Velocity.Angular;

                // Add it in the new engine
                newPreload.Physics.Add(m);
            }
        }
Exemple #7
0
        /// <summary>
        /// The internal version of the building that functions while
        /// thread-safe.
        /// </summary>
        private void BuildConnectionsLocked()
        {
            // Don't bother if we have connections already
            if (builtConnections)
                return;

            // Sanity checking
            if (isBuildingConnections)
                throw new Exception("Building connections is not reentrant");

            isBuildingConnections = true;

            // Make sure our shapes are built to keep the order consistent
            BuildShapes();

            // Keep track of the overlap detection code
            LinkedList<IPoly> overlaps = new LinkedList<IPoly>();

            // Process the parent element
            if (ParentJunction != null)
            {
                // Find our input segment
                Segment ps = ParentJunction.GetSegment(this);

                if (ps == null)
                    throw new Exception("We got a null segment from parent");

                // Add the parent segment with swapped directions
                ps = ps.Swap();
                segments.Add(ps);

                // Add to the overlap, but don't bother checking (we
                // are guarenteed to the first).
                CheckOverlapIntersection(overlaps, ps);
            }

            // We want to create a random number of connections
            int connectionCount = Random.Next(
                Constants.BuildMinimumConnections,
                Constants.BuildMaximumConnections);

            // Go through each connection
            for (int i = 0; i < connectionCount; i++)
            {
                // Build up a connection in a random direction
                float angle = Random.NextSingle(0, 2 * (float) Math.PI);
                float length = Random.NextSingle(
                    Constants.MinimumConnectionDistance,
                    Constants.MaximumConnectionDistance);

                // Junction points are relative to the parent node
                PointF point = new PointF(
                    (float) Math.Cos(angle) * length,
                    (float) Math.Sin(angle) * length);

                // Create a new junction at this point
                Junction junction = new Junction(Random.Next());
                junction.ParentJunction = this;
                junction.BuildShapes();

                // Get the segment factory and create the segment
                ISegmentFactory isf =
                    FactoryManager.ChooseSegmentFactory(junction);
                Segment segment = isf.Create(junction, point, Distance);
                segment.ParentJunction = this;
                segment.ChildJunction = junction;
                segment.ChildJunctionPoint = point;

                // Set the junction's distance
                junction.Distance =
                    Distance + segment.CenterPoints.MaximumRelativeDistance;

                // Check and add the overlap
                if (CheckOverlapIntersection(overlaps, segment))
                {
                    // We intersect
                    Log.Debug("Rejection because segments overlap");
                    continue;
                }

                // Add some clutter
                IClutterFactory icf =
                    FactoryManager.ChooseClutterFactory(Random);
                icf.Create(segment);

                // Add it to the segments
                segments.Add(segment);
            }

            // Create the physics shapes
            if (GeneratePhysics)
            {
            #if DEBUG
                Stopwatch stopwatch = Stopwatch.StartNew();
            #endif
                BuildCombinedShape();
            #if DEBUG
                // Show timing information
                stopwatch.Stop();
                Log.Debug("   Physics Shape: {0}", stopwatch.Elapsed);
                stopwatch.Reset();
                stopwatch.Start();
            #endif
                CreateJunctionPhysics(0);

            #if DEBUG
                // Show timing information
                stopwatch.Stop();
                Log.Debug("Physics Creation: {0}", stopwatch.Elapsed);
            #endif
            }

            // We are done
            builtConnections = true;
            isBuildingConnections = false;
        }
Exemple #8
0
        /// <summary>
        /// Retrieves a segment based on the child junction.
        /// </summary>
        public Segment GetSegment(Junction junction)
        {
            foreach (Segment s in segments)
                if (s.ChildJunction == junction)
                    return s;

            return null;
        }
 /// <summary>
 /// Creates a new preloaded stub and prepares for the
 /// background processing.
 /// </summary>
 public JunctionManagerPreload(Junction junction)
 {
     this.junction = junction;
     this.physics = new Physics();
 }
        /// <summary>
        /// Constructs the junction node's shape and sets internal
        /// structures to match the new shape.
        /// </summary>
        public void Create(Junction junction)
        {
            // We always start with one shape
            IPoly shape = Geometry.CreateShape(junction, PointF.Empty,
                Constants.JunctionAverageWidth);

            // Figure out the basic points by creating an array
            // simples, which is determined by the random number generator.
            int simpleCount = junction.Random.Next(8, 32);

            // Populate the simple points
            for (int i = 0; i < simpleCount; i++)
            {
                // Create the length from a random number in meters.
                float length = junction.Random
                    .NextSingle(0, Constants.JunctionAverageWidth);

                // Figure out the angle we are calculating for the
                // internal shape, then use that to calculate the
                // internal point. These points are relative to (0,0).
                float angle = (float) Math.PI * 2 * i / simpleCount;
                float px = (float) Math.Cos(angle) * length;
                float py = (float) Math.Sin(angle) * length;
                int retry = 0;

                while (true)
                {
                    // Create a shape at that point
                    IPoly p = Geometry.CreateShape(junction,
                        new PointF(px, py),
                        retry * Constants.JunctionAverageWidth);

                    // If we have no shape, this is automatically
                    // included.
                    if (shape == null)
                    {
                        shape = p;
                        break;
                    }

                    // We have another shape, so we want to build up
                    // an intersection to make sure they are touching.
                    IPoly intersect = shape.Intersection(p);

                    if (intersect.PointCount == 0)
                    {
                        // If there is no intersection, then we need
                        // to try again and make the radius range larger.
                        retry++;
                        continue;
                    }

                    // Make a union of the two shapes
                    IPoly union = shape.Union(p);

                    // See if we have two shapes
                    if (union.InnerPolygonCount > 1)
                    {
                        // We didn't quite reach each other
                        retry++;
                        continue;
                    }

                    // Set the new shape
                    shape = union;
                    break;
                }
            }

            // TODO: Do some fractal generation

            // TODO add solid clutter

            // Set the polygons in the junction
            junction.InternalShape = shape;
        }
        /// <summary>
        /// Renders out a single junction to the canvas.
        /// </summary>
        private void RenderJunction(
			Context g, Junction junction, 
			PointF point,
			int recursion)
        {
            // Get the shape we need to draw and draw it
            IPoly poly = junction.InternalShape;
            RenderPolygon(g, poly, point, new Color(0, 0, 0));

            // See if we are recursive
            if (recursion-- > 0)
            {
                // Got through the shapes
                foreach (Segment s in junction.Segments)
                {
                    // Render the junction
                    RenderJunction(g,
                        s.ChildJunction,
                        s.ChildJunctionPoint,
                        recursion);
                }

                // Got through the shapes
                foreach (Segment s in junction.Segments)
                {
                    // Render the segment between the two
                    RenderSegment(g, s);

                    // Render and save the junction handles
                    RenderJunctionHandle(
                        g,
                    s.ChildJunctionPoint,
                        s.ChildJunction
                        == junctionManager.Junction.ParentJunction,
                        s.ChildJunction == hoverJunction);

                    // Save the point
                    junctionHandles.Add(s);
                }
            }
        }
 /// <summary>
 /// Rebuilds the internal junction.
 /// </summary>
 public void Rebuild()
 {
     rootJunction = new Junction();
     junctionManager.Junction = rootJunction;
     QueueDraw();
 }
        /// <summary>
        /// Triggered when the mouse is moved around the widget.
        /// </summary>
        public void OnMotionNotify(object sender, MotionNotifyEventArgs args)
        {
            // Get the x and y coordinates
            double x, y;

            if (args.Event.IsHint)
            {
                Gdk.ModifierType m;
                int ix, iy;
                args.Event.Window.GetPointer(out ix, out iy, out m);
                x = ix;
                y = iy;
            }
            else
            {
                x = args.Event.X;
                y = args.Event.Y;
            }

            double hs = handleSize / scale;
            x = x / scale - cx;
            y = y / scale - cy;

            // Go through the list and see if we are near a handle
            hoverJunction = null;

            foreach (Segment s in junctionHandles)
            {
                // Get the point, swapping it if needed
                Junction jn = s.ChildJunction;
                PointF p = s.ChildJunctionPoint;

                // See if we are in range
                if (p.X - hs <= x && x <= p.X + hs &&
                    p.Y - hs <= y && y <= p.Y + hs)
                {
                    hoverJunction = jn;
                    break;
                }
            }

            // Force the drawing
            QueueDraw();
        }