Пример #1
0
		public static Polygons GetCorrectedWinding(this Polygons polygonsToFix)
		{
			polygonsToFix = Clipper.CleanPolygons(polygonsToFix);
			Polygon boundsPolygon = new Polygon();
			IntRect bounds = Clipper.GetBounds(polygonsToFix);
			bounds.left -= 10;
			bounds.bottom += 10;
			bounds.right += 10;
			bounds.top -= 10;

			boundsPolygon.Add(new IntPoint(bounds.left, bounds.top));
			boundsPolygon.Add(new IntPoint(bounds.right, bounds.top));
			boundsPolygon.Add(new IntPoint(bounds.right, bounds.bottom));
			boundsPolygon.Add(new IntPoint(bounds.left, bounds.bottom));

			Clipper clipper = new Clipper();

			clipper.AddPaths(polygonsToFix, PolyType.ptSubject, true);
			clipper.AddPath(boundsPolygon, PolyType.ptClip, true);

			PolyTree intersectionResult = new PolyTree();
			clipper.Execute(ClipType.ctIntersection, intersectionResult);

			Polygons outputPolygons = Clipper.ClosedPathsFromPolyTree(intersectionResult);

			return outputPolygons;
		}
Пример #2
0
		/// <summary>
		/// This method creates the primary and secondary surfaces
		/// </summary>
		public void CreateSurfaces()
		{
			// Every surface needs a description
			// This is where you set the parameters for the surface
			SurfaceDescription desc = new SurfaceDescription();
  
			// This is the clipper for the primary surface
			// -> connect it to the target control
			Clipper graphicsClipper = new Clipper(graphicsDevice);
			graphicsClipper.Window = target;

			// First we want to create a primary surface
			desc.SurfaceCaps.PrimarySurface = true;

#if !windowed
			// In release mode, we enable flipping, set the complex
			// flag and tell the surface that we will use one back
			// buffer
			desc.SurfaceCaps.Flip = true;
			desc.SurfaceCaps.Complex = true;
			desc.BackBufferCount = 1;
#endif

			// Create the surface
			surfacePrimary = new Surface(desc, graphicsDevice);
			srcRect = new Rectangle(0,0,target.Width,target.Height);

			// Attach clipper to the surface
			surfacePrimary.Clipper = graphicsClipper;

			// To build the secondary surface, we need 
			// a new description -> clear all values
			desc.Clear();

#if windowed
			// In debug mode, we simply copy the primary surfaces
			// dimensions and create a offscreenplain secondary
			// surface
			desc.Width = surfacePrimary.SurfaceDescription.Width;
			desc.Height = surfacePrimary.SurfaceDescription.Height;
			desc.SurfaceCaps.OffScreenPlain = true;
			surfaceSecondary = new Surface(desc, this.graphicsDevice);
#else
			// In release mode, we set the backbuffer flag to true
			// and retrieve a backbuffer surface from the primary
			// surface
			desc.SurfaceCaps.BackBuffer = true;
			surfaceSecondary = surfacePrimary.GetAttachedSurface(desc.SurfaceCaps);
#endif

			//surfaceSecondary.Clipper=graphicsClipper;
		} 
Пример #3
0
 public static List<List<IntPoint>> ClipPolygons(List<Polygon> polygons)
 {
     var subj = new List<List<IntPoint>>(polygons.Count);
     var clip = new List<List<IntPoint>>(polygons.Count);
     foreach (var polygon in polygons)
     {
         subj.Add(polygon.ToClipperPath());
         clip.Add(polygon.ToClipperPath());
     }
     var solution = new List<List<IntPoint>>();
     var c = new Clipper();
     c.AddPaths(subj, PolyType.PtSubject, true);
     c.AddPaths(clip, PolyType.PtClip, true);
     c.Execute(ClipType.CtUnion, solution, PolyFillType.PftPositive, PolyFillType.PftEvenOdd);
     return solution;
 }
Пример #4
0
		public static void GenerateLinePaths(Polygons in_outline, ref Polygons result, int lineSpacing, int infillExtendIntoPerimeter_um, double rotation, long rotationOffset = 0)
		{
			if (in_outline.Count > 0)
			{
				Polygons outlines = in_outline.Offset(infillExtendIntoPerimeter_um);
				if (outlines.Count > 0)
				{
					PointMatrix matrix = new PointMatrix(-(rotation + 90)); // we are rotating the part so we rotate by the negative so the lines go the way we expect

					outlines.ApplyMatrix(matrix);

					Aabb boundary = new Aabb(outlines);

					boundary.min.X = ((boundary.min.X / lineSpacing) - 1) * lineSpacing - rotationOffset;
					int xLineCount = (int)((boundary.max.X - boundary.min.X + (lineSpacing - 1)) / lineSpacing);
					Polygons unclipedPatern = new Polygons();

					long firstX = boundary.min.X / lineSpacing * lineSpacing;
					for (int lineIndex = 0; lineIndex < xLineCount; lineIndex++)
					{
						Polygon line = new Polygon();
						line.Add(new IntPoint(firstX + lineIndex * lineSpacing, boundary.min.Y));
						line.Add(new IntPoint(firstX + lineIndex * lineSpacing, boundary.max.Y));
						unclipedPatern.Add(line);
					}

					PolyTree ret = new PolyTree();
					Clipper clipper = new Clipper();
					clipper.AddPaths(unclipedPatern, PolyType.ptSubject, false);
					clipper.AddPaths(outlines, PolyType.ptClip, true);
					clipper.Execute(ClipType.ctIntersection, ret, PolyFillType.pftPositive, PolyFillType.pftEvenOdd);

					Polygons newSegments = Clipper.OpenPathsFromPolyTree(ret);
					PointMatrix inversematrix = new PointMatrix((rotation + 90));
					newSegments.ApplyMatrix(inversematrix);

					result.AddRange(newSegments);
				}
			}
		}
Пример #5
0
        public static List <Polygon> MergePolygons(List <Polygon> firstPolygon, List <Polygon> secondPolygon,
                                                   ClipType clipType)
        {
            // Result merged polygon
            List <Polygon> mergedPolygon = new List <Polygon>();


            // Prepare the second (main) polygon to be merged
            List <CyclicalList <IntPoint> > subj = new List <CyclicalList <IntPoint> >();

            foreach (Polygon p in secondPolygon)
            {
                if (p.GetVerticesCount() > 0)
                {
                    subj.Add(new CyclicalList <IntPoint>());
                    for (int i = 0; i < p.GetVerticesCount(); i++)
                    {
                        subj[subj.Count - 1].Add(new IntPoint(p.GetPoint(i).x, p.GetPoint(i).y));
                    }
                }
            }


            // The current seen area so it will be merged with the previous area
            List <CyclicalList <IntPoint> > clip = new List <CyclicalList <IntPoint> >();

            foreach (Polygon p in firstPolygon)
            {
                if (p.GetVerticesCount() > 0)
                {
                    clip.Add(new CyclicalList <IntPoint>());
                    for (int i = 0; i < p.GetVerticesCount(); i++)
                    {
                        clip[clip.Count - 1].Add(new IntPoint(p.GetPoint(i).x, p.GetPoint(i).y));
                    }
                }
            }


            // Merge the two polygons
            List <CyclicalList <IntPoint> > solution = new List <CyclicalList <IntPoint> >();

            Clipper c = new Clipper();

            c.AddPaths(clip, PolyType.ptClip, true);
            c.AddPaths(subj, PolyType.ptSubject, true);
            c.Execute(clipType, solution, PolyFillType.pftEvenOdd, PolyFillType.pftEvenOdd);


            // Fill the result
            int polygonIndex = 0;

            if (solution.Count > 0)
            {
                foreach (CyclicalList <IntPoint> polygon in solution)
                {
                    // if the merge is between seen area then the first polygon is seen area and the rest are seen area holes
                    mergedPolygon.Add(new Polygon());

                    for (int i = 0; i < polygon.Count; i++)
                    {
                        mergedPolygon[mergedPolygon.Count - 1].AddPoint(new Vector2(polygon[i].X, polygon[i].Y));
                    }

                    // Smooth the polygon
                    mergedPolygon[mergedPolygon.Count - 1].SmoothPolygon(0.2f);

                    polygonIndex++;
                }
            }

            return(mergedPolygon);
        }
Пример #6
0
        public static bool IsOutside(this Vector2 point, Polygon poly)
        {
            var p = new IntPoint(point.X, point.Y);

            return(Clipper.PointInPolygon(p, poly.ToClipperPath()) != 1);
        }
Пример #7
0
        /* GENERATE LINE */

        public void generateLine()
        {
            if (inputs.Count == 0)
            {
                return;
            }

            Clipper c = new Clipper(Clipper.ioPreserveCollinear);

            c.PreserveCollinear = true;
            AXParameter input = null;
            AXParameter src   = null;

            //Debug.Log ("GENERATE LINE");


//			// DON'T ALTER AN "OPEN" SHAPE OR RAIL IF IT IS NOT BEING COMBINED WITH OTHER INPUTS AND IS NOT THICKENED OR OFFSET
            if (inputs.Count == 1 && inputs[0].offset == 0 && inputs[0].thickness == 0)
            {
                if (inputs[0].DependsOn != null)
                {
                    difference.polyTree = inputs[0].DependsOn.polyTree;
                    difference.paths    = inputs[0].DependsOn.paths;
                }


                //Archimatix.printPath(output.paths[0]);
                return;
            }

            // GROUPED COMBINE
            grouped.paths = new Paths();
            foreach (AXParameter inp in inputs)
            {
                if (inp.paths == null)
                {
                    continue;
                }

                foreach (Path _path in inp.paths)
                {
                    grouped.paths.Add(_path);
                }
            }


            // EACH INPUT (PREPROCESSING)

            for (int i = 0; i < inputs.Count; i++)
            {
                input = inputs [i];
                src   = input.DependsOn;

                if (src != null && src.parametricObject != null && !src.parametricObject.isActive)
                {
                    continue;
                }

                if (src == null)
                {
                    continue;
                }
                input.polyTree = null;

                thickenAndOffset(ref input, src);

                // Add as a Solid or Void (subj or clip) to Clipper c
                //bool isClosed = (input.shapeState == ShapeState.Closed || input.polyType == PolyType.ptSubject) ? true : false;
                bool isClosed = true;
                if (input.polyTree != null)
                {
                    c.AddPaths(AXGeometryTools.Utilities.cleanPaths(Clipper.PolyTreeToPaths(input.polyTree)), input.polyType, isClosed);
                }
                else if (input.paths != null)
                {
                    c.AddPaths(AXGeometryTools.Utilities.cleanPaths(input.paths), input.polyType, isClosed);
                }
            }             // end inputs preprocessing



            // COMBINE INPUTS

            // Output

            AX.Generators.Generator2D gener2D = parametricObject.generator as AX.Generators.Generator2D;

            // DIFFERENCE

            if ((difference.Dependents != null && difference.Dependents.Count > 0) || combineType == CombineType.Difference)
            {
                difference.polyTree = new AXClipperLib.PolyTree();
                c.Execute(ClipType.ctDifference, difference.polyTree, PolyFillType.pftNonZero, PolyFillType.pftNonZero);


                thickenAndOffset(ref difference, difference);


                AXGeometryTools.Utilities.transformPolyTree(difference.polyTree, gener2D.localMatrix);

                if (difference.reverse)
                {
                    AXGeometryTools.Utilities.reversePolyTree(difference.polyTree);
                }

                AX.Generators.Generator2D.deriveStatsETC(difference);
            }

            // INTERSECTION
            //if((intersection.Dependents != null && intersection.Dependents.Count > 0) || combineType == CombineType.Intersection)
            //{
            intersection.polyTree = new AXClipperLib.PolyTree();
            c.Execute(ClipType.ctIntersection, intersection.polyTree, PolyFillType.pftNonZero, PolyFillType.pftNonZero);


            thickenAndOffset(ref intersection, intersection);

            AXGeometryTools.Utilities.transformPolyTree(intersection.polyTree, gener2D.localMatrix);

            if (intersection.reverse)
            {
                AXGeometryTools.Utilities.reversePolyTree(intersection.polyTree);
            }

            AX.Generators.Generator2D.deriveStatsETC(intersection);

            //}

            // UNION
            if ((union.Dependents != null && union.Dependents.Count > 0) || combineType == CombineType.Union)
            {
                union.polyTree = new AXClipperLib.PolyTree();
                c.Execute(ClipType.ctUnion, union.polyTree, PolyFillType.pftNonZero, PolyFillType.pftNonZero);


                thickenAndOffset(ref union, union);

                AXGeometryTools.Utilities.transformPolyTree(intersection.polyTree, gener2D.localMatrix);

                if (union.reverse)
                {
                    AXGeometryTools.Utilities.reversePolyTree(union.polyTree);
                }

                AX.Generators.Generator2D.deriveStatsETC(union);
            }
        }
        /// <summary>
        /// Checks if the point is outside of polygon
        /// </summary>
        /// <param name="val">Polygon to check</param>
        /// <param name="point">Point to check</param>
        /// <returns>true if point is outside of polygon</returns>
        public static bool IsOutside(this Geometry.Polygon val, Vector2 point)
        {
            var p = new IntPoint(point.X, point.Y);

            return(Clipper.PointInPolygon(p, val.ToClipperPath()) != 1);
        }
Пример #9
0
 public static Polygons CreateUnion(this Polygons polygons, Polygons other)
 {
     Polygons ret = new Polygons();
     Clipper clipper = new Clipper();
     clipper.AddPaths(polygons, PolyType.ptSubject, true);
     clipper.AddPaths(other, PolyType.ptSubject, true);
     clipper.Execute(ClipType.ctUnion, ret, PolyFillType.pftNonZero, PolyFillType.pftNonZero);
     return ret;
 }
Пример #10
0
		public static Polygons CreateLineIntersections(this Polygons polygons, Polygons other)
		{
			Clipper clipper = new Clipper();

			clipper.AddPaths(other, PolyType.ptSubject, false);
			clipper.AddPaths(polygons, PolyType.ptClip, true);

			PolyTree clippedLines = new PolyTree();

			clipper.Execute(ClipType.ctIntersection, clippedLines);

			return Clipper.OpenPathsFromPolyTree(clippedLines);
		}
Пример #11
0
        /// <summary>
        /// remove portions of polyline that are inside set of solids
        /// </summary>
        public static List <PolyLine2d> ClipAgainstPolygon(List <GeneralPolygon2d> solids, PolyLine2d polyline, bool bIntersect = false)
        {
            double            nIntScale = Math.Max(GetIntScale(solids), GetIntScale(polyline.Vertices));
            List <PolyLine2d> result    = new List <PolyLine2d>();

            Clipper  clip = new Clipper();
            PolyTree tree = new PolyTree();

            try {
                foreach (GeneralPolygon2d poly in solids)
                {
                    CPolygonList clipper_poly = ConvertToClipper(poly, nIntScale);
                    clip.AddPaths(clipper_poly, PolyType.ptClip, true);
                }

                CPolyPath path = ConvertToClipper(polyline, nIntScale);
                clip.AddPath(path, PolyType.ptSubject, false);

                if (bIntersect)
                {
                    clip.Execute(ClipType.ctIntersection, tree);
                }
                else
                {
                    clip.Execute(ClipType.ctDifference, tree);
                }

                for (int ci = 0; ci < tree.ChildCount; ++ci)
                {
                    if (tree.Childs[ci].IsOpen == false)
                    {
                        continue;
                    }
                    PolyLine2d clippedPath = ConvertFromClipperPath(tree.Childs[ci].Contour, nIntScale);

                    // clipper just cuts up the polylines, we still have to figure out containment ourselves.
                    // Currently just checking based on point around middle of polyline...
                    // [TODO] can we get clipper to not return the inside ones?
                    Vector2d qp = (clippedPath.VertexCount > 2) ?
                                  clippedPath[clippedPath.VertexCount / 2] : clippedPath.Segment(0).Center;
                    bool inside = false;
                    foreach (var poly in solids)
                    {
                        if (poly.Contains(qp))
                        {
                            inside = true;
                            break;
                        }
                    }
                    if (inside == bIntersect)
                    {
                        result.Add(clippedPath);
                    }
                }
            } catch /*(Exception e)*/ {
                // [TODO] what to do here?
                //System.Diagnostics.Debug.WriteLine("ClipperUtil.ClipAgainstPolygon: Clipper threw exception: " + e.Message);
                return(new List <PolyLine2d>());
            }

            return(result);
        }
