Пример #1
0
        public async Task TimeSeriesInsightsTypeWithNumericVariable_ExpectsError()
        {
            // Arrange
            TimeSeriesInsightsClient client = GetClient();
            var    timeSeriesTypes          = new List <TimeSeriesType>();
            var    tsiTypeNamePrefix        = "type";
            var    timeSeriesTypesName      = Recording.GenerateAlphaNumericId(tsiTypeNamePrefix);
            string timeSeriesTypeId         = Recording.GenerateId();

            // Build Numeric variable
            // Below is an invalid expression
            var numExpression      = new TimeSeriesExpression("$event");
            var aggregation        = new TimeSeriesExpression("avg($value)");
            var numericVariable    = new NumericVariable(numExpression, aggregation);
            var variables          = new Dictionary <string, TimeSeriesVariable>();
            var variableNamePrefix = "numericVariableName";

            variables.Add(Recording.GenerateAlphaNumericId(variableNamePrefix), numericVariable);

            var type = new TimeSeriesType(timeSeriesTypesName, variables);

            type.Id = timeSeriesTypeId;
            timeSeriesTypes.Add(type);

            // Act and Assert
            await TestTimeSeriesTypeWhereErrorIsExpected(client, timeSeriesTypes, timeSeriesTypesName).ConfigureAwait(false);
        }
Пример #2
0
        private async Task RunQueryAggregateSeriesSample(TimeSeriesInsightsQueries queriesClient, TimeSeriesId tsId)
        {
            #region Snippet:TimeSeriesInsightsSampleQueryAggregateSeriesWithNumericVariable
            Console.WriteLine("\n\nQuery for the average temperature over the past 30 seconds, in 2-second time slots.\n");

            var numericVariable = new NumericVariable(
                new TimeSeriesExpression("$event.Temperature"),
                new TimeSeriesExpression("avg($value)"));

            var requestOptions = new QueryAggregateSeriesRequestOptions();
            requestOptions.InlineVariables["Temperature"] = numericVariable;
            requestOptions.ProjectedVariableNames.Add("Temperature");

            QueryAnalyzer aggregateSeriesQuery = queriesClient.CreateAggregateSeriesQuery(
                tsId,
                TimeSpan.FromSeconds(2),
                TimeSpan.FromSeconds(30),
                null,
                requestOptions);

            await foreach (TimeSeriesPoint point in aggregateSeriesQuery.GetResultsAsync())
            {
                double?averageTemperature = point.GetNullableDouble("Temperature");
                if (averageTemperature != null)
                {
                    Console.WriteLine($"{point.Timestamp} - Average temperature: {averageTemperature}.");
                }
            }
            #endregion Snippet:TimeSeriesInsightsSampleQueryAggregateSeriesWithNumericVariable

            #region Snippet:TimeSeriesInsightsSampleQueryAggregateSeriesWithAggregateVariable
            Console.WriteLine("\n\nCount the number of temperature events over the past 3 minutes, in 1-minute time slots.\n");

            // Get the count of events in 60-second time slots over the past 3 minutes
            DateTimeOffset endTime   = DateTime.UtcNow;
            DateTimeOffset startTime = endTime.AddMinutes(-3);

            var aggregateVariable = new AggregateVariable(
                new TimeSeriesExpression("count()"));

            var countVariableName = "Count";

            var aggregateSeriesRequestOptions = new QueryAggregateSeriesRequestOptions();
            aggregateSeriesRequestOptions.InlineVariables[countVariableName] = aggregateVariable;
            aggregateSeriesRequestOptions.ProjectedVariableNames.Add(countVariableName);

            QueryAnalyzer query = queriesClient.CreateAggregateSeriesQuery(
                tsId,
                startTime,
                endTime,
                TimeSpan.FromSeconds(60),
                aggregateSeriesRequestOptions);

            await foreach (TimeSeriesPoint point in query.GetResultsAsync())
            {
                long?temperatureCount = (long?)point.GetValue(countVariableName);
                Console.WriteLine($"{point.Timestamp} - Temperature count: {temperatureCount}");
            }
            #endregion Snippet:TimeSeriesInsightsSampleQueryAggregateSeriesWithAggregateVariable
        }
Пример #3
0
        private async Task RunQuerySeriesSampleWithInlineVariables(TimeSeriesInsightsQueries queriesClient, TimeSeriesId tsId)
        {
            // Query for two series, one with the temperature values in Celsius and another in Fahrenheit
            #region Snippet:TimeSeriesInsightsSampleQuerySeriesWithInlineVariables
            Console.WriteLine("\n\nQuery for temperature series in Celsius and Fahrenheit over the past 10 minutes.\n");

            var celsiusVariable = new NumericVariable(
                new TimeSeriesExpression("$event.Temperature"),
                new TimeSeriesExpression("avg($value)"));
            var fahrenheitVariable = new NumericVariable(
                new TimeSeriesExpression("$event.Temperature * 1.8 + 32"),
                new TimeSeriesExpression("avg($value)"));

            var querySeriesRequestOptions = new QuerySeriesRequestOptions();
            querySeriesRequestOptions.InlineVariables["TemperatureInCelsius"]    = celsiusVariable;
            querySeriesRequestOptions.InlineVariables["TemperatureInFahrenheit"] = fahrenheitVariable;

            QueryAnalyzer seriesQuery = queriesClient.CreateSeriesQuery(
                tsId,
                TimeSpan.FromMinutes(10),
                null,
                querySeriesRequestOptions);

            await foreach (TimeSeriesPoint point in seriesQuery.GetResultsAsync())
            {
                double?tempInCelsius    = (double?)point.GetValue("TemperatureInCelsius");
                double?tempInFahrenheit = (double?)point.GetValue("TemperatureInFahrenheit");

                Console.WriteLine($"{point.Timestamp} - Average temperature in Celsius: {tempInCelsius}. Average temperature in Fahrenheit: {tempInFahrenheit}.");
            }
            #endregion Snippet:TimeSeriesInsightsSampleQuerySeriesWithInlineVariables
        }
        public void NumericVariableChangeValueTest()
        {
            var variable = new NumericVariable(3.14);

            Assert.AreEqual(3.14, variable.Value);
            variable.Value = -36;
            Assert.AreEqual(-36, variable.Value);
        }
Пример #5
0
        private void CartesianToPolar(NumericVariable[] input, NumericVariable[] output)
        {
            double          x   = input[0].GetValue();
            double          y   = input[1].GetValue();
            NumericVariable r   = output[0];
            NumericVariable phi = output[1];

            r.Set(Math.Sqrt(x * x + y * y));
            phi.Set(Math.Atan2(y, x));
        }
Пример #6
0
 public void ExitSimplenumericvariable(BASICParser.SimplenumericvariableContext context)
 {
     currentSimpleNumericVariable = new SimpleNumericVariable(context.GetText());
     wasArray = false;
     if (!varFound)
     {
         letNumericVar = currentSimpleNumericVariable;
         varFound      = true;
     }
 }
Пример #7
0
        public void ExitNumericvariable(BASICParser.NumericvariableContext context)
        {
            currentNumericVariable = wasArray ? (NumericVariable)currentNumericArrayElement : (NumericVariable)currentSimpleNumericVariable;

            primaryOp = PrimaryOptions.VAR;
            if (currentInputLine != null)
            {
                currentInputLine.vars.Add(currentNumericVariable);
            }
        }
