private static IList <CutSubcurve> CalculateReshapeLines(
            [NotNull] IList <IFeature> sourceFeatures,
            [NotNull] IList <IFeature> targetFeatures,
            [NotNull] CalculateReshapeLinesRequest request,
            [CanBeNull] ITrackCancel trackCancel,
            out ReshapeAlongCurveUsability usability)
        {
            Stopwatch watch = Stopwatch.StartNew();

            IEnvelope visibleExtent;
            ReshapeCurveFilterOptions filterOptions =
                GetLineFilterOptions(request.FilterOptions, out visibleExtent);

            TargetBufferOptions targetBufferOptions =
                GetTargetBufferOptions(request.TargetBufferOptions);

            IList <CutSubcurve> resultLines = new List <CutSubcurve>();

            usability = ChangeGeometryAlongUtils.CalculateReshapeCurves(
                sourceFeatures, targetFeatures, visibleExtent,
                request.Tolerance, targetBufferOptions, filterOptions,
                resultLines, trackCancel);

            _msg.DebugStopTiming(watch, "Calculated {0} reshape lines", resultLines.Count);

            return(resultLines);
        }
        private static ReshapeCurveFilterOptions GetLineFilterOptions(
            [CanBeNull] ReshapeLineFilterOptionsMsg filterOptionsMsg,
            [CanBeNull] out IEnvelope visibleExtent)
        {
            visibleExtent = null;

            if (filterOptionsMsg == null)
            {
                return(new ReshapeCurveFilterOptions());
            }

            var result = new ReshapeCurveFilterOptions(
                filterOptionsMsg.ClipLinesOnVisibleExtent,
                filterOptionsMsg.ExcludeOutsideTolerance,
                filterOptionsMsg.ExcludeOutsideSource,
                filterOptionsMsg.ExcludeResultingInOverlaps);

            List <IEnvelope> extents = filterOptionsMsg.VisibleExtents.Select(
                ProtobufGeometryUtils.FromEnvelopeMsg)
                                       .ToList();

            // TODO: Determine the policy on the main map extent vs. any visible extent?
            visibleExtent = extents.Count > 0 ? extents[0] : null;

            return(result);
        }
        private static GeometryReshaperBase CreateReshaper(
            [NotNull] ApplyReshapeLinesRequest request)
        {
            GetFeatures(request.CalculationRequest.SourceFeatures,
                        request.CalculationRequest.TargetFeatures,
                        request.CalculationRequest.ClassDefinitions,
                        out IList <IFeature> sourceFeatures, out IList <IFeature> targetFeatures);

            GeometryReshaperBase reshaper =
                sourceFeatures.Count == 1
                                        ? (GeometryReshaperBase) new GeometryReshaper(sourceFeatures[0])
                                        : new MultipleGeometriesReshaper(sourceFeatures)
            {
                MultipleSourcesTreatIndividually = true,
                MultipleSourcesTreatAsUnion      = false
            };

            if (request.InsertVerticesInTarget)
            {
                reshaper.TargetFeatures = targetFeatures;
            }

            IEnvelope visibleExtent;
            ReshapeCurveFilterOptions filterOptions =
                GetLineFilterOptions(request.CalculationRequest.FilterOptions, out visibleExtent);

            IEnumerable <IFeature> unallowedOverlapFeatures = null;

            if (filterOptions.ExcludeResultingInOverlaps)
            {
                unallowedOverlapFeatures = targetFeatures;

                reshaper.RemoveClosedReshapePathAreas = true;
            }

            List <IEnvelope> allowedExtents =
                visibleExtent == null ? null : new List <IEnvelope> {
                visibleExtent
            };

            bool useMinimalTolerance = MathUtils.AreEqual(0, request.CalculationRequest.Tolerance);

            reshaper.ResultFilter = new ReshapeResultFilter(allowedExtents,
                                                            unallowedOverlapFeatures,
                                                            useMinimalTolerance);

            reshaper.ResultFilter.UseNonDefaultReshapeSide = request.UseNonDefaultReshapeSide;

            reshaper.UseMinimumTolerance = useMinimalTolerance;

            return(reshaper);
        }