Ejemplo n.º 1
0
        public override void Create()
        {
            if (!Scene.NextStage("Create SplitByRayNode"))
            {
                Shapes.AddRange(Children.SelectMany(a => a.Shapes).Select(a => a.Copy())); // if not doing this stage, just copy over the none split convexes
                return;
            }
            else if (Scene.IsCurrentStage())
            {
                Scene.AddDebugLine(RayStart - RayDir * 10, RayStart + RayDir * 10);
            }

            Shapes.AddRange(Children.SelectMany(a => a.Shapes).Select(a => a.Copy().Split2d(RayStart, RayDir, SplitMode))); //do full copy then split
        }
Ejemplo n.º 2
0
        public void SplitByRay(Point3D raystart, Vector3D raydir, out Face inside_face, out Face outside_face)
        {
            //default to just returning this as inside and outside
            inside_face  = this;
            outside_face = null;
            raydir.Normalize();

            if (!Scene.NextStage("SplitByRay"))
            {
                return;
            }
            else if (Scene.IsCurrentStage())
            {
                Scene.AddDebugLine(raystart - raydir * 10, raystart + raydir * 10);
            }

            //get the edges, feature info and params that describe how the ray intersects the face
            Edge   edge0, edge1;
            double param0, param1;

            MathUtils.RayLineResult res0, res1;
            GetRaySplitParams(raystart, raydir, out edge0, out param0, out res0, out edge1, out param1, out res1);

            //debug draw the results
            if (Scene.IsCurrentStage())
            {
                if (res0 == MathUtils.RayLineResult.INTERSECTING_LINE)
                {
                    Scene.AddDebugLine(edge0.Vertices[0].Pos, edge0.Vertices[1].Pos);
                }
                else if (res0 == MathUtils.RayLineResult.INTERSECTING_POS0)
                {
                    Scene.AddDebugCross(edge0.Vertices[0].Pos, 0.5);
                }
                else if (res0 == MathUtils.RayLineResult.PARALLEL_OVERLAPPING)
                {
                    Scene.AddDebugCross(edge0.Vertices[0].Pos, 0.5);
                    Scene.AddDebugCross(edge0.Vertices[1].Pos, 0.5);
                }
                if (res1 == MathUtils.RayLineResult.INTERSECTING_LINE)
                {
                    Scene.AddDebugLine(edge1.Vertices[0].Pos, edge1.Vertices[1].Pos);
                }
                else if (res1 == MathUtils.RayLineResult.INTERSECTING_POS0)
                {
                    Scene.AddDebugCross(edge1.Vertices[0].Pos, 0.5);
                }
                else if (res1 == MathUtils.RayLineResult.PARALLEL_OVERLAPPING)
                {
                    Scene.AddDebugCross(edge1.Vertices[1].Pos, 0.5);
                    Scene.AddDebugCross(edge1.Vertices[1].Pos, 0.5);
                }
            }

            //check if centre is initially inside ray
            Vector3D centre_offset = Centre - raystart;
            double   centre_cp     = MathUtils.CrossXY(centre_offset, raydir);

            //valid results for closed, convex, clockwise polygon are:
            //  res0 == no intersection                         res1 == no intersection
            //when res0 is parallel:
            //  res0 == parallel overlapping                    res1 == intersecting pos0 of next edge (this is treated as no intersection as there is no split required)
            //  res0 == parallel overlapping                    res1 == parallel overlapping next edge IF next edge is colinear
            //when res0 is vertex cases
            //  res0 == intersecting pos0 of first edge         res1 == parallel overlapping last edge (note: in any other scenario res0 would detect the parallel line, and res1 will be the vertex)
            //  res0 == intersecting pos0 of any edge           res1 == no intersection (i.e. we just touched 1 vertex)
            //  res0 == intersecting pos0 of any edge           res1 == intersecting pos0 of any none-neighour edge
            //  res0 == intersecting pos0 of any edge           res1 == intersecting line of any edge other than previous neighbour
            //when res0 is line cases
            //  res0 == intersecting line of any edge           res1 == intersecting pos0 of any edge other than next neighbour
            //  res0 == intersecting line of any edge           res1 == intersecting line of any edge

            //check intersection results for each valid combination of res0 and res1
            if (res0 == MathUtils.RayLineResult.PARALLEL_OVERLAPPING)
            {
                //first edge is both parallel and overlapping the ray, so just return this face as left or right
                if (edge1 != NextEdge(edge0))
                {
                    throw new System.ApplicationException("If res0 is parallel, expected res1 to be the next edge");
                }
                if (res1 == MathUtils.RayLineResult.PARALLEL_OVERLAPPING)
                {
                    if (Math.Abs(1 - Vector3D.DotProduct(edge0.Direction, edge1.Direction)) > MathUtils.EPSILON)
                    {
                        throw new System.ApplicationException("If res0 is parallel and res1 is parallel, res1 must be colinear");
                    }
                    //pick side and return
                    if (centre_cp <= 0)
                    {
                        inside_face = this;
                    }
                }
                else if (res1 == MathUtils.RayLineResult.INTERSECTING_POS0)
                {
                    //pick side and return
                    if (centre_cp <= 0)
                    {
                        inside_face = this;
                    }
                }
                else
                {
                    throw new System.ApplicationException("If res0 is parallel, expected res1 must be overlapping (if colinear) or pos0");
                }
            }
            else if (res0 == MathUtils.RayLineResult.INTERSECTING_POS0)
            {
                //first edge overlaps its starting vertex
                if (res1 == MathUtils.RayLineResult.UNKOWN)
                {
                    //no intersection (we just clipped the first vertex of edge0) - still pick side and return?
                    if (centre_cp <= 0)
                    {
                        inside_face = this;
                    }
                }
                else if (res1 == MathUtils.RayLineResult.INTERSECTING_POS0)
                {
                    if (edge1 == NextEdge(edge0) || edge1 == PrevEdge(edge0))
                    {
                        throw new System.ApplicationException("If res0 is pos0 and res1 is pos0, edge1 must not be neighbour of edge0");
                    }

                    //got intersection - need to do vertex-vertex split
                    Face     newface           = Split(edge0, edge1);
                    Vector3D new_centre_offset = Centre - raystart;
                    double   new_centre_cp     = MathUtils.CrossXY(new_centre_offset, raydir);
                    if (new_centre_cp <= 0)
                    {
                        inside_face  = this;
                        outside_face = newface;
                    }
                    else
                    {
                        outside_face = this;
                        inside_face  = newface;
                    }
                }
                else if (res1 == MathUtils.RayLineResult.INTERSECTING_LINE)
                {
                    if (edge1 == PrevEdge(edge0))
                    {
                        throw new System.ApplicationException("If res0 is pos0 and res1 is line, edge1 must not be neighbour of edge0");
                    }

                    //got intersection - need to do vertex-edge split
                    Face     newface           = Split(edge0, edge1, param1);
                    Vector3D new_centre_offset = Centre - raystart;
                    double   new_centre_cp     = MathUtils.CrossXY(new_centre_offset, raydir);
                    if (new_centre_cp <= 0)
                    {
                        inside_face  = this;
                        outside_face = newface;
                    }
                    else
                    {
                        outside_face = this;
                        inside_face  = newface;
                    }
                }
                else if (res1 == MathUtils.RayLineResult.PARALLEL_OVERLAPPING)
                {
                    if (edge1 != Edges.Last())
                    {
                        throw new System.ApplicationException("If res1 is parallel, expected it to be the last edge");
                    }
                    if (edge0 != Edges.First())
                    {
                        throw new System.ApplicationException("If res1 is parallel, expected res0 to be the first edge");
                    }

                    //pick side and return
                    if (centre_cp <= 0)
                    {
                        inside_face = this;
                    }
                }
                else
                {
                    throw new System.ApplicationException("If res0 is pos0, res1 must be none, pos0 or line");
                }
            }
            else if (res0 == MathUtils.RayLineResult.INTERSECTING_LINE)
            {
                //first edge is overlaps the line
                if (res1 == MathUtils.RayLineResult.INTERSECTING_POS0)
                {
                    if (edge1 == NextEdge(edge0))
                    {
                        throw new System.ApplicationException("If res0 is line, edge1 must not be next neighbour of edge0");
                    }

                    //got intersection - need to do edge-vertex split
                    Face     newface           = Split(edge0, param0, edge1);
                    Vector3D new_centre_offset = Centre - raystart;
                    double   new_centre_cp     = MathUtils.CrossXY(new_centre_offset, raydir);
                    if (new_centre_cp <= 0)
                    {
                        inside_face  = this;
                        outside_face = newface;
                    }
                    else
                    {
                        outside_face = this;
                        inside_face  = newface;
                    }
                }
                else if (res1 == MathUtils.RayLineResult.INTERSECTING_LINE)
                {
                    //got intersection - need to do edge-edge split
                    Face     newface           = Split(edge0, param0, edge1, param1);
                    Vector3D new_centre_offset = Centre - raystart;
                    double   new_centre_cp     = MathUtils.CrossXY(new_centre_offset, raydir);
                    if (new_centre_cp <= 0)
                    {
                        inside_face  = this;
                        outside_face = newface;
                    }
                    else
                    {
                        outside_face = this;
                        inside_face  = newface;
                    }
                }
                else
                {
                    throw new System.ApplicationException("If res0 is line, res1 must be pos or line");
                }
            }
            else
            {
                if (res1 != MathUtils.RayLineResult.UNKOWN)
                {
                    throw new System.ApplicationException("If res0 is no intersection, res1 should also be no intersection");
                }

                //no intersection at all - still pick side and return?
                if (centre_cp <= 0)
                {
                    inside_face = this;
                }
            }
        }