Пример #8
0
        public void TestRangeConstraint()
        {
            {
                var             solver = new SimpleConstraintSolver();
                NumericVariable a      = solver.CreateVariable("a");

                var r = new Range(3, 4, EPS);
                RangeConstraint.CreateRangeConstraint(a, r);
                solver.Solve(_noAbortCheck);
                Assert.AreEqual(r, a.Value);
            }
        }
Пример #9
0
        public async Task SeedAsync(InventoryDbContext context, ILogger <InventoryContextSeed> logger)
        {
            var policy = CreatePolicy(logger, nameof(InventoryContextSeed));

            await policy.ExecuteAsync(async() =>
            {
                if (!context.Groups.Any())
                {
                    var operatingSystems = GetOperatingSystems();
                    var servers          = GetFakeServers(operatingSystems);
                    var groups           = GetFakeGroups();

                    var sv = new StringVariable()
                    {
                        Name = "a", Value = "a"
                    };
                    var nv = new NumericVariable()
                    {
                        Name = "b", Value = 1
                    };
                    var lv = new List <Variable>()
                    {
                        sv, nv
                    };

                    groups[0].Variables = lv;

                    foreach (Server srv in servers)
                    {
                        //srv.Variables = lv;

                        var group = groups.Single(grp => grp.Name == srv.OperatingSystem.Name);
                        group.AddServer(srv);
                    }

                    context.OperatingSystems.AddRange(operatingSystems);
                    context.Groups.AddRange(groups);
                    context.Servers.AddRange(servers);

                    await context.SaveChangesAsync();
                }
            });
        }
        public async Task TimeSeriesInsightsQuery_AggregateSeriesWithNumericVariable()
        {
            // Arrange
            TimeSeriesInsightsClient tsiClient    = GetClient();
            DeviceClient             deviceClient = await GetDeviceClient().ConfigureAwait(false);

            // Figure out what the Time Series Id is composed of
            TimeSeriesModelSettings modelSettings = await tsiClient.ModelSettings.GetAsync().ConfigureAwait(false);

            // Create a Time Series Id where the number of keys that make up the Time Series Id is fetched from Model Settings
            TimeSeriesId tsiId = await GetUniqueTimeSeriesInstanceIdAsync(tsiClient, modelSettings.TimeSeriesIdProperties.Count)
                                 .ConfigureAwait(false);

            try
            {
                // Send some events to the IoT hub with with a second between each event
                await QueryTestsHelper.SendEventsToHubAsync(
                    deviceClient,
                    tsiId,
                    modelSettings.TimeSeriesIdProperties.ToArray(),
                    30)
                .ConfigureAwait(false);

                DateTimeOffset now       = Recording.UtcNow;
                DateTimeOffset endTime   = now.AddMinutes(10);
                DateTimeOffset startTime = now.AddMinutes(-10);

                var temperatureNumericVariable = new NumericVariable(
                    new TimeSeriesExpression($"$event.{QueryTestsHelper.Temperature}"),
                    new TimeSeriesExpression("avg($value)"));

                var queryAggregateSeriesRequestOptions = new QueryAggregateSeriesRequestOptions();
                queryAggregateSeriesRequestOptions.InlineVariables[QueryTestsHelper.Temperature] = temperatureNumericVariable;
                queryAggregateSeriesRequestOptions.ProjectedVariables.Add(QueryTestsHelper.Temperature);

                // This retry logic was added as the TSI instance are not immediately available after creation
                await TestRetryHelper.RetryAsync <AsyncPageable <QueryResultPage> >(async() =>
                {
                    QueryAnalyzer queryAggregateSeriesPages = tsiClient.Queries.CreateAggregateSeriesQueryAnalyzer(
                        tsiId,
                        startTime,
                        endTime,
                        TimeSpan.FromSeconds(5),
                        queryAggregateSeriesRequestOptions);

                    var nonNullFound = false;
                    await foreach (Page <TimeSeriesPoint> aggregateSeriesPage in queryAggregateSeriesPages.GetResultsAsync().AsPages())
                    {
                        foreach (TimeSeriesPoint point in aggregateSeriesPage.Values)
                        {
                            point.GetUniquePropertyNames().Should().HaveCount(1).And.Contain((property) => property == QueryTestsHelper.Temperature);
                            var value = (double?)point.GetValue(QueryTestsHelper.Temperature);
                            if (value != null)
                            {
                                nonNullFound = true;
                            }
                        }

                        nonNullFound.Should().BeTrue();
                    }

                    queryAggregateSeriesPages.Progress.Should().Be(100);

                    return(null);
                }, MaxNumberOfRetries, s_retryDelay);

                // Add an interpolated variable
                var linearInterpolationNumericVariable = new NumericVariable(
                    new TimeSeriesExpression($"$event.{QueryTestsHelper.Temperature}"),
                    new TimeSeriesExpression("left($value)"));

                linearInterpolationNumericVariable.Interpolation = new InterpolationOperation
                {
                    Kind     = InterpolationKind.Linear,
                    Boundary = new InterpolationBoundary()
                    {
                        Span = TimeSpan.FromSeconds(1),
                    },
                };

                const string linearInterpolation = "linearInterpolation";
                queryAggregateSeriesRequestOptions.InlineVariables[linearInterpolation] = linearInterpolationNumericVariable;
                queryAggregateSeriesRequestOptions.ProjectedVariables.Add(linearInterpolation);

                await TestRetryHelper.RetryAsync <AsyncPageable <QueryResultPage> >(async() =>
                {
                    QueryAnalyzer queryAggregateSeriesPages = tsiClient.Queries.CreateAggregateSeriesQueryAnalyzer(
                        tsiId,
                        startTime,
                        endTime,
                        TimeSpan.FromSeconds(5),
                        queryAggregateSeriesRequestOptions);

                    await foreach (Page <TimeSeriesPoint> aggregateSeriesPage in queryAggregateSeriesPages.GetResultsAsync().AsPages())
                    {
                        aggregateSeriesPage.Values.Should().HaveCountGreaterThan(0);
                        foreach (var point in aggregateSeriesPage.Values)
                        {
                            point.GetUniquePropertyNames().Should().HaveCount(2)
                            .And
                            .Contain((property) => property == QueryTestsHelper.Temperature)
                            .And
                            .Contain((property) => property == linearInterpolation);
                        }
                    }

                    return(null);
                }, MaxNumberOfRetries, s_retryDelay);

                // Send 2 events with a special condition that can be used later to query on
                IDictionary <string, object> messageBase = QueryTestsHelper.BuildMessageBase(modelSettings.TimeSeriesIdProperties.ToArray(), tsiId);
                messageBase[QueryTestsHelper.Temperature] = 1.2;
                messageBase[QueryTestsHelper.Humidity]    = 3.4;
                string messageBody = JsonSerializer.Serialize(messageBase);
                var    message     = new Message(Encoding.ASCII.GetBytes(messageBody))
                {
                    ContentType     = "application/json",
                    ContentEncoding = "utf-8",
                };

                Func <Task> sendEventAct = async() => await deviceClient.SendEventAsync(message).ConfigureAwait(false);

                sendEventAct.Should().NotThrow();

                // Send it again
                sendEventAct.Should().NotThrow();

                // Query for the two events with a filter
                queryAggregateSeriesRequestOptions.Filter = "$event.Temperature.Double = 1.2";
                await TestRetryHelper.RetryAsync <AsyncPageable <QueryResultPage> >(async() =>
                {
                    QueryAnalyzer queryAggregateSeriesPages = tsiClient.Queries.CreateAggregateSeriesQueryAnalyzer(
                        tsiId,
                        startTime,
                        endTime,
                        TimeSpan.FromSeconds(5),
                        queryAggregateSeriesRequestOptions);

                    var valueFound = false;
                    await foreach (TimeSeriesPoint point in queryAggregateSeriesPages.GetResultsAsync())
                    {
                        point.GetUniquePropertyNames().Should().HaveCount(2)
                        .And
                        .Contain((property) => property == QueryTestsHelper.Temperature)
                        .And
                        .Contain((property) => property == linearInterpolation);

                        var value = (double?)point.GetValue(QueryTestsHelper.Temperature);
                        if (value == 1.2)
                        {
                            valueFound = true;
                        }
                    }

                    valueFound.Should().BeTrue();

                    return(null);
                }, MaxNumberOfRetries, s_retryDelay);
            }
            finally
            {
                deviceClient?.Dispose();
            }
        }
