Skip to content

Commit

Permalink
Merge pull request #210 from JdeRobot/bt-status-subtrees
Browse files Browse the repository at this point in the history
Bt status for subtrees
  • Loading branch information
OscarMrZ authored Nov 5, 2024
2 parents 713d2eb + 2dbf4a0 commit a5a5e75
Show file tree
Hide file tree
Showing 12 changed files with 316 additions and 53 deletions.
9 changes: 8 additions & 1 deletion backend/filesystem/library_demo/config.json
Original file line number Diff line number Diff line change
@@ -1 +1,8 @@
{"name": "library_demo", "config": {"editorShowAccentColors": true, "theme": "dark", "btOrder": "bottom-to-top"}}
{
"name": "library_demo",
"config": {
"editorShowAccentColors": true,
"theme": "dark",
"btOrder": "top-to-bottom"
}
}
6 changes: 3 additions & 3 deletions backend/tree_api/json_translator.py
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,7 @@ def translate(content, tree_path, raw_order):
f.close()


def translate_tree_structure(content):
def translate_tree_structure(content, raw_order):
# Parse the JSON data
parsed_json = content

Expand All @@ -209,12 +209,12 @@ def translate_tree_structure(content):
# Get the tree structure
tree_structure = get_tree_structure(link_models, node_models)
# Get the order of bt: True = Ascendent; False = Descendent
# order = raw_order == "bottom-to-top"
order = raw_order == "bottom-to-top"

# Generate XML
start_node_id = get_start_node_id(node_models, link_models)
root = build_tree_structure(
node_models, link_models, tree_structure, start_node_id, False
node_models, link_models, tree_structure, start_node_id, order
)