Пример #12
0
		public static void GenerateHexLinePaths(Polygons in_outline, ref Polygons result, int lineSpacing, int infillExtendIntoPerimeter_um, double rotationDegrees, int layerIndex)
		{
			int extraRotationAngle = 0;
			if (in_outline.Count > 0)
			{
				Polygons outlines = in_outline.Offset(infillExtendIntoPerimeter_um);
				if (outlines.Count > 0)
				{
					int perIncrementOffset = (int)(lineSpacing * Math.Sqrt(3) / 2 + .5);
					PointMatrix matrix = new PointMatrix(-(rotationDegrees + extraRotationAngle)); // we are rotating the part so we rotate by the negative so the lines go the way we expect

					outlines.ApplyMatrix(matrix);

					Aabb boundary = new Aabb(outlines);

					boundary.min.X = ((boundary.min.X / lineSpacing) - 1) * lineSpacing;
					boundary.min.Y = ((boundary.min.Y / perIncrementOffset) - 2) * perIncrementOffset;
					boundary.max.X += lineSpacing;
					boundary.max.Y += perIncrementOffset;
					Polygons unclipedPatern = new Polygons();

					foreach (IntPoint startPoint in StartPositionIterator(boundary, lineSpacing, layerIndex))
					{
						Polygon attachedLine = new Polygon();
						foreach (IntPoint center in IncrementPositionIterator(startPoint, boundary, lineSpacing, layerIndex))
						{
							// what we are adding are the little plusses that define the points
							//        | top
							//        |
							//        /\ center
							//   left/  \ right
							//
							IntPoint left = center + new IntPoint(-lineSpacing / 2, -perIncrementOffset / 3);
							IntPoint right = center + new IntPoint(lineSpacing / 2, -perIncrementOffset / 3);
							IntPoint top = center + new IntPoint(0, perIncrementOffset * 2 / 3);

							switch (layerIndex % 3)
							{
								case 0: // left to right
									attachedLine.Add(left); attachedLine.Add(center);
									attachedLine.Add(center); attachedLine.Add(right);
									unclipedPatern.Add(new Polygon() { top, center });
									break;

								case 1: // left to top
									attachedLine.Add(left); attachedLine.Add(center);
									attachedLine.Add(center); attachedLine.Add(top);
									unclipedPatern.Add(new Polygon() { center, right });
									break;

								case 2: // top to right
									attachedLine.Add(top); attachedLine.Add(center);
									attachedLine.Add(center); attachedLine.Add(right);
									unclipedPatern.Add(new Polygon() { left, center });
									break;
							}
						}
						if (attachedLine.Count > 0)
						{
							unclipedPatern.Add(attachedLine);
						}
					}

					PolyTree ret = new PolyTree();
					Clipper clipper = new Clipper();
					clipper.AddPaths(unclipedPatern, PolyType.ptSubject, false);
					clipper.AddPaths(outlines, PolyType.ptClip, true);
					clipper.Execute(ClipType.ctIntersection, ret, PolyFillType.pftPositive, PolyFillType.pftEvenOdd);

					Polygons newSegments = Clipper.OpenPathsFromPolyTree(ret);
					PointMatrix inversematrix = new PointMatrix((rotationDegrees + extraRotationAngle));
					newSegments.ApplyMatrix(inversematrix);

					result.AddRange(newSegments);
				}
			}
		}
        protected override JobHandle OnUpdate(JobHandle inputDeps)
        {
            List <List <IntPoint> > polygons;

            switch (Parameters.processingScheme)
            {
            case ProcessingScheme.JobWithCode:
                polygons = PolygonsFromRoadOutlineJobWithCode(Parameters.extensionDistance, inputDeps);
                break;

            case ProcessingScheme.IJobParallelFor:
                polygons = PolygonsFromRoadOutlineIJobParallelFor(Parameters.extensionDistance, inputDeps);
                break;

            case ProcessingScheme.EntityForEachTempDynamicArrays:
                polygons = PolygonsFromRoadOutlineEntityForEach(Parameters.extensionDistance, inputDeps);
                break;

            case ProcessingScheme.EntityForEachSeparateBuffer:
                polygons = PolygonsFromRoadOutlineEntityForEachSeparateBuffer(Parameters.extensionDistance, inputDeps);
                break;

            default:
                throw new NotSupportedException();
            }

            Profiler.BeginSample("Clipper");
            var clipper = new Clipper();

            foreach (var polygon in polygons)
            {
                if (!Clipper.Orientation(polygon))
                {
                    polygon.Reverse();
                }
                if (Clipper.Area(polygon) > 0)
                {
                    clipper.AddPath(polygon, PolyType.ptSubject, true);
                }
            }

            var solution = new List <List <IntPoint> >();

            clipper.Execute(ClipType.ctUnion, solution, PolyFillType.pftNonZero, PolyFillType.pftNonZero);

            solution.RemoveAll(IsSmallerThanMinimumArea);
            Profiler.EndSample();

            Profiler.BeginSample("Create sample entities");
            foreach (var polygon in solution)
            {
                var entity = EntityManager.CreateEntity(m_SamplesArchetype);
                EntityManager.SetComponentData(entity, new PolygonOrientationComponent
                {
                    Orientation = Clipper.Orientation(polygon)
                        ? PolygonOrientation.Outside
                        : PolygonOrientation.Inside
                });

                var buffer = EntityManager.GetBuffer <PointSampleGlobal>(entity);
                var count  = polygon.Count;
                for (var i = 0; i < polygon.Count; i++)
                {
                    var previousPoint = polygon[((i - 1) % count + count) % count];
                    var point         = polygon[i];
                    var nextPoint     = polygon[(i + 1) % polygon.Count];

                    var v1       = new float3(point.X - previousPoint.X, 0, point.Y - previousPoint.Y);
                    var v2       = new float3(nextPoint.X - point.X, 0, nextPoint.Y - point.Y);
                    var rotation = quaternion.LookRotation(v2 + v1, new float3(0, 1, 0));

                    var fromClipperToGlobal = new PointSampleGlobal(new RigidTransform
                    {
                        pos = new float3(
                            point.X * PlacementUtility.DownScaleFactor,
                            0,
                            point.Y * PlacementUtility.DownScaleFactor),
                        rot = rotation
                    });
                    buffer.Add(fromClipperToGlobal);
                }
            }
            Profiler.EndSample();

            return(inputDeps);
        }
Пример #14
0
        public static List <GeneralPolygon2d> PolygonBoolean(
            List <GeneralPolygon2d> poly1, List <GeneralPolygon2d> poly2,
            BooleanOp opType, double minArea = -1)
        {
            // handle cases where one list is empty
            if (poly1.Count == 0)
            {
                if (opType == BooleanOp.Difference || opType == BooleanOp.Intersection)
                {
                    return(new List <GeneralPolygon2d>());
                }
                else
                {
                    return(DeepCopy.List(poly2));
                }
            }
            else if (poly2.Count == 0)
            {
                if (opType == BooleanOp.Intersection)
                {
                    return(new List <GeneralPolygon2d>());
                }
                else
                {
                    return(DeepCopy.List(poly1));
                }
            }


            double nIntScale = Math.Max(GetIntScale(poly1), GetIntScale(poly2));

            if (minArea < 0)
            {
                minArea = DiscardMinArea;
            }

            try {
                Clipper clipper = new Clipper(Clipper.ioStrictlySimple);

                foreach (GeneralPolygon2d sub in poly1)
                {
                    CPolygonList cpoly = ConvertToClipper(sub, nIntScale);
                    clipper.AddPaths(cpoly, PolyType.ptSubject, true);
                }
                foreach (GeneralPolygon2d clip in poly2)
                {
                    CPolygonList cpoly = ConvertToClipper(clip, nIntScale);
                    clipper.AddPaths(cpoly, PolyType.ptClip, true);
                }

                ClipType cType = ClipType.ctUnion;
                if (opType == BooleanOp.Difference)
                {
                    cType = ClipType.ctDifference;
                }
                else if (opType == BooleanOp.Intersection)
                {
                    cType = ClipType.ctIntersection;
                }
                else if (opType == BooleanOp.Xor)
                {
                    cType = ClipType.ctXor;
                }

                PolyTree tree = new PolyTree();
                bool     bOK  = clipper.Execute(cType, tree);
                if (bOK == false)
                {
                    //System.Diagnostics.Debug.WriteLine("ClipperUtil.PolygonBoolean: Clipper failed");
                    return(new List <GeneralPolygon2d>());
                }

                List <GeneralPolygon2d> result = new List <GeneralPolygon2d>();
                for (int ci = 0; ci < tree.ChildCount; ++ci)
                {
                    Convert(tree.Childs[ci], result, nIntScale, minArea);
                }
                return(result);
            } catch /*(Exception e)*/ {
                //System.Diagnostics.Debug.WriteLine("ClipperUtil.PolygonBoolean: Clipper threw exception: " + e.Message);
                return(new List <GeneralPolygon2d>());
            }
        }
        /// <summary>
        /// This approach extends the idea in Job.WithCode() by manually generating batches of work with one job per batch for better load balancing.
        /// Setup is tedious, but is slightly faster (~1-2ms) than Entities.ForEach with a separate buffer. We should probably avoid this pattern due to the large overhead and brittle code.
        ///
        /// Test results:
        /// Total: 36ms
        /// Setup: 1.12ms
        /// Combine: 2.12ms
        /// </summary>
        private List <List <IntPoint> > PolygonsFromRoadOutlineIJobParallelFor(float extensionDistance, JobHandle jobHandle)
        {
            Profiler.BeginSample("PolygonsFromRoadOutlineIJobParallelFor");
            Profiler.BeginSample("PolygonsFromRoadOutlineIJobParallelFor_Setup");
            var polygons = new List <List <IntPoint> >();

            var outlineJobParams = new NativeList <OutlineJobParams>(300, Allocator.TempJob);
            var sampleCountTotal = 0;

            Entities.ForEach((int entityInQueryIndex, Entity entity, ref EcsRoad road) =>
            {
                var sampleCount = GeometrySampling.ComputeSampleCountForRoadOutline(road, .5f);
                outlineJobParams.Add(new OutlineJobParams
                {
                    entity     = entity,
                    startIndex = sampleCountTotal,
                    count      = sampleCount
                });
                sampleCountTotal += sampleCount;
            }).Run();

            var samples = new NativeArray <PointSampleGlobal>(sampleCountTotal, Allocator.TempJob, NativeArrayOptions.UninitializedMemory);


            var ecsRoadGetter         = GetComponentDataFromEntity <EcsRoad>(true);
            var geometryGetter        = GetBufferFromEntity <Geometry>(true);
            var laneSectionGetter     = GetBufferFromEntity <EcsLaneSection>(true);
            var laneGetter            = GetBufferFromEntity <EcsLane>(true);
            var laneOffsetGetter      = GetBufferFromEntity <LaneOffset>(true);
            var laneWidthRecordGetter = GetBufferFromEntity <LaneWidthRecord>(true);

            var batchSize              = samples.Length / 64;
            var jobBatches             = new NativeList <JobHandle>(Allocator.TempJob);
            int currentBatchSize       = 0;
            int currentBatchStartIndex = 0;

            for (int i = 0; i < outlineJobParams.Length; i++)
            {
                var currentJobParams = outlineJobParams[i];
                currentBatchSize += currentJobParams.count;
                if (currentBatchSize >= batchSize || i == outlineJobParams.Length - 1)
                {
                    var job = new BuildSamplesJob()
                    {
                        extensionDistance = extensionDistance,
                        outlineJobBatch   = new OutlineJobBatch
                        {
                            startIndex = currentBatchStartIndex,
                            count      = i - currentBatchStartIndex + 1
                        },
                        outlineJobParams      = outlineJobParams,
                        ecsRoadGetter         = ecsRoadGetter,
                        geometryGetter        = geometryGetter,
                        laneSectionGetter     = laneSectionGetter,
                        laneGetter            = laneGetter,
                        laneOffsetGetter      = laneOffsetGetter,
                        laneWidthRecordGetter = laneWidthRecordGetter,
                        samples = samples
                    }.Schedule(jobHandle);
                    jobBatches.Add(job);

                    currentBatchSize       = 0;
                    currentBatchStartIndex = i + 1;
                }
            }

            Profiler.EndSample();
            Profiler.BeginSample("PolygonsFromRoadOutlineIJobParallelFor_CompleteJob");
            JobHandle.CombineDependencies(jobBatches).Complete();

            Profiler.EndSample();
            Profiler.BeginSample("PolygonsFromRoadOutlineIJobParallelFor_Combine");

            foreach (var outlineJobParam in outlineJobParams)
            {
                var sampleSlice = new NativeSlice <PointSampleGlobal>(samples, outlineJobParam.startIndex, outlineJobParam.count);
                var path        = new List <IntPoint>(sampleSlice.Length);
                foreach (var point in sampleSlice)
                {
                    path.Add(new IntPoint(
                                 point.pose.pos.x * PlacementUtility.UpScaleFactor,
                                 point.pose.pos.z * PlacementUtility.UpScaleFactor));
                }

                if (!Clipper.Orientation(path))
                {
                    path.Reverse();
                }

                polygons.Add(path);
            }

            outlineJobParams.Dispose();
            jobBatches.Dispose();
            samples.Dispose();
            Profiler.EndSample();
            Profiler.EndSample();

            return(polygons);
        }
Пример #16
0
    public override List <SubdividableEdgeLoop <CityEdge> > GetChildren(SubdividableEdgeLoop <CityEdge> parent)
    {
        Polygon parentPoly = parent.GetPolygon();

        Path polygonAsClip = parentPoly.ClipperPath(HelperFunctions.clipperScale);


        CityEdge[] edges = parent.GetEdges();

        //------------------------------------------ OLD BAD STUFF
        //Paths edgePaths = new Paths();

        //Paths expandedLine = new Paths();

        //float width = 2f;
        //ClipperOffset clipperOffset = new ClipperOffset();
        //clipperOffset.AddPath(polygonAsClip, JoinType.jtSquare, EndType.etClosedPolygon);
        //clipperOffset.Execute(ref expandedLine, HelperFunctions.clipperScale * (-width / 2));

        //if (expandedLine.Count > 0)
        //{
        //    Path shrunkPoly = expandedLine[0];
        //    LinkedGraphVertex[] subPlotVerts = new LinkedGraphVertex[shrunkPoly.Count];
        //    for (int i = 0; i < shrunkPoly.Count; i++)
        //    {
        //        subPlotVerts[i] = new LinkedGraphVertex(HelperFunctions.GetPoint(shrunkPoly[i]));
        //    }
        //    CityEdge[] subPlotEdges = new CityEdge[shrunkPoly.Count];
        //    for (int i = 0; i < shrunkPoly.Count; i++)
        //    {
        //        subPlotEdges[i] = new CityEdge(subPlotVerts[i], subPlotVerts[(i + 1) % shrunkPoly.Count], CityEdgeType.PlotBoundary, 0f);
        //    }

        //    SubdividableEdgeLoop<CityEdge> plot = parent.GetNextChild(subPlotEdges);
        //    Polygon plotPoly = parent.GetPolygon();


        //    return new List<SubdividableEdgeLoop<CityEdge>> { plot };
        //}

        //return new List<SubdividableEdgeLoop<CityEdge>>();


        //--------------------------------------------------------------------------- OLD BAD STUFF END


        bool shapeRemains = true;

        //int uniqueEdgeStartEdge = -1;
        //for (int i = 0; i < edges.Length; i ++)
        //{
        //    if (!edges[(i+1)%edges.Length].GetID().Equals(edges[i].GetID()))
        //    {
        //        uniqueEdgeStartEdge = (i + 1) % edges.Length;
        //        break;
        //    }
        //}

        //LinkedGraphVertex anchorVert = edges[uniqueEdgeStartEdge].GetOppositeVertex(edges[uniqueEdgeStartEdge].GetSharedVertex(edges[(uniqueEdgeStartEdge+1)%edges.Length]));
        //LinkedGraphVertex previusVert = null;

        for (int j = 0; j < edges.Length; j++)
        {
            CityEdge edge = edges[j];

            //int nextIndex = (j + uniqueEdgeStartEdge + 1) % edges.Length;
            //LinkedGraphVertex thisVert = edge.GetOppositeVertex()

            Path edgeLine = new Path();
            edgeLine.Add(HelperFunctions.GetIntPoint(edge.a.pt));
            edgeLine.Add(HelperFunctions.GetIntPoint(edge.b.pt));

            Paths expandedLine = new Paths();

            float         width         = edge.GetWidth() * HelperFunctions.clipperScale;
            ClipperOffset clipperOffset = new ClipperOffset();
            clipperOffset.AddPath(edgeLine, JoinType.jtMiter, EndType.etOpenSquare);
            clipperOffset.Execute(ref expandedLine, width / 2);

            //since we only expand a single line, we should only have one path left

            Paths   differenceSolution = new Paths();
            Clipper clipper            = new Clipper();
            clipper.AddPath(polygonAsClip, PolyType.ptSubject, true);
            clipper.AddPath(expandedLine[0], PolyType.ptClip, true);
            clipper.Execute(ClipType.ctDifference, differenceSolution);
            //Debug.Log("diff sol count: " + differenceSolution.Count);
            if (differenceSolution.Count == 0)
            {
                shapeRemains = false;
                break;
            }
            else
            {
                Path  maxAreaPath = null;
                float maxArea     = 0f;

                foreach (Path path in differenceSolution)
                {
                    Vector2[] points = new Vector2[path.Count];
                    int       i      = 0;
                    foreach (IntPoint p in path)
                    {
                        points[i] = HelperFunctions.GetPoint(p);
                        i++;
                    }
                    Polygon testPoly = new Polygon(points);
                    if (testPoly.area > maxArea)
                    {
                        maxArea     = testPoly.area;
                        maxAreaPath = path;
                    }
                }
                polygonAsClip = maxAreaPath;

                if (maxAreaPath == null)
                {
                    shapeRemains = false;
                    break;
                }
            }
        }
        if (shapeRemains)
        {
            for (int i = polygonAsClip.Count - 1; i >= 0; i--)
            {
                for (int j = 0; j < i; j++)
                {
                    if (polygonAsClip[i].X == polygonAsClip[j].X && polygonAsClip[i].Y == polygonAsClip[j].Y)
                    {
                        polygonAsClip.RemoveAt(i);
                        Debug.Log("removed dup of interior plot");
                    }
                }
            }
        }

        Vector2[] parentPoints = parent.GetPoints();
        ILinkedGraphEdgeFactory <CityEdge> factory = new CityEdgeFactory();

        System.Object[] roadCapBoundarySettings = new System.Object[] { CityEdgeType.EdgeCap, 0f };
        System.Object[] plotBoundarySettings    = new System.Object[] { CityEdgeType.PlotBoundary, 0f };

        if (shapeRemains && polygonAsClip.Count > 0)
        {
            List <DividingEdge> dividingEdges = new List <DividingEdge>();
            Vector2[]           subPlotVerts  = new Vector2[polygonAsClip.Count];
            for (int i = 0; i < polygonAsClip.Count; i++)
            {
                subPlotVerts[i] = HelperFunctions.GetPoint(polygonAsClip[i]);
            }

            List <CityEdge> knownEdges = new List <CityEdge>(parent.GetEdgesEnumerable());


            for (int i = 0; i < parentPoints.Length; i++)
            {
                float closestVertDistance = float.MaxValue;
                int   closestVertIndex    = -1;
                for (int j = 0; j < subPlotVerts.Length; j++)
                {
                    float thisDist = (parentPoints[i] - subPlotVerts[j]).sqrMagnitude;
                    if (thisDist < closestVertDistance)
                    {
                        closestVertDistance = thisDist;
                        closestVertIndex    = j;
                    }
                }
                dividingEdges.Add(new DividingEdge(parentPoints[i], subPlotVerts[closestVertIndex], factory, roadCapBoundarySettings));
            }

            for (int i = 0; i < subPlotVerts.Length; i++)
            {
                dividingEdges.Add(new DividingEdge(subPlotVerts[i], subPlotVerts[(i + 1) % subPlotVerts.Length], factory, plotBoundarySettings));
            }

            List <CityEdge[]> formedChildRegions = CollectChildLoops(parent, dividingEdges);

            List <SubdividableEdgeLoop <CityEdge> > children = new List <SubdividableEdgeLoop <CityEdge> >();

            for (int i = 0; i < formedChildRegions.Count; i++)
            {
                CityEdge[] loop = formedChildRegions[i];
                bool       allPlotBoundaries = true;
                for (int j = 0; j < loop.Length; j++)
                {
                    if (loop[j].GetRoadType() != CityEdgeType.PlotBoundary)
                    {
                        allPlotBoundaries = false;
                    }
                }
                if (allPlotBoundaries)
                {
                    children.Add(parent.GetNextChild(loop));
                }
                else
                {
                    children.Add(new Road(loop, city));
                }
            }

            return(children);
            //return new List<SubdividableEdgeLoop<CityEdge>>();
        }


        return(new List <SubdividableEdgeLoop <CityEdge> >());
    }
