In Unity3d, How can I read the position data from .txt file continuously? - parsing

In Unity3D, I want to load position data from text file. Here is an example of the text file. These are simulation results. The simulation program generate 30 data per a second. So, I want to visualize result in realtime. The contents are x, y, z position.
data_01.txt
1 -5 -10
data_ 02.txt
2 2 5
data_03.txt
3 2 4
...............
All files consist of 1 line.
I'd like to input these data into a object.
I want to load text file in 30 text files per 1 second.
I write code that read first text file.
But, I need some advice about reading text file continuously. I want to read 1 text file per frame.
using UnityEngine;
using System.Collections;
using System;
using System.IO;
public class parsing : MonoBehaviour {
public string fileName = "Data_01.txt"
// Use this for initialization
void Start () {
}
// Update is called once per frame
void Update () {
if (!File.Exists(fileName))
{
Debug.Log(fileName + "does not exist.");
return;
}
using (StreamReader sr = File.OpenText(fileName))
{
String fileData;
fileData = sr.ReadToEnd();
sr.Close();
Debug.Log("Data Read: " + fileData);
}
}
}

Transfering continuous data via text files is a pretty bad idea/approach.
You are better off using (for example) a tcp connection and send your simulation data to unity using .Nets' System.Net.Sockets (more precisely TcpListener and TcpClient).
See: https://msdn.microsoft.com/en-us/library/system.net.sockets(v=vs.110).aspx
(If you want to stick to your approach, you would have to know the name of the text files to read each Update(). You could use a counter variable (name it counter for example), that is incremented each Update(). That way you can glue together the current text file name like string filename = "data_" + counter.ToString("D2") + ".txt". (The ToString("D2") will add leading zeros if the value of counter is only one digit, e.g. 1 -> "01")

Related

Google Sheets IMORTHTML converting to scientific notation

I am importing a table to google sheets with a formula like:
=IMPORTHTML("http://TheServer/FetchBatchData.php,"table",1)
In a web browser I get data that looks like the following:
Batch Batches Mix Customer Status
30DE 3 AGPDHIGH Joe Sent
30DF 3 KHM100 Nancy Sent
30E0 1 DEER100 Bob Sent
30E1 3 KHM100 Ted Sent
My problem is that Google Sheets converts the Batch data (a simple Hex value) to scientific notation when it sees the "E" in the batch. The result is that "30E0" becomes 30 and "30E1" becomes 300. I have tried changing cell formats with no luck. Is there something that I am missing in setting up the formatting or the formula that can get Google to not help me?
I made several tests using formulas. The values like "30E0" are always taken and calculated automatically, even with the fix in the comments.
Because of that, the only way I found to fix the issue was to create a custom formula that takes the values of the HTML and returns plain text automatically, which will fix the issue.
The custom formula was created based on the URL in the sample sheet "https://ex1.svfeeds.com." However, you can change it to the correct one.
Here is the sample code:
function parseXml() {
// URL where the data is located and calling the URL fetch services.
let url = "https://ex1.svfeeds.com/";
let xml = UrlFetchApp.fetch(url).getContentText();
let document = XmlService.parse(xml);
let root = document.getRootElement();
// path to reach the raw data
let body = root.getChild('body');
let table = body.getChild('table');
let tbody = table.getChild('tbody');
let rows = tbody.getChildren('tr');
// empty variable, it will be updated with the new array
// with the data of the table
let tableData = [];
// starts the for loop to each of the rows and columns of the HTML table
for (let i = 0; i < rows.length; i++){
var columns = rows[i].getChildren('td');
if (columns.length == 0){
columns = rows[i].getChildren('th');
}
// empty variable, it will be updated with the new array
// with the information in the rows
var rowValues = []
// new "for" that will call the values in each cell in the table
for (var j = 0; j < columns.length; j++){
var cell = columns[j].getValue();
// push the cell values to the rows
rowValues.push(cell);
}
// push the values to the complete table
tableData.push(rowValues);
}
return tableData;
}
After that, you can call the custom function by adding =parseXml() to A1 for example, like this:
And it will look like this:
The path of the values use in this sample code, can be change base on how is the information is place in the original link. For example for the current page we use these variables to get to the raw data:
// path to reach the raw data
let body = root.getChild('body'); // 1
let table = body.getChild('table'); // 2
let tbody = table.getChild('tbody'); //3
let rows = tbody.getChildren('tr'); //4
and
columns = rows[i].getChildren('th'); //5
Base in the HTML source:
Reference:
Apps Script XML Service.
Custom Formulas.
Let me know if you have further questions.
I found a workaround though it is not something that I really like. Since the google Sheets are the only thing currently reading this table, I prepended a single quote to the output, so the 30E1 data becomes '30E1, and that will get me by until I can get Google Sheets to stop reformulating the data.
I'm still interested in more better if anyone has it.

swift smooth (interpolate) between incoming continuous data

Working in Swift I have a function which is called on arrival of new data (Double between 0 and 1). I need this function to go smoothly to the next value. In another language (MaxMSP) I could simply say go in 20 milliseconds from the previous value to the new one, this would even work if new data arrived before the set time was over. How could I achieve this in Swift? I've found vDSP.convolve() but I'd need an array of values to interpolate between, in my case data is real time and I have the latest value and previous value(s). The code I have is
var previousValue: Double = 0
var value: Double = 0 {
didSet {
valueDidChange()
}
}
private func valueDidChange() {
let valueSmooth = value * //smoothing magic with previousValue
}

How can I add extra data to Alte Beacon

I was building a beacon with AlteBeacon library, this was created fined but I would like to add extra data but I do not know how to do that. For example I would like to register product name and price in my new beacon.
public class Tab1Register extends Fragment {
private BluetoothAdapter blVer;
private TextView device;
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.tab1reg, container, false);
device = rootView.findViewById(R.id.device);
blVer = BluetoothAdapter.getDefaultAdapter();
boolean le2MPhySupported;
//device.setText("hola");
if (Build.VERSION.SDK_INT >= 21) {
// Call some material design APIs here
device.setText("supported");
Beacon beacon = new Beacon.Builder()
.setId1("2f234454-cf6d-4a0f-adf2-f4911ba9ffa6")
.setId2("1")
.setId3("2")
.setManufacturer(0x0118)
.setTxPower(-59)
.setDataFields(Arrays.asList(new Long[] {0l}))
.setBluetoothName("Paulo")
.build();
BeaconParser beaconParser = new BeaconParser()
.setBeaconLayout("m:2-3=beac,i:4-19,i:20-21,i:22-23,p:24-24,d:25-25");
BeaconTransmitter beaconTransmitter = new BeaconTransmitter(getActivity(), beaconParser);
beaconTransmitter.startAdvertising(beacon);
} else {
// Implement this feature without material design
device.setText("Not supported");
}
return rootView;
}
Understand that there is limited data space in a BLE advertisement. Each beacon format has a different number of data bytes available. For iBeacon, the number is 0 bytes, for Eddystone-UID, the number is 2 bytes and for AltBeacon, there is one byte.
The code shown in the question already adds this one byte of data to the advertisement, giving it a value of 0. If you want to change the value to 255, for example, change the code to this:
.setDataFields(Arrays.asList(new Long[] {255l}))
Don't let the fact that the data type in the setDataFields method takes an array of Long confuse you. Because only one byte is available in the single data field for this beacon format, you cannot store an entire long value (which would be 8 bytes) in the data field. The value must be between 0-255.

Add data to a new line in UITextView every time button is pressed

I currently have a function that, when a button is pressed, takes a value that is determined from a UIStepper and adds it to a list of numbers. When I press the Add Tip button, it correctly displays the tip amount in the text view, but when I add a new value it replaces it rather than adding it underneath.
Here is the function:
#IBAction func addTipButton(_ sender: UIButton) {
let tipDollarCent = dollar + cent
sampleLog.text = "\(tipDollarCent)\n"
totalLabel.text = tipDollarCent
}
sampleLog is the Text View that needs to take a variable amount of lines of data, depending on how many time the user presses addTipButton
I am aware that my best course of action is probably to do an incremental loop, and I have tried implementing a separate addNewLine function, but tipDollarCent was out of scope and gave me an error.
I also initially tried adding sampleLog.text = "\(tipDollarCent)\n" += "\(tipDollarCent)\n" directly to the function.
I am hoping someone would be able to patiently and kindly explain to me what the best loop to use in this scenario would be, and how to properly implement it.
Here is a screenshot of my app so it is easier to see what I am trying to accomplish
If you want the textView text to append the newly created string, you can use the compound-assign operator for addition += to concatenate the what you previous had and grow it with a new string value.
var foo:String = "Foo"
let bar:String = "Bar"
foo += bar /* FooBar */ /* foo = foo + bar */
And for your comment on additions with doubles, the compound operator will also work with same-typed operands.
var pi:Double = 3.0
let fourteen:Double = 0.14
pi += fourteen /* 3.14 */ /* pi = pi + fourteen */