Пример #11
0
        private async Task RunQuerySeriesSampleWithPreDefinedVariables(TimeSeriesInsightsClient client, TimeSeriesId tsId)
        {
            // Setup
            TimeSeriesInsightsInstances instancesClient = client.GetInstancesClient();
            TimeSeriesInsightsTypes     typesClient     = client.GetTypesClient();
            TimeSeriesInsightsQueries   queriesClient   = client.GetQueriesClient();

            // First create the Time Series type along with the numeric variables
            var timeSeriesTypes = new List <TimeSeriesType>();

            var celsiusVariable = new NumericVariable(
                new TimeSeriesExpression("$event.Temperature"),
                new TimeSeriesExpression("avg($value)"));
            var fahrenheitVariable = new NumericVariable(
                new TimeSeriesExpression("$event.Temperature * 1.8 + 32"),
                new TimeSeriesExpression("avg($value)"));

            var celsiusVariableName    = "TemperatureInCelsius";
            var fahrenheitVariableName = "TemperatureInFahrenheit";
            var variables = new Dictionary <string, TimeSeriesVariable>
            {
                { celsiusVariableName, celsiusVariable },
                { fahrenheitVariableName, fahrenheitVariable }
            };

            timeSeriesTypes.Add(new TimeSeriesType("TemperatureSensor", variables)
            {
                Id = "TemperatureSensorTypeId"
            });

            Response <TimeSeriesTypeOperationResult[]> createTypesResult = await typesClient
                                                                           .CreateOrReplaceAsync(timeSeriesTypes)
                                                                           .ConfigureAwait(false);

            if (createTypesResult.Value.First().Error != null)
            {
                Console.WriteLine($"\n\nFailed to create a Time Series Insights type. " +
                                  $"Error Message: '{createTypesResult.Value.First().Error.Message}.' " +
                                  $"Code: '{createTypesResult.Value.First().Error.Code}'.");
            }

            // Get the Time Series instance and replace its type with the one we just created
            Response <InstancesOperationResult[]> getInstanceResult = await instancesClient
                                                                      .GetAsync(new List <TimeSeriesId> {
                tsId
            });

            if (getInstanceResult.Value.First().Error != null)
            {
                Console.WriteLine($"\n\nFailed to retrieve Time Series instance with Id '{tsId}'. " +
                                  $"Error Message: '{getInstanceResult.Value.First().Error.Message}.' " +
                                  $"Code: '{getInstanceResult.Value.First().Error.Code}'.");
            }

            TimeSeriesInstance instanceToReplace = getInstanceResult.Value.First().Instance;

            instanceToReplace.TypeId = createTypesResult.Value.First().TimeSeriesType.Id;
            Response <InstancesOperationResult[]> replaceInstanceResult = await instancesClient
                                                                          .ReplaceAsync(new List <TimeSeriesInstance> {
                instanceToReplace
            });

            if (replaceInstanceResult.Value.First().Error != null)
            {
                Console.WriteLine($"\n\nFailed to retrieve Time Series instance with Id '{tsId}'. " +
                                  $"Error Message: '{replaceInstanceResult.Value.First().Error.Message}.' " +
                                  $"Code: '{replaceInstanceResult.Value.First().Error.Code}'.");
            }

            // Now that we set up the instance with the property type, query for the data
            #region Snippet:TimeSeriesInsightsSampleQuerySeries
            Console.WriteLine($"\n\nQuery for temperature series in Celsius and Fahrenheit over the past 10 minutes. " +
                              $"The Time Series instance belongs to a type that has predefined numeric variable that represents the temperature " +
                              $"in Celsuis, and a predefined numeric variable that represents the temperature in Fahrenheit.\n");

            DateTimeOffset endTime     = DateTime.UtcNow;
            DateTimeOffset startTime   = endTime.AddMinutes(-10);
            QueryAnalyzer  seriesQuery = queriesClient.CreateSeriesQuery(
                tsId,
                startTime,
                endTime);

            await foreach (TimeSeriesPoint point in seriesQuery.GetResultsAsync())
            {
                double?tempInCelsius    = point.GetNullableDouble(celsiusVariableName);
                double?tempInFahrenheit = point.GetNullableDouble(fahrenheitVariableName);

                Console.WriteLine($"{point.Timestamp} - Average temperature in Celsius: {tempInCelsius}. " +
                                  $"Average temperature in Fahrenheit: {tempInFahrenheit}.");
            }
            #endregion Snippet:TimeSeriesInsightsSampleQuerySeries
        }