Пример #17
0
        public void UnionTwoSquaresWithSquareHoles()
        {
            var subject = new List <List <PointD> >
            {
                new List <PointD>()
                {
                    new PointD(9, 9),
                    new PointD(0, 9),
                    new PointD(0, 0),
                    new PointD(9, 0),
                },

                new List <PointD>()
                {
                    new PointD(1, 1),
                    new PointD(1, 8),
                    new PointD(8, 8),
                    new PointD(8, 1),
                }
            };

            var clipping = new List <List <PointD> >
            {
                new List <PointD>()
                {
                    new PointD(4, 4),
                    new PointD(14, 4),
                    new PointD(14, 14),
                    new PointD(4, 14),
                },

                new List <PointD>()
                {
                    new PointD(5, 5),
                    new PointD(5, 13),
                    new PointD(13, 13),
                    new PointD(13, 5),
                }
            };

            var expected = new List <List <PointD> >
            {
                new List <PointD>
                {
                    new PointD(0, 0),
                    new PointD(9, 0),
                    new PointD(9, 4),
                    new PointD(14, 4),
                    new PointD(14, 14),
                    new PointD(4, 14),
                    new PointD(4, 9),
                    new PointD(0, 9),
                },
                new List <PointD>
                {
                    new PointD(1, 1),
                    new PointD(1, 8),
                    new PointD(4, 8),
                    new PointD(4, 4),
                    new PointD(8, 4),
                    new PointD(8, 1),
                },
                new List <PointD>
                {
                    new PointD(5, 5),
                    new PointD(5, 8),
                    new PointD(8, 8),
                    new PointD(8, 5),
                },
                new List <PointD>
                {
                    new PointD(5, 9),
                    new PointD(5, 13),
                    new PointD(13, 13),
                    new PointD(13, 5),
                    new PointD(9, 5),
                    new PointD(9, 9),
                },
            };

            _clipper = new Clipper(subject, clipping);
            _clipper.Execute();

            var actual = _clipper.GetSolution();

            AssertPolygonsAreSame(expected, actual);
        }
Пример #18
0
        /// <summary>
        ///     Gets if the position is outside of the polygon.
        /// </summary>
        /// <param name="point">The Point</param>
        /// <returns>Whether the Vector2 is inside the polygon</returns>
        public bool IsOutside(Vector2 point)
        {
            var p = new IntPoint(point.X, point.Y);

            return(Clipper.PointInPolygon(p, this.ToClipperPath()) != 1);
        }
Пример #19
0
            public bool IsOutside(Vector2 pointVector2)
            {
                var point = new IntPoint(pointVector2.X, pointVector2.Y);

                return(Clipper.PointInPolygon(point, ToClipperPath()) != 1);
            }
Пример #20
0
        public void SetUp()
        {
            _subject = new List <List <PointD> >
            {
                new List <PointD>()
                {
                    new PointD(6, 6),
                    new PointD(0, 6),
                    new PointD(0, 0),
                    new PointD(6, 0),
                },

                new List <PointD>()
                {
                    new PointD(4, 4),
                    new PointD(4, 2),
                    new PointD(2, 2),
                    new PointD(2, 4),
                }
            };

            _clipping = new List <List <PointD> >
            {
                new List <PointD>()
                {
                    new PointD(9, 9),
                    new PointD(3, 9),
                    new PointD(3, 3),
                    new PointD(9, 3),
                }
            };

            _insertEdgeMethod = typeof(Clipper).GetMethod("InsertEdge", BindingFlags.Instance | BindingFlags.NonPublic);
            _buildModelMethod = typeof(Clipper).GetMethod("BuildModel", BindingFlags.Instance | BindingFlags.NonPublic);
            _markEdgesMethod  = typeof(Clipper).GetMethod("MarkEdges", BindingFlags.Instance | BindingFlags.NonPublic);
            _sortByAntiClockWiseOrderMethod = typeof(Clipper).GetMethod("SortPointsByAntiClockwiseOrder", BindingFlags.Instance | BindingFlags.NonPublic);

            _edgeSet   = typeof(Clipper).GetField("_edgesSet", BindingFlags.Instance | BindingFlags.NonPublic);
            _pointsSet = typeof(Clipper).GetField("_pointsSet", BindingFlags.Instance | BindingFlags.NonPublic);

            _clipper = new Clipper(_subject, _clipping);

            _expectedEdgesAfterBuildModel = new HashSet <Edge>
            {
                new Edge(new PointD(6, 6), new PointD(3, 6), true, false),
                new Edge(new PointD(3, 6), new PointD(0, 6), true, false),
                new Edge(new PointD(0, 6), new PointD(0, 0), true, false),
                new Edge(new PointD(0, 0), new PointD(6, 0), true, false),
                new Edge(new PointD(6, 0), new PointD(6, 3), true, false),
                new Edge(new PointD(6, 3), new PointD(6, 6), true, false),

                new Edge(new PointD(4, 4), new PointD(4, 3), true, false),
                new Edge(new PointD(4, 3), new PointD(4, 2), true, false),
                new Edge(new PointD(4, 2), new PointD(2, 2), true, false),
                new Edge(new PointD(2, 2), new PointD(2, 4), true, false),
                new Edge(new PointD(2, 4), new PointD(3, 4), true, false),
                new Edge(new PointD(3, 4), new PointD(4, 4), true, false),


                new Edge(new PointD(9, 9), new PointD(3, 9), false, true),
                new Edge(new PointD(3, 9), new PointD(3, 6), false, true),
                new Edge(new PointD(3, 6), new PointD(3, 4), false, true),
                new Edge(new PointD(3, 4), new PointD(3, 3), false, true),
                new Edge(new PointD(3, 3), new PointD(4, 3), false, true),
                new Edge(new PointD(4, 3), new PointD(6, 3), false, true),
                new Edge(new PointD(6, 3), new PointD(9, 3), false, true),
                new Edge(new PointD(9, 3), new PointD(9, 9), false, true),
            };
        }
        private void ComboBoxOnSelectionChanged(object sender, SelectionChangedEventArgs selectionChangedEventArgs)
        {
            // INIT THE SIMULATION
            InitSimulation();

            // INTERMEDIATE AREAS FROM ROOMS/SPACES
            var storey = (sender as ComboBox).SelectedItem as IfcBuildingStorey;

            foreach (var space in storey.Spaces)
            {
                // var points = DeriveGeometry(space);
                // var points = DeriveGeometry2D(space);

                var points = CastPoints(GeometryHandler.GetFootPrint(space, context));

                if (points == null)
                {
                    continue;
                }

                sim.layouts[0].scenario.AddArea(space.Name, points, PedSimXMLWriter.areaType.Intermediate);
            }

            // INTERMEDIATE AREAS FROM DOORS
            List <List <point> > doorOpeningElements = new List <List <point> >();

            var doors = xModel.Instances.OfType <IfcRelFillsElement>();

            foreach (var item in doors)
            {
                if (item.RelatedBuildingElement.GetType().ToString().Contains("Door"))
                {
                    var points = CastPoints(GeometryHandler.GetFootPrint(item.RelatingOpeningElement, context));
                    // var points = DeriveGeometry2D(item.RelatingOpeningElement);
                    if (points == null)
                    {
                        continue;
                    }
                    doorOpeningElements.Add(points);
                    sim.layouts[0].scenario.AddArea(item.Name, points, PedSimXMLWriter.areaType.Intermediate);
                }
            }

            // COMPUTE THE ORIGIN AREAS FOR EACH ROOM/SPACE
            // foreach (var space in storey.Spaces)
            // {
            //     var points = DeriveGeometry2D(space);
            // }

            // Get the openings ...
            // List<IfcProduct> doors = new List<IfcProduct>();
            // List<List<point>> doorPolygons = new List<List<point>>();
            // foreach (var item in storey.ContainsElements.ElementAt(0).RelatedElements)
            // {
            //     if (item.GetType().ToString().Contains(@"Door"))
            //     {
            //         // var relVoids = xModel.Instances.OfType<IfcRelFillsElement>();
            //         // foreach (var relVoid in relVoids)
            //         // {
            //         //     if (relVoid.RelatedBuildingElement == item)
            //         //     {
            //         //         var points = DeriveGeometry(relVoid.RelatingOpeningElement);
            //         //         sim.layouts[0].scenario.AddArea(relVoid.RelatingOpeningElement.Name, points, PedSimXMLWriter.areaType.Intermediate);
            //         //     }
            //         // }
            //         // (item as IfcDoor).FillsVoids.
            //         doors.Add(item);
            //     }
            // }
            // foreach (var door in doors)
            // {
            //     var points = DeriveGeometry(door);
            //     doorPolygons.Add(points);
            //     sim.layouts[0].scenario.AddArea(door.Name, points, PedSimXMLWriter.areaType.Intermediate);
            // }

            // GET THE COLUMNS AS OBSTACLES
            // List<IfcProduct> columns = new List<IfcProduct>();
            //
            // foreach (var item in storey.ContainsElements.ElementAt(0).RelatedElements)
            // {
            //     if (item.GetType().ToString().Contains("Column"))
            //     {
            //         columns.Add(item);
            //     }
            // }

            // foreach (var column in columns)
            // {
            //     var columnPoints = DeriveGeometry2D(column);
            //     sim.layouts[0].scenario.AddSolidObstacle(column.Name, columnPoints);
            // }

            // GET THE WALLS AS OBSTACLES
            List <IfcProduct> walls = new List <IfcProduct>();

            foreach (var item in storey.ContainsElements.ElementAt(0).RelatedElements)
            {
                if (item.GetType().ToString().Contains("Wall"))
                {
                    walls.Add(item);
                }
            }

            foreach (var wall in walls)
            {
                // var wallPoints = DeriveGeometry2D(wall);
                var wallPoints = CastPoints(GeometryHandler.GetFootPrint(wall, context));
                // Clipping - Walls are clipped by openings
                int multiplyFactor = 90;

                // WallPolygon
                List <List <IntPoint> > subj = new List <List <IntPoint> >();
                subj.Add(new List <IntPoint>());

                foreach (var item in wallPoints)
                {
                    subj[0].Add(new IntPoint((long)(item.x * multiplyFactor), (long)(item.y * multiplyFactor)));
                }
                // subj[0].Distinct();

                // Clipping Opening Area from doors
                List <List <IntPoint> > clip = new List <List <IntPoint> >();
                int i = 0;
                foreach (var opening in doorOpeningElements)
                {
                    clip.Add(new List <IntPoint>());
                    foreach (var item in opening)
                    {
                        clip[i].Add(new IntPoint((long)(item.x * multiplyFactor), (long)(item.y * multiplyFactor)));
                    }
                    i++;
                }

                var solution = new List <List <IntPoint> >();
                var c        = new Clipper();
                // c.ReverseSolution = true;

                c.AddPolygons(subj, PolyType.ptSubject);
                c.AddPolygons(clip, PolyType.ptClip);

                c.Execute(ClipType.ctDifference, solution, PolyFillType.pftNonZero, PolyFillType.pftNonZero);

                foreach (var solutionItem in solution)
                {
                    List <point> sol = new List <point>();
                    foreach (var coord in  solutionItem)
                    {
                        sol.Add(new point {
                            x = ((double)coord.X) / multiplyFactor, y = ((double)coord.Y) / multiplyFactor
                        });
                    }

                    var convexSol = CreateConvexHull(sol);

                    sim.layouts[0].scenario.AddSolidObstacle(wall.Name, convexSol);
                }
                if (solution.Count == 0)
                {
                    sim.layouts[0].scenario.AddSolidObstacle(wall.Name, wallPoints);
                }
            }

            // SET MIN & MAX
            sim.layouts[0].scenario.maxX = MaxX;
            sim.layouts[0].scenario.minX = MinX;
            sim.layouts[0].scenario.maxY = MaxY;
            sim.layouts[0].scenario.minY = MinY;

            // SERIALIZE
            SerializeSimulation();
        }
Пример #22
0
 public static Polygons CreateIntersection(this Polygons polygons, Polygons other)
 {
     Polygons ret = new Polygons();
     Clipper clipper = new Clipper();
     clipper.AddPaths(polygons, PolyType.ptSubject, true);
     clipper.AddPaths(other, PolyType.ptClip, true);
     clipper.Execute(ClipType.ctIntersection, ret);
     return ret;
 }
Пример #23
0
        public void GenerateTopAndBottoms(ConfigSettings config, int layerIndex, int extrusionWidth_um, int outerPerimeterWidth_um, int downLayerCount, int upLayerCount, long infillExtendIntoPerimeter_um)
        {
            var clippingOffset = infillExtendIntoPerimeter_um * 2;

            ExtruderLayers extruder = this;
            SliceLayer     layer    = extruder.Layers[layerIndex];

            for (int islandIndex = 0; islandIndex < layer.Islands.Count; islandIndex++)
            {
                LayerIsland island = layer.Islands[islandIndex];
                if (island.InsetToolPaths.Count == 0)
                {
                    continue;
                }
                // this is the entire extrusion width to make sure we are outside of the extrusion line
                Polygons lastInset         = island.InsetToolPaths[island.InsetToolPaths.Count - 1];
                Polygons infillRegionPath  = lastInset.Offset(-extrusionWidth_um);
                Polygons sparseInfillPaths = new Polygons(infillRegionPath);

                // calculate the bottom outlines
                if (downLayerCount > 0)
                {
                    Polygons bottomOutlines = new Polygons(infillRegionPath);

                    if (layerIndex - 1 >= 0)
                    {
                        var previousLayer = extruder.Layers[layerIndex - 1];

                        bottomOutlines = RemoveIslandsFromPolygons(previousLayer.Islands, island.BoundingBox, bottomOutlines);
                        bottomOutlines.RemoveSmallAreas(extrusionWidth_um);
                    }

                    sparseInfillPaths = sparseInfillPaths.CreateDifference(bottomOutlines);
                    sparseInfillPaths = Clipper.CleanPolygons(sparseInfillPaths, cleanDistance_um);

                    island.BottomPaths = bottomOutlines;
                }

                // calculate the top outlines
                if (upLayerCount > 0)
                {
                    Polygons topOutlines = new Polygons(infillRegionPath);
                    topOutlines = topOutlines.CreateDifference(island.BottomPaths.Offset(clippingOffset));
                    topOutlines = Clipper.CleanPolygons(topOutlines, cleanDistance_um);

                    if (layerIndex + 1 < extruder.Layers.Count)
                    {
                        // Remove the top layer that is above this one to get only the data that is a top layer on this layer.
                        topOutlines = RemoveIslandsFromPolygons(extruder.Layers[layerIndex + 1].Islands, island.BoundingBox, topOutlines);
                    }

                    topOutlines.RemoveSmallAreas(extrusionWidth_um);

                    sparseInfillPaths = sparseInfillPaths.CreateDifference(topOutlines.Offset(clippingOffset));
                    sparseInfillPaths = Clipper.CleanPolygons(sparseInfillPaths, cleanDistance_um);

                    island.TopPaths = topOutlines;
                }

                // calculate the solid infill outlines
                if (upLayerCount > 1 || downLayerCount > 1)
                {
                    Polygons solidInfillPaths = new Polygons(infillRegionPath);

                    // remove all the top layers
                    solidInfillPaths = solidInfillPaths.CreateDifference(island.BottomPaths.Offset(clippingOffset));
                    solidInfillPaths = Clipper.CleanPolygons(solidInfillPaths, cleanDistance_um);

                    // remove all the bottom layers
                    solidInfillPaths = solidInfillPaths.CreateDifference(island.TopPaths.Offset(clippingOffset));
                    solidInfillPaths = Clipper.CleanPolygons(solidInfillPaths, cleanDistance_um);

                    int upEnd = layerIndex + upLayerCount + 1;
                    if (upEnd <= extruder.Layers.Count && layerIndex - downLayerCount >= 0)
                    {
                        // find all the regions that have more top and bottom layers than should be solid (will remain sparse)
                        Polygons regionsThatWillBeSparse = new Polygons(infillRegionPath);

                        int upStart = layerIndex + 2;

                        for (int layerToTest = upStart; layerToTest < upEnd; layerToTest++)
                        {
                            regionsThatWillBeSparse = IntersectWithPolygons(extruder.Layers[layerToTest].Islands, island.BoundingBox, regionsThatWillBeSparse);
                            regionsThatWillBeSparse = Clipper.CleanPolygons(regionsThatWillBeSparse, cleanDistance_um);
                        }

                        // find all the solid infill bottom layers
                        int downStart = layerIndex - 1;
                        int downEnd   = layerIndex - downLayerCount;

                        for (int layerToTest = downStart; layerToTest >= downEnd; layerToTest--)
                        {
                            regionsThatWillBeSparse = IntersectWithPolygons(extruder.Layers[layerToTest].Islands, island.BoundingBox, regionsThatWillBeSparse);
                            regionsThatWillBeSparse = Clipper.CleanPolygons(regionsThatWillBeSparse, cleanDistance_um);
                        }

                        solidInfillPaths = solidInfillPaths.CreateDifference(regionsThatWillBeSparse);
                        solidInfillPaths.RemoveSmallAreas(extrusionWidth_um);
                        solidInfillPaths = Clipper.CleanPolygons(solidInfillPaths, cleanDistance_um);
                    }

                    // remove the solid infill from the sparse infill
                    sparseInfillPaths = sparseInfillPaths.CreateDifference(solidInfillPaths.Offset(clippingOffset));
                    sparseInfillPaths.RemoveSmallAreas(extrusionWidth_um);
                    sparseInfillPaths        = Clipper.CleanPolygons(sparseInfillPaths, cleanDistance_um);
                    island.SparseInfillPaths = sparseInfillPaths;

                    if (config == null ||                   // this is to make our tests test the bridgeOverInfill
                        config.BridgeOverInfill)
                    {
                        // no figure out what partof the solid infill is actuall first top layers and switch it to that
                        // we can only have a first topy layer at the bottom of the top layers
                        if (layerIndex == extruder.Layers.Count - upLayerCount)
                        {
                            // all of it is first top layers
                            island.FirstTopPaths = solidInfillPaths;
                            solidInfillPaths     = new Polygons();
                        }
                        else if (layerIndex > 0 &&
                                 layerIndex < extruder.Layers.Count - upLayerCount)
                        {
                            // Intersect the current solid layer with the previous spars layer
                            // that will be all of the new solid layers that are currently on sparse layer

                            var firstTopPaths = new Polygons(solidInfillPaths);
                            firstTopPaths = IntersectWithSparsePolygons(extruder.Layers[layerIndex - 1].Islands, island.BoundingBox, firstTopPaths);
                            firstTopPaths.RemoveSmallAreas(extrusionWidth_um);
                            firstTopPaths = Clipper.CleanPolygons(firstTopPaths, cleanDistance_um);

                            if (firstTopPaths.Count > 0)
                            {
                                solidInfillPaths = solidInfillPaths.CreateDifference(firstTopPaths.Offset(clippingOffset));
                                solidInfillPaths.RemoveSmallAreas(extrusionWidth_um);
                                solidInfillPaths = Clipper.CleanPolygons(solidInfillPaths, cleanDistance_um);

                                island.FirstTopPaths = firstTopPaths;
                            }
                        }
                    }

                    island.SolidInfillPaths = solidInfillPaths;
                }
            }
        }