return root
5 changes: 5 additions & 0 deletions backend/tree_api/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,11 @@
path("save_file/", views.save_file, name="save_file"),
path("translate_json/", views.translate_json, name="translate_json"),
path("get_tree_structure/", views.get_tree_structure, name="get_tree_structure"),
path(
"get_subtree_structure/",
views.get_subtree_structure,
name="get_subtree_structure",
),
path(
"get_universe_configuration/",
views.get_universe_configuration,
Expand Down
84 changes: 73 additions & 11 deletions backend/tree_api/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,7 @@ def get_project_configuration(request):
def get_tree_structure(request):

project_name = request.GET.get("project_name")
bt_order = request.GET.get("bt_order")

# Generate the paths
base_path = os.path.join(settings.BASE_DIR, "filesystem")
Expand All @@ -208,7 +209,45 @@ def get_tree_structure(request):
graph_data = json.load(f)

# Get the tree structure
tree_structure = json_translator.translate_tree_structure(graph_data)
tree_structure = json_translator.translate_tree_structure(
graph_data, bt_order
)

return JsonResponse({"success": True, "tree_structure": tree_structure})
except Exception as e:
return JsonResponse(
{"success": False, "message": f"Error reading file: {str(e)}"},
status=500,
)
else:
return Response(
{"error": "The project does not have a graph definition"}, status=404
)


@api_view(["GET"])
def get_subtree_structure(request):

project_name = request.GET.get("project_name")
subtree_name = request.GET.get("subtree_name")
bt_order = request.GET.get("bt_order")

# Generate the paths
base_path = os.path.join(settings.BASE_DIR, "filesystem")
project_path = os.path.join(base_path, project_name)
subtree_path = os.path.join(project_path, "code/trees/subtrees/json")
graph_path = os.path.join(subtree_path, subtree_name + ".json")

# Check if the project exists
if os.path.exists(graph_path):
try:
with open(graph_path, "r") as f:
graph_data = json.load(f)

# Get the tree structure
tree_structure = json_translator.translate_tree_structure(
graph_data, bt_order
)

return JsonResponse({"success": True, "tree_structure": tree_structure})
except Exception as e:
Expand Down Expand Up @@ -345,7 +384,7 @@ def save_subtree(request):
f.write(subtree_json)

# TOFIX: order hardcoded
json_translator.translate(subtree_json, xml_path, "top-to-bottom")
# json_translator.translate(subtree_json, xml_path, "top-to-bottom")

return JsonResponse({"success": True}, status=status.HTTP_200_OK)

Expand Down Expand Up @@ -886,11 +925,18 @@ def generate_app(request):

# Copy all the subtrees to the temp folder
for subtree_file in os.listdir(subtree_path):
if subtree_file.endswith(".xml"):
shutil.copy(
os.path.join(subtree_path, subtree_file), result_trees_tmp_path
if subtree_file.endswith(".json"):
subtree_name = base = os.path.splitext(os.path.basename(subtree_file))[
0
]
xml_path = os.path.join(
project_path, "code", "trees", "subtrees", f"{subtree_name}.xml"
)

json_translator.translate(subtree_file, xml_path, bt_order)

shutil.copy(xml_path, result_trees_tmp_path)

# Generate a self-contained tree
tree_generator.generate(
result_trees_tmp_path, action_path, self_contained_tree_path
Expand Down Expand Up @@ -958,7 +1004,7 @@ def generate_dockerized_app(request):
action_path = os.path.join(project_path, "code/actions")

working_folder = "/tmp/wf"
subtree_path = os.path.join(project_path, "code/trees/subtrees")
subtree_path = os.path.join(project_path, "code/trees/subtrees/json")
result_trees_tmp_path = os.path.join("/tmp/trees/")
self_contained_tree_path = os.path.join(working_folder, "self_contained_tree.xml")
tree_gardener_src = os.path.join(settings.BASE_DIR, "tree_gardener")
Expand All @@ -980,11 +1026,27 @@ def generate_dockerized_app(request):
json_translator.translate(main_tree_graph, main_tree_tmp_path, bt_order)

# 3. Copy all the subtrees to the temp folder
for subtree_file in os.listdir(subtree_path):
if subtree_file.endswith(".xml"):
shutil.copy(
os.path.join(subtree_path, subtree_file), result_trees_tmp_path
)
try:
for subtree_file in os.listdir(subtree_path):
if subtree_file.endswith(".json"):
subtree_name = base = os.path.splitext(
os.path.basename(subtree_file)
)[0]
print(os.path.join(subtree_path, subtree_file))

xml_path = os.path.join(
project_path, "code", "trees", "subtrees", f"{subtree_name}.xml"
)

with open(os.path.join(subtree_path, subtree_file), "r+") as f:
# Reading from a file
subtree_json = f.read()

json_translator.translate(subtree_json, xml_path, bt_order)

shutil.copy(xml_path, result_trees_tmp_path)
except:
print("No subtrees")

# 4. Generate a self-contained tree
tree_generator.generate(
Expand Down
4 changes: 2 additions & 2 deletions backend/tree_gardener/tree_gardener/tree_factory.py
Original file line number Diff line number Diff line change
Expand Up @@ -312,15 +312,15 @@ def get_branches(element):
if child_instance is not None:
child = child_instance
retry_name = "Retry_" + str(nfailures)
instance = Class(name=retry_name, num_failures=int(nfailures), child=child)
instance = Class(name=class_name, num_failures=int(nfailures), child=child)
elif "Repeat" in class_name:
num_cycles = element.get("num_cycles")
for child_element in element:
child_instance = get_branches(child_element)
if child_instance is not None:
child = child_instance
repeat_name = "Repeat_" + str(num_cycles)
instance = Class(name=repeat_name, child=child, num_success=int(num_cycles))
instance = Class(name=class_name, child=child, num_success=int(num_cycles))
elif (
"Inverter" in class_name
or "Force" in class_name
Expand Down
17 changes: 10 additions & 7 deletions backend/tree_gardener/tree_gardener/tree_tools.py
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,8 @@ def ascii_blackboard_to_json(blackboard):
json_str = '"blackboard":{'
do_append_coma = False

# FIX: [entry, value] = line.strip()[1:].split(":")
ansi_escape = re.compile(r"\x1B(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~])")
blackboard = ansi_escape.sub("", blackboard)

for line in iter(blackboard.splitlines()):
if "Blackboard Data" in line:
Expand All @@ -115,18 +116,20 @@ def ascii_blackboard_to_json(blackboard):
continue
if do_append_coma:
json_str += ","
else:
do_append_coma = True
# Remove whitespaces with strip and remove / from entry
[entry, value] = line.strip()[1:].split(":")
json_str += f'"{entry.strip()}":"{value.strip()}"'
try:
[entry, value] = line.strip()[1:].split(":")
json_str += f'"{entry.strip()}":"{value.strip()}"'
do_append_coma = True
except:
pass
json_str += "}"
return json_str


def ascii_bt_to_json(tree, blackboard, file):
file.write("{")
# file.write(f"{ascii_tree_to_json(tree)},{ascii_blackboard_to_json(blackboard)}")
file.write(f"{ascii_tree_to_json(tree)}")
file.write(f"{ascii_tree_to_json(tree)},{ascii_blackboard_to_json(blackboard)}")
# file.write(f"{ascii_tree_to_json(tree)}")
file.write("}")
file.close()
8 changes: 6 additions & 2 deletions frontend/src/components/header_menu/HeaderMenu.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { MouseEventHandler, useEffect, useState } from "react";
import { MouseEventHandler, useContext, useEffect, useState } from "react";
import AppBar from "@mui/material/AppBar";
import Toolbar from "@mui/material/Toolbar";
import {
Expand All @@ -25,6 +25,7 @@ import { ReactComponent as ResetIcon } from "./img/reset.svg";
import ProjectModal from "./modals/ProjectModal";
import UniversesModal from "./modals/UniverseModal";
import SettingsModal from "../settings_popup/SettingsModal";
import { OptionsContext } from "../options/Options";

const HeaderMenu = ({
currentProjectname,
Expand All @@ -50,6 +51,9 @@ const HeaderMenu = ({
setGazeboEnabled: Function;
manager: CommsManager;
}) => {
// Settings
const settings = useContext(OptionsContext);

// Project state
const [existingProjects, setExistingProjects] = useState("");

Expand Down Expand Up @@ -202,7 +206,7 @@ const HeaderMenu = ({
const appBlob = await generateDockerizedApp(
modelJson,
currentProjectname,
"top-to-bottom",
settings.btOrder.value,
);

// Convert the blob to base64 using FileReader
Expand Down
30 changes: 30 additions & 0 deletions frontend/src/components/helper/TreeEditorHelper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -261,3 +261,33 @@ export const configureEngine = (
.getActionEventBus()
.registerAction(new ZoomCanvasAction({ inverseZoom: true }));
};

export const findSubtree = (
baseTree: any,
subTree: string,
oldIndex: number = -1,
): number[] | undefined => {
var path: number[] = [];
var nodeChilds;
var name = baseTree.name;

if (name === subTree) {
return oldIndex >= 0 ? [] : undefined;
}

try {
nodeChilds = baseTree["childs"];
} catch (error) {
return undefined;
}

for (let index = 0; index < nodeChilds.length; index++) {
var result = findSubtree(nodeChilds[index], subTree, index);
if (result) {
path = [index].concat(result);
return path;
}
}

return undefined;
};
Loading

0 comments on commit a5a5e75

Please sign in to comment.