Пример #12
0
        public async Task TimeSeriesInsightsQuery_GetSeriesLifecycle()
        {
            // Arrange
            TimeSeriesInsightsClient tsiClient    = GetClient();
            DeviceClient             deviceClient = await GetDeviceClient().ConfigureAwait(false);

            // Figure out what the Time Series Id is composed of
            TimeSeriesModelSettings modelSettings = await tsiClient.ModelSettings.GetAsync().ConfigureAwait(false);

            // Create a Time Series Id where the number of keys that make up the Time Series Id is fetched from Model Settings
            TimeSeriesId tsiId = await GetUniqueTimeSeriesInstanceIdAsync(tsiClient, modelSettings.TimeSeriesIdProperties.Count)
                                 .ConfigureAwait(false);

            try
            {
                // Send some events to the IoT hub
                await QueryTestsHelper.SendEventsToHubAsync(
                    deviceClient,
                    tsiId,
                    modelSettings.TimeSeriesIdProperties.ToArray(),
                    10)
                .ConfigureAwait(false);

                // Act

                // Query for temperature events with two calculateions. First with the temperature value as is, and the second
                // with the temperature value multiplied by 2.
                DateTimeOffset now       = Recording.UtcNow;
                DateTimeOffset endTime   = now.AddMinutes(10);
                DateTimeOffset startTime = now.AddMinutes(-10);

                var temperatureNumericVariable = new NumericVariable(
                    new TimeSeriesExpression($"$event.{QueryTestsHelper.Temperature}"),
                    new TimeSeriesExpression("avg($value)"));
                var temperatureNumericVariableTimesTwo = new NumericVariable(
                    new TimeSeriesExpression($"$event.{QueryTestsHelper.Temperature} * 2"),
                    new TimeSeriesExpression("avg($value)"));
                var temperatureTimesTwoVariableName = $"{QueryTestsHelper.Temperature}TimesTwo";

                var querySeriesRequestOptions = new QuerySeriesRequestOptions();
                querySeriesRequestOptions.InlineVariables[QueryTestsHelper.Temperature]    = temperatureNumericVariable;
                querySeriesRequestOptions.InlineVariables[temperatureTimesTwoVariableName] = temperatureNumericVariableTimesTwo;

                // This retry logic was added as the TSI instance are not immediately available after creation
                await TestRetryHelper.RetryAsync <AsyncPageable <QueryResultPage> >(async() =>
                {
                    AsyncPageable <QueryResultPage> querySeriesEventsPages = tsiClient.Query.GetSeriesAsync(
                        tsiId,
                        startTime,
                        endTime,
                        querySeriesRequestOptions);

                    await foreach (QueryResultPage seriesEventsPage in querySeriesEventsPages)
                    {
                        seriesEventsPage.Timestamps.Should().HaveCount(10);
                        seriesEventsPage.Timestamps.Should().OnlyContain(timeStamp => timeStamp >= startTime)
                        .And
                        .OnlyContain(timeStamp => timeStamp <= endTime);
                        seriesEventsPage.Properties.Count.Should().Be(3); // EventCount, Temperature and TemperatureTimesTwo
                        seriesEventsPage.Properties.Should().Contain((property) => property.Name == QueryTestsHelper.Temperature)
                        .And
                        .Contain((property) => property.Name == temperatureTimesTwoVariableName);

                        // Assert that the values for the Temperature property is equal to the values for the other property, multiplied by 2
                        var temperatureValues = seriesEventsPage
                                                .Properties
                                                .First((property) => property.Name == QueryTestsHelper.Temperature)
                                                .Values.Cast <double>().ToList();

                        var temperatureTimesTwoValues = seriesEventsPage
                                                        .Properties
                                                        .First((property) => property.Name == temperatureTimesTwoVariableName)
                                                        .Values.Cast <double>().ToList();
                        temperatureTimesTwoValues.Should().Equal(temperatureValues.Select((property) => property * 2).ToList());
                    }

                    return(null);
                }, MaxNumberOfRetries, s_retryDelay);

                // Query for all the series events using a timespan
                AsyncPageable <QueryResultPage> querySeriesEventsPagesWithTimespan = tsiClient.Query.GetSeriesAsync(tsiId, TimeSpan.FromMinutes(10), null, querySeriesRequestOptions);
                await foreach (QueryResultPage seriesEventsPage in querySeriesEventsPagesWithTimespan)
                {
                    seriesEventsPage.Timestamps.Should().HaveCount(10);
                    seriesEventsPage.Properties.Count.Should().Be(3); // EventCount, Temperature and TemperatureTimesTwo
                }

                // Query for temperature and humidity
                var humidityNumericVariable = new NumericVariable(
                    new TimeSeriesExpression("$event.Humidity"),
                    new TimeSeriesExpression("avg($value)"));
                querySeriesRequestOptions.InlineVariables[QueryTestsHelper.Humidity] = humidityNumericVariable;
                querySeriesRequestOptions.ProjectedVariables.Add(QueryTestsHelper.Temperature);
                querySeriesRequestOptions.ProjectedVariables.Add(QueryTestsHelper.Humidity);
                await TestRetryHelper.RetryAsync <AsyncPageable <QueryResultPage> >(async() =>
                {
                    AsyncPageable <QueryResultPage> querySeriesEventsPages = tsiClient.Query.GetSeriesAsync(tsiId, startTime, endTime, querySeriesRequestOptions);

                    await foreach (QueryResultPage seriesEventsPage in querySeriesEventsPages)
                    {
                        seriesEventsPage.Timestamps.Should().HaveCount(10);
                        seriesEventsPage.Timestamps.Should().OnlyContain(timeStamp => timeStamp >= startTime)
                        .And
                        .OnlyContain(timeStamp => timeStamp <= endTime);
                        seriesEventsPage.Properties.Count.Should().Be(2); // Temperature and Humidity
                        seriesEventsPage.Properties.Should().Contain((property) => property.Name == QueryTestsHelper.Temperature)
                        .And
                        .Contain((property) => property.Name == QueryTestsHelper.Humidity);
                    }

                    return(null);
                }, MaxNumberOfRetries, s_retryDelay);

                // Send 2 events with a special condition that can be used later to query on
                IDictionary <string, object> messageBase = QueryTestsHelper.BuildMessageBase(modelSettings.TimeSeriesIdProperties.ToArray(), tsiId);
                messageBase[QueryTestsHelper.Temperature] = 1.2;
                messageBase[QueryTestsHelper.Humidity]    = 3.4;
                string messageBody = JsonSerializer.Serialize(messageBase);
                var    message     = new Message(Encoding.ASCII.GetBytes(messageBody))
                {
                    ContentType     = "application/json",
                    ContentEncoding = "utf-8",
                };

                Func <Task> sendEventAct = async() => await deviceClient.SendEventAsync(message).ConfigureAwait(false);

                sendEventAct.Should().NotThrow();

                // Send it again
                sendEventAct.Should().NotThrow();

                // Query for the two events with a filter
                querySeriesRequestOptions.Filter = "$event.Temperature.Double = 1.2";
                await TestRetryHelper.RetryAsync <AsyncPageable <QueryResultPage> >(async() =>
                {
                    AsyncPageable <QueryResultPage> querySeriesEventsPages = tsiClient.Query.GetSeriesAsync(tsiId, startTime, endTime, querySeriesRequestOptions);
                    await foreach (QueryResultPage seriesEventsPage in querySeriesEventsPages)
                    {
                        seriesEventsPage.Timestamps.Should().HaveCount(2);
                        seriesEventsPage.Properties.Should().HaveCount(2)
                        .And
                        .Contain((property) => property.Name == QueryTestsHelper.Temperature)
                        .And
                        .Contain((property) => property.Name == QueryTestsHelper.Humidity);

                        var temperatureValues = seriesEventsPage
                                                .Properties
                                                .First((property) => property.Name == QueryTestsHelper.Temperature)
                                                .Values.Cast <double>().ToList();
                        temperatureValues.Should().AllBeEquivalentTo(1.2);
                    }

                    return(null);
                }, MaxNumberOfRetries, s_retryDelay);

                // Query for the two events with a filter, but only take 1
                querySeriesRequestOptions.MaximumNumberOfEvents = 1;
                AsyncPageable <QueryResultPage> querySeriesEventsPagesWithFilter = tsiClient.Query.GetSeriesAsync(tsiId, startTime, endTime, querySeriesRequestOptions);
                await foreach (QueryResultPage seriesEventsPage in querySeriesEventsPagesWithFilter)
                {
                    seriesEventsPage.Timestamps.Should().HaveCount(1);
                    seriesEventsPage.Properties.Should().HaveCount(2)
                    .And
                    .Contain((property) => property.Name == QueryTestsHelper.Temperature)
                    .And
                    .Contain((property) => property.Name == QueryTestsHelper.Humidity);

                    var temperatureValues = seriesEventsPage
                                            .Properties
                                            .First((property) => property.Name == QueryTestsHelper.Temperature)
                                            .Values.Cast <double>().ToList();
                    temperatureValues.Should().AllBeEquivalentTo(1.2);
                }
            }
            finally
            {
                deviceClient?.Dispose();
            }
        }