Пример #24
0
		/// <summary>
		/// Gets the union coordinates of specified district key.
		/// </summary>
		/// <returns>The coordinates.</returns>
		/// <param name="districtKeys">Array of district key.</param>
		public static IEnumerable<Coordinate> GetUnionCoordinates(String[] districtKeys)
		{
			// Using Clipper library to do polygon operation.
			var clipper = new Clipper();
			foreach (var dk in districtKeys)
			{
				var polies = new List<List<IntPoint>>();

				var areas = GetCoordinates(dk);
				foreach(var a in areas)
				{
					polies.Add(new List<IntPoint>());

					foreach (var c in a)
						polies[0].Add(new IntPoint(Utils.ToLong(c.X), Utils.ToLong(c.Y)));
				}

				clipper.AddPaths(polies, PolyType.ptSubject, true);
			}

			var solution = new List<List<IntPoint>>();

			clipper.Execute(ClipType.ctUnion, solution, 
				PolyFillType.pftEvenOdd, PolyFillType.pftEvenOdd);

			var coords = new List<Coordinate>();

			foreach (var areas in solution)
			{
				foreach(var p in areas)
				{
					var c = new Coordinate() { X = Utils.ToDouble(p.X), Y = Utils.ToDouble(p.Y) };
					coords.Add(c);
				}
			}

			return coords;
		}
Пример #25
0
 public PolygonGeneralizationCoreClipper(Clipper clipper)
 {
     _clipper = clipper;
     _adapter = new PolygonsAdapter();
 }
Пример #26
0
        // This is used with rails since the Clipper Lib does not support
        // difference with the lines of the clip object removed.
        // In other words, to open a door in a closed polygon,
        // we use this to remove the edges that were originally on the clip object
        // leaving only the line segments of the subject that were not inside the clip shape.
        public Paths assembleRailPathsFromClippedSegments(AXClipperLib.PolyTree solutionRail)
        {
            // Take all the clipped segments and connect
            Paths clippedSegments = Clipper.OpenPathsFromPolyTree(solutionRail);

            //Debug.Log ("clipped segments " + clippedSegments.Count);
            //Archimatix.printPaths(clippedSegments);

            Dictionary <Path, AXSegment> axsegs = new Dictionary <Path, AXSegment>();

            foreach (Path p in clippedSegments)
            {
                axsegs.Add(p, new AXSegment(p));
            }

            int cc = 0;

            foreach (Path clipseg in clippedSegments)
            {
                //Debug.Log ("PASS["+cc+"] " + AXGeometryTools.Utilities.pathToString(clipseg));

                if (axsegs[clipseg].prev != null && axsegs[clipseg].next != null)
                {
                    //Debug.Log("Already done");
                    cc++;
                    continue;
                }
                int ccc = 0;
                foreach (Path compseg in clippedSegments)
                {
                    if (compseg == clipseg)
                    {
                        //Debug.Log("COMP["+cc+"]["+ccc+"] skip same");
                        ccc++;
                        continue;
                    }
                    //Debug.Log ("COMP["+cc+"]["+ccc+"]"+AXGeometryTools.Utilities.pathToString(clipseg)+ " with "+AXGeometryTools.Utilities.pathToString(compseg));

                    if (axsegs[clipseg].prev == null && axsegs[compseg].next == null)
                    {
                        if (AXSegment.pointsAreEqual(clipseg[0], compseg[1]))
                        {
                            axsegs[clipseg].prev = axsegs[compseg];
                            axsegs[compseg].next = axsegs[clipseg];
                            //Debug.Log ("prev");
                        }
                    }
                    if (axsegs[clipseg].prev == null && axsegs[compseg].prev == null)
                    {
                        if (AXSegment.pointsAreEqual(clipseg[0], compseg[0]))
                        {
                            compseg.Reverse();
                            axsegs[clipseg].prev = axsegs[compseg];
                            axsegs[compseg].next = axsegs[clipseg];
                        }
                    }
                    if (axsegs[clipseg].next == null && axsegs[compseg].prev == null)
                    {
                        if (AXSegment.pointsAreEqual(clipseg[1], compseg[0]))
                        {
                            axsegs[clipseg].next = axsegs[compseg];
                            axsegs[compseg].prev = axsegs[clipseg];
                        }
                    }
                    if (axsegs[clipseg].next == null && axsegs[compseg].next == null)
                    {
                        if (AXSegment.pointsAreEqual(clipseg[1], compseg[1]))
                        {
                            compseg.Reverse();
                            axsegs[clipseg].next = axsegs[compseg];
                            axsegs[compseg].prev = axsegs[clipseg];
                        }
                    }
                    ccc++;
                }
                cc++;
            }

            // now all segs should be linked.
            // go through each that has no prev and create new paths...
            Paths retPaths = new Paths();

            foreach (KeyValuePair <Path, AXSegment> item in axsegs)
            {
                Path path = item.Key;
                if (item.Value.prev == null)
                {                   // now crawl up the nexts adding pt[1]s
                    AXSegment next = item.Value;
                    while ((next = next.next) != null)
                    {
                        path.Add(next.path[1]);
                    }

                    retPaths.Add(path);
                }
            }

            return(retPaths);
        }
Пример #27
0
        public static bool MergePerimeterOverlaps(this Polygon perimeter, long overlapMergeAmount_um, out Polygons separatedPolygons, bool pathIsClosed = true)
        {
            separatedPolygons = new Polygons();

            long cleanDistance_um = overlapMergeAmount_um / 40;

            Polygons cleanedPolygs = Clipper.CleanPolygons(new Polygons()
            {
                perimeter
            }, cleanDistance_um);

            perimeter = cleanedPolygs[0];

            if (perimeter.Count == 0)
            {
                return(false);
            }
            bool pathWasOptomized = false;

            for (int i = 0; i < perimeter.Count; i++)
            {
                perimeter[i] = new IntPoint(perimeter[i])
                {
                    Width = overlapMergeAmount_um
                };
            }

            perimeter = QTPolygonExtensions.MakeCloseSegmentsMergable(perimeter, overlapMergeAmount_um, pathIsClosed);

            // make a copy that has every point duplicated (so that we have them as segments).
            List <Segment> polySegments = Segment.ConvertToSegments(perimeter, pathIsClosed);

            Altered[] markedAltered = new Altered[polySegments.Count];

            var touchingEnumerator = new CloseSegmentsIterator(polySegments, overlapMergeAmount_um);
            int segmentCount       = polySegments.Count;

            // now walk every segment and check if there is another segment that is similar enough to merge them together
            for (int firstSegmentIndex = 0; firstSegmentIndex < segmentCount; firstSegmentIndex++)
            {
                foreach (int checkSegmentIndex in touchingEnumerator.GetTouching(firstSegmentIndex, segmentCount))
                {
                    // The first point of start and the last point of check (the path will be coming back on itself).
                    long startDelta = (polySegments[firstSegmentIndex].Start - polySegments[checkSegmentIndex].End).Length();
                    // if the segments are similar enough
                    if (startDelta < overlapMergeAmount_um)
                    {
                        // The last point of start and the first point of check (the path will be coming back on itself).
                        long endDelta = (polySegments[firstSegmentIndex].End - polySegments[checkSegmentIndex].Start).Length();
                        if (endDelta < overlapMergeAmount_um)
                        {
                            // only considre the merge if the directions of the lines are towards eachother
                            var firstSegmentDirection = polySegments[firstSegmentIndex].End - polySegments[firstSegmentIndex].Start;
                            var checkSegmentDirection = polySegments[checkSegmentIndex].End - polySegments[checkSegmentIndex].Start;
                            if (firstSegmentDirection.Dot(checkSegmentDirection) > 0)
                            {
                                continue;
                            }
                            pathWasOptomized = true;
                            // move the first segments points to the average of the merge positions
                            long startEndWidth = Math.Abs((polySegments[firstSegmentIndex].Start - polySegments[checkSegmentIndex].End).Length());
                            long endStartWidth = Math.Abs((polySegments[firstSegmentIndex].End - polySegments[checkSegmentIndex].Start).Length());
                            long width         = Math.Min(startEndWidth, endStartWidth) + overlapMergeAmount_um;
                            polySegments[firstSegmentIndex].Start       = (polySegments[firstSegmentIndex].Start + polySegments[checkSegmentIndex].End) / 2;                     // the start
                            polySegments[firstSegmentIndex].Start.Width = width;
                            polySegments[firstSegmentIndex].End         = (polySegments[firstSegmentIndex].End + polySegments[checkSegmentIndex].Start) / 2;                     // the end
                            polySegments[firstSegmentIndex].End.Width   = width;

                            markedAltered[firstSegmentIndex] = Altered.merged;
                            // mark this segment for removal
                            markedAltered[checkSegmentIndex] = Altered.remove;
                            // We only expect to find one match for each segment, so move on to the next segment
                            break;
                        }
                    }
                }
            }

            // remove the marked segments
            for (int segmentIndex = segmentCount - 1; segmentIndex >= 0; segmentIndex--)
            {
                if (markedAltered[segmentIndex] == Altered.remove)
                {
                    polySegments.RemoveAt(segmentIndex);
                }
            }

            // go through the polySegments and create a new polygon for every connected set of segments
            Polygon currentPolygon = new Polygon();

            separatedPolygons.Add(currentPolygon);
            // put in the first point
            for (int segmentIndex = 0; segmentIndex < polySegments.Count; segmentIndex++)
            {
                // add the start point
                currentPolygon.Add(polySegments[segmentIndex].Start);

                // if the next segment is not connected to this one
                if (segmentIndex < polySegments.Count - 1 &&
                    polySegments[segmentIndex].End != polySegments[segmentIndex + 1].Start)
                {
                    // add the end point
                    currentPolygon.Add(polySegments[segmentIndex].End);

                    // create a new polygon
                    currentPolygon = new Polygon();
                    separatedPolygons.Add(currentPolygon);
                }
            }

            // add the end point
            currentPolygon.Add(polySegments[polySegments.Count - 1].End);

            return(pathWasOptomized);
        }
Пример #28
0
        public static void thickenAndOffset(ref AXParameter sp, AXParameter src)
        {
            if (sp == null || src == null)
            {
                return;
            }
            //sp.polyTree = null;



            float thickness = sp.thickness;
            float roundness = sp.roundness;
            float offset    = sp.offset;
            bool  flipX     = sp.flipX;

            //Debug.Log(sp.parametricObject.Name + "." + sp.Name +"."+ sp.offset);

            //bool srcIsCC = src.isCCW();



            Paths subjPaths = src.getClonePaths();

            if (subjPaths == null)
            {
                return;
            }


            // FLIP_X
            if (flipX)
            {
                //Debug.Log(subjPaths.Count);
                //AXGeometryTools.Utilities.printPaths(subjPaths);

                subjPaths = AXGeometryTools.Utilities.transformPaths(subjPaths, Matrix4x4.TRS(Vector3.zero, Quaternion.identity, new Vector3(-1, 1, 1)));

                sp.transformedControlPaths = AXGeometryTools.Utilities.transformPaths(sp.transformedControlPaths, Matrix4x4.TRS(Vector3.zero, Quaternion.identity, new Vector3(-1, 1, 1)));
            }



            // SYMMETRY
            if (sp.symmetry)
            {
                if (subjPaths != null && subjPaths.Count > 0)
                {
                    for (int i = 0; i < subjPaths.Count; i++)
                    {
                        Path orig = subjPaths[i];

                        Path sym = new Path();

                        float seperation = sp.symSeperation * AXGeometryTools.Utilities.IntPointPrecision;
                        float apex       = .1f * seperation;


                        for (int j = 0; j < orig.Count; j++)
                        {
                            sym.Add(new IntPoint(orig[j].X + seperation / 2, orig[j].Y));
                        }

                        // midpoint. slightly raised
                        sym.Add(new IntPoint(0, orig[orig.Count - 1].Y + apex));

                        for (int j = orig.Count - 1; j >= 0; j--)
                        {
                            sym.Add(new IntPoint(-orig[j].X - seperation / 2, orig[j].Y));
                        }

                        subjPaths[i] = sym;
                    }
                }
            }



            AX.Generators.Generator2D gener2D = sp.parametricObject.generator as AX.Generators.Generator2D;


            if (subjPaths != null && gener2D != null && (gener2D.scaleX != 1 || gener2D.scaleY != 1))
            {
                sp.transformedButUnscaledOutputPaths = AX.Generators.Generator2D.transformPaths(subjPaths, gener2D.localUnscaledMatrix);
            }
            else
            {
                sp.transformedButUnscaledOutputPaths = null;
            }



            //cleanPolygonPrecision
            IntRect brect = Clipper.GetBounds(subjPaths);

            if ((brect.right - brect.left) < 100000)
            {
                cleanPolygonPrecision = 2;
            }
            else
            {
                cleanPolygonPrecision = 30;
            }

            //Debug.Log("cleanPolygonPrecision="+cleanPolygonPrecision);

            /*
             * if (offset_p.FloatVal == 0 && wallthick_p.FloatVal == 0)
             * {
             *      sp.polyTree = src.polyTree;
             *      sp.paths = src.paths;
             *      return;
             * }
             *
             */
            //sp.polyTree = null;



            //Debug.Log("new count a = " + subjPaths[0].Count);


            bool hasOffset = false;

            sp.hasThickness = false;


            Paths resPaths = new Paths();

            AXClipperLib.PolyTree resPolytree = null;


            // OFFSETTER
            ClipperOffset co = new ClipperOffset();


            //co.ArcTolerance = sp.arcTolerance;
            float smooth    = (float)(120 / (sp.arcTolerance * sp.arcTolerance));
            float smoothLOD = ((smooth - .048f) * sp.parametricObject.model.segmentReductionFactor) + .048f;

            co.ArcTolerance = (float)(Mathf.Sqrt(120 / smoothLOD));


            co.MiterLimit = 2.0f;


            //if (offset != 0)


            // 1. Offset? Can't offset an open shape
            if (sp.shapeState == ShapeState.Closed && (sp.endType == AXClipperLib.EndType.etClosedLine || sp.endType == AXClipperLib.EndType.etClosedPolygon))
            {
                //AXClipperLib.JoinType jt = (sp.endType == AXClipperLib.EndType.etClosedLine) ? JoinType.jtMiter : sp.joinType;//output.joinType;
                AXClipperLib.JoinType jt = (sp.parametricObject.model.segmentReductionFactor < .15f) ? AXClipperLib.JoinType.jtSquare  : sp.joinType;                //output.joinType;
                //Debug.Log ("sp.endType="+sp.endType+", jt="+jt);

                if (roundness != 0)
                {
                    // reduce
                    co.Clear();

                    if (subjPaths != null)
                    {
                        co.AddPaths(AXGeometryTools.Utilities.cleanPaths(subjPaths, cleanPolygonPrecision), jt, AXClipperLib.EndType.etClosedPolygon);                           //JoinType.jtSquare, AXClipperLib.EndType.etClosedPolygon);
                    }
                    co.Execute(ref subjPaths, (double)(-roundness * AXGeometryTools.Utilities.IntPointPrecision));
                }

                offset += roundness;

                if (subjPaths != null)
                {
                    subjPaths = Clipper.SimplifyPolygons(subjPaths, PolyFillType.pftNonZero);
                }

                co.Clear();

                hasOffset = true;

//				if (offset != 0 || thickness == 0) { // --! PUC ** Removed because the pass thru was causing a problem with Instance2D of a ShapeMerger
                // Do Offset

                // = true;

                if (subjPaths != null)
                {
                    // After changes made mid April to allow for FlipX, this started doubling the localMatrix and thus became redundent, though not sure why.
                    //if (gener2D != null)
                    //	sp.transformedAndScaledButNotOffsetdOutputPaths = AX.Generators.Generator2D.transformPaths(subjPaths, gener2D.localMatrix);

                    co.AddPaths(AXGeometryTools.Utilities.cleanPaths(subjPaths, cleanPolygonPrecision), jt, AXClipperLib.EndType.etClosedPolygon);                              //JoinType.jtSquare, AXClipperLib.EndType.etClosedPolygon);

                    // this resPolytree has transformed curves in it
                    resPolytree = new AXClipperLib.PolyTree();
                    co.Execute(ref resPolytree, (double)(offset * AXGeometryTools.Utilities.IntPointPrecision));
                }
//				}
                if (thickness > 0)
                {                       // No offset, but is closed
                    sp.transformedAndScaledButNotOffsetdOutputPaths = null;
                    if (src.polyTree != null)
                    {
                        if (thickness > 0)
                        {
                            resPaths = subjPaths;                             // Clipper.PolyTreeToPaths(src.polyTree);
                        }
                        else
                        {
                            resPolytree = src.polyTree;
                        }
                    }
                    else
                    {
                        resPaths = subjPaths;
                    }
                }
            }
            else
            {
                //resPolytree = src.polyTree;
                if (src.polyTree != null)
                {
                    if (thickness > 0)
                    {
                        resPaths = subjPaths;                         // Clipper.PolyTreeToPaths(src.polyTree);
                    }
                    else
                    {
                        resPolytree = src.polyTree;
                    }
                }
                else
                {
                    resPaths = subjPaths;
                }
            }


            // 2. Thickness?
            //subjPaths = sp.getPaths();


            if ((sp.endType != AXClipperLib.EndType.etClosedPolygon) && thickness > 0)              //input.endType != AXClipperLib.EndType.etClosedPolygon) {
            {
                // this is a wall
                if (resPaths != null && gener2D != null)
                {
                    sp.transformedFullyAndOffsetdButNotThickenedOutputPaths = AX.Generators.Generator2D.transformPaths(resPaths, gener2D.localMatrix);
                }

                sp.hasThickness = true;


                co.Clear();
                if (resPolytree != null)                                                                                                                     // closed block has happened
                {
                    co.AddPaths(AXGeometryTools.Utilities.cleanPaths(Clipper.PolyTreeToPaths(resPolytree), cleanPolygonPrecision), sp.joinType, sp.endType); //input.endType);
                }
                else if (resPaths != null)
                {
                    co.AddPaths(AXGeometryTools.Utilities.cleanPaths(resPaths, cleanPolygonPrecision), sp.joinType, sp.endType);                     //input.endType);
                }

                resPolytree = new AXClipperLib.PolyTree();
                co.Execute(ref resPolytree, (double)(thickness * AXGeometryTools.Utilities.IntPointPrecision));
            }
            else
            {
                sp.transformedFullyAndOffsetdButNotThickenedOutputPaths = null;
            }



            // 3. Update input data
            //Debug.Log(sp.parametricObject.Name  + "." + sp.Name + " here ["+hasOffset+"] " + (! sp.symmetry) + " " +  (! flipX)  + " " + (! hasOffset)  + " " +  (! hasThicken)  + " " +  (roundness == 0));


            // SIMPLE PASSTHRU?
            if (!sp.symmetry && !flipX && !hasOffset && !sp.hasThickness && roundness == 0)
            {
                // SIMPLE PASS THROUGH
                sp.polyTree = src.polyTree;
                sp.paths    = src.paths;
            }

            else
            {
                if (resPolytree == null)
                {
                    //sp.paths      = resPaths; //Generator2D.transformPaths(resPaths, gener2D.localMatrix);
                    //if (Clipper.Orientation(resPaths[0]) != srcIsCC)
                    //	AXGeometryTools.Utilities.reversePaths(ref resPaths);

                    sp.paths = AXGeometryTools.Utilities.cleanPaths(resPaths, cleanPolygonPrecision);
                }
                else
                {
                    //Generator2D.transformPolyTree(resPolytree, gener2D.localMatrix);

                    //if (resPolytree != null && resPolytree.Childs.Count > 0 &&  Clipper.Orientation(resPolytree.Childs[0].Contour) != srcIsCC)
                    //	AXGeometryTools.Utilities.reversePolyTree(resPolytree);


                    sp.polyTree = resPolytree;
                }
            }



            // REVERSE
            if (sp.reverse)
            {
                if (sp.polyTree != null)
                {
                    AXGeometryTools.Utilities.reversePolyTree(sp.polyTree);
                }
                else if (sp.paths != null && sp.paths.Count > 0)
                {
                    for (int i = 0; i < sp.paths.Count; i++)
                    {
                        sp.paths[i].Reverse();
                    }
                }
            }



//			if (sp.paths != null && sp.paths.Count > 0)
//			{
//				// SUBDIVISION
//				Debug.Log("sp.paths.Count="+sp.paths.Count);
//
//				for(int i=0; i<sp.paths.Count; i++)
//				{
//
//
//					Path path = sp.paths[i];
//					Path subdivPath = new Path();
//
//					for (int j=0; j<path.Count-1; j++)
//					{
//						subdivPath.Add(path[j]);
//						Vector2 v0 = new Vector2(path[j].X, path[j].Y);
//						Vector2 v1 = new Vector2(path[j+1].X, path[j+1].Y);
//
//						Debug.Log("["+i+"]["+j+"] " + Vector2.Distance(v0, v1)/10000);
//						 Vector2 newp = Vector2.Lerp(v0, v1, .5f);
//
//						subdivPath.Add(new IntPoint(newp.x, newp.y));
//					}
//					subdivPath.Add(path[path.Count-1]);
//
//
//					sp.paths[i] = subdivPath;
//
//					Debug.Log("------------");
//					AXGeometryTools.Utilities.printPath(sp.paths[i]);
//				}
//					// SUBDIVISION ---
//			}
//
        }
