I'm developing a C# Winforms app where I need to determine if a truck took a specifed route, and passed through the points in the correct order. An example of valid routes would be as follows:
ROUTE 1
Entry gate 1
Scale gate entry side
Scale gate exit side
Exit gate 1
ROUTE 2
Entry gate 2
Scale gate entry side
Scale gate exit side
Exit gate 2
The scale gates are the same for both routes, but the entry and exit gates are what I need to worry about. If a truck enters in through gate 1 and exits through the gate 1, then the route followed was correct. However, if a truck enters gate 2 and exits through gate 1, then I need to send a notification.
Each gate has hardware configured as a read point. When the truck passes the read point a record is created in the database with the timestamp. I have a timer set up so that at the specified interval it retrieves a list of the valid the truck ID's. It then retrieves the read points that each truck passed within a specified time period and stores those in a list as well. What I'm not sure of is how to compare the "correct route" list with the list of read points that the truck passed. Right now I'm going on the basis that each truck will only make the trip once a day, and will tweak for additional trips after I get this covered.
Here's my code for the timer
private void tmr_Tick(object sender, EventArgs e)
{
int maxTime = int.Parse(AppSettings.GetAppSetting("MaxTime"));
List<string> _assets = new List<string>();
List<ReadPoint> _assetReads = new List<ReadPoint>();
//Get the list of assets to process
DataSet ds = du.ExecuteTextCommand("SELECT DISTINCT AssetId FROM " +
"(SELECT a.TagId, a.AssetId, a.Description, rp.Comments, DateScanned " +
"FROM AssetsReads ar JOIN Assets a on ar.AssetTagID = a.AssetTagID " +
"JOIN ReadPointLocations rp on " +
"ar.ReadPointLocationsID = rp.ReadPointLocationsID) AS AssetResult " +
"ORDER BY AssetId");
if (ds != null && ds.Tables[0].Rows.Count > 0)
{
foreach (DataRow dr in ds.Tables[0].Rows)
{
_assets.Add(dr["AssetId"].ToString());
}
}
//Loop through and process the assets
foreach (string asset in _assets)
{
ds = du.ExecuteTextCommand("SELECT a.TagId, a.AssetId, a.Description, " +
"rp.ReadPointLocationId, rp.Comments, DateScanned " +
"FROM AssetsReads ar JOIN Assets a on ar.AssetTagID = a.AssetTagID " +
"JOIN ReadPointLocations rp on " +
"ar.ReadPointLocationsID = rp.ReadPointLocationsID " +
"WHERE a.AssetID = '" + asset + "' ORDER BY DateScanned");
if (ds != null && ds.Tables[0].Rows.Count > 0)
{
_assetReads.Clear();
foreach (DataRow dr in ds.Tables[0].Rows)
{
ReadPoint ar = new ReadPoint();
ar.ReadPointLocationId = int.Parse(dr["ReadPointLocationId"].ToString());
ar.ReadpointName = dr["Comments"].ToString();
ar.DateScanned = DateTime.Parse(dr["DateScanned"].ToString());
_assetReads.Add(ar);
}
//Check to see if the asset has been seen in the last (MaxTime) minutes
if (DateTime.Parse(_assetReads[0].DateScanned.ToString()) < DateTime.Now)
{
///////////////////////
//Send notification
///////////////////////
continue;
}
//Determine the correct route to follow
Route currentRoute = null;
foreach (Route rt in _routes)
{
foreach (ReadPoint rp in rt.ReadPoints)
{
if (_assetReads[0].ReadPointLocationId == rp.ReadPointLocationId)
{
currentRoute = rt;
break;
}
}
if (currentRoute != null)
break;
}
//Check if the route was correctly followed
if (currentRoute != null)
{
//////////////////////////////
//This is where I'm stuck
//////////////////////////////
}
}
}
}
Well, I think you're really close here. You have a list of the ReadPointLocations (gates) the Asset (truck) has been through, in the order the truck went through the gates. You also have a list of the "proper" paths through these gates, and can identify which one should have been followed, based on which gate the truck went through first. The only thing left to do is to line up the truck's gate reads next to the expected reads, and verify that the truck went through all the gates it should have, in order:
//Check if the route was correctly followed
if (currentRoute != null)
{
var gatesInOrder = 0;
for(var i=0; i<_assetReads.Length; i++)
{
if(_assetReads[i].ReadPointLocationId == currentRoute[gatesInOrder])
//gate crossed in order; increment to next gate
gatesInOrder++;
}
//if we didn't get to the end of the route, send a notification
if(gatesInOrder != currentRoute.Length)
{
///////////////////////
//Send notification
///////////////////////
}
}
Now, this assumes two things. First, that all reads are performed without error. I can tell you from experience that location scans are missed with a very high frequency, even in automated systems. This means that if your entry gate scan was missed, you won't be able to determine which gate the truck should have exited through; you'll pick a Route (probably Gate 1) based on the first read you have, which is the scale entry gate, but because that node is common to both the Gate 1 and Gate 2 paths, you'll falsely notify that the truck exited through the wrong gate if the truck exits through Gate 2, even if it entered through Gate 2. In order to avoid this, you'll have to be able to identify gates in each Route that are unique to that Route (in this case, the entry and exit gates) and identify the proper route to use based on the first gate scan for one of those locations, and not just any location. You'll now have picked the proper route, but you won't find the entry gate scan; you can detect this and send a different "gate scan missed" notification.
Second, we assume that once a truck enters a route, that it must continue through that path and cannot deviate at any point. Nothing can be done out of order. So, in a more complex example, let's say the truck also goes through a simple inspection (taillights working, no visible leaks, tire tread OK, no billowing smoke at idle, etc). If the inspection and weighing can happen in either order, you would falsely send a notification with the above algorithm if the weighing and inspection happened in the opposite order than expected. You can avoid this naively by simply checking that all of the proper path's locations were scanned at some point, but that wouldn't catch, for instance, a truck going the wrong way through the whole thing. If that's possible then you'll need something more complex, such as an overall route map with conditional paths (you may proceed either to the weighing or the inspection gate from either entry gate, then from the inspection exit if you haven't been weighed you must proceed to the weighing entry and vice-versa, while if you have been through both sub-paths, you must proceed to exit gate 1 if you went through entry gate 1, or exit 2 if you entered through entry 2.
Related
// EDIT:
This is not a duplicate to: "When should I use a List vs a LinkedList". Check the answer I've provided below.
LinkedList might be useful though if someone wants to insert some positions at a specific place after we have a properly ordered List (in that case - LinkedList) already - how to make one, check my answer below. //
How would you iterate backwards (with pauses for player input) through a set of randomly generated numbers?
I'm trying to build a turn-based game. The order of actions is determined by a result of something like that:
int randomPosition = Random.Range(1,31) + someModifier;
// please note that someModifier can be a negative number!
// There is no foreseeable min or max someModifier.
// Let's assume we can't set limits.
I have a List of KeyValue pairs already containing names of objects and their corresponding randomPosition. // Update: Values of it are already sorted by a custom Sort() function, from highest to lowest.
// A list of KeyValue pairs containing names of objects and their corresponding randomPosition.
public List<KeyValuePair<string, int>> turnOrder = new List<KeyValuePair<string, int>> ();
// GameObject names are taken from a list of player and AI GameObjects.
List <GameObject> listOfCombatants = new List<GameObjects>();
// Each GameObject name is taken from listOfCombatants list.
listOfCombatants[i].name;
I thought, maybe let's add player and AI GameObjects to a list on Index positions equal to each of their randomPosition. Unfortunately, a Generic List can't have "gaps" in it. So we can't create it, let alone iterate it backwards.
Also, I'm not sure how we'd stop a for loop to wait for player input. I have a button, pressing which will perfom an action - switch state and run some functions.
Button combat_action_button;
combat_action_button.onClick.AddListener (AttackButton);
// When player takes his turn, so in TurnState.PLAYER_ACTION:
public void AttackButton() {
switch(actionState) {
case PlayerAction.ATTACK:
Debug.Log (actionState);
// Do something here - run function, etc. Then...
currentState = TurnState.ENEMY_ACTION;
break;
}
To make things worse, I've read that "pausing" a while loop isn't good for performance. That it's better to take player input out of loops.
So maybe I should create more for loops, iterate a new loop from position to position until the last GameObject acted, and use some delegates/events, as some things players/AI can do are in different scripts (classes).
This is not a real-time project, so we can't base anything on time (other than potential max turn time).
Another thing is, we don't know how many GameObjects will take turns.
But maybe there's some collection type that can store GameObjects with gaps between their index positions and iterate a loop from highest to lowest with no problem?...
I want to make it as simple as possible.
For the issue of simultaneously having user input and looping, I recommend looking into background workers or threading/tasks. This should facilitate your problem with simultaneously doing two things at once.
For your list problem I personally prefer the lists as well which is why I would designate each "gap" with a specific character like - 1, and when referencing the data ignore the - 1. To ignore the gaps I recommend LINQ queries but if you don't want to use LINQ that should not be a problem.
EDIT*
I know very little about Unity but from what people have been saying it sounds like running multiple threads is or can be an issue. I looked into this issue and it sounds like you just cannot call the unity api from a background thread. So basically, as long as you do not reference the unity api from the background thread, you should be ok. With that said, you may possibly need/want to make a call to the api inside of the background worker. To do this you need to either invoke the call before or after the background worker thread. I am pretty sure there is also a simultaneous invocation from the main thread by setting the workers step property to true.
I've decided to share my own solutions as I think I've developped some accurate answers to my questions.
Solution #1. First, declare an array, 2 variables and 1 function:
int[] arrayOrderedCombatants;
int min = 100000;
int max;
public void SomePlayerAction() {
Debug.Log ("This is some player or AI action.");
}
public void IterateThroughTurnOrderPositions() {
for (int i=max; i >= min; i--) {
if (arrayOrderedCombatants [i] >= 0 && arrayOrderedCombatants [i] >= min) {
Debug.Log ("This is an existing position in turn order: " + arrayOrderedCombatants [i]);
foreach (var position in turnOrder) {
if (position.Value == arrayOrderedCombatants [i]) {
max = (arrayOrderedCombatants [i] - 1);
goto ExitLoop;
}
}
}
}
ExitLoop:
SomePlayerAction ();
}
Then, for our testing purposes let's use an Update() method triggered by Input.GetKeyDown:
if (Input.GetKeyDown (KeyCode.O)) {
arrayOrderedCombatants = new int[turnOrder[0].Value + 1];
Debug.Log ("This is arrayOrderedCombatants Length: " + arrayOrderedCombatants.Length);
foreach (var number in turnOrder) {
if (number.Value < min)
min = number.Value;
}
Debug.Log ("This is min result in random combat order: " + min);
for (int i=0; i < arrayOrderedCombatants.Length; i++)
arrayOrderedCombatants[i] = min -1;
foreach (var combatant in turnOrder) {
if (combatant.Value >= 0) {
arrayOrderedCombatants [combatant.Value] = combatant.Value;
}
}
max = turnOrder [0].Value;
while (max >= min)
IterateThroughTurnOrderPositions ();
}
The above code answers my question. Unfortunately, problems with this solution may be two. First - you can't have a negative index position. So if someModifier makes randomPosition go below 0, it won't work. Second problem - if you have more than 1 occurance of any value from randomPosition, it will be added to the arrayOrderedCombatants only once. So it will be iterated once too.
But that's obvious - you can't have more than one value occupying an int type Arrays' index position.
So I will provide you a better solution. It's a different approach, but works like it should.
Solution #2. First, declare a list of GameObjects:
List<GameObject> orderedCombatants = new List<GameObject> ();
Then, in Update() method:
if (Input.GetKeyDown (KeyCode.I)) {
orderedCombatants.Clear ();
foreach (var combatant in initiative) {
Debug.Log (combatant);
for (int i=0; i < listOfCombatants.Count; i++) {
if (listOfCombatants[i].name.Contains(combatant.Key)) {
orderedCombatants.Add(listOfCombatants[i]);
}
}
}
foreach (var combatant in orderedCombatants) {
Debug.Log (combatant.name);
}
}
The above creates a new list of GameObjects already set in the right order. Now you can iterate through it, easily access each GameObject and perform any actions you need.
For some reason i my code doesn't properly compare when an instantiated object is being overlapped.
What i want to do is, to generate random platforms with different positions and scale (X).
And since its random, it is possible of overlapping happening. So in order to solve this problem, ive tried to compare each and every platform and see if it overlaps and when it does, it will delete itself and instantiate another one.
An addition to this question is,
If i have the overlapping problem solved, is it possible to make it so the platforms are at a certain distance away from each other, for X Y and Z.
So . .
What have i done wrong ?
What can i do ?
void Platform_Position_Scale_Generator(int i) {
posX[i] = Random.Range(minPosRange, maxPosRange + 1);
posY[i] = Random.Range(minPosRange, maxPosRange + 1);
posZ[i] = 0;
scaleX[i] = Random.Range(minScaleRange, maxScaleRange + 1);
scaleY[i] = 1;
scaleZ[i] = 1;
}
void Platform_Generator(int i) {
platformPrefabPosition[i].x = posX[i];
platformPrefabPosition[i].y = posY[i];
platformPrefabPosition[i].z = posZ[i];
Instantiate(platformPrefab, platformPrefabPosition[i], Quaternion.identity);
platformPrefab.transform.localScale = new Vector3(scaleX[i], 1, 1);
}
// Error with this
void Detect_Collision(int i) {
for(int f = 0; f < i; f++) {
for(int s = f + 1; s < i; s++) {
bool xOverlap = (posX[s] > posX[f] && posX[s] < posX[f] + scaleX[i]) || (posX[f] > posX[s] && posX[f] < posX[s] + scaleX[i]);
bool yOverlap = (posY[s] > posY[f] && posY[s] < posY[f] + scaleY[i]) || (posY[f] > posY[s] && posY[f] < posY[s] + scaleY[i]);
if(xOverlap && yOverlap) {
Debug.Log("xOverlap: " + xOverlap + " yOverlap: " + yOverlap);
}
else {
//Debug.Log("xOverlap: " + xOverlap + " yOverlap: " + yOverlap);
}
}
}
}
I wouldn't recommend using completely random generation for something like this, as it can easily create something totally unplayable, and making it playable can be more difficult than trying a more methodical approach.
One interesting approach could be the one shown in this video:
https://www.youtube.com/watch?v=VkGG9Umag0M
That approach is using pre-built chunks of levels manually generated to be playable, that are later randomly chosen in run-time, to create infinite levels.
Another approach could be dynamically generating a sequence of "viable" platforms.
I'm assuming this is a 2D platform game, but the same logic could apply to other types.
For example, the following sequence:
Add a platform on the left edge (random Y position and size, if desired).
Determine viable positions of the next platform to the right and vertically, taking into account both the end position of the previous platform and other things, such as jumping distance. That would give you a max position at which you can place things and still have the player make it. You can use that max and possibly a min. distance to chose a random value between them and still have a viable platform without overlaps.
Repeat step 2 until you reach some end condition, such as size of level, amount of platforms, etc.
You can also add a more complex logic, such as allowing overlaps on one axis as long as there isn't any on the other axis, or a minimum separation between both. That way you could get two nearly parallel platforms, and things like that.
Other rules could be more complex, expecting an actual specific solution from the player, such as double-jumps, bouncing off walls, etc. In that scenario you could have item 2 just be one of many generation strategies from which to chose from.
This type of generation would also be much less expensive than actual instantiation and deletion in case of collisions.
NOTE:
If you still want to stick to 100% random generation, but guarantee gaps between platforms. Just assume an "imaginary" border surrounding the actual platform. Instead of just taking into account current real points, just add offsets to them when testing collisions.
You should be able to test intersection without physics, using something similar to what is show here:
http://answers.unity3d.com/questions/581014/2d-collision-detection-box-intersection-without-ph.html
if (object1.renderer.bounds.Intersects(object2.renderer.bounds)) {
// Do some stuff
}
I'm creating a program which collects some personal info and persons' salary to calculate their earnings after tax.
I'm using a switch statement for the menu. Which looks like this:
Get a person’s details (p)
Get the Salary (s)
Calculate and display (d)
Exit (x)
I want the users to complete these in a sequential order, so before entering their salary or trying to calculate their pay, they are forced to enter their details. e.g.: Full name is the first personal detail that they have to fill in.
At this point the users has selected (d) to display their earnings, but they will be stopped because they haven't filled in their personal details.
Console.WriteLine("\nUser selected to calculate and display their earnings\n");
if (full_name == "")
{
Console.WriteLine("Error: Please enter personal details before attempting to display your pay\n");
break;
}
This works fine because it's a string, so if it has been left empty, they return to the original menu.
But I also want to stop them from trying to select option (d) if they haven't filled in option (s), their salary, which is stored in a float. If I try this:
if (annual_salary == null)
{break;}
it says that it will always be false since a value of type float is never equal to null of type float.
This is my while loop for option (s) which collects the data when the user selects this option.
while (valid == false)
{
Console.Write("Enter your annual salary: > ");
vtemp = Console.ReadLine();
// Validate the data entered
if (vtemp == "")
{
Console.WriteLine("\nError : Annual salary cannot be empty. Please try again...\n");
}
else
// Check if data is a valid integer
returnVal = float.TryParse(vtemp, out annual_salary);
if (returnVal == false)
{
Console.WriteLine("\nError : Please enter numbers only. Please try again...\n");
}
else
// Check value is positive
if (i < 0)
{
Console.WriteLine("\nError : Annual salary must be positive. Please try again...\n");
}
else
{
valid = true;
break;
}
}// End while
But if the users never select (s) and decide to go straight to (d) after filling in (p), They will get an incorrect value from the output.
So to clarify: How do I check if a float value has been left empty or skipped?
Simplest solution will be to give your s a default negative value, and make sure it's not negative before you continue.
Depending on how / where you're enforcing this, you can do different things. If you're doing a WPF or other GUI development, you can disable the button until it's all set.
If you want to do it in logic, you can go with the above solution, or have some flags that will be set to true when you select an option, and you will only continue if all flags are set to true, and so one.
Edit:
I've updated p to s. It's the same really. When he hits d either check that s is not negative (you can initialize it to -1), or if you go with the flag option, make sure the flag for it is true (it's set when you hit s for example).
Then, if you have all input, calculate, otherwise write a message saying he needs to input salary.
My Problem
I have a data stream coming from a program that connects to a GPS device and an inclinometer (they are actually both stand alone devices, not a cellphone) and logs the data while the user drives around in a car. The essential data that I receive are:
Latitude/Longitude - from GPS, with a resolution of about +-5 feet,
Vehicle land-speed - from GPS, in knots, which I convert to MPH
Sequential record index - from the database, it's an auto-incrementing integer and nothing ever gets deleted,
some other stuff that isn't pertinent to my current problem.
This data gets stored in a database and read back from the database into an array. From start to finish, the recording order is properly maintained, so even though the timestamp that is recorded from the GPS device is only to 1 second precision and we sample at 5hz, the absolute value of the time is of no interest and the insertion order suffices.
In order to aid in analyzing the data, a user performs a very basic data input task of selecting the "start" and "end" of curves on the road from the collected path data. I get a map image from Google and I draw the curve data on top of it. The user zooms into a curve of interest, based on their own knowledge of the area, and clicks two points on the map. Google is actually very nice and reports where the user clicked in Latitude/Longitude rather than me having to try to backtrack it from pixel values, so the issue of where the user clicked in relation to the data is covered.
The zooming in on the curve clips the data: I only retrieve data that falls in the Lat/Lng window defined by the zoom level. Most of the time, I'm dealing with fewer than 300 data points, when a single driving session could result in over 100k data points.
I need to find the subsegment of the curve data that falls between those to click points.
What I've Tried
Originally, I took the two points that are closest to each click point and the curve was anything that fell between them. That worked until we started letting the drivers make multiple passes over the road. Typically, a driver will make 2 back-and-forth runs over an interesting piece of road, giving us 4 total passes. If you take the two closest points to the two click points, then you might end up with the first point corresponding to a datum on one pass, and the second point corresponding to a datum on a completely different pass. The points in the sequence between these two points would then extend far beyond the curve. And, even if you got lucky and all the data points found were both on the same pass, that would only give you one of the passes, and we need to collect all passes.
For a while, I had a solution that worked much better. I calculated two new sequences representing the distance from each data point to each of the click points, then the approximate second derivative of that distance, looking for the inflection points of the distance from the click point over the data points. I reasoned that the inflection point meant that the points previous to the inflection were getting closer to the click point and the points after the inflection were getting further away from the click point. Doing this iteratively over the data points, I could group the curves as I came to them.
Perhaps some code is in order (this is C#, but don't worry about replying in kind, I'm capable of reading most languages):
static List<List<LatLngPoint>> GroupCurveSegments(List<LatLngPoint> dataPoints, LatLngPoint start, LatLngPoint end)
{
var withDistances = dataPoints.Select(p => new
{
ToStart = p.Distance(start),
ToEnd = p.Distance(end),
DataPoint = p
}).ToArray();
var set = new List<List<LatLngPoint>>();
var currentSegment = new List<LatLngPoint>();
for (int i = 0; i < withDistances.Length - 2; ++i)
{
var a = withDistances[i];
var b = withDistances[i + 1];
var c = withDistances[i + 2];
// the edge of the map can clip the data, so the continuity of
// the data is not exactly mapped to the continuity of the array.
var ab = b.DataPoint.RecordID - a.DataPoint.RecordID;
var bc = c.DataPoint.RecordID - b.DataPoint.RecordID;
var inflectStart = Math.Sign(a.ToStart - b.ToStart) * Math.Sign(b.ToStart - c.ToStart);
var inflectEnd = Math.Sign(a.ToEnd - b.ToEnd) * Math.Sign(b.ToEnd - c.ToEnd);
// if we haven't started a segment yet and we aren't obviously between segments
if ((currentSegment.Count == 0 && (inflectStart == -1 || inflectEnd == -1)
// if we have started a segment but we haven't changed directions away from it
|| currentSegment.Count > 0 && (inflectStart == 1 && inflectEnd == 1))
// and we're continuous on the data collection path
&& ab == 1
&& bc == 1)
{
// extend the segment
currentSegment.Add(b.DataPoint);
}
else if (
// if we have a segment collected
currentSegment.Count > 0
// and we changed directions away from one of the points
&& (inflectStart == -1
|| inflectEnd == -1
// or we lost data continuity
|| ab > 1
|| bc > 1))
{
// clip the segment and start a new one
set.Add(currentSegment);
currentSegment = new List<LatLngPoint>();
}
}
return set;
}
This worked great until we started advising the drivers to drive around 15MPH through turns (supposedly, it helps reduce sensor error. I'm personally not entirely convinced what we're seeing at higher speed is error, but I'm probably not going to win that argument). A car traveling at 15MPH is traveling at 22fps. Sampling this data at 5hz means that each data point is about four and a half feet apart. However, our GPS unit's precision is only about 5 feet. So, just the jitter of the GPS data itself could cause an inflection point in the data at such low speeds and high sample rates (technically, at this sample rate, you'd have to go at least 35MPH to avoid this problem, but it seems to work okay at 25MPH in practice).
Also, we're probably bumping up sampling rate to 10 - 15 Hz pretty soon. You'd need to drive at about 45MPH to avoid my inflection problem, which isn't safe on most of the curves of interest. My current procedure ends up splitting the data into dozens of subsegments, over road sections that I know had only 4 passes. One section that only had 300 data points came out to 35 subsegments. The rendering of the indication of the start and end of each pass (a small icon) indicated quite clearly that each real pass was getting chopped up into several pieces.
Where I'm Thinking of Going
Find the minimum distance of all points to both the start and end click points
Find all points that are within +10 feet of that distance.
Group each set of points by data continuity, i.e. each group should be continuous in the database, because more than one point on a particular pass could fall within the distance radius.
Take the data mid-point of each of those groups for each click point as the representative start and end for each pass.
Pair up points in the two sets per click point by those that would minimize the record index distance between each "start" and "end".
Halp?!
But I had tried this once before and it didn't work very well. Step #2 can return an unreasonably large number of points if the user doesn't click particularly close to where they intend. It can return too few points if the user clicks very, particularly close to where they intend. I'm not sure just how computationally intensive step #3 will be. And step #5 will fail if the driver were to drive over a particularly long curve and immediately turn around just after the start and end to perform the subsequent passes. We might be able to train the drivers to not do this, but I don't like taking chances on such things. So I could use some help figuring out how to clip and group this path that doubles back over itself into subsegments for passes over the curve.
Okay, so here is what I ended up doing, and it seems to work well for now. I like that it is a little simpler to follow than before. I decided that Step #4 from my question was not necessary. The exact point used as the start and end isn't critical, so I just take the first point that is within the desired radius of the first click point and the last point within the desired radius of the second point and take everything in the middle.
protected static List<List<T>> GroupCurveSegments<T>(List<T> dbpoints, LatLngPoint start, LatLngPoint end) where T : BBIDataPoint
{
var withDistances = dbpoints.Select(p => new
{
ToStart = p.Distance(start),
ToEnd = p.Distance(end),
DataPoint = p
}).ToArray();
var minToStart = withDistances.Min(p => p.ToStart) + 10;
var minToEnd = withDistances.Min(p => p.ToEnd) + 10;
bool startFound = false,
endFound = false,
oldStartFound = false,
oldEndFound = false;
var set = new List<List<T>>();
var cur = new List<T>();
foreach(var a in withDistances)
{
// save the previous values, because they
// impact the future values.
oldStartFound = startFound;
oldEndFound = endFound;
startFound =
!oldStartFound && a.ToStart <= minToStart
|| oldStartFound && !oldEndFound
|| oldStartFound && oldEndFound
&& (a.ToStart <= minToStart || a.ToEnd <= minToEnd);
endFound =
!oldEndFound && a.ToEnd <= minToEnd
|| !oldStartFound && oldEndFound
|| oldStartFound && oldEndFound
&& (a.ToStart <= minToStart || a.ToEnd <= minToEnd);
if (startFound || endFound)
{
cur.Add(a.DataPoint);
}
else if (cur.Count > 0)
{
set.Add(cur);
cur = new List<T>();
}
}
// if a data stream ended near the end of the curve,
// then the loop will not have saved it the pass.
if (cur.Count > 0)
{
cur = new List<T>();
}
return set;
}
I've got a strange problem. I'm creating a NUI for application and I binded some simple gestures to right and left arrow. The problem is when I start application. When I make gesture for the first time my application is hitting 2 times in a row. After that it works 100% as I want. Only the start is the problem.
I'm adding two Joints and timestamp to my history struct which is put into the ArrayList
this._history.Add(new HistoryItem()
{
timestamp = timestamp,
activeHand = hand,
controlJoint = controlJoint
}
);
then in foreach loop I'm comparing data
if (Math.Abs((hand.Position.X - item.controlJoint.Position.X)) < MainWindow.treshold && Math.Abs((hand.Position.Y - item.controlJoint.Position.Y)) < MainWindow.verticalTreshold)
If it hits I instantly break the lopp with
break;
after that I clear the history ArrayList
this._history.Clear();
So I don't get it. Why after the start it hits two times in a row ?
// edit
history ArrayList initialization
private List<HistoryItem> _history = new List<HistoryItem>(16);
in loop
foreach (HistoryItem item in this._history)
{
if ((hand.Position.X - item.controlJoint.Position.X) < MainWindow.treshold)
{
float tmp = (hand.Position.X - controlJoint.Position.X);
MainWindow.slideNumber++;
this._logger.Log("Next slide: " + MainWindow.slideNumber);
this._logger.Log(hand.Position.X + " - " + controlJoint.Position.X + " = " + tmp + " | " + MainWindow.treshold);
this.startTime = 0;
this.gestureStart = false;
answerFlag = true;
System.Windows.Forms.SendKeys.SendWait("{Right}");
break;
}
}
Now. As you can see i'm breaking here. So this code shouldn't be invoked second time in a row
How this clears something
// edit 2
I'll also add that to get into this part of code the gestureStart flag need to be set to true. As you can see after getting into the 'if' part here I'm setting it to false. So it is impossible that the code instantly can get to this part
// edit 3 WORKING WORKAROUND
I've created kind of workaround. I've added time control. I'm comparing timestamp of invoking the code and timestamp of last gesture recognition. If its too fast ( i meen couple of ms which it impossible to make ) I don't allow to hit an arrow. I'm not sure if it's a perfect solution but it is a working solution
Ok my problem was the code. Ofc a small bug untracable in the debug. I used one function to analyse a history of frames.
The method was working in 2 modes. I`ve detached that and created 2 diffrent methods, each for each task and now it works great