Пример #13
0
        private static void Check(Node node, [NotNull] FunctionCall call,
                                  [NotNull] FunctionDeclaration definition)
        {
            var table         = node.SymbolTable;
            var parameters    = definition.Profile.Parameters;
            var callerProfile = call.AsProfile(node);
            var callArgsCount = call.Arguments != null ? call.Arguments.Length : 0;

            if (callArgsCount > parameters.Count)
            {
                var m = string.Format("Function '{0}' only takes {1} parameter(s)", call.FunctionName,
                                      parameters.Count);
                DiagnosticUtils.AddError(node, m);
            }

            if (callerProfile.InputParameters.Count != definition.Profile.InputParameters.Count ||
                callerProfile.InoutParameters.Count != definition.Profile.InoutParameters.Count ||
                callerProfile.OutputParameters.Count != definition.Profile.OutputParameters.Count)
            {
                var m = string.Format("No suitable function signature found for '{0}' {1}", call.FunctionName,
                                      callerProfile.GetSignature());
                DiagnosticUtils.AddError(node, m);
            }

            for (int c = 0; c < parameters.Count; c++)
            {
                var expected = parameters[c];
                if (c < callArgsCount)
                {
                    //Omitted
                    if (call.Arguments[c].IsOmitted)
                    {
                        if (expected.IsOmittable)
                        {
                            continue;
                        }
                        else
                        {
                            DiagnosticUtils.AddError(node, "Omitted not allowed for this parameter");
                            return;
                        }
                    }


                    var actual = call.Arguments[c].StorageAreaOrValue;
                    if (actual.IsLiteral)
                    {
                        continue;                   //TODO
                    }
                    var callArgName = actual.StorageArea.ToString();
                    var found       = node.GetDataDefinitionFromStorageAreaDictionary(actual.StorageArea);
                    if (found == null)
                    {
                        continue;
                    }

                    var actualDataDefinition = found;

                    var actualSpecialRegister = actual.StorageArea as StorageAreaPropertySpecialRegister;
                    if (actualSpecialRegister != null)
                    {
                        var tokenType = actualSpecialRegister.SpecialRegisterName.TokenType;
                        if (tokenType == TokenType.LENGTH)
                        {
                            if (call is ProcedureCall)
                            {
                                ProcedureCall procedureCall = call as ProcedureCall;
                                if (procedureCall.OutputParameters.Contains(call.Arguments[c]))
                                {
                                    DiagnosticUtils.AddError(node, "LENGTH cannot be used as an output",
                                                             actualSpecialRegister.SpecialRegisterName);
                                    continue;
                                }
                            }

                            // accepted format is "PIC [S]9(5..9) comp-5"
                            if (expected.PrimitiveDataType.Name != "Numeric" || expected.Length < 5 ||
                                expected.Length > 9 || expected.Usage != DataUsage.NativeBinary)
                            {
                                DiagnosticUtils.AddError(node, "LENGTH can only be used as PIC S9(5..9) comp-5",
                                                         actualSpecialRegister.SpecialRegisterName);
                                continue;
                            }
                        }
                        else if (tokenType == TokenType.ADDRESS && expected.Usage == DataUsage.Pointer)
                        {
                            if (!actualDataDefinition.IsFlagSet(Node.Flag.LinkageSectionNode) &&
                                call.Arguments[c].SharingMode.Value == ParameterSharingMode.ByReference)
                            {
                                DiagnosticUtils.AddError(node,
                                                         "ADDRESS OF can only be used with a LINKAGE variable, or with a sharing mode BY CONTENT/BY VALUE",
                                                         actualSpecialRegister.SpecialRegisterName);
                            }

                            continue;
                        }
                        else if (tokenType == TokenType.LINAGE_COUNTER)
                        {
                            //Do not know what to do : RFC
                            DiagnosticUtils.AddError(node, "LINAGE_COUNTER not allowed yet with procedure");
                            return;
                        }

                        continue; //If it's a special register we don't want to check more rules.
                    }



                    //TODO use SubscriptExpression and ReferenceModifier of the StorageArea to correct the type
                    //Ex: MyVar1(1:10) has a length of 10 and is of type Alphanumeric
                    //Ex: MyArray(1) only target one element of the array, so we need to get the type of this element.



                    //If the actual dataDefinition is a table occurence try to match it with subscripts
                    //If the actual dataDefinition is under a table occurence, then don't care about subscripts
                    long            actualMinOccurencesCount             = actualDataDefinition.MinOccurencesCount;
                    long            actualMaxOccurencesCount             = actualDataDefinition.MaxOccurencesCount;
                    bool            actualHasUnboundedNumberOfOccurences = actualDataDefinition.HasUnboundedNumberOfOccurences;
                    NumericVariable actualOccursDependingOn = actualDataDefinition.OccursDependingOn;
                    bool            actualIsTableOccurence  = actualDataDefinition.IsTableOccurence;

                    if (actualDataDefinition.IsTableOccurence)
                    {
                        var subscriptedStorageArea = actual.StorageArea as DataOrConditionStorageArea;
                        if (subscriptedStorageArea != null && subscriptedStorageArea.Subscripts.Count > 0)
                        {
                            //if there are subscripts


                            //Do not allow ALL
                            if (subscriptedStorageArea.Subscripts.Any(s => s.ALL != null))
                            {
                                DiagnosticUtils.AddError(node, "You cannot use ALL for procedure argument");
                                return;
                            }

                            actualMinOccurencesCount             = 0;
                            actualMaxOccurencesCount             = 0;
                            actualHasUnboundedNumberOfOccurences = false;
                            actualOccursDependingOn = null;
                            actualIsTableOccurence  = false;
                        }
                    }


                    //Cobol 85 Type will be checked with their picture
                    if (actualDataDefinition.DataType.CobolLanguageLevel > CobolLanguageLevel.Cobol85 ||
                        expected.DataType.CobolLanguageLevel > CobolLanguageLevel.Cobol85)
                    {
                        if (actualDataDefinition.DataType.CobolLanguageLevel == CobolLanguageLevel.Cobol85 ||
                            expected.DataType.CobolLanguageLevel == CobolLanguageLevel.Cobol85)
                        {
                            var m = string.Format(
                                "Function '{0}' expected parameter '{1}' of type {2} and received '{3}' of type {4} ",
                                call.FunctionName, expected.Name, expected.DataType,
                                callArgName ?? string.Format("position {0}", c + 1), actualDataDefinition.DataType);
                            DiagnosticUtils.AddError(node, m);
                        }
                        else if (actualDataDefinition.DataType != expected.DataType)
                        {
                            TypeDefinition callerType = actualDataDefinition.TypeDefinition;
                            TypeDefinition calleeType = expected.TypeDefinition;
                            if (callerType == null || calleeType == null)
                            {
                                //Ignore, it's an unknown DataType. It's already checked
                            }
                            else if (!Equals(callerType.QualifiedName, calleeType.QualifiedName))
                            {
                                var m = string.Format(
                                    "Function '{0}' expected parameter '{1}' of type {2} and received '{3}' of type {4} ",
                                    call.FunctionName, calleeType.Name, calleeType.DataType,
                                    callArgName ?? string.Format("position {0}", c + 1), callerType.DataType);
                                DiagnosticUtils.AddError(node, m);
                            }
                        }
                    }

                    if (actualDataDefinition.Picture != null && expected.Picture != null &&
                        actualDataDefinition.Picture.NormalizedValue != expected.Picture.NormalizedValue)
                    {
                        var m =
                            string.Format(
                                "Function '{0}' expected parameter '{1}' with picture {2} and received '{3}' with picture {4}",
                                call.FunctionName, expected.Name, expected.Picture.Value,
                                callArgName ?? string.Format("position {0}", c + 1),
                                actualDataDefinition.Picture.Value);
                        DiagnosticUtils.AddError(node, m);
                    }


//                    if (dataDefinitionOfActual.Length != expectedParameter.Length)
//                    {
//                        var m =
//                            string.Format(
//                                "Function '{0}' expected parameter '{1}' of length {2} and received '{3}' of length {4}",
//                                call.FunctionName, expectedParameter.Name, expectedParameter.Length,
//                                callArgName ?? string.Format("position {0}", c + 1), dataDefinitionOfActual.Length);
//                        DiagnosticUtils.AddError(e, m);
//                    }

                    if (actualDataDefinition.Usage != expected.Usage)
                    {
                        var m =
                            string.Format(
                                "Function '{0}' expected parameter '{1}' of usage {2} and received '{3}' of usage {4}",
                                call.FunctionName, expected.Name, expected.Usage,
                                callArgName ?? string.Format("position {0}", c + 1), actualDataDefinition.Usage);
                        DiagnosticUtils.AddError(node, m);
                    }

                    if (actualDataDefinition.IsJustified != expected.IsJustified)
                    {
                        var m =
                            string.Format(
                                "Function '{0}' expected parameter '{1}' {2} and received '{3}' {4}",
                                call.FunctionName, expected.Name, expected.IsJustified ? "justified" : "non-justified",
                                callArgName ?? string.Format("position {0}", c + 1),
                                actualDataDefinition.IsJustified ? "justified" : "non-justified");
                        DiagnosticUtils.AddError(node, m);
                    }

                    if (actualDataDefinition.IsGroupUsageNational != expected.IsGroupUsageNational)
                    {
                        var m =
                            string.Format(
                                "Function '{0}' expected parameter '{1}' {2} and received '{3}' {4}",
                                call.FunctionName, expected.Name,
                                expected.IsGroupUsageNational ? "national group-usage" : "non national group-usage",
                                callArgName ?? string.Format("position {0}", c + 1),
                                actualDataDefinition.IsGroupUsageNational
                                    ? "national group-usage"
                                    : "non national group-usage");
                        DiagnosticUtils.AddError(node, m);
                    }



                    //Array
                    if (actualIsTableOccurence != expected.IsTableOccurence)
                    {
                        var m =
                            string.Format(
                                "Function '{0}' expected parameter '{1}' to {2} an array and received '{3}' which {4} an array",
                                call.FunctionName, expected.Name, expected.IsTableOccurence ? "be" : "be NOT",
                                actualDataDefinition.Name,
                                actualIsTableOccurence ? "is" : "is NOT ");
                        DiagnosticUtils.AddError(node, m);
                    }
                    else if (actualIsTableOccurence && expected.IsTableOccurence)
                    {
                        if (actualMinOccurencesCount != expected.MinOccurencesCount)
                        {
                            var m =
                                string.Format(
                                    "Function '{0}' expected parameter '{1}' to have at least {2} occurences and received '{3}' with a minimum of {4} occurences",
                                    call.FunctionName, expected.Name, expected.MinOccurencesCount,
                                    callArgName ?? string.Format("position {0}", c + 1), actualMinOccurencesCount);
                            DiagnosticUtils.AddError(node, m);
                        }

                        if (actualMaxOccurencesCount != expected.MaxOccurencesCount)
                        {
                            var m =
                                string.Format(
                                    "Function '{0}' expected parameter '{1}' to have at most {2} occurences and received '{3}' with a maximum of {4} occurences",
                                    call.FunctionName, expected.Name, expected.MaxOccurencesCount,
                                    callArgName ?? string.Format("position {0}", c + 1), actualMaxOccurencesCount);
                            DiagnosticUtils.AddError(node, m);
                        }
                    }

                    if (actualOccursDependingOn != expected.OccursDependingOn)
                    {
                        var m =
                            string.Format(
                                "Function '{0}' expected parameter '{1}' occurs depending on ({2}) occurences and received '{3}' occurs depending on ({4})",
                                call.FunctionName, expected.Name, expected.OccursDependingOn,
                                callArgName ?? string.Format("position {0}", c + 1), actualOccursDependingOn);
                        DiagnosticUtils.AddError(node, m);
                    }

                    if (actualHasUnboundedNumberOfOccurences != expected.HasUnboundedNumberOfOccurences)
                    {
                        var m =
                            string.Format(
                                "Function '{0}' expected parameter '{1}' {2} and received '{3}' {4}",
                                call.FunctionName, expected.Name,
                                expected.HasUnboundedNumberOfOccurences
                                    ? "has unbounded number of occurences"
                                    : "hasn't unbounded number of occurences",
                                callArgName ?? string.Format("position {0}", c + 1),
                                actualHasUnboundedNumberOfOccurences
                                    ? "has unbounded number of occurences"
                                    : "hasn't unbounded number of occurences");
                        DiagnosticUtils.AddError(node, m);
                    }


                    if (actualDataDefinition.SignIsSeparate != expected.SignIsSeparate)
                    {
                        var m =
                            string.Format(
                                "Function '{0}' expected parameter '{1}' {2} and received '{3}' {4}",
                                call.FunctionName, expected.Name,
                                expected.HasUnboundedNumberOfOccurences
                                    ? "has unbounded number of occurences"
                                    : "hasn't unbounded number of occurences",
                                callArgName ?? string.Format("position {0}", c + 1),
                                actualDataDefinition.HasUnboundedNumberOfOccurences
                                    ? "has unbounded number of occurences"
                                    : "hasn't unbounded number of occurences");
                        DiagnosticUtils.AddError(node, m);
                    }

                    if (actualDataDefinition.SignPosition != expected.SignPosition)
                    {
                        var m =
                            string.Format(
                                "Function '{0}' expected parameter '{1}' with sign position {2} and received '{3}' with sign position {4}",
                                call.FunctionName, expected.Name,
                                expected.SignPosition == null ? "empty" : expected.SignPosition.ToString(),
                                callArgName ?? string.Format("position {0}", c + 1),
                                actualDataDefinition.SignPosition == null
                                    ? "empty"
                                    : actualDataDefinition.SignPosition.ToString());
                        DiagnosticUtils.AddError(node, m);
                    }

                    if (actualDataDefinition.IsSynchronized != expected.IsSynchronized)
                    {
                        var m =
                            string.Format(
                                "Function '{0}' expected parameter '{1}' {2} and received '{3}' {4}",
                                call.FunctionName, expected.Name,
                                expected.IsSynchronized ? "synchonized" : "not synchronized",
                                callArgName ?? string.Format("position {0}", c + 1),
                                actualDataDefinition.IsSynchronized ? "synchonized" : "not synchronized");
                        DiagnosticUtils.AddError(node, m);
                    }

                    if (actualDataDefinition.ObjectReferenceClass != expected.ObjectReferenceClass)
                    {
                        var m =
                            string.Format(
                                "Function '{0}' expected parameter '{1}' and received '{2}' with wrong object reference.",
                                call.FunctionName, expected.Name, callArgName ?? string.Format("position {0}", c + 1));
                        DiagnosticUtils.AddError(node, m);
                    }
                }
                else
                {
                    var m = string.Format("Function '{0}' is missing parameter '{1}' of type {2} and length {3}",
                                          call.FunctionName, expected.Name, expected.DataType, expected.Length);
                    DiagnosticUtils.AddError(node, m);
                }
            }
        }
        protected override void PlaceObjects([NotNull, ItemNotNull] IEnumerable <Dependency> dependencies)
        {
            // ASCII-art sketch of what I want to accomplish:
            //
            //    |         |         |             |          |        |<--------+-----+
            //    |         |         |             |          |<-----------------|     |
            //    |         |         |             |<----------------------------| Top |
            //    |         |         |<------------------------------------------|     |
            //    |         |<----------------------------------------------------+-----+
            //    |         |         |             |          |        |
            //    |         |         |             |          |<-------+-----+
            //    |         |         |             |<------------------|     |
            //    |         |         |<--------------------------------| IMP |
            //    |         |<------------------------------------------|     |
            //    |<----------------------------------------------------+-----+
            //    |         |         |             |          |          |
            //    |         |         |             |<---------+-----+    |
            //    |         |         |<-----------------------|     |    |
            //    |         |<---------------------------------| WLG |    |
            //    |<-------------------------------------------+-----+    |
            //    |         |         |             |          | | |      |
            //    |         |         |<------------|          | | |      |
            //    |         |         | |<::::::::::+-----+    | | |      |
            //    |         |<----------|-----------| VKF |----|--------->|
            //    |<--------------------|-----------+-----+    | | |      |
            //    |         |         | |             | |      | | |      Imp.MI
            //    |<--------------------|---------------|      | | |
            //    |<--------------------|-------------| |      | | |
            //    |         |         | |     ...     | |      | | |
            //    |         |         | |             | |      | | |
            //    |         |         +-----+=================>| | |
            //    |         |         | KAH |---------->|        | |
            //    |         |         +-----+-------->| |        | |
            //    |         |           |             | |        | |
            //    |         +-----+------------------------------->|
            //    |         |     |----------------------------->| |
            //    |         | KST |-------------------->|        | |
            //    |         |     |------------------>| |        | |
            //    |<--------+-----+---->|             | |        | |
            //    |                     |             | |        | |
            //    |        ...          |             | |        | |
            //    |                    Kah         Vkf1 Vkf2  Wlg1 Wlg2
            //    +-----+              .MI          .MI .MI    .MI .MI
            //    | BAC |
            //    +-----+
            //
            // ===> is a dependency from a "lower" to a "higher" module
            // that circumvents the MI. It should most probably be flagged
            // as incorrect and then red in the diagram.
            // :::> is a dependency from a "higher" to a "lower" module
            // via an MI ("module interface"). This is ok, it is only
            // highlighted to show that the Renderer must be able to deal
            // with this.

            // The itemtype is expected to have 3 fields Name:Module:Order.
            // In the example diagram above, we would have items about like the following:
            //        BAC    :BAC:0100
            //        KST    :KST:0200
            //        KAH    :KAH:0300
            //        Kah.MI :KAH:0301
            //        VKF    :VKF:0400
            //        Vkf1.MI:VKF:0401
            //        Vkf2.MI:VKF:0402
            //        WLG    :WLG:0500
            //        Wlg1.MI:WLG:0501
            //        Wlg2.MI:WLG:0502
            //        IMP    :IMP:0600
            //        Imp.MI :IMP:0601
            //        Top    :TOP:0700

            VariableVector itemDistance = new VariableVector(nameof(itemDistance), Solver);
            VariableVector pos          = F(0, 30);

            //itemDistance.MaxY(80);
            //itemDistance.SetX(300);

            Arrow(F(0, 0), F(100, 0), 1, Color.Chartreuse, "100px", textFont: _lineFont);
            Box(F(200, 0), _title + "(" + DateTime.Now + ")", boxAnchoring: BoxAnchoring.LowerLeft);

            const int DELTA_Y_MAIN = 8;

            IEnumerable <Item> items            = dependencies.SelectMany(e => new[] { e.UsingItem, e.UsedItem }).Distinct();
            IEnumerable <Item> parents          = items.Where(i => !IsMI(i));
            IEnumerable <Item> misWithoutParent = items.Where(i => IsMI(i) && parents.All(p => GetModule(p) != GetModule(i)));

            var mainBoxes                 = new Dictionary <Item, IBox>();
            var interfaceBoxes            = new Dictionary <Item, IBox>();
            var mainBoxesNextFreePos      = new Dictionary <Item, VariableVector>();
            var interfaceBoxesNextFreePos = new Dictionary <Item, VariableVector>();
            var mainItems                 = new Dictionary <Item, Item>();

            // Main modules along diagonal, separated by itemDistance


            foreach (var i in parents.Concat(misWithoutParent).OrderBy(_orderSupport.OrderSelector))
            {
                string name = GetName(i);

                string countText = "\n<" + Sum(dependencies, d => d.UsingItem.Equals(i) && !d.UsedItem.Equals(i))
                                   + " =" + Sum(dependencies, d => d.UsingItem.Equals(i) && d.UsedItem.Equals(i))
                                   + " >" + Sum(dependencies, d => !d.UsingItem.Equals(i) && d.UsedItem.Equals(i));
                // TODO: Add option and computation to split this into .,?,!

                pos.AlsoNamed(name);
                IBox mainBox = Box(pos, boxAnchoring: BoxAnchoring.LowerLeft, text: name + countText, borderWidth: 3,
                                   boxColor: IsMI(i) ? Color.LemonChiffon : Color.Coral, textFont: _boxFont, drawingOrder: 1, fixingOrder: 4);
                //mainBox.Diagonal.Y.Set(100);
                //mainBox.Diagonal.Y.Min(40);
                mainBox.Diagonal.Y.Max(60 + dependencies.Count(d => Equals(d.UsingItem, i)) * DELTA_Y_MAIN); // Help for solving
                mainBox.Diagonal.Y.Min(10 + dependencies.Count(d => Equals(d.UsingItem, i)) * DELTA_Y_MAIN); // Help for solving
                mainBoxes[i]            = mainBox;
                mainBoxesNextFreePos[i] = mainBox.LowerLeft;
                {
                    IBox interfaceBox = Box(new VariableVector(name + ".I", Solver).SetX(mainBox.LowerLeft.X),
                                            text: "", boxAnchoring: BoxAnchoring.LowerLeft, borderWidth: 1,
                                            boxColor: Color.Coral, fixingOrder: 3);
                    interfaceBox.Diagonal.SetX(10);

                    interfaceBox.UpperLeft.MinY(mainBox.UpperLeft.Y + 7);
                    interfaceBox.LowerLeft.MaxY(mainBox.LowerLeft.Y - 7);

                    interfaceBoxes[i]            = interfaceBox;
                    interfaceBoxesNextFreePos[i] = mainBox.LowerLeft - F(0, 10);
                }

                NumericVariable interfacePos = Solver.CreateConstant("", 18);

                foreach (var mi in items.Where(mi => IsMI(mi) && GetModule(mi) == GetModule(i)).OrderBy(_orderSupport.OrderSelector))
                {
                    VariableVector miPos = new VariableVector(name + _interfaceSelector, Solver).SetX(mainBox.CenterLeft.X + interfacePos);

                    var miBox = Box(miPos, text: GetName(mi), boxAnchoring: BoxAnchoring.UpperLeft,
                                    boxTextPlacement: BoxTextPlacement.LeftUp, borderWidth: 1, boxColor: Color.LemonChiffon,
                                    textFont: _interfaceFont, fixingOrder: 3);
                    mainItems[mi]      = i;
                    interfaceBoxes[mi] = miBox;

                    miBox.UpperLeft.MinY(mainBox.UpperLeft.Y + 7);
                    miBox.LowerLeft.MaxY(mainBox.LowerLeft.Y - miBox.TextBox.Y);

                    interfacePos += 18;
                }

                mainBox.Diagonal.MinX(interfacePos);
                itemDistance.MinX(mainBox.Diagonal.X + 12);
                itemDistance.MinY(mainBox.Diagonal.Y + 15);

                pos += itemDistance;
            }

            foreach (var d in dependencies)
            {
                Item from = d.UsingItem;
                Item to   = d.UsedItem;
                if (IsMI(from))
                {
                    IBox           fromBox     = interfaceBoxes[from];
                    Item           mainItem    = mainItems[from];
                    VariableVector nextFreePos = interfaceBoxesNextFreePos[mainItem];

                    VariableVector fromPos = new VariableVector(from + "->" + to, fromBox.LowerLeft.X, nextFreePos.Y);
                    ArrowToInterfaceBox(fromBox, interfaceBoxes[to], fromPos, d, "(I)");

                    interfaceBoxesNextFreePos[mainItem] -= F(0, 15);
                }
                else
                {
                    IBox           mainBox = mainBoxes[from];
                    VariableVector fromPos = mainBoxesNextFreePos[from];

                    ArrowToInterfaceBox(mainBox, interfaceBoxes[to], fromPos, d, "");

                    mainBoxesNextFreePos[from] += F(0, DELTA_Y_MAIN);

                    itemDistance.MinY(fromPos.Y - mainBox.LowerLeft.Y);

                    // mainBox.Diagonal.MinY(fromPos.Y - mainBox.LowerLeft.Y); ==> NO SOLUTION; therefore explcit computation above
                }
            }
        }