Пример #29
0
            public int PointInPolygon(Vector2 point)
            {
                var p = new IntPoint(point.X, point.Y);

                return(Clipper.PointInPolygon(p, ToClipperPath()));
            }
Пример #30
0
        private void CutPoly(Int3[] verts, int[] tris, ref Int3[] outVertsArr, ref int[] outTrisArr, out int outVCount, out int outTCount, Int3[] extraShape, Int3 cuttingOffset, Bounds realBounds, TileHandler.CutMode mode = (TileHandler.CutMode) 3, int perturbate = 0)
        {
            if (verts.Length == 0 || tris.Length == 0)
            {
                outVCount   = 0;
                outTCount   = 0;
                outTrisArr  = new int[0];
                outVertsArr = new Int3[0];
                return;
            }
            List <IntPoint> list = null;

            if (extraShape == null && (mode & TileHandler.CutMode.CutExtra) != (TileHandler.CutMode) 0)
            {
                throw new Exception("extraShape is null and the CutMode specifies that it should be used. Cannot use null shape.");
            }
            if ((mode & TileHandler.CutMode.CutExtra) != (TileHandler.CutMode) 0)
            {
                list = new List <IntPoint>(extraShape.Length);
                for (int i = 0; i < extraShape.Length; i++)
                {
                    list.Add(new IntPoint((long)(extraShape[i].x + cuttingOffset.x), (long)(extraShape[i].z + cuttingOffset.z)));
                }
            }
            List <IntPoint> list2 = new List <IntPoint>(5);
            Dictionary <TriangulationPoint, int> dictionary = new Dictionary <TriangulationPoint, int>();
            List <PolygonPoint> list3 = new List <PolygonPoint>();
            IntRect             b     = new IntRect(verts[0].x, verts[0].z, verts[0].x, verts[0].z);

            for (int j = 0; j < verts.Length; j++)
            {
                b = b.ExpandToContain(verts[j].x, verts[j].z);
            }
            List <Int3> list4 = ListPool <Int3> .Claim(verts.Length * 2);

            List <int> list5 = ListPool <int> .Claim(tris.Length);

            PolyTree polyTree             = new PolyTree();
            List <List <IntPoint> > list6 = new List <List <IntPoint> >();
            Stack <Polygon>         stack = new Stack <Polygon>();

            if (this.clipper == null)
            {
                this.clipper = new Clipper(0);
            }
            this.clipper.ReverseSolution = true;
            List <NavmeshCut> list7;

            if (mode == TileHandler.CutMode.CutExtra)
            {
                list7 = ListPool <NavmeshCut> .Claim();
            }
            else
            {
                list7 = NavmeshCut.GetAllInRange(realBounds);
            }
            List <int> list8 = ListPool <int> .Claim();

            List <IntRect> list9 = ListPool <IntRect> .Claim();

            List <Int2> list10 = ListPool <Int2> .Claim();

            List <List <IntPoint> > list11 = new List <List <IntPoint> >();
            List <bool>             list12 = ListPool <bool> .Claim();

            List <bool> list13 = ListPool <bool> .Claim();

            if (perturbate > 10)
            {
                Debug.LogError("Too many perturbations aborting : " + mode);
                Debug.Break();
                outVCount   = verts.Length;
                outTCount   = tris.Length;
                outTrisArr  = tris;
                outVertsArr = verts;
                return;
            }
            Random random = null;

            if (perturbate > 0)
            {
                random = new Random();
            }
            for (int k = 0; k < list7.Count; k++)
            {
                Bounds  bounds = list7[k].GetBounds();
                Int3    @int   = (Int3)bounds.min + cuttingOffset;
                Int3    int2   = (Int3)bounds.max + cuttingOffset;
                IntRect a      = new IntRect(@int.x, @int.z, int2.x, int2.z);
                if (IntRect.Intersects(a, b))
                {
                    Int2 int3 = new Int2(0, 0);
                    if (perturbate > 0)
                    {
                        int3.x = random.Next() % 6 * perturbate - 3 * perturbate;
                        if (int3.x >= 0)
                        {
                            int3.x++;
                        }
                        int3.y = random.Next() % 6 * perturbate - 3 * perturbate;
                        if (int3.y >= 0)
                        {
                            int3.y++;
                        }
                    }
                    int count = list11.Count;
                    list7[k].GetContour(list11);
                    for (int l = count; l < list11.Count; l++)
                    {
                        List <IntPoint> list14 = list11[l];
                        if (list14.Count == 0)
                        {
                            Debug.LogError("Zero Length Contour");
                            list9.Add(default(IntRect));
                            list10.Add(new Int2(0, 0));
                        }
                        else
                        {
                            IntRect item = new IntRect((int)list14[0].X + cuttingOffset.x, (int)list14[0].Y + cuttingOffset.y, (int)list14[0].X + cuttingOffset.x, (int)list14[0].Y + cuttingOffset.y);
                            for (int m = 0; m < list14.Count; m++)
                            {
                                IntPoint value = list14[m];
                                value.X += (long)cuttingOffset.x;
                                value.Y += (long)cuttingOffset.z;
                                if (perturbate > 0)
                                {
                                    value.X += (long)int3.x;
                                    value.Y += (long)int3.y;
                                }
                                list14[m] = value;
                                item      = item.ExpandToContain((int)value.X, (int)value.Y);
                            }
                            list10.Add(new Int2(@int.y, int2.y));
                            list9.Add(item);
                            list12.Add(list7[k].isDual);
                            list13.Add(list7[k].cutsAddedGeom);
                        }
                    }
                }
            }
            List <NavmeshAdd> allInRange = NavmeshAdd.GetAllInRange(realBounds);

            Int3[] array  = verts;
            int[]  array2 = tris;
            int    num    = -1;
            int    n      = -3;

            Int3[] array3 = null;
            Int3[] array4 = null;
            Int3   int4   = Int3.zero;

            if (allInRange.Count > 0)
            {
                array3 = new Int3[7];
                array4 = new Int3[7];
                int4   = (Int3)realBounds.extents;
            }
            for (;;)
            {
                n += 3;
                while (n >= array2.Length)
                {
                    num++;
                    n = 0;
                    if (num >= allInRange.Count)
                    {
                        array = null;
                        break;
                    }
                    if (array == verts)
                    {
                        array = null;
                    }
                    allInRange[num].GetMesh(cuttingOffset, ref array, out array2);
                }
                if (array == null)
                {
                    break;
                }
                Int3    int5 = array[array2[n]];
                Int3    int6 = array[array2[n + 1]];
                Int3    int7 = array[array2[n + 2]];
                IntRect a2   = new IntRect(int5.x, int5.z, int5.x, int5.z);
                a2 = a2.ExpandToContain(int6.x, int6.z);
                a2 = a2.ExpandToContain(int7.x, int7.z);
                int num2 = Math.Min(int5.y, Math.Min(int6.y, int7.y));
                int num3 = Math.Max(int5.y, Math.Max(int6.y, int7.y));
                list8.Clear();
                bool flag = false;
                for (int num4 = 0; num4 < list11.Count; num4++)
                {
                    int x = list10[num4].x;
                    int y = list10[num4].y;
                    if (IntRect.Intersects(a2, list9[num4]) && y >= num2 && x <= num3 && (list13[num4] || num == -1))
                    {
                        Int3 int8 = int5;
                        int8.y = x;
                        Int3 int9 = int5;
                        int9.y = y;
                        list8.Add(num4);
                        flag |= list12[num4];
                    }
                }
                if (list8.Count == 0 && (mode & TileHandler.CutMode.CutExtra) == (TileHandler.CutMode) 0 && (mode & TileHandler.CutMode.CutAll) != (TileHandler.CutMode) 0 && num == -1)
                {
                    list5.Add(list4.Count);
                    list5.Add(list4.Count + 1);
                    list5.Add(list4.Count + 2);
                    list4.Add(int5);
                    list4.Add(int6);
                    list4.Add(int7);
                }
                else
                {
                    list2.Clear();
                    if (num == -1)
                    {
                        list2.Add(new IntPoint((long)int5.x, (long)int5.z));
                        list2.Add(new IntPoint((long)int6.x, (long)int6.z));
                        list2.Add(new IntPoint((long)int7.x, (long)int7.z));
                    }
                    else
                    {
                        array3[0] = int5;
                        array3[1] = int6;
                        array3[2] = int7;
                        int num5 = Utility.ClipPolygon(array3, 3, array4, 1, 0, 0);
                        if (num5 == 0)
                        {
                            continue;
                        }
                        num5 = Utility.ClipPolygon(array4, num5, array3, -1, 2 * int4.x, 0);
                        if (num5 == 0)
                        {
                            continue;
                        }
                        num5 = Utility.ClipPolygon(array3, num5, array4, 1, 0, 2);
                        if (num5 == 0)
                        {
                            continue;
                        }
                        num5 = Utility.ClipPolygon(array4, num5, array3, -1, 2 * int4.z, 2);
                        if (num5 == 0)
                        {
                            continue;
                        }
                        for (int num6 = 0; num6 < num5; num6++)
                        {
                            list2.Add(new IntPoint((long)array3[num6].x, (long)array3[num6].z));
                        }
                    }
                    dictionary.Clear();
                    Int3 int10 = int6 - int5;
                    Int3 int11 = int7 - int5;
                    Int3 int12 = int10;
                    Int3 int13 = int11;
                    int12.y = 0;
                    int13.y = 0;
                    for (int num7 = 0; num7 < 16; num7++)
                    {
                        if ((mode >> (num7 & 31) & TileHandler.CutMode.CutAll) != (TileHandler.CutMode) 0)
                        {
                            if (1 << num7 == 1)
                            {
                                this.clipper.Clear();
                                this.clipper.AddPolygon(list2, 0);
                                for (int num8 = 0; num8 < list8.Count; num8++)
                                {
                                    this.clipper.AddPolygon(list11[list8[num8]], 1);
                                }
                                polyTree.Clear();
                                this.clipper.Execute(2, polyTree, 0, 1);
                            }
                            else if (1 << num7 == 2)
                            {
                                if (!flag)
                                {
                                    goto IL_1161;
                                }
                                this.clipper.Clear();
                                this.clipper.AddPolygon(list2, 0);
                                for (int num9 = 0; num9 < list8.Count; num9++)
                                {
                                    if (list12[list8[num9]])
                                    {
                                        this.clipper.AddPolygon(list11[list8[num9]], 1);
                                    }
                                }
                                list6.Clear();
                                this.clipper.Execute(0, list6, 0, 1);
                                this.clipper.Clear();
                                for (int num10 = 0; num10 < list6.Count; num10++)
                                {
                                    this.clipper.AddPolygon(list6[num10], (!Clipper.Orientation(list6[num10])) ? 0 : 1);
                                }
                                for (int num11 = 0; num11 < list8.Count; num11++)
                                {
                                    if (!list12[list8[num11]])
                                    {
                                        this.clipper.AddPolygon(list11[list8[num11]], 1);
                                    }
                                }
                                polyTree.Clear();
                                this.clipper.Execute(2, polyTree, 0, 1);
                            }
                            else if (1 << num7 == 4)
                            {
                                this.clipper.Clear();
                                this.clipper.AddPolygon(list2, 0);
                                this.clipper.AddPolygon(list, 1);
                                polyTree.Clear();
                                this.clipper.Execute(0, polyTree, 0, 1);
                            }
                            for (int num12 = 0; num12 < polyTree.ChildCount; num12++)
                            {
                                PolyNode        polyNode = polyTree.Childs[num12];
                                List <IntPoint> contour  = polyNode.Contour;
                                List <PolyNode> childs   = polyNode.Childs;
                                if (childs.Count == 0 && contour.Count == 3 && num == -1)
                                {
                                    for (int num13 = 0; num13 < contour.Count; num13++)
                                    {
                                        Int3   item2 = new Int3((int)contour[num13].X, 0, (int)contour[num13].Y);
                                        double num14 = (double)(int6.z - int7.z) * (double)(int5.x - int7.x) + (double)(int7.x - int6.x) * (double)(int5.z - int7.z);
                                        if (num14 == 0.0)
                                        {
                                            Debug.LogWarning("Degenerate triangle");
                                        }
                                        else
                                        {
                                            double num15 = ((double)(int6.z - int7.z) * (double)(item2.x - int7.x) + (double)(int7.x - int6.x) * (double)(item2.z - int7.z)) / num14;
                                            double num16 = ((double)(int7.z - int5.z) * (double)(item2.x - int7.x) + (double)(int5.x - int7.x) * (double)(item2.z - int7.z)) / num14;
                                            item2.y = (int)Math.Round(num15 * (double)int5.y + num16 * (double)int6.y + (1.0 - num15 - num16) * (double)int7.y);
                                            list5.Add(list4.Count);
                                            list4.Add(item2);
                                        }
                                    }
                                }
                                else
                                {
                                    Polygon polygon = null;
                                    int     num17   = -1;
                                    for (List <IntPoint> list15 = contour; list15 != null; list15 = ((num17 >= childs.Count) ? null : childs[num17].Contour))
                                    {
                                        list3.Clear();
                                        for (int num18 = 0; num18 < list15.Count; num18++)
                                        {
                                            PolygonPoint polygonPoint = new PolygonPoint((double)list15[num18].X, (double)list15[num18].Y);
                                            list3.Add(polygonPoint);
                                            Int3   item3 = new Int3((int)list15[num18].X, 0, (int)list15[num18].Y);
                                            double num19 = (double)(int6.z - int7.z) * (double)(int5.x - int7.x) + (double)(int7.x - int6.x) * (double)(int5.z - int7.z);
                                            if (num19 == 0.0)
                                            {
                                                Debug.LogWarning("Degenerate triangle");
                                            }
                                            else
                                            {
                                                double num20 = ((double)(int6.z - int7.z) * (double)(item3.x - int7.x) + (double)(int7.x - int6.x) * (double)(item3.z - int7.z)) / num19;
                                                double num21 = ((double)(int7.z - int5.z) * (double)(item3.x - int7.x) + (double)(int5.x - int7.x) * (double)(item3.z - int7.z)) / num19;
                                                item3.y = (int)Math.Round(num20 * (double)int5.y + num21 * (double)int6.y + (1.0 - num20 - num21) * (double)int7.y);
                                                dictionary[polygonPoint] = list4.Count;
                                                list4.Add(item3);
                                            }
                                        }
                                        Polygon polygon2;
                                        if (stack.Count > 0)
                                        {
                                            polygon2 = stack.Pop();
                                            polygon2.AddPoints(list3);
                                        }
                                        else
                                        {
                                            polygon2 = new Polygon(list3);
                                        }
                                        if (polygon == null)
                                        {
                                            polygon = polygon2;
                                        }
                                        else
                                        {
                                            polygon.AddHole(polygon2);
                                        }
                                        num17++;
                                    }
                                    try
                                    {
                                        P2T.Triangulate(polygon);
                                    }
                                    catch (PointOnEdgeException)
                                    {
                                        Debug.LogWarning(string.Concat(new object[]
                                        {
                                            "PointOnEdgeException, perturbating vertices slightly ( at ",
                                            num7,
                                            " in ",
                                            mode,
                                            ")"
                                        }));
                                        this.CutPoly(verts, tris, ref outVertsArr, ref outTrisArr, out outVCount, out outTCount, extraShape, cuttingOffset, realBounds, mode, perturbate + 1);
                                        return;
                                    }
                                    for (int num22 = 0; num22 < polygon.Triangles.Count; num22++)
                                    {
                                        DelaunayTriangle delaunayTriangle = polygon.Triangles[num22];
                                        list5.Add(dictionary[delaunayTriangle.Points._0]);
                                        list5.Add(dictionary[delaunayTriangle.Points._1]);
                                        list5.Add(dictionary[delaunayTriangle.Points._2]);
                                    }
                                    if (polygon.Holes != null)
                                    {
                                        for (int num23 = 0; num23 < polygon.Holes.Count; num23++)
                                        {
                                            polygon.Holes[num23].Points.Clear();
                                            polygon.Holes[num23].ClearTriangles();
                                            if (polygon.Holes[num23].Holes != null)
                                            {
                                                polygon.Holes[num23].Holes.Clear();
                                            }
                                            stack.Push(polygon.Holes[num23]);
                                        }
                                    }
                                    polygon.ClearTriangles();
                                    if (polygon.Holes != null)
                                    {
                                        polygon.Holes.Clear();
                                    }
                                    polygon.Points.Clear();
                                    stack.Push(polygon);
                                }
                            }
                        }
                        IL_1161 :;
                    }
                }
            }
            Dictionary <Int3, int> dictionary2 = this.cached_Int3_int_dict;

            dictionary2.Clear();
            if (this.cached_int_array.Length < list4.Count)
            {
                this.cached_int_array = new int[Math.Max(this.cached_int_array.Length * 2, list4.Count)];
            }
            int[] array5 = this.cached_int_array;
            int   num24  = 0;

            for (int num25 = 0; num25 < list4.Count; num25++)
            {
                int num26;
                if (!dictionary2.TryGetValue(list4[num25], out num26))
                {
                    dictionary2.Add(list4[num25], num24);
                    array5[num25] = num24;
                    list4[num24]  = list4[num25];
                    num24++;
                }
                else
                {
                    array5[num25] = num26;
                }
            }
            outTCount = list5.Count;
            if (outTrisArr == null || outTrisArr.Length < outTCount)
            {
                outTrisArr = new int[outTCount];
            }
            for (int num27 = 0; num27 < outTCount; num27++)
            {
                outTrisArr[num27] = array5[list5[num27]];
            }
            outVCount = num24;
            if (outVertsArr == null || outVertsArr.Length < outVCount)
            {
                outVertsArr = new Int3[outVCount];
            }
            for (int num28 = 0; num28 < outVCount; num28++)
            {
                outVertsArr[num28] = list4[num28];
            }
            for (int num29 = 0; num29 < list7.Count; num29++)
            {
                list7[num29].UsedForCut();
            }
            ListPool <Int3> .Release(list4);

            ListPool <int> .Release(list5);

            ListPool <int> .Release(list8);

            ListPool <Int2> .Release(list10);

            ListPool <bool> .Release(list12);

            ListPool <bool> .Release(list13);

            ListPool <IntRect> .Release(list9);

            ListPool <NavmeshCut> .Release(list7);
        }