Custom List with lazy loading

I have successfully implemented like this for lazy loading in custom list
and the code I used for this is here:Custom List With Images in Blackberry
In the linked question, I position the y coordinate of heart icon and I resolved the problemm of linked Question.
if (logoThumbnailImage != null
&& logoThumbnailImage.length > index
&& logoThumbnailImage[index] != null) {
EncodedImage img = logoThumbnailImage[index];
graphics.drawImage(0, y + 10, Display.getWidth(),
Display.getHeight() - 100, img, 0, 0, 0);
graphics.drawImage(300,
y+400,
heart.getWidth(), heart.getHeight(), heart,
0, 0, 0);
Now I want to handle click event for both; that is, for list row click and on heart click
For that I saw a post written by #Nate here Custom List Field click event. But in that code the images are not loading from server and they are static Images. I want to implement #Nate's code with my code (That is lazy loading ).
If you have any Idea please suggest how can I do that. Thanks in Advance
Assuming you start with the code I posted in this answer, and use the code you show in this question to download images from a list of URLs, then you should be able to achieve lazy image loading with the following changes:
Create a listener interface that gets notified when downloads complete:
public interface DownloadListener {
// invokes if download success
public void downloadSuccess(Bitmap bitmap);
// invokes if download failed
public void errorOccured();
}
Then, the Manager subclass that represents one list row, CustomListRow, is modified to implement this interface, and update the _thumb image when the download completes:
public class CustomListRow extends Manager implements DownloadListener, FieldChangeListener {
public void downloadSuccess(final Bitmap img) {
_data.setThumb(img);
// make sure bitmap is updated on the UI / main thread
UiApplication.getUiApplication().invokeLater(new Runnable() {
public void run() {
_thumb.setBitmap(img);
}
});
}
public void errorOccured() {
// TODO: handle error
}
Then, you'll need to add some code to create all your threads to download images in the background, and notify the DownloadListeners when the image downloads complete. You can decide where to do this. In my example, I will do this in my ListScreen class, where I instantiate the ListRander data objects and the CustomListField:
for (int i = 0; i < numberOfItem; i++) {
ListRander lr = new ListRander("Product Name " + i, icon); // icon is placeholder for thumbnail image
data.addElement(lr);
}
final CustomListField list = new CustomListField(data);
add(list);
list.setChangeListener(this);
pool = new ThreadPool(3); // 3 concurrent download threads
for (int i = 0; i < numberOfItem; i++) {
final int row = i;
// create a new runnable to download the next image, and resize it:
pool.assign(new Runnable() {
public void run() {
try {
String text=object[row].getJSONArray("UrlArray").getString(0).toString();
EncodedImage encodedImg = JPEGEncodedImage.encode(connectServerForImage(text), quality); //connectserverForImage load Images from server
EncodedImage logoThumbnail = sizeImage(encodedImg, Display.getWidth(), Display.getHeight()-100);
list.getRow(row).downloadSuccess(logoThumbnail.getBitmap());
} catch (Exception e) {
e.printStackTrace();
list.getRow(row).errorOccured();
}
}
}
});
}
You could do this in the ListScreen constructor, or whenever you have your object[] array of URLs.
You'll need to add a new method to CustomListField:
public CustomListRow getRow(int row) {
return (CustomListRow)getField(row);
}
The code above also needs a member variable added (in ListScreen) to create a thread pool:
private ThreadPool pool;
This thread pool implementation is based on this tutorial here, with very minor modifications, simply to change ArrayList (not available on BlackBerry Java) to Vector ... and removing the calls to Thread#destroy(). You'll need to copy that tutorial's ThreadPool, WorkerThread, and Done classes to your project. The above example I show creates a thread pool of 3 threads. On a single CPU smartphone, 2 or 3 threads is probably fine for your needs. Read more here if you want to get the perfect number of threads for your application.
Note: if possible, you can usually improve performance if you download images that are exactly the right size for your application, instead of burdening the network with larger images, and then resizing them inside your app. However, I realize that this depends on having some control over the images' web server, which you may not have. Just a thought for later optimization.
I am sure that I seen a good answer to this question on my travels, but can't find it now. I do recommend reviewing the BB forums here:
http://supportforums.blackberry.com/t5/Java-Development/bd-p/java_dev
as there are similar questions there.
For now, just the highlights of what you need to do:
Create an image downloading runnable to process the download - you have pretty much already done this in your previous code.
Use the Observer pattern (search the internet for this), so that the BitmapField is the Observer for the completion of your image downloading. So when the image has been downloaded, the Runnable invokes the observer, which can then update the Bitmap.
Use a Thread pool with a limited number of Threads (I would say 3), so that you do not start a whole load of image downloads at the same time. Search the internet for information on Thread Pool for help implementing this. You had not done this step in your previous example, and you can get away with running all the downloads, but I expect at some stage that this will fail.
Put these together and you have your solution. Not trivial I know. Good luck.

Resources