static void Main(string[] args) { // Check if we need to print help by checking for -h or --help at the first or second index // Also, when fewer arguments are available, print the help int shortIndex = Array.IndexOf(args, "-h"); int longIndex = Array.IndexOf(args, "--help"); if (args.Length < 2 || shortIndex == 0 || shortIndex == 1 || longIndex == 0 || longIndex == 1) { PrintHelp(); return; } int commandIndex = 1; byte runOnDays = 0; if (args[1] == "--days") { commandIndex += 2; string[] splitDays = args[2].Split(","); for (int i = 0; i < splitDays.Length; i++) { if (splitDays[i].Length == 1) { // Attempt to parse it as an integer int dayIndex; if (int.TryParse(splitDays[i], out dayIndex)) { Day?foundIntDay = DayUtils.FindDay(dayIndex); if (foundIntDay.HasValue) { runOnDays |= (byte)foundIntDay.Value; continue; } } } // Attempt to find the day as valid string Day?foundStrDay = DayUtils.FindDay(splitDays[i]); if (!foundStrDay.HasValue) { Console.Error.WriteLine($"Invalid day: {splitDays[i]}"); Environment.Exit(1); } runOnDays |= (byte)foundStrDay.Value; } } string commandFileName = args[commandIndex++]; string commandArguments = CommandAction.BuildArguments(args, commandIndex); IntervalRange[] intervals = IntervalRange.GetIntervals(args[0], Console.Error); if (intervals == null) { Environment.Exit(1); } IntervalScheduler intervalScheduler = new IntervalScheduler( new CommandAction(commandFileName, commandArguments), intervals); if (runOnDays != 0) { intervalScheduler.SetDayFlags(runOnDays); } intervalScheduler.RunScheduler(CancellationToken.None); }
/// <summary> /// Entrypoint of this program which parses the following arguments from the CLI: /// <list type="bullet"> /// <item><code>--raw-dir</code>: The path to output directory to put the raw downloaded files in</item> /// <item><code>--processed-dir</code>: The path to the directory to put the processed files in</item> /// <item><code>--fetch-url</code>: The url to download to use as raw data</item> /// </list> /// </summary> /// <param name="args">The arguments passed from the command line</param> public static void Main(string[] args) { List <string> arguments = new List <string>(); arguments.AddRange(args); // Print the help section when requested string[] helpLong = FindOption(arguments, "--help", 0); string[] helpShort = FindOption(arguments, "-h", 0); if (helpLong != null || helpShort != null) { PrintHelp(); return; } // First parse the interval, if available string[] intervalOption = FindOption(arguments, "--interval"); IntervalRange[] intervalRanges = null; if (intervalOption != null) { intervalRanges = IntervalRange.GetIntervals(intervalOption[0], Console.Error); if (intervalRanges == null) { Environment.Exit(1); } } DataWriterOption selectedOption = null; DataWriterOption[] availableOptions = { new DbDataWriterOption(), new FileDataWriterOption() }; foreach (DataWriterOption option in availableOptions) { if (option.isAvailable(arguments)) { if (!option.validArguments()) { Environment.Exit(1); } selectedOption = option; break; } } // Parse the arguments Options options = new Options { RawDataOutput = GetDirectory(arguments, "--raw-dir"), ProcessedDataOutput = GetDirectory(arguments, "--processed-dir"), ReaderOption = GetEnumOption <ReaderOption>(arguments, "--reader"), DataWriterOption = selectedOption, RemoveRawFiles = FindOption(arguments, "--remove-raw", 0) != null }; // Parse the Fetch url string[] urlOption = FindOption(arguments, "--fetch-url"); if (urlOption != null) { Uri fetchUrl; if (!Uri.TryCreate(urlOption[0], UriKind.Absolute, out fetchUrl) || (fetchUrl.Scheme != Uri.UriSchemeHttp && fetchUrl.Scheme != Uri.UriSchemeHttps)) { Console.Error.WriteLine($"Invalid fetch url {urlOption[0]}"); Environment.Exit(1); } options.FetchUri = fetchUrl; } BaseAction action = new DownloadAndProcessAction(options); if (intervalRanges == null) { action.Execute(); } else { IntervalScheduler intervalScheduler = new IntervalScheduler(action, intervalRanges); intervalScheduler.RunScheduler(CancellationToken.None); } }
private void InsertInternalInternal(IntLineSegment2 s, int sRangeId, double insertionThetaLower, double insertionThetaUpper, bool supportOverlappingLines, bool furthestSegmentWins) { // ReSharper disable once CompareOfFloatsByEqualityOperator if (insertionThetaLower == insertionThetaUpper) { return; } // See distrsxy for why this makes sense. // var sDist = _origin.To(sMidpoint).SquaredNorm2D(); var srange = new IntervalRange { Id = sRangeId, ThetaStart = insertionThetaLower, ThetaEnd = insertionThetaUpper, Segment = s }; var splittableBeginIndexInclusive = FindOverlappingRangeIndex(insertionThetaLower, 0, true); var splittableEndIndexInclusive = FindOverlappingRangeIndex(insertionThetaUpper, splittableBeginIndexInclusive, false); // a given segment can be split into 3 at max - technically this overallocates because it's impossible // for two 3-splits to happen in a row. Actually, assuming no overlaps one can only really produce // # splittables + 2 total new segments (new segments on left/right side). var n = new IntervalRange[(splittableEndIndexInclusive - splittableBeginIndexInclusive + 1) * 3]; //new IntervalRange[(splittableEndIndexInclusive - splittableBeginIndexInclusive + 1) + 2]; var nSize = 0; void EmitRange(int rangeId, ref IntLineSegment2 segment, double thetaStart, double thetaEnd) { if (thetaStart == thetaEnd) { return; } if (nSize > 0 && n[nSize - 1].Id == rangeId) { n[nSize - 1].ThetaEnd = thetaEnd; } else { n[nSize] = new IntervalRange { Id = rangeId, Segment = segment, ThetaStart = thetaStart, ThetaEnd = thetaEnd }; nSize++; } } // near and far unioned must cover thetaUpper void HandleNearFarSplit(IntervalRange nearRange, IntervalRange farRange, double thetaLower, double thetaUpper) { // case: near covers range if (nearRange.ThetaStart <= thetaLower && thetaUpper <= nearRange.ThetaEnd) { EmitRange(nearRange.Id, ref nearRange.Segment, thetaLower, thetaUpper); return; // return new[] { new IntervalRange { Id = nearRange.Id, ThetaStart = thetaLower, ThetaEnd = thetaUpper, Segment = nearRange.Segment } }; } // case: near exclusively within range if (thetaLower < nearRange.ThetaStart && nearRange.ThetaEnd < thetaUpper) { EmitRange(farRange.Id, ref farRange.Segment, thetaLower, nearRange.ThetaStart); EmitRange(nearRange.Id, ref nearRange.Segment, nearRange.ThetaStart, nearRange.ThetaEnd); EmitRange(farRange.Id, ref farRange.Segment, nearRange.ThetaEnd, thetaUpper); return; // return new[] { // new IntervalRange { Id = farRange.Id, ThetaStart = thetaLower, ThetaEnd = nearRange.ThetaStart, Segment = farRange.Segment}, // new IntervalRange { Id = nearRange.Id, ThetaStart = nearRange.ThetaStart, ThetaEnd = nearRange.ThetaEnd, Segment = nearRange.Segment }, // new IntervalRange { Id = farRange.Id, ThetaStart = nearRange.ThetaEnd, ThetaEnd = thetaUpper, Segment = farRange.Segment} // }; } // case: near covers left of range (as in, covers the lower thetas of range) if (nearRange.ThetaStart <= thetaLower && nearRange.ThetaEnd < thetaUpper) { EmitRange(nearRange.Id, ref nearRange.Segment, thetaLower, nearRange.ThetaEnd); EmitRange(farRange.Id, ref farRange.Segment, nearRange.ThetaEnd, thetaUpper); return; // return new[] { // new IntervalRange { Id = nearRange.Id, ThetaStart = thetaLower, ThetaEnd = nearRange.ThetaEnd, Segment = nearRange.Segment }, // new IntervalRange { Id = farRange.Id, ThetaStart = nearRange.ThetaEnd, ThetaEnd = thetaUpper, Segment = farRange.Segment } // }; } // case: near covers right of range if (nearRange.ThetaStart > thetaLower && thetaUpper <= nearRange.ThetaEnd) { EmitRange(farRange.Id, ref farRange.Segment, thetaLower, nearRange.ThetaStart); EmitRange(nearRange.Id, ref nearRange.Segment, nearRange.ThetaStart, thetaUpper); return; // return new[] { // new IntervalRange { Id = farRange.Id, ThetaStart = thetaLower, ThetaEnd = nearRange.ThetaStart, Segment = farRange.Segment }, // new IntervalRange { Id = nearRange.Id, ThetaStart = nearRange.ThetaStart, ThetaEnd = thetaUpper, Segment = nearRange.Segment } // }; } // impossible to reach here throw new Exception($"Impossible state at null split of {nameof(HandleNearFarSplit)}."); } void HandleSplit(IntervalRange range) { Debug.Assert(IsRangeOverlap(insertionThetaLower, insertionThetaUpper, range.ThetaStart, range.ThetaEnd)); if (range.Id == RANGE_ID_INFINITELY_FAR) { HandleNearFarSplit(srange, range, range.ThetaStart, range.ThetaEnd); return; } var rsxy = range.Segment; // // is this code necessary? Seems like not... though not sure why. We do have intersecting segments // // but the intersect is quite minor (just at corners)... DoubleVector2 intersection; // HACK: No segment-segment intersect point implemented // sxy.Intersects(rsxy) && GeometryOperations.TryFindLineLineIntersection(sxy, rsxy, out intersection) if (GeometryOperations.TryFindSegmentSegmentIntersection(ref s, ref rsxy, out intersection)) { // conceptually a ray from _origin to intersection hits s and rs at the same time. // If shifted perpendicular to angle of intersection, then the near segment emerges. var thetaIntersect = FindXYRadiansRelativeToOrigin(intersection.X, intersection.Y); if (range.ThetaStart <= thetaIntersect && thetaIntersect <= range.ThetaEnd) { var directionToLower = DoubleVector2.FromRadiusAngle(1.0, thetaIntersect - PiDiv2); var vsxy = s.First.To(s.Second).ToDoubleVector2().ToUnit(); var vrsxy = rsxy.First.To(rsxy.Second).ToDoubleVector2().ToUnit(); var lvsxy = vsxy.ProjectOntoComponentD(directionToLower) > 0 ? vsxy : -1.0 * vsxy; var lvrsxy = vrsxy.ProjectOntoComponentD(directionToLower) > 0 ? vrsxy : -1.0 * vrsxy; var originToIntersect = _origin.To(intersection); var clvsxy = lvsxy.ProjectOntoComponentD(originToIntersect); var clvrsxy = lvrsxy.ProjectOntoComponentD(originToIntersect); var isInserteeNearerAtLower = clvsxy < clvrsxy; // Console.WriteLine("IINAL: " + isInserteeNearerAtLower); if (isInserteeNearerAtLower) { HandleNearFarSplit(range, srange, range.ThetaStart, thetaIntersect); HandleNearFarSplit(srange, range, thetaIntersect, range.ThetaEnd); } else { HandleNearFarSplit(srange, range, range.ThetaStart, thetaIntersect); HandleNearFarSplit(range, srange, thetaIntersect, range.ThetaEnd); } return; } } // At here, one segment completely overlaps the other for the theta range // Either that, or inserted segment in front of (but not totally covering) range // Either way, it will always be the case that any point on the "near" segment is closer // to _origin than any point on the "far" segment assuming within correct theta. // I take center of segments as their endpoints are ambiguous between neighboring segments // of a polygon. // var distrsxy = range.MidpointDistanceToOriginSquared; bool ComputeIsInserteeNearer() { //range.Id != RANGE_ID_INFINITELY_FAR && (sRangeId == RANGE_ID_INFINITELY_FAR || _segmentComparer.Compare(s, rsxy) < 0); if (range.Id == RANGE_ID_INFINITELY_FAR) { return(true); } if (range.Id == RANGE_ID_INFINITESIMALLY_NEAR) { return(false); } if (srange.Id == RANGE_ID_INFINITELY_FAR) { return(false); } if (srange.Id == RANGE_ID_INFINITESIMALLY_NEAR) { return(true); } return(_segmentComparer.Compare(s, rsxy) < 0); } bool inserteeNearer = ComputeIsInserteeNearer(); var nearRange = inserteeNearer ? srange : range; var farRange = inserteeNearer ? range : srange; if (furthestSegmentWins) { (nearRange, farRange) = (farRange, nearRange); } HandleNearFarSplit(nearRange, farRange, range.ThetaStart, range.ThetaEnd); } // n.AddRange(_intervalRanges.Take(ibegin)); for (int it = splittableBeginIndexInclusive; it <= splittableEndIndexInclusive; it++) { HandleSplit(_intervalRanges[it]); } // n.AddRange(_intervalRanges.Skip(iend + 1)); bool segmentInserted = false; for (int i = 0; i < nSize && !segmentInserted; i++) { if (n[i].Id == srange.Id) { segmentInserted = true; } } if (!segmentInserted) { return; } var nhead = splittableBeginIndexInclusive; var ntail = _intervalRanges.Length - splittableEndIndexInclusive - 1; var result = new IntervalRange[nhead + nSize + ntail]; Array.Copy(_intervalRanges, 0, result, 0, nhead); Array.Copy(n, 0, result, nhead, nSize); Array.Copy(_intervalRanges, _intervalRanges.Length - ntail, result, nhead + nSize, ntail); _intervalRanges = result; }