Пример #31
0
		public static List<Polygons> ProcessIntoSeparatIslands(this Polygons polygons)
		{
			List<Polygons> ret = new List<Polygons>();
			Clipper clipper = new Clipper();
			PolyTree resultPolyTree = new PolyTree();
			clipper.AddPaths(polygons, PolyType.ptSubject, true);
			clipper.Execute(ClipType.ctUnion, resultPolyTree);

			polygons.ProcessPolyTreeNodeIntoSeparatIslands(resultPolyTree, ret);
			return ret;
		}
Пример #32
0
        /// <summary>
        /// Create the list of polygon segments (not closed) that represent the parts of the source polygons that are close (almost touching).
        /// </summary>
        /// <param name="polygons"></param>
        /// <param name="overlapMergeAmount">If edges under consideration, are this distance or less apart (but greater than minimumRequiredWidth) they will generate edges</param>
        /// <param name="minimumRequiredWidth">If the distance between edges is less this they will not be generated. This lets us avoid considering very thin lines.</param>
        /// <param name="onlyMergeLines">The output segments that are calculated</param>
        /// <param name="pathIsClosed">Is the source path closed (does not contain the last edge but assumes it).</param>
        /// <returns></returns>
        public static bool FindThinLines(this Polygons polygons, long overlapMergeAmount, long minimumRequiredWidth, out Polygons onlyMergeLines, bool pathIsClosed = true)
        {
            polygons = Clipper.CleanPolygons(polygons, overlapMergeAmount / 8);
            bool pathHasMergeLines = false;

            polygons = MakeCloseSegmentsMergable(polygons, overlapMergeAmount, pathIsClosed);

            // make a copy that has every point duplicated (so that we have them as segments).
            List <Segment> polySegments = Segment.ConvertToSegments(polygons);

            var markedAltered = new Altered[polySegments.Count];

            var touchingEnumerator = new CloseSegmentsIterator(polySegments, overlapMergeAmount);
            int segmentCount       = polySegments.Count;

            // now walk every segment and check if there is another segment that is similar enough to merge them together
            for (int firstSegmentIndex = 0; firstSegmentIndex < segmentCount; firstSegmentIndex++)
            {
                foreach (int checkSegmentIndex in touchingEnumerator.GetTouching(firstSegmentIndex, segmentCount))
                {
                    // The first point of start and the last point of check (the path will be coming back on itself).
                    long startDelta = (polySegments[firstSegmentIndex].Start - polySegments[checkSegmentIndex].End).Length();
                    // if the segments are similar enough
                    if (startDelta < overlapMergeAmount)
                    {
                        // The last point of start and the first point of check (the path will be coming back on itself).
                        long endDelta = (polySegments[firstSegmentIndex].End - polySegments[checkSegmentIndex].Start).Length();
                        if (endDelta < overlapMergeAmount)
                        {
                            // move the first segments points to the average of the merge positions
                            long startEndWidth = Math.Abs((polySegments[firstSegmentIndex].Start - polySegments[checkSegmentIndex].End).Length());
                            long endStartWidth = Math.Abs((polySegments[firstSegmentIndex].End - polySegments[checkSegmentIndex].Start).Length());
                            long width         = Math.Min(startEndWidth, endStartWidth);

                            if (width > minimumRequiredWidth)
                            {
                                // We need to check if the new start position is on the inside of the curve. We can only add thin lines on the insides of our existing curves.
                                IntPoint newStartPosition  = (polySegments[firstSegmentIndex].Start + polySegments[checkSegmentIndex].End) / 2;                                // the start;
                                IntPoint newStartDirection = newStartPosition - polySegments[firstSegmentIndex].Start;
                                IntPoint normalLeft        = (polySegments[firstSegmentIndex].End - polySegments[firstSegmentIndex].Start).GetPerpendicularLeft();
                                long     dotProduct        = normalLeft.Dot(newStartDirection);
                                if (dotProduct > 0)
                                {
                                    pathHasMergeLines = true;

                                    polySegments[firstSegmentIndex].Start       = newStartPosition;
                                    polySegments[firstSegmentIndex].Start.Width = width;
                                    polySegments[firstSegmentIndex].End         = (polySegments[firstSegmentIndex].End + polySegments[checkSegmentIndex].Start) / 2;                             // the end
                                    polySegments[firstSegmentIndex].End.Width   = width;

                                    markedAltered[firstSegmentIndex] = Altered.merged;
                                    // mark this segment for removal
                                    markedAltered[checkSegmentIndex] = Altered.remove;
                                    // We only expect to find one match for each segment, so move on to the next segment
                                    break;
                                }
                            }
                        }
                    }
                }
            }

            // remove the marked segments
            for (int segmentIndex = segmentCount - 1; segmentIndex >= 0; segmentIndex--)
            {
                // remove every segment that has not been merged
                if (markedAltered[segmentIndex] != Altered.merged)
                {
                    polySegments.RemoveAt(segmentIndex);
                }
            }

            // go through the polySegments and create a new polygon for every connected set of segments
            onlyMergeLines = new Polygons();
            var currentPolygon = new Polygon();

            onlyMergeLines.Add(currentPolygon);
            // put in the first point
            for (int segmentIndex = 0; segmentIndex < polySegments.Count; segmentIndex++)
            {
                // add the start point
                currentPolygon.Add(polySegments[segmentIndex].Start);


                // if the next segment is not connected to this one
                if (segmentIndex < polySegments.Count - 1 &&
                    polySegments[segmentIndex].End != polySegments[segmentIndex + 1].Start)
                {
                    // add the end point
                    currentPolygon.Add(polySegments[segmentIndex].End);

                    // create a new polygon
                    currentPolygon = new Polygon();
                    onlyMergeLines.Add(currentPolygon);
                }
            }

            // add the end point
            if (polySegments.Count > 0)
            {
                currentPolygon.Add(polySegments[polySegments.Count - 1].End);
            }

            long cleanDistance = overlapMergeAmount / 40;

            Clipper.CleanPolygons(onlyMergeLines, cleanDistance);

            return(pathHasMergeLines);
        }
Пример #33
0
        /**
         * Note: this method will close all unclosed subpaths of the passed path.
         *
         * @param fillingRule If the subpath is contour, pass any value.
         */
        protected internal Path FilterFillPath(Path path, Matrix ctm, int fillingRule) {
            path.CloseAllSubpaths();

            Clipper clipper = new Clipper();
            AddPath(clipper, path);

            foreach (Rectangle rectangle in rectangles) {
                Point2D[] transfRectVertices = TransformPoints(ctm, true, GetVertices(rectangle));
                AddRect(clipper, transfRectVertices, PolyType.ptClip);
            }

            PolyFillType fillType = PolyFillType.pftNonZero;

            if (fillingRule == PathPaintingRenderInfo.EVEN_ODD_RULE) {
                fillType = PolyFillType.pftEvenOdd;
            }

            PolyTree resultTree = new PolyTree();
            clipper.Execute(ClipType.ctDifference, resultTree, fillType, PolyFillType.pftNonZero);

            return ConvertToPath(resultTree);
        }
Пример #34
0
        public string MinimalDXFSave(string outputfile, double offset = 3.0, double holediameter = 3.2)
        {
            if (Directory.Exists(outputfile))
            {
                outputfile = Path.Combine(outputfile, "SickOfBeige");
            }

            PolyLine      Biggest     = null;
            double        BiggestArea = 0;
            List <PointD> Holes       = new List <PointD>();
            var           holeradius  = holediameter / 2.0;


            double Circumference = 2 * Math.PI * holeradius;

            foreach (var a in PLSs.Where(x => x.Layer == BoardLayer.Outline))
            {
                foreach (var b in a.OutlineShapes)
                {
                    var    A      = b.toPolygon();
                    double LRatio = (b.OutlineLength() / Circumference);
                    double Lperc  = Math.Abs(LRatio - 1);
                    if (Lperc < 0.1)
                    {
                        if (b.Vertices.Count > 5)
                        {
                            var  C     = b.GetCentroid();
                            bool round = true;
                            foreach (var v in b.Vertices)
                            {
                                var L = (C - v).Length();
                                if (Math.Abs(L - holeradius) > 0.2)
                                {
                                    // not very round!
                                    round = false;
                                }
                            }
                            if (round)
                            {
                                Console.WriteLine("Hole detected in outline:{0} {1} {2} {3} {4} {5}", a.Layer, a.Side, C, LRatio, Lperc, b.Vertices.Count);
                                Holes.Add(C);
                            }
                        }
                        // might be hole!
                    }
                    var Area = Clipper.Area(A);
                    if (Area > BiggestArea)
                    {
                        Biggest     = b;
                        BiggestArea = Area;
                    }
                }
            }

            Polygons Offsetted = new Polygons();

            List <String> Lines = new List <string>();

            Lines.Add("0");
            Lines.Add("SECTION");
            Lines.Add("2 ");
            Lines.Add("ENTITIES");


            if (Biggest != null)
            {
                Polygons clips = new Polygons();
                clips.Add(Biggest.toPolygon());
                Offsetted = Clipper.OffsetPolygons(clips, offset * 100000.0f, JoinType.jtRound);
                foreach (var poly in Offsetted)
                {
                    PolyLine P = new PolyLine();

                    P.fromPolygon(poly);

                    for (int i = 0; i < P.Vertices.Count; i++)
                    {
                        var V1 = P.Vertices[i];
                        var V2 = P.Vertices[(i + 1) % P.Vertices.Count];

                        Lines.Add("0");
                        Lines.Add("LINE");
                        Lines.Add("8");
                        Lines.Add("Outline");
                        Lines.Add("10");
                        Lines.Add(V1.X.ToString().Replace(',', '.'));
                        Lines.Add("20");
                        Lines.Add(V1.Y.ToString().Replace(',', '.'));
                        Lines.Add("11");
                        Lines.Add(V2.X.ToString().Replace(',', '.'));
                        Lines.Add("21");
                        Lines.Add(V2.Y.ToString().Replace(',', '.'));
                    }
                }
            }
            else
            {
                Errors.Add("No longest outline found - not generating offset curve");
            }

            foreach (var a in Excellons)
            {
                foreach (var t in a.Tools)
                {
                    var R = t.Value.Radius;
                    if (Math.Abs(R * 2 - holediameter) < 0.05)
                    {
                        foreach (var h in t.Value.Drills)
                        {
                            Holes.Add(h);
                        }
                    }
                }
            }


            foreach (var a in Holes)
            {
                for (int i = 0; i < 40; i++)
                {
                    double P  = i * Math.PI * 2.0 / 40.0;
                    double P2 = (i + 1) * Math.PI * 2.0 / 40.0;
                    var    C1 = Math.Cos(P) * holeradius;
                    var    C2 = Math.Cos(P2) * holeradius;
                    var    S1 = Math.Sin(P) * holeradius;
                    var    S2 = Math.Sin(P2) * holeradius;
                    double x1 = a.X + C1;
                    double y1 = a.Y + S1;
                    double x2 = a.X + C2;
                    double y2 = a.Y + S2;

                    Lines.Add("0");
                    Lines.Add("LINE");
                    Lines.Add("8");
                    Lines.Add("Holes");
                    Lines.Add("10");
                    Lines.Add(x1.ToString().Replace(',', '.'));
                    Lines.Add("20");
                    Lines.Add(y1.ToString().Replace(',', '.'));
                    Lines.Add("11");
                    Lines.Add(x2.ToString().Replace(',', '.'));
                    Lines.Add("21");
                    Lines.Add(y2.ToString().Replace(',', '.'));
                }
            }

            Lines.Add("0");
            Lines.Add("ENDSEC");
            Lines.Add("0");
            Lines.Add("EOF");
            File.WriteAllLines(outputfile + ".dxf", Lines);
            float scalefac = 10;

            Console.WriteLine("Report: {0} holes created in case ({1} spacers and {1} screws needed!)", Holes.Count, Holes.Count * 2);
            {
                var BB = new GerberLibrary.PolyLineSet.Bounds();
                BB.AddPolygons(Offsetted);
                BB.AddPolyLine(Biggest);

                Bitmap   B = new Bitmap((int)((BB.Width()) * scalefac) + 6, (int)((BB.Height()) * scalefac) + 6);
                Graphics G = Graphics.FromImage(B);
                G.Clear(Color.Transparent);
                G.Clear(Color.White);

                G.TranslateTransform(3, 3);
                G.ScaleTransform(scalefac, scalefac);
                G.TranslateTransform((float)-(BB.TopLeft.X), (float)-(BB.TopLeft.Y));
                Pen pen  = new Pen(Color.Black, 0.1f);
                Pen pen2 = new Pen(Color.FromArgb(160, 160, 160), 0.1f);
                pen2.DashPattern = new float[2] {
                    2, 2
                };
                GerberImageCreator.ApplyAASettings(G);
                RectangleF R = new RectangleF(0, 0, (float)holediameter, (float)holediameter);

                foreach (var a in Holes)
                {
                    R.X = (float)a.X - (float)holeradius;
                    R.Y = (float)a.Y - (float)holeradius;
                    G.DrawEllipse(pen, R);
                }

                foreach (var poly in Offsetted)
                {
                    PolyLine Pl = new PolyLine();

                    Pl.fromPolygon(poly);
                    var Points = new List <PointF>(Pl.Vertices.Count);
                    for (int i = 0; i < Pl.Vertices.Count; i++)
                    {
                        Points.Add(Pl.Vertices[i].ToF());
                    }
                    Points.Add(Pl.Vertices[0].ToF());
                    G.DrawLines(pen, Points.ToArray());
                }

                {
                    PolyLine Pl = Biggest;

                    var Points = new List <PointF>(Pl.Vertices.Count);

                    for (int i = 0; i < Pl.Vertices.Count; i++)
                    {
                        Points.Add(Pl.Vertices[i].ToF());
                    }

                    Points.Add(Pl.Vertices[0].ToF());
                    G.DrawLines(pen2, Points.ToArray());
                }

                var ImagePNG = outputfile + ".png";
                B.Save(ImagePNG);
                return(ImagePNG);
            }
        }