Ejemplo n.º 3
0
        public override void Create()
        {
            /*foreach (Node n in Children)
             * {
             *  Shapes.AddRange(n.Shapes.Select(a => a.Copy()));
             * }
             * return;*/

            if (Is3d)
            {
            }
            else
            {
                Shapes.AddRange(Children[0].Shapes.Select(a => a.Copy()));

                Shapes[0].Convexes[0].Faces[0].Split(Shapes[0].Convexes[0].Edges[1], 0.3, Shapes[0].Convexes[0].Edges[3], 0.25);
                Shapes[0].Convexes[0].Faces[0].IntegrityCheck();
                Shapes[0].Convexes[0].Faces[1].IntegrityCheck();
                double   closestdist, closestu, closestv;
                Point3D  raystart           = new Point3D(0, 0, 0);
                Vector3D raydir             = new Vector3D(5, 1, 0);
                MathUtils.RayLineResult res = MathUtils.ClosestPointRayLine(out closestdist, out closestu, out closestv, raystart, raydir, Shapes[0].Convexes[0].Edges[1].Vertices[0].Pos, Shapes[0].Convexes[0].Edges[1].Vertices[1].Pos);
                Scene.AddDebugLine(raystart - raydir * 10, raystart + raydir * 10);
                Scene.AddDebugCross(raystart + raydir * closestu, 0.5);
                Scene.AddDebugCross(Shapes[0].Convexes[0].Edges[1].Vertices[0].Pos + Shapes[0].Convexes[0].Edges[1].Offset * closestv, 0.5);

                //this'll be the clever algorithm. it takes advantage of the fact that we always maintain:
                //- for any given node, none of it's child convexes overlap
                //therefore:
                //- no node should test it's own convexes against each other


/*
 *
 *              //this is the simplest algorithm - we assume every convex could potentially overlap every other convex
 *              //and keep iterating until no more splits occur. it works, but involves a lot of unnecessary overlap tests
 *              Convexes = new List<Convex>();
 *              foreach (Node n in Children)
 *                  Convexes.AddRange(n.Convexes.Select(a => a.Copy()));
 *
 *              //draw all initial convexes if this is the current stage
 *              if (!CSGScene.NextStage("Begin union"))
 *              {
 *                  foreach (Convex c in Convexes)
 *                      c.DebugDraw();
 *                  return;
 *              }
 *
 *              //now do the iterative splitting
 *              //loop until no splits done
 *              bool done_split = true;
 *              while (done_split)
 *              {
 *                  //spin over every convex
 *                  done_split = false;
 *                  for (int i = 0; i < Convexes.Count; i++)
 *                  {
 *                      //go over every other convex
 *                      for (int j = i + 1; j < Convexes.Count; j++)
 *                      {
 *                          //get the 2 convexes to compare
 *                          Convex acvx = Convexes[i];
 *                          Convex bcvx = Convexes[j];
 *
 *                          //do a clip test
 *                          List<Convex> otherconvexsplit = new List<Convex>();
 *                          Convex overlap = null;
 *                          if (Convex.CalculateClippedConvexes2d(acvx, bcvx, otherconvexsplit, ref overlap))
 *                          {
 *                              //got a split, so remove the convex that was split (cvx a), and re-add the sections
 *                              //that didn't overlap
 *                              Convexes.RemoveAt(i);
 *                              Convexes.AddRange(otherconvexsplit);
 *                              done_split = true;
 *
 *                              //if last stage, draw the convex we were splitting and then bail
 *                              if (!CSGScene.NextStage("Done a split"))
 *                              {
 *                                  return;
 *                              }
 *                              break;
 *                          }
 *                      }
 *
 *                      //break out (so we iterate round again) if a split happened
 *                      if (done_split)
 *                          break;
 *                  }
 *              }*/
            }
        }