Пример #15
0
        protected override void PlaceObjects([NotNull, ItemNotNull] IEnumerable <Dependency> dependencies)
        {
            // ASCII-art sketch of what I want to accomplish:
            //   +-----+
            //   |     |--------------------------------------------->|
            //   | VKF |--------->|                                   |
            //   +-----+          |                                   |
            //                    |                                   |
            //   +-----+          |                                   |
            //   |     |--------------------------------------------->|
            //   | WLG |--------------------->|                       |
            //   +-----+          |           |                       |
            //                    |           |                       |
            //   +-----+          |           |                       |
            //   |     |--------------------------------->|           |
            //   | KST |--------------------->|           |           |
            //   |     |--------->|           |           |           |
            //   +-----+          |           |           |           |
            //                +-------+   +-------+   +-------+   +-------+
            //                | IMP.A |   | IMP.B |   | IMP.C |   | IMP.D |
            //                +-------+   +-------+   +-------+   +-------+
            //

            // The itemtype is expected to have 1 or 2 fields Name[:HtmlRef]
            // In the example diagram above, we would have items about like the following:
            //        BAC:
            //        WLG:
            //        KST:
            //        IMP.A:
            //        IMP.B:
            //        IMP.C:
            //        IMP.D:

            Arrow(F(0, 0), F(100, 0), 1, Color.Chartreuse, "100px", textFont: _lineFont);
            Box(F(-20, -20), _title + "(" + DateTime.Now + ")", boxAnchoring: BoxAnchoring.UpperRight);

            List <Item> yItems = dependencies.Select(e => e.UsingItem).Distinct().ToList();
            List <Item> xItems = dependencies.Select(e => e.UsedItem).Distinct().
                                 Where(i => _bottomItemMatch == null || _bottomItemMatch.Matches(i).Success).
                                 ToList();

            Dependency[] relevantDependencies = dependencies.Where(d => yItems.Contains(d.UsingItem) && xItems.Contains(d.UsedItem)).ToArray();
            if (_showOnlyReferencedOnBottom)
            {
                xItems.RemoveAll(ix => !relevantDependencies.Any(d => d.UsedItem.Equals(ix)));
            }
            if (_showOnlyReferencingOnLeft)
            {
                yItems.RemoveAll(iy => !relevantDependencies.Any(d => d.UsingItem.Equals(iy)));
            }

            _orderSupport.SortWithEdgeCount(xItems, relevantDependencies, (i, d) => d.UsedItem.Equals(i));
            _orderSupport.SortWithEdgeCount(yItems, relevantDependencies, (i, d) => d.UsingItem.Equals(i));

            double x      = 100;
            var    xBoxes = new Dictionary <Item, IBox>();

            foreach (var ix in xItems)
            {
                string name = GetName(ix);
                var    xPos = new VariableVector(name + ".POS", Solver);
                IBox   box  = Box(xPos, boxAnchoring: BoxAnchoring.LowerLeft, text: name, borderWidth: 3, boxColor: Color.LemonChiffon, boxTextPlacement: BoxTextPlacement.LeftUp,
                                  textFont: _boxFont, drawingOrder: 1, fixingOrder: 4, htmlRef: GetXHtmlRef(ix));
                xPos.SetX(x).SetY(-box.TextBox.Y);
                xBoxes[ix] = box;

                x += 40;
            }

            const int       DELTA_Y_MAIN = 12;
            NumericVariable y            = Solver.CreateConstant("y", 10);

            foreach (var iy in yItems)
            {
                string name = GetName(iy);
                var    yPos = new VariableVector(name + ".POS", Solver);
                IBox   box  = Box(yPos, boxAnchoring: BoxAnchoring.LowerRight, text: name, borderWidth: 3, boxColor: Color.Coral,
                                  boxTextPlacement: BoxTextPlacement.Left, textFont: _boxFont, drawingOrder: 1, fixingOrder: 4,
                                  htmlRef: GetYHtmlRef(iy) ?? GetXHtmlRef(iy));
                yPos.SetX(0).SetY(y);

                double minBoxHeight = 45;
                foreach (var d in relevantDependencies.Where(d => iy.Equals(d.UsingItem)))
                {
                    IBox usedBox = xBoxes[d.UsedItem];
                    yPos += F(0, 3);
                    Arrow(yPos, new VariableVector(name + "->...", usedBox.LowerLeft.X, yPos.Y), width: 2,
                          color: d.NotOkCt > 0 ? Color.Red : d.QuestionableCt > 0 ? Color.Blue : Color.Black,
                          text: "#=" + d.Ct, placement: LineTextPlacement.Left, textLocation: -85,
                          edgeInfo: d.ExampleInfo, drawingOrder: 1);
                    usedBox.UpperRight.MinY(yPos.Y + 5);
                    yPos         += F(0, DELTA_Y_MAIN);
                    minBoxHeight += DELTA_Y_MAIN;
                    box.UpperRight.MinY(yPos.Y);
                }
                box.Diagonal.MinY(minBoxHeight);
                //Console.WriteLine(name + ".LR.Y=" + y + " .H>=" + minBoxHeight + "  H.ShortName=" + box.Diagonal.Y.ShortName);
                y += minBoxHeight + 10;
            }

            //string countText = "\n<" + SumAsString(dependencies, d => d.UsingItem.Equals(i) && !d.UsedItem.Equals(i))
            //                   + " =" + SumAsString(dependencies, d => d.UsingItem.Equals(i) && d.UsedItem.Equals(i))
            //                   + " >" + SumAsString(dependencies, d => !d.UsingItem.Equals(i) && d.UsedItem.Equals(i));
            // TODO: Add option and computation to split this into .,?,!
        }
        public void NumericVariableInitialValueTest()
        {
            var variable = new NumericVariable(3.14);

            Assert.AreEqual(3.14, variable.Value);
        }