Пример #35
0
 private static void AddRect(Clipper clipper, Point2D[] rectVertices, PolyType polyType) {
     clipper.AddPath(ConvertToIntPoints(new List<Point2D>(rectVertices)), polyType, true);
 }
Пример #36
0
        public static List <List <IntPoint> > FindClosedPolygons(List <Segment> UnorderedSegments)
        {
            var startIndexes = CreateFastIndexLookup(UnorderedSegments);

            var segmentHasBeenAdded = new bool[UnorderedSegments.Count];

            var openPolygonList = new List <List <IntPoint> >();
            var closedPolygons  = new List <List <IntPoint> >();

            for (int startingSegmentIndex = 0; startingSegmentIndex < UnorderedSegments.Count; startingSegmentIndex++)
            {
                if (segmentHasBeenAdded[startingSegmentIndex])
                {
                    continue;
                }

                var poly = new List <IntPoint>();
                // We start by adding the start, as we will add ends from now on.
                var polygonStartPosition = UnorderedSegments[startingSegmentIndex].Start;
                poly.Add(polygonStartPosition);

                int  segmentIndexBeingAdded = startingSegmentIndex;
                bool canClose;

                while (true)
                {
                    canClose = false;
                    segmentHasBeenAdded[segmentIndexBeingAdded] = true;
                    var addedSegmentEndPoint = UnorderedSegments[segmentIndexBeingAdded].End;

                    poly.Add(addedSegmentEndPoint);
                    segmentIndexBeingAdded = GetTouchingSegmentIndex(UnorderedSegments, startIndexes, segmentHasBeenAdded, addedSegmentEndPoint);
                    if (segmentIndexBeingAdded == -1)
                    {
                        // if we have looped back around to where we started
                        if (addedSegmentEndPoint == polygonStartPosition)
                        {
                            canClose = true;
                        }

                        break;
                    }
                    else
                    {
                        var foundSegmentStart = UnorderedSegments[segmentIndexBeingAdded].Start;
                        if (addedSegmentEndPoint == foundSegmentStart)
                        {
                            // if we have looped back around to where we started
                            if (addedSegmentEndPoint == polygonStartPosition)
                            {
                                canClose = true;
                            }
                        }
                    }
                }

                if (canClose)
                {
                    closedPolygons.Add(poly);
                }
                else
                {
                    openPolygonList.Add(poly);
                }
            }

            // Remove all polygons from the open polygon list that have 0 points
            for (int i = openPolygonList.Count - 1; i >= 0; i--)
            {
                // add in the position of the last point
                if (openPolygonList[i].Count == 0)
                {
                    openPolygonList.RemoveAt(i);
                }
                else                 // check if every point is the same
                {
                    bool allSame = true;
                    var  first   = openPolygonList[i][0];
                    for (int j = 1; j < openPolygonList[i].Count; j++)
                    {
                        if (openPolygonList[i][j] != first)
                        {
                            allSame = false;
                            break;
                        }
                    }

                    if (allSame)
                    {
                        openPolygonList.RemoveAt(i);
                    }
                }
            }

            var startSorter = new SortedIntPoint();

            for (int i = 0; i < openPolygonList.Count; i++)
            {
                startSorter.Add(i, openPolygonList[i][0]);
            }

            startSorter.Sort();

            var endSorter = new SortedIntPoint();

            for (int i = 0; i < openPolygonList.Count; i++)
            {
                endSorter.Add(i, openPolygonList[i][openPolygonList[i].Count - 1]);
            }

            endSorter.Sort();

            // Link up all the missing ends, closing up the smallest gaps first. This is an inefficient implementation which can run in O(n*n*n) time.
            while (true)
            {
                double bestScore = double.MaxValue;
                int    bestA     = -1;
                int    bestB     = -1;
                bool   reversed  = false;
                for (int polygonAIndex = 0; polygonAIndex < openPolygonList.Count; polygonAIndex++)
                {
                    if (openPolygonList[polygonAIndex].Count < 1)
                    {
                        continue;
                    }

                    var aEndPosition = openPolygonList[polygonAIndex][openPolygonList[polygonAIndex].Count - 1];
                    // find the closestStartFromEnd
                    int bStartIndex = startSorter.FindClosetIndex(aEndPosition, out double distanceToStartSqrd);
                    if (distanceToStartSqrd < bestScore)
                    {
                        bestScore = distanceToStartSqrd;
                        bestA     = polygonAIndex;
                        bestB     = bStartIndex;
                        reversed  = false;

                        if (bestScore == 0)
                        {
                            // found a perfect match stop looking
                            break;
                        }
                    }

                    // find the closestStartFromStart
                    int bEndIndex = endSorter.FindClosetIndex(aEndPosition, out double distanceToEndSqrd, polygonAIndex);
                    if (distanceToEndSqrd < bestScore)
                    {
                        bestScore = distanceToEndSqrd;
                        bestA     = polygonAIndex;
                        bestB     = bEndIndex;
                        reversed  = true;

                        if (bestScore == 0)
                        {
                            // found a perfect match stop looking
                            break;
                        }
                    }

                    if (bestScore == 0)
                    {
                        // found a perfect match stop looking
                        break;
                    }
                }

                if (bestScore >= double.MaxValue)
                {
                    // we could not find any points to connect this to
                    break;
                }

                if (bestA == bestB)                 // This loop connects to itself, close the polygon.
                {
                    closedPolygons.Add(new List <IntPoint>(openPolygonList[bestA]));
                    openPolygonList[bestA].Clear();                     // B is cleared as it is A
                    endSorter.Remove(bestA);
                    startSorter.Remove(bestA);
                }
                else
                {
                    if (reversed)
                    {
                        if (openPolygonList[bestA].Count > openPolygonList[bestB].Count)
                        {
                            for (int indexB = openPolygonList[bestB].Count - 1; indexB >= 0; indexB--)
                            {
                                openPolygonList[bestA].Add(openPolygonList[bestB][indexB]);
                            }

                            openPolygonList[bestB].Clear();
                            endSorter.Remove(bestB);
                            startSorter.Remove(bestB);
                        }
                        else
                        {
                            for (int indexA = openPolygonList[bestA].Count - 1; indexA >= 0; indexA--)
                            {
                                openPolygonList[bestB].Add(openPolygonList[bestA][indexA]);
                            }

                            openPolygonList[bestA].Clear();
                            endSorter.Remove(bestA);
                            startSorter.Remove(bestA);
                        }
                    }
                    else
                    {
                        openPolygonList[bestA].AddRange(openPolygonList[bestB]);
                        openPolygonList[bestB].Clear();
                        endSorter.Remove(bestB);
                        startSorter.Remove(bestB);
                    }
                }
            }

            double minimumPerimeter = .01;

            for (int polygonIndex = 0; polygonIndex < closedPolygons.Count; polygonIndex++)
            {
                double perimeterLength = 0;

                for (int intPointIndex = 1; intPointIndex < closedPolygons[polygonIndex].Count; intPointIndex++)
                {
                    perimeterLength += (closedPolygons[polygonIndex][intPointIndex] - closedPolygons[polygonIndex][intPointIndex - 1]).Length();
                    if (perimeterLength > minimumPerimeter)
                    {
                        break;
                    }
                }
                if (perimeterLength < minimumPerimeter)
                {
                    closedPolygons.RemoveAt(polygonIndex);
                    polygonIndex--;
                }
            }

            return(Clipper.CleanPolygons(closedPolygons, 10));
        }
