Skip to content

Commit

Permalink
Feature/filter controls (#61)
Browse files Browse the repository at this point in the history
* Add FilterControls utility to create subset of traffic controls for testing

* Add FilterControls usage to README

* FilterControls remove commented out code

* Update README.md fix testing typo
  • Loading branch information
kruegersp authored Jun 18, 2024
1 parent b1e6053 commit a6efa71
Show file tree
Hide file tree
Showing 2 changed files with 181 additions and 0 deletions.
16 changes: 16 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,22 @@ Example:
> x<sub>(n-2)</sub><sub>0</sub>,y<sub>(n-2)</sub><sub>0</sub>,x<sub>(n-2)</sub><sub>1</sub>,y<sub>(n-2)</sub><sub>1</sub>,x<sub>(n-2)</sub><sub>2</sub>,y<sub>(n-2)</sub><sub>2</sub>,x<sub>(n-2)</sub><sub>3</sub>,y<sub>(n-2)</sub><sub>3</sub>
> x<sub>(n-1)</sub><sub>0</sub>,y<sub>(n-1)</sub><sub>0</sub>,x<sub>(n-1)</sub><sub>1</sub>,y<sub>(n-1)</sub><sub>1</sub>,x<sub>(n-1)</sub><sub>2</sub>,y<sub>(n-1)</sub><sub>2</sub>,x<sub>(n-1)</sub><sub>3</sub>,y<sub>(n-1)</sub><sub>3</sub>
## Testing Considerations

Upon startup, CARMA Cloud automatically creates traffic controls for later sending to CARMA platform by reading XML OpenDrive files placed in its XODR work folder, e.g. <tomcat_home>/work/xodr. This can result in thousands of traffic controls that are mostly uninteresting for testing purposes. The cc.util.FilterControls command-line application accepts a list of traffic control identifiers, and creates a much smaller and more manageable subset of traffic controls that can be saved along with their respective testing scenarios.

After CARMA Cloud has been started for the first time in a testing scenario, XODR files will have been processed, and the tester can login to CARMA Cloud to add traffic controls for his testing needs. Executing an ls -lrt in the traffic controls folder, typically <tomcat_home>/work/carmacloud/traf_ctrls, will put the newly created traffic controls at the bottom of the list. The hexadecimal encoded text for the 16-byte traffic control ids to be kept can then be derived from three levels of folder paths and the traffic control filename.

The FilterControls application takes the source work folder name, the destination work folder name, and a space-separated list of at least one 16-byte hexadecimal encoded text traffic control id.
```
<java_home>/bin/java -cp <path_to_carmacloud_classes>:<path_to_carmacloud_lib>/keccakj.jar cc.util.FilterControls <source_path> <destination_path> <id1> <id2> ... <idN>
```
For example:
```
<java_home>/bin/java -cp <path_to_carmacloud_classes>:<path_to_carmacloud_lib>/keccakj.jar cc.util.FilterControls <tomcat_home>/work/carmacloud <tomcat_home>/work/filtered 00109ab6d542f12ca8942b436c9c9d8d
```
FilterControls creates the destination folder structure containing geolanes, linearcs, td, and traf_ctrls subfolders. The filtered traffic control files can then be saved with the appropriate testing scenarios. Both the td and traf_ctrls folders should always contain at least one file, and it is also normal under some circumstances that the geolanes and linearcs folders may contain no files.

## Contribution
Welcome to the CARMA contributing guide. Please read this guide to learn about our development process, how to propose pull requests and improvements, and how to build and test your changes to this project. [CARMA Contributing Guide](Contributing.md)

Expand Down
165 changes: 165 additions & 0 deletions src/cc/util/FilterControls.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
package cc.util;


import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
import java.io.IOException;
import cc.ctrl.proc.TdFeature;
import cc.ctrl.proc.TdLayer;
import cc.ctrl.CtrlIndex;
import cc.ctrl.TrafCtrl;
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/

/**
*
* @author Federal Highway Administration
*/
public class FilterControls
{
public static void main(String[] sArgs)
throws Exception
{
String sInputDir = sArgs[0];
if (!sInputDir.endsWith("/"))
sInputDir += "/";
String sOutputDir = sArgs[1];
if (!sOutputDir.endsWith("/"))
sOutputDir += "/";
Files.createDirectories(Paths.get(sOutputDir));
Files.createDirectories(Paths.get(sOutputDir + "linearcs/direction"));
Files.createDirectories(Paths.get(sOutputDir + "linearcs/rdmks"));
Files.createDirectories(Paths.get(sOutputDir + "linearcs/pavement"));
Files.createDirectories(Paths.get(sOutputDir + "xodr/"));
Files.createDirectories(Paths.get(sOutputDir + "td/"));
Files.createDirectories(Paths.get(sOutputDir + "geolanes/"));
Files.createDirectories(Paths.get(sOutputDir + "traf_ctrls/"));
ArrayList<byte[]> oIds = new ArrayList();
StringBuilder sBuf = new StringBuilder();
for (int n = 2; n < sArgs.length; n++)
{
String sId = sArgs[n];
sBuf.setLength(0);
sBuf.append(sId);
oIds.add(Text.fromHexString(sBuf));
}

Collections.sort(oIds, TrafCtrl.ID_COMP);

Path oTdDir = Paths.get(sInputDir + "td/");
Path oOutputTdDir = Paths.get(sOutputDir + "td/");
Path oOutputGeoLanes = Paths.get(sOutputDir + "geolanes");
Path oOutputCtrl = Paths.get(sOutputDir + "traf_ctrls");

List<Path> oPaths = Files.walk(oTdDir).filter(Files::isRegularFile).collect(Collectors.toList());
byte[] yIdBuf = new byte[16];
for (Path oFile : oPaths)
{
String sFilename = oFile.toString();
ByteArrayOutputStream oBaos = new ByteArrayOutputStream();
if (sFilename.endsWith(".bin")) // td file
{
try (DataOutputStream oOut = new DataOutputStream(new BufferedOutputStream(oBaos));
DataInputStream oIn = new DataInputStream(new BufferedInputStream(Files.newInputStream(oFile))))
{
while (oIn.available() > 0)
{
TdLayer oTemp = new TdLayer(oIn, false);
int nFeatures = oIn.readInt();
for (int nIndex = 0; nIndex < nFeatures; nIndex++)
{
oIn.read(yIdBuf);
int nBytesToSkip = oIn.readInt();
int nSearch = Collections.binarySearch(oIds, yIdBuf, TrafCtrl.ID_COMP);
if (nSearch < 0)
oIn.skipBytes(nBytesToSkip);
else
oTemp.add(new TdFeature(oIn, oTemp.m_oKeys.length * 2, yIdBuf));
}
oTemp.write(oOut);
}
}

}
else if (sFilename.endsWith(".ndx")) // index file
{
try (DataOutputStream oOut = new DataOutputStream(new BufferedOutputStream(oBaos));
DataInputStream oIn = new DataInputStream(new BufferedInputStream(Files.newInputStream(oFile))))
{

while (oIn.available() > 0)
{
CtrlIndex oIndex = new CtrlIndex(oIn);
int nSearch = Collections.binarySearch(oIds, oIndex.m_yId, TrafCtrl.ID_COMP);
if (nSearch >= 0)
writeIndex(oIndex, oOut);
}
}
}

if (oBaos.size() > 0)
{
String sPath = oOutputTdDir.toString() + "/" + oFile.subpath(oFile.getNameCount() - 2, oFile.getNameCount()).toString();
Path oPath = Paths.get(sPath);
Files.createDirectories(oPath.getParent());
try (BufferedOutputStream oOut = new BufferedOutputStream(Files.newOutputStream(oPath)))
{
oOut.write(oBaos.toByteArray());
}
}
}

for (byte[] yId : oIds)
{
createFilePath(sBuf, yId);

Path oInTraf = Paths.get(sInputDir + "traf_ctrls/" + sBuf.toString() + ".bin");
Path oOutTraf = Paths.get(oOutputCtrl.toString() + "/" + sBuf.toString() + ".bin");
Files.createDirectories(oOutTraf.getParent());
Files.copy(oInTraf, oOutTraf);

oInTraf = Paths.get(sInputDir + "traf_ctrls/" + sBuf.toString() + ".bin.json");
oOutTraf = Paths.get(oOutputCtrl.toString() + "/" + sBuf.toString() + ".bin.json");
Files.copy(oInTraf, oOutTraf);
}
}


public static void createFilePath(StringBuilder sBuf, byte[] oId)
{
sBuf.setLength(0);
int nOffset = 0;
int nCount = 3;
while (nCount-- > 0)
{
Text.toHexString(oId, nOffset, nOffset + 4, sBuf);
nOffset += 4;
sBuf.append("/");
}
Text.toHexString(oId, nOffset, nOffset + 4, sBuf);
}

public static void writeIndex(CtrlIndex oIndex, DataOutputStream oOut)
throws IOException
{
oOut.writeInt(oIndex.m_nType);
oOut.write(oIndex.m_yId);
oOut.writeLong(oIndex.m_lStart);
oOut.writeLong(oIndex.m_lEnd);
for (int nIndex = 0; nIndex < oIndex.m_dBB.length; nIndex++)
oOut.writeInt((int)(oIndex.m_dBB[nIndex] * 100.0 + 0.5));
}
}

0 comments on commit a6efa71

Please sign in to comment.