Пример #37
0
		public static Polygons CreateLineDifference(this Polygons linePolygons, Polygons removePolygons)
		{
			Clipper clipper = new Clipper();

			clipper.AddPaths(linePolygons, PolyType.ptSubject, false);
			clipper.AddPaths(removePolygons, PolyType.ptClip, true);

			PolyTree clippedLines = new PolyTree();

			clipper.Execute(ClipType.ctDifference, clippedLines);

			return Clipper.OpenPathsFromPolyTree(clippedLines);
		}
        /// <summary>
        /// Inits DirectDraw and map.
        /// </summary>
        public void InitDraw()
        {
            _map = new Map(this, MAP_WIDTH_CELLS, MAP_HEIGHT_CELLS);
            var clipper = new Clipper {Window = _parentControl};
            _renderRect = new Rectangle(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
            _mapRect = new Rectangle(
                0,
                MAP_TOP_BORDER_OFFSET,
                MAP_WIDTH_CELLS * CELL_SIZE,
                MAP_HEIGHT_CELLS * CELL_SIZE);

            _fDirectDraw = new Device();
            _fDirectDraw.SetCooperativeLevel(_parentControl, CooperativeLevelFlags.Normal);

            //            _fDirectDraw.SetCooperativeLevel(_parentControl, CooperativeLevelFlags.FullscreenExclusive);
            //            _fDirectDraw.SetDisplayMode(SCREEN_WIDTH, SCREEN_HEIGHT, BIT_DEPTH, 0, false);

            var ddPrimarySurfaceDesc = new SurfaceDescription
                                           {
                                               SurfaceCaps = new SurfaceCaps
                                                                 {
                                                                     PrimarySurface = true,
                                                                     VideoMemory = true
                                                                 }
                                           };

            _fPrimarySurface = new Surface(ddPrimarySurfaceDesc, _fDirectDraw)
                                   {
                                       Clipper = clipper
                                   };

            var ddBackSurfaceDesc = new SurfaceDescription
                                    {
                                        SurfaceCaps =
                                            {
                                                OffScreenPlain = true,
                                                VideoMemory = true
                                            },
                                        Width = _renderRect.Width,
                                        Height = _renderRect.Height
                                    };

            _backSurface = new Surface(ddBackSurfaceDesc, _fDirectDraw);

            var ddSurfaceDesc2 = new SurfaceDescription
            {
                SurfaceCaps =
                {
                    OffScreenPlain = true,
                    VideoMemory = true
                },
                Width = MAP_WIDTH_CELLS * CELL_SIZE,
                Height = MAP_HEIGHT_CELLS * CELL_SIZE
            };
            MapSurface = new Surface(ddSurfaceDesc2, _fDirectDraw);

            BackSurface.ColorFill(Color.Black);
        }
        private void CreateSurfaces()
        {
            SurfaceDescription desc = new SurfaceDescription();
            SurfaceCaps caps = new SurfaceCaps();

            localClipper = new Clipper(localDevice);
            localClipper.Window = owner;

            desc.SurfaceCaps.PrimarySurface = true;
            if (null != surfacePrimary)
                surfacePrimary.Dispose();
            surfacePrimary = new Surface(desc, localDevice);
            surfacePrimary.Clipper = localClipper;

            desc.Clear();
            desc.SurfaceCaps.OffScreenPlain = true;
            desc.Width = surfacePrimary.SurfaceDescription.Width;
            desc.Height = surfacePrimary.SurfaceDescription.Height;

            if (null != surfaceSecondary)
                surfaceSecondary.Dispose();
            surfaceSecondary = new Surface(desc, localDevice);
            surfaceSecondary.FillStyle = 0;
        }
Пример #40
0
 private static void AddPath(Clipper clipper, Path path) {
     foreach (Subpath subpath in path.Subpaths) {
         if (!subpath.IsSinglePointClosed() && !subpath.IsSinglePointOpen()) {
             IList<Point2D> linearApproxPoints = subpath.GetPiecewiseLinearApproximation();
             clipper.AddPath(ConvertToIntPoints(linearApproxPoints), PolyType.ptSubject, subpath.Closed);
         }
     }
 }
 private static void AddRect(Clipper clipper, Point2D[] rectVertices, PolyType polyType)
 {
     clipper.AddPath(ConvertToIntPoints(new List <Point2D>(rectVertices)), polyType, true);
 }
Пример #42
0
        private bool Intersect(Point2D[] rect1, Point2D[] rect2) {
            Clipper clipper = new Clipper();
            AddRect(clipper, rect1, PolyType.ptSubject);
            AddRect(clipper, rect2, PolyType.ptClip);

            List<List<IntPoint>> paths = new List<List<IntPoint>>();
            clipper.Execute(ClipType.ctIntersection, paths, PolyFillType.pftNonZero, PolyFillType.pftNonZero);

            return paths.Count != 0;
        }
Пример #43
0
        public override void Check(IEnumerable <Autodesk.AutoCAD.DatabaseServices.ObjectId> selectedObjectIds)
        {
            if (!selectedObjectIds.Any())
            {
                return;
            }

            var precision = 0.000001;
            // First we need to make sure all intersections are vertices of polygon
            var missingVertexSearcher = new MissingVertexSearcherQuadTree(Editor);

            missingVertexSearcher.Check(selectedObjectIds);
            if (missingVertexSearcher.MissingVertexInfos.Any())
            {
                missingVertexSearcher.FixAll();
            }

            // Use clipper to search holes
            var subject = new List <List <IntPoint> >(1);
            var clipper = new List <List <IntPoint> >(1);

            var       database = Editor.Document.Database;
            Extents3d extents  = new Extents3d(new Point3d(0, 0, 0), new Point3d(1, 1, 0));
            bool      first    = true;

            // Use all polygons to make up clipper.
            using (var transaction = database.TransactionManager.StartTransaction())
            {
                foreach (var objId in selectedObjectIds)
                {
                    var curve = transaction.GetObject(objId, OpenMode.ForRead) as Curve;
                    if (curve == null)
                    {
                        continue;
                    }
                    if (!IsCurveClosed(curve))
                    {
                        continue;
                    }

                    // Calculate its extents.
                    if (first)
                    {
                        extents = curve.GeometricExtents;
                        first   = false;
                    }
                    else
                    {
                        extents.AddExtents(curve.GeometricExtents);
                    }

                    // Add it to the clipper.
                    var vertices = CurveUtils.GetDistinctVertices2D(curve, transaction);
                    // Only for polygon.
                    if (vertices.Count() < 3)
                    {
                        continue;
                    }

                    // That has the same vertex for the first and last array members.
                    if (vertices[0] != vertices[vertices.Count - 1])
                    {
                        vertices.Add(vertices[0]);
                    }
                    var clockwise = ComputerGraphics.ClockWise2(vertices.ToArray());
                    if (!clockwise)
                    {
                        vertices.Reverse();
                    }
                    if (vertices[0] == vertices[vertices.Count - 1])
                    {
                        vertices.RemoveAt(vertices.Count - 1);
                    }

                    clipper.Add(vertices.Select(it => new IntPoint(it.X / precision, it.Y / precision)).ToList());
                }
                transaction.Commit();
            }

            // Create subject rectangle.

            var vector   = (extents.MaxPoint - extents.MinPoint) * 0.1;
            var minPoint = extents.MinPoint - vector;
            var maxPoint = extents.MaxPoint + vector;

            subject.Add(new List <IntPoint>()
            {
                new IntPoint(minPoint.X / precision, minPoint.Y / precision),
                new IntPoint(minPoint.X / precision, maxPoint.Y / precision),
                new IntPoint(maxPoint.X / precision, maxPoint.Y / precision),
                new IntPoint(maxPoint.X / precision, minPoint.Y / precision)
            });


            var result = new List <List <IntPoint> >();
            var cpr    = new Clipper();

            cpr.AddPaths(subject, PolyType.ptSubject, true);
            cpr.AddPaths(clipper, PolyType.ptClip, true);
            cpr.Execute(ClipType.ctXor, result, PolyFillType.pftNonZero, PolyFillType.pftNonZero);
            if (result.Count <= 0)
            {
                return;
            }

            foreach (var path in result)
            {
                // Ignore the outmost loop.
                if (path.Contains(new IntPoint(minPoint.X / precision, minPoint.Y / precision)))
                {
                    continue;
                }

                var points = path.Select(it => new Point2d(it.X * precision, it.Y * precision)).ToList();
                if (points[0] != points[points.Count - 1])
                {
                    points.Add(points[0]);
                }
                var array = points.ToArray();
                if (ComputerGraphics.ClockWise2(array))
                {
                    continue;
                }

                var polyline = CreatePolygon(array);
                if (polyline.Area.Smaller(0.001))
                {
                    polyline.Dispose();
                    continue;
                }

                _holes.Add(polyline);
            }
        }
        /// <summary>
        /// Gets the Isovist polygon.
        /// </summary>
        /// <param name="vantagePoint">The vantage point.</param>
        /// <param name="viewDepth">The view depth.</param>
        /// <param name="edges">The edges.</param>
        /// <returns>BarrierPolygons.</returns>
        public BarrierPolygon IsovistPolygon(UV vantagePoint, double viewDepth, HashSet <UVLine> edges)
        {
            /*first and expand and shrink operation is performed to merge the shadowing edges*/
            double expandShrinkFactor = Math.Pow(10.0, this.PolygonalBooleanPrecision) * UnitConversion.Convert(0.075, Length_Unit_Types.FEET, UnitType);
            //offsetting the excluded area of each edge
            INTPolygons   offsetedPolygons = new INTPolygons();
            ClipperOffset clipperOffset    = new ClipperOffset();

            foreach (UVLine edgeItem in edges)
            {
                clipperOffset.AddPath(this.excludedArea(vantagePoint, viewDepth + 1, edgeItem), ClipperLib.JoinType.jtMiter, EndType.etClosedPolygon);
                INTPolygons plygns = new INTPolygons();
                clipperOffset.Execute(ref plygns, expandShrinkFactor);
                offsetedPolygons.AddRange(plygns);
                clipperOffset.Clear();
            }
            //Unioning the expanded exclusions
            INTPolygons offsetUnioned = new INTPolygons();
            Clipper     c             = new Clipper();

            c.AddPaths(offsetedPolygons, PolyType.ptSubject, true);
            c.Execute(ClipType.ctUnion, offsetUnioned, PolyFillType.pftNonZero, PolyFillType.pftNonZero);
            //shrink the polygons to retain their original size
            INTPolygons results = new INTPolygons();

            clipperOffset.Clear();
            clipperOffset.AddPaths(offsetUnioned, JoinType.jtMiter, EndType.etClosedPolygon);
            clipperOffset.Execute(ref results, -expandShrinkFactor);
            clipperOffset.Clear();
            offsetUnioned.Clear();

            /*
             * What ever is a hole in the resulting mereged polygon is the visibility polygon
             * Now we classify the polygons based on being a hole or not
             */
            //filtering out the holes that do not include the center
            INTPolygons holesNOT             = new INTPolygons();
            INTPolygons holesIncludingCenter = new INTPolygons();
            IntPoint    iCenter = ConvertUVToIntPoint(vantagePoint);

            foreach (INTPolygon item in results)
            {
                if (!Clipper.Orientation(item))
                {
                    if (Clipper.PointInPolygon(iCenter, item) == 1)
                    {
                        holesIncludingCenter.Add(item);
                    }
                }
                else
                {
                    holesNOT.Add(item);
                }
            }
            if (holesIncludingCenter.Count == 0)
            {
                //there is no hole. The shadow polygones should clip the potential field of visibility (i.e. circle) by an subtraction operation
                INTPolygon circle = createCircle(vantagePoint, viewDepth);
                //subtraction
                c.Clear();
                c.AddPath(circle, PolyType.ptSubject, true);
                c.AddPaths(holesNOT, PolyType.ptClip, true);
                INTPolygons isovistPolygon = new INTPolygons();
                c.Execute(ClipType.ctDifference, isovistPolygon);
                //searching for a polygon that includes the center
                foreach (INTPolygon item in isovistPolygon)
                {
                    if (Clipper.PointInPolygon(iCenter, item) == 1)
                    {
                        BarrierPolygon isovist = this.ConvertINTPolygonToBarrierPolygon(item);
                        results              = null;
                        c                    = null;
                        clipperOffset        = null;
                        offsetedPolygons     = null;
                        circle               = null;
                        holesNOT             = null;
                        holesIncludingCenter = null;
                        isovistPolygon       = null;
                        return(isovist);
                    }
                }
                MessageBox.Show(string.Format("Isovist not found!\nNo hole detected\n{0} polygons can be isovist", isovistPolygon.Count.ToString()));
            }
            else if (holesIncludingCenter.Count == 1)
            {
                INTPolygons isovistPolygon = holesIncludingCenter;
                foreach (INTPolygon item in isovistPolygon)
                {
                    if (Clipper.PointInPolygon(iCenter, item) == 1)
                    {
                        item.Reverse();
                        BarrierPolygon isovist = this.ConvertINTPolygonToBarrierPolygon(item);
                        results              = null;
                        c                    = null;
                        clipperOffset        = null;
                        offsetedPolygons     = null;
                        holesNOT             = null;
                        holesIncludingCenter = null;
                        isovistPolygon       = null;
                        return(isovist);
                    }
                }
                MessageBox.Show(string.Format("Isovist not found!\nOne hole detected\n{0} polygons can be isovist", isovistPolygon.Count.ToString()));
            }
            else if (holesIncludingCenter.Count > 1)
            {
                MessageBox.Show("Isovist not found!\nMore than one hole found that can include the vantage point");
            }
            return(null);
        }
Пример #45
0
        public override void Render(Graphics ctx, float dt)
        {
            preferredSize        = ctx.MeasureString(Text, Font).ToSize();
            preferredSize.Width += 10;

            var state = ctx.Save();

            var sf = new StringFormat();

            var baseOp = Fill.A / 255.0f;

            var anim     = ActiveAnimation;
            var clipping = false;
            var opacity  = (int)(Opacity * 255.0f * baseOp);

            Rectangle clipBounds = Rectangle.Empty;

            if (anim != null)
            {
                if (anim is Reveal)
                {
                    clipBounds = AnimatableProperties.Bounds;
                    clipping   = true;
                }
                else if (anim is Fade)
                {
                    opacity = (int)(AnimatableProperties.Opacity * 255.0f * baseOp);
                }
            }

            opacity = Math.Max(0, Math.Min(opacity, 255));
            var sb = new SolidBrush(Color.FromArgb(opacity, Fill));

            switch (HorizontalAlign)
            {
            case Alignment.Near: sf.Alignment = StringAlignment.Near; break;

            case Alignment.Center: sf.Alignment = StringAlignment.Center; break;

            case Alignment.Far: sf.Alignment = StringAlignment.Far; break;
            }

            switch (VerticalAlign)
            {
            case Alignment.Near: sf.LineAlignment = StringAlignment.Near; break;

            case Alignment.Center: sf.LineAlignment = StringAlignment.Center; break;

            case Alignment.Far: sf.LineAlignment = StringAlignment.Far; break;
            }

            var sz = GetPreferredSize();

            var clip = new Region(new Rectangle(Bounds.Location, sz));

            if (clipping)
            {
                clip.Intersect(clipBounds);
            }

            if (Clipper != null)
            {
                if (!clipping)
                {
                    clip.Intersect(Clipper.GetClipPath(ctx, Clipper.Bounds));
                }
                else
                {
                    clip.Intersect(Clipper.Bounds);
                }

                if (Clipper.AnimationPlaying)
                {
                    clip.Intersect(Clipper.GetClipPath(ctx, Clipper.AnimatableProperties.Bounds));
                }
            }

            ctx.Clip = clip;

            //List<Line> lines = GetLines(ctx);
            //var boxHeight = lines.Select(l => l.Height).Aggregate((a, b) => a + b);
            //var boxWidth = 0.0;
            //foreach (var line in lines) boxWidth = Math.Max(boxWidth, line.Width);

            //float y = Bounds.Height / 2.0f;
            //switch (VerticalAlign) {
            //	case Alignment.Near: y += 0; break;
            //	case Alignment.Center: y += (Bounds.Height / 2 - boxHeight / 2); break;
            //	case Alignment.Far: y += (Bounds.Height - boxHeight); break;
            //}

            ctx.DrawString(Text, Font, sb, new RectangleF(Bounds.X, Bounds.Y, sz.Width, sz.Height), sf);
            //foreach (var line in lines) {
            //	float x = Bounds.Width / 2.0f;
            //	//switch (HorizontalAlign) {
            //	//	case Alignment.Near: x = 0; break;
            //	//	case Alignment.Center: x = (Bounds.Width / 2 - line.Width / 2); break;
            //	//	case Alignment.Far: x = (Bounds.Width - line.Width); break;
            //	//}

            //	ctx.DrawString(line.Text, Font, sb, x + Bounds.X, y + Bounds.Y);

            //	y += line.Height;
            //}
            ctx.ResetClip();
            ctx.Restore(state);
        }
Пример #46
0
        public static List<Polygons> CreateLayerOutlines(this Polygons polygons, LayerOpperation opperation)
        {
            List<Polygons> ret = new List<Polygons>();
            Clipper clipper = new Clipper();
            PolyTree resultPolyTree = new PolyTree();
            clipper.AddPaths(polygons, PolyType.ptSubject, true);
            if (opperation == LayerOpperation.UnionAll)
            {
                clipper.Execute(ClipType.ctUnion, resultPolyTree, PolyFillType.pftNonZero, PolyFillType.pftNonZero);
            }
            else
            {
                clipper.Execute(ClipType.ctUnion, resultPolyTree);
            }

            polygons._processPolyTreeNode(resultPolyTree, ret);
            return ret;
        }
Пример #47
0
        public override void Render(Graphics ctx, float dt)
        {
            var state = ctx.Save();

            var anim     = ActiveAnimation;
            var opacity  = Opacity;
            var clipping = false;

            Rectangle clipBounds = Rectangle.Empty;

            if (anim != null)
            {
                if (anim is Reveal)
                {
                    clipBounds = AnimatableProperties.Bounds;
                    clipping   = true;
                }
                else if (anim is Fade)
                {
                    opacity = AnimatableProperties.Opacity;
                }
            }

            opacity = Math.Max(0.0f, Math.Min(opacity, 1.0f));

            ColorMatrix colormatrix = new ColorMatrix();

            colormatrix.Matrix33 = opacity;

            ImageAttributes attr = new ImageAttributes();

            attr.SetColorMatrix(colormatrix, ColorMatrixFlag.Default, ColorAdjustType.Bitmap);

            var clip = new Region(Bounds);

            if (clipping)
            {
                clip.Intersect(clipBounds);
            }

            if (Clipper != null)
            {
                if (!clipping)
                {
                    clip.Intersect(Clipper.GetClipPath(ctx, Clipper.Bounds));
                }
                else
                {
                    clip.Intersect(Clipper.Bounds);
                }

                if (Clipper.AnimationPlaying)
                {
                    clip.Intersect(Clipper.GetClipPath(ctx, Clipper.AnimatableProperties.Bounds));
                }
            }

            ctx.Clip = clip;
            if (Image != null)
            {
                ctx.DrawImage(Image, new Rectangle(Bounds.X, Bounds.Y, Bounds.Width, Bounds.Height), Source.X, Source.Y, Source.Width, Source.Height, GraphicsUnit.Pixel, attr);
            }
            else
            {
                ctx.FillRectangle(Brushes.Magenta, Bounds);
            }
            ctx.ResetClip();
            ctx.Restore(state);
        }
Пример #48
0
 public static Polygons ProcessEvenOdd(this Polygons polygons)
 {
     Polygons ret = new Polygons();
     Clipper clipper = new Clipper();
     clipper.AddPaths(polygons, PolyType.ptSubject, true);
     clipper.Execute(ClipType.ctUnion, ret);
     return ret;
 }
Пример #49
0
        // RAIL

        public void genrateRail()
        {
            // generate a rail for all three: difference, intersection, union


            if (inputs.Count == 0)
            {
                return;
            }


            PolyFillType subjPolyFillType = PolyFillType.pftNonZero;
            //if (hasHoles)
            //subjPolyFillType = PolyFillType.pftPositive;


            //* organize by solids, holes (from SOLID designation) and clippers (from VOID designation)
            Paths subjPaths = new Paths();
            Paths clipPaths = new Paths();

            AXParameter inp = null;
            AXParameter src = null;


            Paths segments = new Paths();
            Path  tmp      = null;


            for (int i = 0; i < inputs.Count; i++)
            {
                inp = inputs [i];
                src = inp.DependsOn;

                if (src == null)
                {
                    continue;
                }

                Paths srcPaths = src.getPaths();

                if (srcPaths == null)
                {
                    continue;
                }

                if (inp.polyType == PolyType.ptSubject)
                {
                    subjPaths.AddRange(srcPaths);


                    foreach (Path sp in srcPaths)
                    {
                        // When clipping open shapes, don't add a closingsegment:
                        int ender = (inp.shapeState == ShapeState.Open) ? sp.Count - 1 : sp.Count;

                        for (int j = 0; j < ender; j++)
                        {
                            int next_j = (j == sp.Count - 1) ? 0 : j + 1;
                            tmp = new Path();
                            tmp.Add(sp[j]);
                            tmp.Add(sp[next_j]);
                            segments.Add(tmp);
                        }
                    }

                    //subjPaths.AddRange (src.getTransformedHolePaths());
                }
                else if (inp.polyType == PolyType.ptClip)
                {
                    clipPaths.AddRange(srcPaths);
                    //clipPaths.AddRange (src.getTransformedHolePaths());
                }
                else
                {
                    continue;
                }
            }


            // turn subjs and holes into segments to be clipped
//			foreach(Path sp in subjPaths)
//			{
//				// each path
//				//int ender =
//				for(int i=0; i<sp.Count-1; i++)
//				{
//					int next_i = (i == sp.Count-1) ? 0 : i+1;
//					tmp = new Path();
//					tmp.Add (sp[i]);
//					tmp.Add (sp[next_i]);
//					segments.Add(tmp);
//				}
//			}

            //Debug.Log ("segments");
            //Archimatix.printPaths(segments);

            Clipper railc = new Clipper(Clipper.ioPreserveCollinear);

            if (segments != null)
            {
                railc.AddPaths(segments, PolyType.ptSubject, false);
            }

            if (clipPaths != null)
            {
                railc.AddPaths(clipPaths, PolyType.ptClip, true);
            }

            AXClipperLib.PolyTree solutionRail = new AXClipperLib.PolyTree();



            // DIFFERENCE_RAIL
            if ((differenceRail.Dependents != null && differenceRail.Dependents.Count > 0) || combineType == CombineType.DifferenceRail)
            {
                // Execute Difference
                railc.Execute(ClipType.ctDifference, solutionRail, subjPolyFillType, PolyFillType.pftNonZero);


                differenceRail.polyTree = null;


                differenceRail.paths = assembleRailPathsFromClippedSegments(solutionRail);



//				Debug.Log("******** " + differenceRail.paths.Count);
//				Pather.printPaths(differenceRail.paths);


                if (differenceRail.paths.Count == 0)
                {
                    differenceRail.paths = subjPaths;
                }

                if (differenceRail.paths.Count > 1)
                {
                    differenceRail.paths = Pather.cleanPaths(differenceRail.paths);
                }

//				Debug.Log("-- " + differenceRail.paths.Count);
//				Pather.printPaths(differenceRail.paths);


                alignPathsDirectionsWithSource(ref differenceRail.paths, ref segments);



                if (differenceRail.paths.Count > 1)
                {
                    joinPathsIfEndpointsMatch(ref differenceRail.paths);
                }



                thickenAndOffset(ref differenceRail, differenceRail);
            }

            // INTERSECTION RAIL
            if ((intersectionRail.Dependents != null && intersectionRail.Dependents.Count > 0) || combineType == CombineType.IntersectionRail)
            {
                //railc.Execute(ClipType.ctIntersection, solutionRail, subjPolyFillType, PolyFillType.pftNonZero);
                railc.Execute(ClipType.ctIntersection, solutionRail, PolyFillType.pftEvenOdd, PolyFillType.pftEvenOdd);

                intersectionRail.polyTree = null;

                intersectionRail.paths = assembleRailPathsFromClippedSegments(solutionRail);
                if (intersectionRail.paths.Count == 0)
                {
                    AXGeometryTools.Utilities.reversePaths(ref intersectionRail.paths);
                }

                alignPathsDirectionsWithSource(ref intersectionRail.paths, ref segments);

                thickenAndOffset(ref intersectionRail, intersectionRail);
            }
        }
Пример #50
0
		/// <summary>
		/// Subtract 2 polygon coordinates by top - bottom.
		/// </summary>
		/// <returns>The subtracted coordinates.</returns>
		/// <param name="top">Top polygon coordinates.</param>
		/// <param name="bottom">Bottom polygon coordinates.</param>
		public static IEnumerable<Coordinate> Subtract(IEnumerable<Coordinate> top, IEnumerable<Coordinate> bottom)
		{
			// Using Clipper library to do polygon operation.
			var clipper = new Clipper();

			var topPolies = new List<List<IntPoint>>();
			topPolies.Add(new List<IntPoint>());

			foreach(var c in top)
			{
				topPolies[0].Add(
					new IntPoint(Utils.ToLong(c.X), Utils.ToLong(c.Y)));
			}

			clipper.AddPaths(topPolies, PolyType.ptSubject, true);

			var bottomPolies = new List<List<IntPoint>>();
			bottomPolies.Add(new List<IntPoint>());

			foreach(var c in bottom)
			{
				bottomPolies[0].Add(
					new IntPoint(Utils.ToLong(c.X), Utils.ToLong(c.Y)));
			}

			clipper.AddPaths(bottomPolies, PolyType.ptClip, true);

			var solution = new List<List<IntPoint>>();

			clipper.Execute(ClipType.ctXor, solution, 
				PolyFillType.pftEvenOdd, PolyFillType.pftEvenOdd);

			var coords = new List<Coordinate>();

			foreach (var areas in solution)
			{
				foreach(var p in areas)
				{
					var c = new Coordinate() { X = Utils.ToDouble(p.X), Y = Utils.ToDouble(p.Y) };
					coords.Add(c);
				}
			}

			return coords;
		}
Пример #51
0
        //------------------------------------------------------------------------------
        public List<List<Point>> Execute(double deltap, double eps = double.Epsilon)
        {
            var solution = new List<List<Point>>();
            FixPerimeters();
            DoOffset(deltap, eps);
            //now clean up 'corners' ...

            var clpr = new Clipper();

            clpr.AddPaths(destPolys, PolyType.Subject);

            if (deltap > 0)
            {
                clpr.Execute(ClipType.Union, solution, PolyFillType.Positive, PolyFillType.Positive);
            }
            else
            {
                var r = destPolys.GetBounds();

                var outer = new List<Point>(4)
                {
                    new Point(r.Left - 10, r.Bottom + 10),
                    new Point(r.Right + 10, r.Bottom + 10),
                    new Point(r.Right + 10, r.Top - 10),
                    new Point(r.Left - 10, r.Top - 10)
                };

                clpr.AddPath(outer, PolyType.Subject);
                clpr.ReverseSolution = true;
                clpr.Execute(ClipType.Union, solution, PolyFillType.Negative, PolyFillType.Negative);
                if (solution.Count > 0) solution.RemoveAt(0);
            }

            return solution;
        }