diff --git a/.idea/misc.xml b/.idea/misc.xml
new file mode 100644
index 00000000..228bc9f0
--- /dev/null
+++ b/.idea/misc.xml
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
new file mode 100644
index 00000000..35eb1ddf
--- /dev/null
+++ b/.idea/vcs.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/workspace.xml b/.idea/workspace.xml
new file mode 100644
index 00000000..715b01f4
--- /dev/null
+++ b/.idea/workspace.xml
@@ -0,0 +1,665 @@
+
+
+
+
+
+
+
+
+
+
+ {
+ "useNewFormat": true
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {
+ "lastFilter": {
+ "state": "OPEN",
+ "assignee": "ARDATI-Rami"
+ }
+}
+ {
+ "selectedUrlAndAccountId": {
+ "url": "https://github.com/ARDATI-Rami/VirtualLeaf2021.git",
+ "accountId": "46d9b9c9-fed6-4371-9312-e4b72aadc5ea"
+ }
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {
+ "associatedIndex": 4
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ PYTHONTEX
+
+
+
+
+
+
+
+
+ PDFLATEX
+
+
+ EVINCE
+
+
+
+ false
+
+
+ {projectDir}/out
+ {projectDir}/auxil
+ false
+ PDF
+ TEXLIVE
+ false
+ []
+ []
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ MAKEINDEX
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 1744026456349
+
+
+ 1744026456349
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 1745330487769
+
+
+
+ 1745330487769
+
+
+
+ 1745346875830
+
+
+
+ 1745346875830
+
+
+
+ 1745395710672
+
+
+
+ 1745395710672
+
+
+
+ 1745403897762
+
+
+
+ 1745403897762
+
+
+
+ 1745404049440
+
+
+
+ 1745404049440
+
+
+
+ 1745404090169
+
+
+
+ 1745404090169
+
+
+
+ 1745404111230
+
+
+
+ 1745404111230
+
+
+
+ 1745415156208
+
+
+
+ 1745415156208
+
+
+
+ 1745416125382
+
+
+
+ 1745416125382
+
+
+
+ 1747130883995
+
+
+
+ 1747130883995
+
+
+
+ 1747131069504
+
+
+
+ 1747131069504
+
+
+
+ 1747131147603
+
+
+
+ 1747131147603
+
+
+
+ 1747933883476
+
+
+
+ 1747933883476
+
+
+
+ 1747933942127
+
+
+
+ 1747933942127
+
+
+
+ 1747933961584
+
+
+
+ 1747933961584
+
+
+
+ 1749665512372
+
+
+
+ 1749665512372
+
+
+
+ 1749674318831
+
+
+
+ 1749674318831
+
+
+
+ 1751037303805
+
+
+
+ 1751037303805
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Change_XML.py b/Change_XML.py
deleted file mode 100644
index 68356a10..00000000
--- a/Change_XML.py
+++ /dev/null
@@ -1,525 +0,0 @@
-from datetime import date, datetime
-from collections import defaultdict
-from lxml import etree, objectify
-import numpy as np
-from virtualleaf_xml_model import VirtualLeaf_XML, Node
-import math
-
-doc = VirtualLeaf_XML("data/leaves/cambium_virgin.xml")
-doc.leaf.name = "Cambium_01"
-doc.leaf.date = str(date.today())
-doc.leaf.simtime = 0
-
-output_xml = "data/leaves/cambium.xml"
-datadir = "/home/ardati/Data_VirtualLeaf/Cambium_01"
-# Parameters
-doc.parameter.set_parameter(name='datadir',value=datadir)
-doc.parameter.set_parameter(name='maxt',value="10000")
-
-# Settings
-doc.settings.set_setting(name='save_movie_frames',value="true")
-
-
-
-# Other
-double_mesh = False
-
-coords = {n.nr: (n.x, n.y) for n in doc.nodes.nodes}
-# add at the top of the script, near the imports, for convenience
-id2node = {n.nr: n for n in doc.nodes.nodes} # nr → Node dataclass
-nodes_elem = doc.nodes.elem
-next_nr = max(coords) + 1
-
-
-if double_mesh:
- # ── STEP 1 & 2 – global edge dictionary ──────────────────────────────────
- edge2mid = {} # { (min(a,b), max(a,b)) : mid_id }
-
- for cell in doc.cells.cells:
- verts = cell.vertices
- for a, b in zip(verts, verts[1:] + verts[:1]): # closed ring
- key = tuple(sorted((a, b)))
- if key in edge2mid:
- continue # midpoint already made
-
- # ----------------------------------------------------------------------
- # create ONE midpoint node for this geometric edge (shared by both cells)
- # ----------------------------------------------------------------------
- x1, y1 = coords[a];
- x2, y2 = coords[b]
- mx, my = (x1 + x2) / 2.0, (y1 + y2) / 2.0
-
- na, nb = id2node[a], id2node[b] # Node dataclasses
-
- sam_flag = na.sam and nb.sam # TRUE only if both endpoints
- boundary_flag = na.boundary and nb.boundary # are TRUE
- fixed_flag = na.fixed and nb.fixed
-
- new_node_elem = etree.Element(
- "node",
- nr=str(next_nr),
- x=f"{mx:.6g}",
- y=f"{my:.6g}",
- sam="true" if sam_flag else "false",
- boundary="true" if boundary_flag else "false",
- fixed="true" if fixed_flag else "false",
- )
-
- nodes_elem.append(new_node_elem)
- new_nd = Node(next_nr, mx, my, sam_flag, boundary_flag, fixed_flag, new_node_elem)
- doc.nodes.nodes.append(new_nd)
- id2node[next_nr] = new_nd # keep lookup in sync
- coords[next_nr] = (mx, my)
- edge2mid[key] = next_nr
- next_nr += 1
-
- # ── STEP 3 & 4 – rebuild every cell with shared midpoints ────────────────
- indent_tail = "\n "
-
- for cell in doc.cells.cells:
- old_ring = cell.vertices
- new_ring = []
-
- for a, b in zip(old_ring, old_ring[1:] + old_ring[:1]):
- new_ring.append(a)
- new_ring.append(edge2mid[tuple(sorted((a, b)))])
-
- cell.vertices = new_ring # keep Python object in sync
-
- # keep the walls to re-attach later
- walls = cell.elem.xpath("./wall")
-
- # 2) remove every existing child exactly once
- for child in list(cell.elem.getchildren()): # make a real Python list first
- cell.elem.remove(child) # no duplicates → no ValueError
-
- # --------------------------------------------------------------------------
- # 3) choose a geometry-aware sort key ← REPLACE THIS SINGLE LINE
- # --------------------------------------------------------------------------
-
- # OLD (pure numeric, gave ugly ordering):
- # for idx in sorted(set(new_ring)):
-
- # NEW (angle about cell centroid):
- vx, vy = zip(*(coords[i] for i in new_ring)) # coordinates of vertices
- cx, cy = sum(vx) / len(vx), sum(vy) / len(vy) # centroid
-
-
- def polar_angle(i):
- x, y = coords[i]
- return math.atan2(y - cy, x - cx)
-
-
- for idx in sorted(set(new_ring), key=polar_angle):
- n_elem = etree.SubElement(cell.elem, "node", n=str(idx))
- n_elem.tail = indent_tail
-
- # re-attach walls
- for w in walls:
- cell.elem.append(w)
- w.tail = indent_tail
-
-
-# # ──────────────────────────────────────────────────────────────────────────
-# # SORT CELLS BY (radius, angle) → re-assign sequential indices
-# # --------------------------------------------------------------------------
-# 1) centroid of the *whole* tissue – average of all node coords
-tx, ty = np.mean(list(coords.values()), axis=0)
-#
-# # ───────────────────────────────────────────────────────────────────────────
-# # CLUSTER + RADIAL-ANGULAR SORT → reassign cell.index & cell.id
-# # ───────────────────────────────────────────────────────────────────────────
-# def kmeans1d(points: np.ndarray, k: int, max_iter: int = 100):
-# """
-# Very simple 1-D k-means clustering.
-# Returns
-# -------
-# labels : np.ndarray of shape (n,)
-# label in [0..k-1] for each point
-# centers : np.ndarray of shape (k,)
-# the final cluster centers
-# """
-# pts = points.copy()
-# # init centers evenly
-# centers = np.linspace(pts.min(), pts.max(), k)
-# for _ in range(max_iter):
-# # assign to nearest center
-# dists = np.abs(pts[:, None] - centers[None, :])
-# labels = np.argmin(dists, axis=1)
-# new_centers = np.array([
-# pts[labels == i].mean() if np.any(labels==i) else centers[i]
-# for i in range(k)
-# ])
-# if np.allclose(new_centers, centers):
-# break
-# centers = new_centers
-# # final assignment
-# dists = np.abs(pts[:, None] - centers[None, :])
-# labels = np.argmin(dists, axis=1)
-# return labels, centers
-#
-# # 1) compute (radius, angle) for each cell, keep original order
-# cell_info = [] # will hold tuples (radius, angle, cell)
-# radii = []
-# for c in doc.cells.cells:
-# # centroid of the cell
-# vx, vy = zip(*(coords[i] for i in c.vertices))
-# cx, cy = sum(vx)/len(vx), sum(vy)/len(vy)
-# # vector from tissue center
-# # tissue center = mean of ALL node coords (or use weighted centroid if you prefer)
-# dx, dy = cx - tx, cy - ty
-# r = math.hypot(dx, dy)
-# θ = math.atan2(dy, dx)
-# cell_info.append((r, θ, c))
-# radii.append(r)
-#
-# radii = np.array(radii)
-#
-# # 2) cluster radii into k rings
-# k = 3 # <-- set this to the number of concentric rings you expect
-# labels, centers = kmeans1d(radii, k)
-#
-# # reorder cluster IDs so that label "0" is the innermost center, etc.
-# order = np.argsort(centers) # e.g. [2,0,1] if center-radii say [84,1,54]
-# cluster_rank = {old: new for new, old in enumerate(order)}
-# ranks = np.array([cluster_rank[l] for l in labels])
-#
-# # 3) build a list of (ring, angle, cell) and sort
-# clustered = [
-# (ranks[i], cell_info[i][1], cell_info[i][2])
-# for i in range(len(cell_info))
-# ]
-# clustered.sort(key=lambda t: (t[0], t[1])) # first by ring, then CCW angle
-#
-# # 4) reassign indices in that new order - innermost gets highest index
-# total_cells = len(doc.cells.cells)
-# for i, (ring, angle, c) in enumerate(clustered):
-# # Reverse the indexing: innermost cells (ring 0) get highest indices
-# new_idx = total_cells - 1 - i # Counts down from (total_cells-1)
-# c.elem.attrib["index"] = str(new_idx)
-# if "id" in c.elem.attrib:
-# c.elem.attrib["id"] = str(new_idx)
-# ────────────────────────────────────────────────────────────────────────────
-# Reorder tags under to match their 'index' attribute
-# ────────────────────────────────────────────────────────────────────────────
-
-cells_parent = doc.root.find("cells") # top-level element
-all_cells = list(cells_parent.findall("cell")) # snapshot of originals
-
-# sort the Element proxies by their integer index
-sorted_cells = sorted(
- all_cells,
- key=lambda c: int(c.attrib.get("index", c.attrib.get("id", 0)))
-)
-
-# remove all originals in one pass
-for c in all_cells:
- cells_parent.remove(c)
-
-# append back in the new order
-for c in sorted_cells:
- cells_parent.append(c)
-#
-# ────────────────────────────────────────────────────────────────────────────
-# COMPUTE & ATTACH target_length TO
-# ────────────────────────────────────────────────────────────────────────────
-
-# 1) collect unique edges from *refined* cells
-edge_set = set()
-for c in doc.cells.cells:
- verts = c.vertices
- for a, b in zip(verts, verts[1:] + verts[:1]): # closed loop
- edge_set.add(tuple(sorted((a, b))))
-
-# 2) compute lengths
-lengths = []
-for a, b in edge_set:
- x1, y1 = coords[a]
- x2, y2 = coords[b]
- lengths.append(math.hypot(x2 - x1, y2 - y1))
-
-# 3) mean segment length and target length (half of mean)
-mean_len = sum(lengths) / len(lengths) if lengths else 0.0
-target_len = mean_len/2
-print(f"Mean segment length: {mean_len:.6g}")
-print(f"Target length (half mean): {target_len:.6g}")
-# 4) attach as attribute on
-nodes_elem.attrib["target_length"] = f"{target_len:.6g}"
-# 5) add the new number of nodes to the element
-nodes_elem.attrib["n"] = str(len(doc.nodes.nodes))
-#
-# ────────────────────────────────────────────────────────────────────────────
-# RESET CHILDREN TO THE REFINED BOUNDARY LOOP
-# ────────────────────────────────────────────────────────────────────────────
-
-# 1) find the boundary_polygon element
-poly = doc.cells.elem.find("boundary_polygon")
-if poly is None:
- raise RuntimeError("No found under .")
-
-# 2) collect all nodes flagged boundary="true"
-b_nodes = [n for n in doc.nodes.nodes if n.boundary]
-
-# 3) sort them CCW around tissue centre (tx,ty from before)
-def angle_about_center(node):
- x, y = node.x, node.y
- return math.atan2(y - ty, x - tx)
-
-b_nodes.sort(key=angle_about_center)
-
-# 4) wipe existing children and append fresh entries
-for ch in list(poly.getchildren()):
- poly.remove(ch)
-
-tail = "\n " # matches the indent in your file
-for n in b_nodes:
- elem = etree.SubElement(poly, "node", n=str(n.nr))
- elem.tail = tail
-
-# reposition the boundary polygon
-cells_elem = doc.root.find("cells")
-poly = cells_elem.find("boundary_polygon")
-if poly is not None:
- cells_elem.remove(poly)
- cells_elem.append(poly)
-
-
-# ────────────────────────────────────────────────────────────────────────────
-# REBUILD WALLS AS CONTIGUOUS SEGMENTS BETWEEN CELL PAIRS
-# ────────────────────────────────────────────────────────────────────────────
-
-
-# 1) locate and clear the existing walls
-walls_parent = doc.root.find("walls")
-for w in list(walls_parent.getchildren()):
- walls_parent.remove(w)
-
-# 2) collect every undirected edge → the two cells sharing it
-edge2cells: dict[tuple[int,int], list[int]] = {}
-for c in doc.cells.cells:
- ci = int(c.elem.get("index"))
- verts = c.vertices
- for a, b in zip(verts, verts[1:] + verts[:1]):
- key = tuple(sorted((a, b)))
- edge2cells.setdefault(key, []).append(ci)
-
-# 3) group edges by the pair of cells (interior walls only)
-pair2edges: dict[tuple[int,int], list[tuple[int,int]]] = {}
-for edge, cells in edge2cells.items():
- if len(cells) == 2:
- pair2edges.setdefault(tuple(sorted(cells)), []).append(edge)
-
-new_walls = []
-
-for (c1, c2), edges in pair2edges.items():
- # build adjacency for this wall
- adj: dict[int, list[int]] = defaultdict(list)
- for u, v in edges:
- adj[u].append(v)
- adj[v].append(u)
-
- # find endpoints (degree == 1)
- endpoints = [n for n, nbrs in adj.items() if len(nbrs) == 1]
- if len(endpoints) == 2:
- start, end = endpoints
- else:
- # fallback: pick the first edge’s nodes
- start, end = edges[0]
-
- # traverse from start to end
- ordered = [start]
- prev, curr = None, start
- while curr != end:
- nbrs = adj[curr]
- # pick the neighbor that isn’t the previous node
- nxt = nbrs[0] if nbrs[0] != prev else nbrs[1]
- ordered.append(nxt)
- prev, curr = curr, nxt
-
- # compute total wall length
- length = 0.0
- for u, v in zip(ordered, ordered[1:]):
- x1, y1 = coords[u]
- x2, y2 = coords[v]
- length += math.hypot(x2 - x1, y2 - y1)
-
- # emit the element
- w = etree.SubElement(walls_parent, "wall",
- length=f"{length:.6g}",
- c1=str(c1), c2=str(c2),
- n1=str(ordered[0]), n2=str(ordered[-1]),
- wall_type="normal",
- viz_flux="0"
- )
- # ─── Add the transporter tags ───────────────────────────────────
- etree.SubElement(w, "transporters1")
- etree.SubElement(w, "transporters2")
-
- new_walls.append(w)
-
-# 4) assign sequential indices and refresh the count
-for idx, w in enumerate(new_walls):
- w.set("index", str(idx))
-walls_parent.set("n", str(len(new_walls)))
-
-
-# ──────────────────────────────────────────────────────────────────────────
-# FINAL SORT: reorder tags by c1, then reindex & recount
-# ──────────────────────────────────────────────────────────────────────────
-walls_parent = doc.root.find("walls")
-
-# 1) snapshot and sort by integer c1
-orig_walls = list(walls_parent.findall("wall"))
-sorted_walls = sorted(orig_walls, key=lambda w: int(w.get("c1", 0)))
-
-# 2) remove all originals
-for w in orig_walls:
- walls_parent.remove(w)
-
-# 3) append back in sorted order
-for w in sorted_walls:
- walls_parent.append(w)
-
-# 4) reassign sequential index and refresh count
-for idx, w in enumerate(walls_parent.findall("wall")):
- w.set("index", str(idx))
-walls_parent.set("n", str(len(walls_parent.findall("wall"))))
-
-
-
-
-# ────────────────────────────────────────────────────────────────────────────
-# REINDEX NODES BY FIRST APPEARANCE IN CELLS → new 0..M-1 ordering
-# ────────────────────────────────────────────────────────────────────────────
-from lxml import etree
-
-# 1) build mapping old_nr → new_nr by scanning cells
-mapping: dict[int,int] = {}
-next_id = 0
-for cell in doc.cells.cells:
- for old_nr in cell.vertices:
- if old_nr not in mapping:
- mapping[old_nr] = next_id
- next_id += 1
-
-# print(f"mapping: {mapping}")
-# 2) any nodes not in any cell (e.g. orphan or boundary_poly) come last
-for n in doc.nodes.nodes:
- old_nr = n.nr
- if old_nr not in mapping:
- mapping[old_nr] = next_id
- next_id += 1
-
-# 3) reorder & rename elements under
-nodes_parent = doc.root.find("nodes")
-orig_nodes = {int(elem.get("nr")): elem for elem in nodes_parent.findall("node")}
-
-# clear existing
-for elem in list(nodes_parent.getchildren()):
- nodes_parent.remove(elem)
-
-# append back in new order
-for old_nr, new_nr in sorted(mapping.items(), key=lambda kv: kv[1]):
- elem = orig_nodes[old_nr]
- elem.set("nr", str(new_nr))
- elem.tail = "\n "
- nodes_parent.append(elem)
-
-# 4) rebuild coords and doc.nodes.nodes list
-new_coords = {}
-new_node_list = []
-for elem in nodes_parent.findall("node"):
- nr = int(elem.get("nr"))
- x, y = float(elem.get("x")), float(elem.get("y"))
- sam = elem.get("sam") == "true"
- boundary = elem.get("boundary") == "true"
- fixed = elem.get("fixed") == "true"
- new_coords[nr] = (x, y)
- new_node_list.append(Node(nr, x, y, sam, boundary, fixed, elem))
-coords.clear(); coords.update(new_coords)
-doc.nodes.nodes[:] = new_node_list
-
-# 5) remap every cell’s membership list (Python + XML)
-for cell in doc.cells.cells:
- old_verts = cell.vertices
- new_verts = [mapping[old] for old in old_verts]
- cell.vertices = new_verts
- # update XML
- for n_elem in cell.elem.findall("node"):
- old = int(n_elem.get("n"))
- n_elem.set("n", str(mapping[old]))
-
-# 6) remap every wall’s endpoints n1/n2
-walls_parent = doc.root.find("walls")
-for w in walls_parent.findall("wall"):
- for attr in ("n1", "n2"):
- old = int(w.get(attr))
- w.set(attr, str(mapping[old]))
-
-
-
-# ────────────────────────────────────────────────────────────────────────────
-# RESET CHILDREN TO THE REFINED BOUNDARY LOOP
-# ────────────────────────────────────────────────────────────────────────────
-
-# 1) find the boundary_polygon element
-poly = doc.cells.elem.find("boundary_polygon")
-if poly is None:
- raise RuntimeError("No found under .")
-
-# 2) collect all nodes flagged boundary="true"
-b_nodes = [n for n in doc.nodes.nodes if n.boundary]
-
-# 3) sort them CCW around tissue centre (tx,ty from before)
-def angle_about_center(node):
- x, y = node.x, node.y
- return math.atan2(y - ty, x - tx)
-
-b_nodes.sort(key=angle_about_center)
-
-# 4) wipe existing children and append fresh entries
-for ch in list(poly.getchildren()):
- poly.remove(ch)
-
-tail = "\n " # matches the indent in your file
-for n in b_nodes:
- elem = etree.SubElement(poly, "node", n=str(n.nr))
- elem.tail = tail
-
-# reposition the boundary polygon
-cells_elem = doc.root.find("cells")
-poly = cells_elem.find("boundary_polygon")
-if poly is not None:
- cells_elem.remove(poly)
- cells_elem.append(poly)
-
-
-# ▶︎ 1) map each cell to its incident walls
-cell2walls: dict[int, list[int]] = defaultdict(list)
-walls_parent = doc.root.find("walls")
-
-for w in walls_parent.findall("wall"):
- idx = int(w.get("index"))
- c1 = int(w.get("c1"))
- c2 = int(w.get("c2"))
- cell2walls[c1].append(idx)
- cell2walls[c2].append(idx)
-
-# ▶︎ 2) rewrite each cell’s children
-for cell in doc.cells.cells:
- ci = int(cell.elem.get("index"))
- # remove all existing tags
- for w_elem in cell.elem.findall("wall"):
- cell.elem.remove(w_elem)
-
- # append new ones in sorted order
- for widx in sorted(cell2walls.get(ci, [])):
- we = etree.SubElement(cell.elem, "wall", w=str(widx))
- we.tail = "\n " # match your cell indentation
-
-
-
-# ── housekeeping and save ────────────────────────────────────────────────
-objectify.deannotate(doc.root, cleanup_namespaces=True)
-etree.indent(doc.tree, space=" ")
-doc.save(output_xml)
diff --git a/Example_of_change_XML.py b/Example_of_change_XML.py
new file mode 100644
index 00000000..3f85f33f
--- /dev/null
+++ b/Example_of_change_XML.py
@@ -0,0 +1,541 @@
+from datetime import date, datetime
+from collections import defaultdict
+from lxml import etree, objectify
+import numpy as np
+from virtualleaf_xml_model import VirtualLeaf_XML, Node
+import math
+
+doc = VirtualLeaf_XML("data/leaves/cambium.xml")
+doc.leaf.name = "Cambium_01"
+doc.leaf.date = str(date.today())
+doc.leaf.simtime = 0
+
+output_xml = "data/leaves/cambium.xml"
+datadir = "/home/ardati/Data_VirtualLeaf/Cambium_01"
+# Parameters
+doc.parameter.set_parameter(name='datadir',value=datadir)
+doc.parameter.set_parameter(name='maxt',value="10000")
+
+# Settings
+doc.settings.set_setting(name='save_movie_frames',value="true")
+
+# Add random target_length to each node
+import random
+
+print("Adding random target_length (2.0-2.5) to each node...")
+for node in doc.nodes.nodes:
+ # Generate random value between 2.0 and 2.5
+ random_length = random.uniform(2.0, 2.5)
+ # Set the attribute on the node element
+ node.elem.set("target_length", f"{random_length:.6g}")
+
+# ── housekeeping and save ────────────────────────────────────────────────
+objectify.deannotate(doc.root, cleanup_namespaces=True)
+etree.indent(doc.tree, space=" ")
+doc.save(output_xml)
+
+
+#
+#
+# # Other
+# double_mesh = False
+#
+# coords = {n.nr: (n.x, n.y) for n in doc.nodes.nodes}
+# # add at the top of the script, near the imports, for convenience
+# id2node = {n.nr: n for n in doc.nodes.nodes} # nr → Node dataclass
+# nodes_elem = doc.nodes.elem
+# next_nr = max(coords) + 1
+#
+#
+# if double_mesh:
+# # ── STEP 1 & 2 – global edge dictionary ──────────────────────────────────
+# edge2mid = {} # { (min(a,b), max(a,b)) : mid_id }
+#
+# for cell in doc.cells.cells:
+# verts = cell.vertices
+# for a, b in zip(verts, verts[1:] + verts[:1]): # closed ring
+# key = tuple(sorted((a, b)))
+# if key in edge2mid:
+# continue # midpoint already made
+#
+# # ----------------------------------------------------------------------
+# # create ONE midpoint node for this geometric edge (shared by both cells)
+# # ----------------------------------------------------------------------
+# x1, y1 = coords[a];
+# x2, y2 = coords[b]
+# mx, my = (x1 + x2) / 2.0, (y1 + y2) / 2.0
+#
+# na, nb = id2node[a], id2node[b] # Node dataclasses
+#
+# sam_flag = na.sam and nb.sam # TRUE only if both endpoints
+# boundary_flag = na.boundary and nb.boundary # are TRUE
+# fixed_flag = na.fixed and nb.fixed
+#
+# new_node_elem = etree.Element(
+# "node",
+# nr=str(next_nr),
+# x=f"{mx:.6g}",
+# y=f"{my:.6g}",
+# sam="true" if sam_flag else "false",
+# boundary="true" if boundary_flag else "false",
+# fixed="true" if fixed_flag else "false",
+# )
+#
+# nodes_elem.append(new_node_elem)
+# new_nd = Node(next_nr, mx, my, sam_flag, boundary_flag, fixed_flag, new_node_elem)
+# doc.nodes.nodes.append(new_nd)
+# id2node[next_nr] = new_nd # keep lookup in sync
+# coords[next_nr] = (mx, my)
+# edge2mid[key] = next_nr
+# next_nr += 1
+#
+# # ── STEP 3 & 4 – rebuild every cell with shared midpoints ────────────────
+# indent_tail = "\n "
+#
+# for cell in doc.cells.cells:
+# old_ring = cell.vertices
+# new_ring = []
+#
+# for a, b in zip(old_ring, old_ring[1:] + old_ring[:1]):
+# new_ring.append(a)
+# new_ring.append(edge2mid[tuple(sorted((a, b)))])
+#
+# cell.vertices = new_ring # keep Python object in sync
+#
+# # keep the walls to re-attach later
+# walls = cell.elem.xpath("./wall")
+#
+# # 2) remove every existing child exactly once
+# for child in list(cell.elem.getchildren()): # make a real Python list first
+# cell.elem.remove(child) # no duplicates → no ValueError
+#
+# # --------------------------------------------------------------------------
+# # 3) choose a geometry-aware sort key ← REPLACE THIS SINGLE LINE
+# # --------------------------------------------------------------------------
+#
+# # OLD (pure numeric, gave ugly ordering):
+# # for idx in sorted(set(new_ring)):
+#
+# # NEW (angle about cell centroid):
+# vx, vy = zip(*(coords[i] for i in new_ring)) # coordinates of vertices
+# cx, cy = sum(vx) / len(vx), sum(vy) / len(vy) # centroid
+#
+#
+# def polar_angle(i):
+# x, y = coords[i]
+# return math.atan2(y - cy, x - cx)
+#
+#
+# for idx in sorted(set(new_ring), key=polar_angle):
+# n_elem = etree.SubElement(cell.elem, "node", n=str(idx))
+# n_elem.tail = indent_tail
+#
+# # re-attach walls
+# for w in walls:
+# cell.elem.append(w)
+# w.tail = indent_tail
+
+
+# # ──────────────────────────────────────────────────────────────────────────
+# # SORT CELLS BY (radius, angle) → re-assign sequential indices
+# # --------------------------------------------------------------------------
+# 1) centroid of the *whole* tissue – average of all node coords
+# tx, ty = np.mean(list(coords.values()), axis=0)
+#
+# # ───────────────────────────────────────────────────────────────────────────
+# # CLUSTER + RADIAL-ANGULAR SORT → reassign cell.index & cell.id
+# # ───────────────────────────────────────────────────────────────────────────
+# def kmeans1d(points: np.ndarray, k: int, max_iter: int = 100):
+# """
+# Very simple 1-D k-means clustering.
+# Returns
+# -------
+# labels : np.ndarray of shape (n,)
+# label in [0..k-1] for each point
+# centers : np.ndarray of shape (k,)
+# the final cluster centers
+# """
+# pts = points.copy()
+# # init centers evenly
+# centers = np.linspace(pts.min(), pts.max(), k)
+# for _ in range(max_iter):
+# # assign to nearest center
+# dists = np.abs(pts[:, None] - centers[None, :])
+# labels = np.argmin(dists, axis=1)
+# new_centers = np.array([
+# pts[labels == i].mean() if np.any(labels==i) else centers[i]
+# for i in range(k)
+# ])
+# if np.allclose(new_centers, centers):
+# break
+# centers = new_centers
+# # final assignment
+# dists = np.abs(pts[:, None] - centers[None, :])
+# labels = np.argmin(dists, axis=1)
+# return labels, centers
+#
+# # 1) compute (radius, angle) for each cell, keep original order
+# cell_info = [] # will hold tuples (radius, angle, cell)
+# radii = []
+# for c in doc.cells.cells:
+# # centroid of the cell
+# vx, vy = zip(*(coords[i] for i in c.vertices))
+# cx, cy = sum(vx)/len(vx), sum(vy)/len(vy)
+# # vector from tissue center
+# # tissue center = mean of ALL node coords (or use weighted centroid if you prefer)
+# dx, dy = cx - tx, cy - ty
+# r = math.hypot(dx, dy)
+# θ = math.atan2(dy, dx)
+# cell_info.append((r, θ, c))
+# radii.append(r)
+#
+# radii = np.array(radii)
+#
+# # 2) cluster radii into k rings
+# k = 3 # <-- set this to the number of concentric rings you expect
+# labels, centers = kmeans1d(radii, k)
+#
+# # reorder cluster IDs so that label "0" is the innermost center, etc.
+# order = np.argsort(centers) # e.g. [2,0,1] if center-radii say [84,1,54]
+# cluster_rank = {old: new for new, old in enumerate(order)}
+# ranks = np.array([cluster_rank[l] for l in labels])
+#
+# # 3) build a list of (ring, angle, cell) and sort
+# clustered = [
+# (ranks[i], cell_info[i][1], cell_info[i][2])
+# for i in range(len(cell_info))
+# ]
+# clustered.sort(key=lambda t: (t[0], t[1])) # first by ring, then CCW angle
+#
+# # 4) reassign indices in that new order - innermost gets highest index
+# total_cells = len(doc.cells.cells)
+# for i, (ring, angle, c) in enumerate(clustered):
+# # Reverse the indexing: innermost cells (ring 0) get highest indices
+# new_idx = total_cells - 1 - i # Counts down from (total_cells-1)
+# c.elem.attrib["index"] = str(new_idx)
+# if "id" in c.elem.attrib:
+# c.elem.attrib["id"] = str(new_idx)
+# ────────────────────────────────────────────────────────────────────────────
+# Reorder tags under to match their 'index' attribute
+# ────────────────────────────────────────────────────────────────────────────
+
+# cells_parent = doc.root.find("cells") # top-level element
+# all_cells = list(cells_parent.findall("cell")) # snapshot of originals
+#
+# # sort the Element proxies by their integer index
+# sorted_cells = sorted(
+# all_cells,
+# key=lambda c: int(c.attrib.get("index", c.attrib.get("id", 0)))
+# )
+#
+# # remove all originals in one pass
+# for c in all_cells:
+# cells_parent.remove(c)
+#
+# # append back in the new order
+# for c in sorted_cells:
+# cells_parent.append(c)
+# #
+# # ────────────────────────────────────────────────────────────────────────────
+# # COMPUTE & ATTACH target_length TO
+# # ────────────────────────────────────────────────────────────────────────────
+#
+# # 1) collect unique edges from *refined* cells
+# edge_set = set()
+# for c in doc.cells.cells:
+# verts = c.vertices
+# for a, b in zip(verts, verts[1:] + verts[:1]): # closed loop
+# edge_set.add(tuple(sorted((a, b))))
+#
+# # 2) compute lengths
+# lengths = []
+# for a, b in edge_set:
+# x1, y1 = coords[a]
+# x2, y2 = coords[b]
+# lengths.append(math.hypot(x2 - x1, y2 - y1))
+#
+# # 3) mean segment length and target length (half of mean)
+# mean_len = sum(lengths) / len(lengths) if lengths else 0.0
+# target_len = mean_len/2
+# print(f"Mean segment length: {mean_len:.6g}")
+# print(f"Target length (half mean): {target_len:.6g}")
+# # 4) attach as attribute on
+# nodes_elem.attrib["target_length"] = f"{target_len:.6g}"
+# # 5) add the new number of nodes to the element
+# nodes_elem.attrib["n"] = str(len(doc.nodes.nodes))
+# #
+# # ────────────────────────────────────────────────────────────────────────────
+# # RESET CHILDREN TO THE REFINED BOUNDARY LOOP
+# # ────────────────────────────────────────────────────────────────────────────
+#
+# # 1) find the boundary_polygon element
+# poly = doc.cells.elem.find("boundary_polygon")
+# if poly is None:
+# raise RuntimeError("No found under .")
+#
+# # 2) collect all nodes flagged boundary="true"
+# b_nodes = [n for n in doc.nodes.nodes if n.boundary]
+#
+# # 3) sort them CCW around tissue centre (tx,ty from before)
+# def angle_about_center(node):
+# x, y = node.x, node.y
+# return math.atan2(y - ty, x - tx)
+#
+# b_nodes.sort(key=angle_about_center)
+#
+# # 4) wipe existing children and append fresh entries
+# for ch in list(poly.getchildren()):
+# poly.remove(ch)
+#
+# tail = "\n " # matches the indent in your file
+# for n in b_nodes:
+# elem = etree.SubElement(poly, "node", n=str(n.nr))
+# elem.tail = tail
+#
+# # reposition the boundary polygon
+# cells_elem = doc.root.find("cells")
+# poly = cells_elem.find("boundary_polygon")
+# if poly is not None:
+# cells_elem.remove(poly)
+# cells_elem.append(poly)
+#
+#
+# # ────────────────────────────────────────────────────────────────────────────
+# # REBUILD WALLS AS CONTIGUOUS SEGMENTS BETWEEN CELL PAIRS
+# # ────────────────────────────────────────────────────────────────────────────
+#
+#
+# # 1) locate and clear the existing walls
+# walls_parent = doc.root.find("walls")
+# for w in list(walls_parent.getchildren()):
+# walls_parent.remove(w)
+#
+# # 2) collect every undirected edge → the two cells sharing it
+# edge2cells: dict[tuple[int,int], list[int]] = {}
+# for c in doc.cells.cells:
+# ci = int(c.elem.get("index"))
+# verts = c.vertices
+# for a, b in zip(verts, verts[1:] + verts[:1]):
+# key = tuple(sorted((a, b)))
+# edge2cells.setdefault(key, []).append(ci)
+#
+# # 3) group edges by the pair of cells (interior walls only)
+# pair2edges: dict[tuple[int,int], list[tuple[int,int]]] = {}
+# for edge, cells in edge2cells.items():
+# if len(cells) == 2:
+# pair2edges.setdefault(tuple(sorted(cells)), []).append(edge)
+#
+# new_walls = []
+#
+# for (c1, c2), edges in pair2edges.items():
+# # build adjacency for this wall
+# adj: dict[int, list[int]] = defaultdict(list)
+# for u, v in edges:
+# adj[u].append(v)
+# adj[v].append(u)
+#
+# # find endpoints (degree == 1)
+# endpoints = [n for n, nbrs in adj.items() if len(nbrs) == 1]
+# if len(endpoints) == 2:
+# start, end = endpoints
+# else:
+# # fallback: pick the first edge’s nodes
+# start, end = edges[0]
+#
+# # traverse from start to end
+# ordered = [start]
+# prev, curr = None, start
+# while curr != end:
+# nbrs = adj[curr]
+# # pick the neighbor that isn’t the previous node
+# nxt = nbrs[0] if nbrs[0] != prev else nbrs[1]
+# ordered.append(nxt)
+# prev, curr = curr, nxt
+#
+# # compute total wall length
+# length = 0.0
+# for u, v in zip(ordered, ordered[1:]):
+# x1, y1 = coords[u]
+# x2, y2 = coords[v]
+# length += math.hypot(x2 - x1, y2 - y1)
+#
+# # emit the element
+# w = etree.SubElement(walls_parent, "wall",
+# length=f"{length:.6g}",
+# c1=str(c1), c2=str(c2),
+# n1=str(ordered[0]), n2=str(ordered[-1]),
+# wall_type="normal",
+# viz_flux="0"
+# )
+# # ─── Add the transporter tags ───────────────────────────────────
+# etree.SubElement(w, "transporters1")
+# etree.SubElement(w, "transporters2")
+#
+# new_walls.append(w)
+#
+# # 4) assign sequential indices and refresh the count
+# for idx, w in enumerate(new_walls):
+# w.set("index", str(idx))
+# walls_parent.set("n", str(len(new_walls)))
+#
+#
+# # ──────────────────────────────────────────────────────────────────────────
+# # FINAL SORT: reorder tags by c1, then reindex & recount
+# # ──────────────────────────────────────────────────────────────────────────
+# walls_parent = doc.root.find("walls")
+#
+# # 1) snapshot and sort by integer c1
+# orig_walls = list(walls_parent.findall("wall"))
+# sorted_walls = sorted(orig_walls, key=lambda w: int(w.get("c1", 0)))
+#
+# # 2) remove all originals
+# for w in orig_walls:
+# walls_parent.remove(w)
+#
+# # 3) append back in sorted order
+# for w in sorted_walls:
+# walls_parent.append(w)
+#
+# # 4) reassign sequential index and refresh count
+# for idx, w in enumerate(walls_parent.findall("wall")):
+# w.set("index", str(idx))
+# walls_parent.set("n", str(len(walls_parent.findall("wall"))))
+#
+#
+#
+#
+# # ────────────────────────────────────────────────────────────────────────────
+# # REINDEX NODES BY FIRST APPEARANCE IN CELLS → new 0..M-1 ordering
+# # ────────────────────────────────────────────────────────────────────────────
+# from lxml import etree
+#
+# # 1) build mapping old_nr → new_nr by scanning cells
+# mapping: dict[int,int] = {}
+# next_id = 0
+# for cell in doc.cells.cells:
+# for old_nr in cell.vertices:
+# if old_nr not in mapping:
+# mapping[old_nr] = next_id
+# next_id += 1
+#
+# # print(f"mapping: {mapping}")
+# # 2) any nodes not in any cell (e.g. orphan or boundary_poly) come last
+# for n in doc.nodes.nodes:
+# old_nr = n.nr
+# if old_nr not in mapping:
+# mapping[old_nr] = next_id
+# next_id += 1
+#
+# # 3) reorder & rename elements under
+# nodes_parent = doc.root.find("nodes")
+# orig_nodes = {int(elem.get("nr")): elem for elem in nodes_parent.findall("node")}
+#
+# # clear existing
+# for elem in list(nodes_parent.getchildren()):
+# nodes_parent.remove(elem)
+#
+# # append back in new order
+# for old_nr, new_nr in sorted(mapping.items(), key=lambda kv: kv[1]):
+# elem = orig_nodes[old_nr]
+# elem.set("nr", str(new_nr))
+# elem.tail = "\n "
+# nodes_parent.append(elem)
+#
+# # 4) rebuild coords and doc.nodes.nodes list
+# new_coords = {}
+# new_node_list = []
+# for elem in nodes_parent.findall("node"):
+# nr = int(elem.get("nr"))
+# x, y = float(elem.get("x")), float(elem.get("y"))
+# sam = elem.get("sam") == "true"
+# boundary = elem.get("boundary") == "true"
+# fixed = elem.get("fixed") == "true"
+# new_coords[nr] = (x, y)
+# new_node_list.append(Node(nr, x, y, sam, boundary, fixed, elem))
+# coords.clear(); coords.update(new_coords)
+# doc.nodes.nodes[:] = new_node_list
+#
+# # 5) remap every cell’s membership list (Python + XML)
+# for cell in doc.cells.cells:
+# old_verts = cell.vertices
+# new_verts = [mapping[old] for old in old_verts]
+# cell.vertices = new_verts
+# # update XML
+# for n_elem in cell.elem.findall("node"):
+# old = int(n_elem.get("n"))
+# n_elem.set("n", str(mapping[old]))
+#
+# # 6) remap every wall’s endpoints n1/n2
+# walls_parent = doc.root.find("walls")
+# for w in walls_parent.findall("wall"):
+# for attr in ("n1", "n2"):
+# old = int(w.get(attr))
+# w.set(attr, str(mapping[old]))
+#
+#
+#
+# # ────────────────────────────────────────────────────────────────────────────
+# # RESET CHILDREN TO THE REFINED BOUNDARY LOOP
+# # ────────────────────────────────────────────────────────────────────────────
+#
+# # 1) find the boundary_polygon element
+# poly = doc.cells.elem.find("boundary_polygon")
+# if poly is None:
+# raise RuntimeError("No found under .")
+#
+# # 2) collect all nodes flagged boundary="true"
+# b_nodes = [n for n in doc.nodes.nodes if n.boundary]
+#
+# # 3) sort them CCW around tissue centre (tx,ty from before)
+# def angle_about_center(node):
+# x, y = node.x, node.y
+# return math.atan2(y - ty, x - tx)
+#
+# b_nodes.sort(key=angle_about_center)
+#
+# # 4) wipe existing children and append fresh entries
+# for ch in list(poly.getchildren()):
+# poly.remove(ch)
+#
+# tail = "\n " # matches the indent in your file
+# for n in b_nodes:
+# elem = etree.SubElement(poly, "node", n=str(n.nr))
+# elem.tail = tail
+#
+# # reposition the boundary polygon
+# cells_elem = doc.root.find("cells")
+# poly = cells_elem.find("boundary_polygon")
+# if poly is not None:
+# cells_elem.remove(poly)
+# cells_elem.append(poly)
+#
+#
+# # ▶︎ 1) map each cell to its incident walls
+# cell2walls: dict[int, list[int]] = defaultdict(list)
+# walls_parent = doc.root.find("walls")
+#
+# for w in walls_parent.findall("wall"):
+# idx = int(w.get("index"))
+# c1 = int(w.get("c1"))
+# c2 = int(w.get("c2"))
+# cell2walls[c1].append(idx)
+# cell2walls[c2].append(idx)
+#
+# # ▶︎ 2) rewrite each cell’s children
+# for cell in doc.cells.cells:
+# ci = int(cell.elem.get("index"))
+# # remove all existing tags
+# for w_elem in cell.elem.findall("wall"):
+# cell.elem.remove(w_elem)
+#
+# # append new ones in sorted order
+# for widx in sorted(cell2walls.get(ci, [])):
+# we = etree.SubElement(cell.elem, "wall", w=str(widx))
+# we.tail = "\n " # match your cell indentation
+#
+
+
+# # ── housekeeping and save ────────────────────────────────────────────────
+# objectify.deannotate(doc.root, cleanup_namespaces=True)
+# etree.indent(doc.tree, space=" ")
+# doc.save(output_xml)
diff --git a/Old_run_in_batch.py b/Old_run_in_batch.py
new file mode 100644
index 00000000..550afe77
--- /dev/null
+++ b/Old_run_in_batch.py
@@ -0,0 +1,130 @@
+import xml.etree.ElementTree as ET
+from pathlib import Path
+import subprocess
+import numpy as np
+
+class MyXML:
+ """Utility to clone a LeafML file and tweak simple entries."""
+
+ def __init__(self, templatefile: str):
+ self.tree = ET.parse(templatefile)
+ self.root = self.tree.getroot()
+ self.parameters = self.root.find("parameter")
+
+ def set_simple_param(self, name: str, value) -> None:
+ """Change the ‘val’ attribute of ."""
+ par = self.parameters.find(f"./par[@name='{name}']")
+ if par is None:
+ raise KeyError(f"Parameter '{name}' not found in XML")
+ par.set("val", str(value))
+
+ def write(self, filename: str) -> None:
+ """Write a full XML document in UTF‑8."""
+ # ① simply pass the *path* to ElementTree; it opens the file in 'wb'
+ self.tree.write(filename, encoding="utf-8", xml_declaration=True)
+
+ # --- alternative ---
+ # with open(filename, "wb") as fh: # binary mode!
+ # self.tree.write(fh, encoding="utf-8", xml_declaration=True)
+
+# -----------------------------------------------------------------------------
+leaf_in = Path("data/leaves/cambium.xml")
+model = "libmodel_exp.so"
+# Fixed expansion rate and different elastic modulus values
+number_of_runs = 3
+for r in number_of_runs:
+ # Create unique output names
+ datadir = f"/home/ardati/Data_VirtualLeaf/Cambium_r_{r}"
+ output_suffix = f"_{r}"
+ leaf_out = leaf_in.with_name(leaf_in.stem + output_suffix + ".xml")
+
+ # Create and modify XML
+ xml = MyXML(leaf_in)
+ xml.set_simple_param("maxt", 1500)
+ xml.set_simple_param("datadir", datadir)
+ xml.set_simple_param("xml_storage_stride", 1) # Pour enregiustrer tous les pas de temps
+ xml.set_simple_param("rseed", 1) #set seed to 1 for reproducibility
+
+
+ # Write XML file
+ xml.write(leaf_out)
+
+ # Run simulation
+ print(f"Running simulation with number {r} and output {leaf_out}")
+ subprocess.run([
+ "./bin/VirtualLeaf",
+ "-b",
+ "-l", str(leaf_out),
+ "-m", model
+ ], check=True)
+
+# After all simulations complete, analyze and plot the results
+import matplotlib.pyplot as plt
+import os
+import re
+
+# Collect area data for each elastic modulus value
+areas = []
+
+for r in number_of_runs:
+ datadir = f"/home/ardati/Data_VirtualLeaf/model_exp_pressure_em{r}"
+ print(f"getcwd : {os.getcwd()}")
+ # Find the latest XML file based on numeric part
+ xml_files = [f for f in os.listdir(datadir) if f.endswith('.xml')]
+ if not xml_files:
+ print(f"No XML files found in {datadir}")
+ continue
+
+ # Extract numbers from filenames like "leaf.000050.xml"
+ pattern = re.compile(r'leaf\.(\d+)\.xml')
+ latest_num = -1
+ latest_file = None
+
+ for file in xml_files:
+ match = pattern.match(file)
+ if match:
+ num = int(match.group(1))
+ if num > latest_num:
+ latest_num = num
+ latest_file = file
+
+ if not latest_file:
+ print(f"No matching XML files found in {datadir}")
+ continue
+
+ latest_xml = os.path.join(datadir, latest_file)
+ print(f"Using {latest_file} for elastic_modulus {elastic_modulus}")
+
+ # Parse the XML
+ # Parse the XML
+ tree = ET.parse(latest_xml)
+ root = tree.getroot()
+ cells = root.find("cells")
+ if cells is not None:
+ found = False
+ for cell in cells.findall("cell"):
+ if cell.get("index") == "0":
+ found = True
+ area = float(cell.get("area"))
+ areas.append((elastic_modulus, area))
+ print(f"Elastic modulus {elastic_modulus}: Cell area = {area}")
+ break # Stop after finding the target cell
+ if not found:
+ print(f"Cell with index 131 not found in {latest_xml}")
+
+# Plot the results
+if areas:
+ modulus_values, area_values = zip(*sorted(areas))
+ area_mean = sum(area_values) / len(area_values)
+ plt.figure(figsize=(10, 6))
+ plt.plot(modulus_values, area_values, 'o-')
+ # plt.ylim(area_mean*0.9, area_mean*1.1) # fixed, generous y‑window
+ # plt.yticks(np.arange(area_mean, area_mean*1.1, 2)) # tidy ticks
+ plt.xlabel('Elastic Modulus')
+ plt.ylabel('Cell Area')
+ plt.title(f'Cell Area vs Elastic Modulus (Expansion Rate = {expansion_rate})')
+ plt.grid(True)
+ plt.savefig('area_vs_elastic_modulus.png')
+ plt.show()
+else:
+ print("No area data found to plot")
\ No newline at end of file
diff --git a/data/leaves/cambium.xml b/data/leaves/cambium.xml
index c9e834ac..10da6743 100644
--- a/data/leaves/cambium.xml
+++ b/data/leaves/cambium.xml
@@ -7,7 +7,7 @@
-
+
@@ -106,7 +106,7 @@
-
+
@@ -161,7 +161,7 @@
-
+
@@ -1385,8 +1385,6 @@
-
-
@@ -1888,10 +1886,10 @@
-
-
+
+
-
+
diff --git a/data/leaves/lateralRoot.xml b/data/leaves/lateralRoot.xml
index 48c0d1ea..5f2d4d17 100644
--- a/data/leaves/lateralRoot.xml
+++ b/data/leaves/lateralRoot.xml
@@ -1,5448 +1,5227 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- |
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- |
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- |
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- |
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- |
-
-
-
-
-
-
-
-
-
-
-
-
- |
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- |
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- |
-
-
-
-
-
-
-
-
-
-
- |
-
-
-
-
-
-
-
-
-
-
- |
-
-
-
-
-
-
-
-
-
-
-
- |
-
-
-
-
-
-
-
-
-
-
-
-
-
- |
-
-
-
-
-
-
-
-
-
- |
-
-
-
-
-
-
-
-
-
-
-
- |
-
-
-
-
-
-
-
-
-
-
-
-
-
- |
-
-
-
-
-
-
-
-
-
-
-
- |
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- |
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- |
-
-
-
-
-
-
-
-
-
- |
-
-
-
-
-
-
-
-
-
-
-
- |
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- |
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- |
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- |
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- |
-
-
-
-
-
-
-
-
-
-
-
-
-
- |
-
-
-
-
-
-
-
-
-
-
-
- |
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- |
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- |
-
-
-
-
-
-
-
-
-
-
-
- |
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- |
-
-
-
-
-
-
-
-
-
-
-
-
-
- |
-
-
-
-
-
-
-
-
-
-
-
-
-
- |
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- |
-
-
-
-
-
-
-
-
-
-
-
-
-
- |
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- |
-
-
-
-
-
-
-
-
-
-
- |
-
-
-
-
-
-
-
-
-
- |
-
-
-
-
-
-
-
-
-
- |
-
-
-
-
-
-
-
-
-
-
-
- |
-
-
-
-
-
-
-
-
-
-
-
-
-
- |
-
-
-
-
-
-
-
-
-
-
-
-
- |
-
-
-
-
-
-
-
-
-
-
- |
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- |
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- |
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- |
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- |
-
-
-
-
-
-
-
-
-
-
-
- |
-
-
-
-
-
-
-
-
-
-
-
-
-
- |
-
-
-
-
-
-
-
-
-
- |
-
-
-
-
-
-
-
-
-
-
-
-
- |
-
-
-
-
-
-
-
-
-
-
-
- |
-
-
-
-
-
-
-
-
-
-
-
-
-
- |
-
-
-
-
-
-
-
-
-
-
-
-
- |
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- |
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- |
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- |
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- |
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- |
-
-
-
-
-
-
-
-
-
-
- |
-
-
-
-
-
-
-
-
-
-
- |
-
-
-
-
-
-
-
-
-
-
-
- |
-
-
-
-
-
-
-
-
-
- |
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- |
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- |
-
-
-
-
-
-
-
-
-
-
-
-
- |
-
-
-
-
-
-
-
-
-
-
- |
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- |
-
-
-
-
-
-
-
-
-
-
-
-
-
- |
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- |
-
-
-
-
-
-
-
-
-
-
-
-
-
- |
-
-
-
-
-
-
-
-
-
-
-
-
- |
-
-
-
-
-
-
-
-
-
-
-
-
- |
-
-
-
-
-
-
-
-
-
-
-
- |
-
-
-
-
-
-
-
-
-
-
-
- |
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- |
-
-
-
-
-
-
-
-
-
-
-
-
-
- |
-
-
-
-
-
-
-
-
-
-
-
-
-
- |
-
-
-
-
-
-
-
-
-
-
-
- |
-
-
-
-
-
-
-
-
-
-
-
- |
-
-
-
-
-
-
-
-
-
-
-
-
- |
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- |
-
-
-
-
-
-
-
-
-
- |
-
-
-
-
-
-
-
-
-
-
-
- |
-
-
-
-
-
-
-
-
-
-
-
-
- |
-
-
-
-
-
-
-
-
-
-
-
-
- |
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- |
-
-
-
-
-
-
-
-
-
-
-
-
-
- |
-
-
-
-
-
-
-
-
-
-
-
- |
-
-
-
-
-
-
-
-
-
-
-
-
- |
-
-
-
-
-
-
-
-
-
- |
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- |
-
-
-
-
-
-
-
-
-
-
-
-
- |
-
-
-
-
-
-
-
-
-
- |
-
-
-
-
-
-
-
-
-
-
-
-
-
- |
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- |
-
-
-
-
-
-
-
-
-
-
-
-
- |
-
-
-
-
-
-
-
-
-
-
-
-
-
- |
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- |
-
-
-
-
-
-
-
-
-
-
-
-
- |
-
-
-
-
-
-
-
-
-
-
-
-
-
- |
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- |
-
-
-
-
-
-
-
-
-
-
-
- |
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- |
-
-
-
-
-
-
-
-
-
-
-
-
- |
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- |
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- |
-
-
-
-
-
-
-
-
-
-
-
- |
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- |
-
-
-
-
-
-
-
-
-
- |
-
-
-
-
-
-
-
-
-
-
-
- |
-
-
-
-
-
-
-
-
-
-
-
-
-
- |
-
-
-
-
-
-
-
-
-
-
-
-
- |
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- |
-
-
-
-
-
-
-
-
-
-
-
-
-
- |
-
-
-
-
-
-
-
-
-
-
- |
-
-
-
-
-
-
-
-
-
-
-
- |
-
-
-
-
-
-
-
-
-
-
-
-
-
- |
-
-
-
-
-
-
-
-
-
-
-
-
- |
-
-
-
-
-
-
-
-
-
-
-
-
-
- |
-
-
-
-
-
-
-
-
-
-
-
- |
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- |
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- |
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- |
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- |
-
-
-
-
-
-
-
-
-
- |
-
-
-
-
-
-
-
-
-
-
-
- |
-
-
-
-
-
-
-
-
-
- |
-
-
-
-
-
-
-
-
-
-
-
- |
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- |
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- |
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- |
-
-
-
-
-
-
-
-
-
- |
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- |
-
-
-
-
-
-
-
-
-
-
-
-
- |
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- |
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- |
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- |
-
-
-
-
-
-
-
-
-
- |
-
-
-
-
-
-
-
-
-
-
-
- |
-
-
-
-
-
-
-
-
-
- |
-
-
-
-
-
-
-
-
-
-
- |
-
-
-
-
-
-
-
-
-
-
-
- |
-
-
-
-
-
-
-
-
-
-
-
-
- |
-
-
-
-
-
-
-
-
-
-
-
-
-
- |
-
-
-
-
-
-
-
-
-
-
-
-
- |
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- |
-
-
-
-
-
-
-
-
-
-
-
-
-
- |
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- |
-
-
-
-
-
-
-
-
-
-
-
-
-
- |
-
-
-
-
-
-
-
-
-
-
-
- |
-
-
-
-
-
-
-
-
-
-
-
-
-
- |
-
-
-
-
-
-
-
-
-
-
-
- |
-
-
-
-
-
-
-
-
-
-
-
-
-
- |
-
-
-
-
-
-
-
-
-
-
-
-
-
- |
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- |
-
-
-
-
-
-
-
-
-
-
-
- |
-
-
-
-
-
-
-
-
-
-
-
-
- |
-
-
-
-
-
-
-
-
-
-
-
-
-
- |
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- |
-
-
-
-
-
-
-
-
-
-
-
- |
-
-
-
-
-
-
-
-
-
-
-
- |
-
-
-
-
-
-
-
-
-
-
-
-
- |
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- |
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- |
-
-
-
-
-
-
-
-
-
-
-
-
-
- |
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/data/leaves/model_exp_init.xml b/data/leaves/model_exp_init.xml
new file mode 100755
index 00000000..57efadfa
--- /dev/null
+++ b/data/leaves/model_exp_init.xml
@@ -0,0 +1,219 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/data/leaves/tutorial1_init.xml b/data/leaves/tutorial1_init.xml
index 324bfecb..273b7e12 100755
--- a/data/leaves/tutorial1_init.xml
+++ b/data/leaves/tutorial1_init.xml
@@ -7,14 +7,15 @@
-
+
-
-
+
+
+
@@ -36,6 +37,7 @@
+
@@ -107,7 +109,7 @@
-
+
@@ -158,16 +160,16 @@
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
@@ -209,7 +211,7 @@
-
+
diff --git a/data/leaves/vleaf2.xml b/data/leaves/vleaf2.xml
index 2ab28202..40830202 100755
--- a/data/leaves/vleaf2.xml
+++ b/data/leaves/vleaf2.xml
@@ -107,7 +107,7 @@
-
+
diff --git a/nCercles.py b/nCercles.py
new file mode 100644
index 00000000..3aa890c7
--- /dev/null
+++ b/nCercles.py
@@ -0,0 +1,1347 @@
+import math as math
+import matplotlib.pyplot as plt
+from random import *
+
+# ----------------------------------------------------------------------------------------------------------#
+# ------------- CONVERSION POLAIRE-CARTÉSIEN ---------------------------------------------------------------#
+# ----------------------------------------------------------------------------------------------------------#
+
+def polaire_vers_cartesien(k_noeuds_n_cercle_polaire):
+ """Convertit les coordonnées polaires des noeuds en coordonnées cartésiennes.
+
+ Args:
+ k_noeuds_n_cercle_polaire: Liste des noeuds en coordonnées polaires pour chaque cercle
+
+ Returns:
+ Liste des noeuds en coordonnées cartésiennes pour chaque cercle
+ """
+ return [
+ {
+ "x": noeud["r"] * math.cos(noeud["theta"]),
+ "y": noeud["r"] * math.sin(noeud["theta"]),
+ "index": noeud["index"],
+ "initial": noeud["initial"],
+ "sam": noeud["sam"],
+ "boundary": noeud["boundary"],
+ "fixed": noeud["fixed"]
+ }
+ for cercle in k_noeuds_n_cercle_polaire
+ for noeud in cercle
+ ]
+
+
+
+#-----------------------------------------------------------------------------------------------------#
+#------------ GÉNÉRATION DES RAYONS ------------------------------------------------------------------#
+#-----------------------------------------------------------------------------------------------------#
+
+def n_cercles(n, rayon_0, a, rapport_R_T, debug=False):
+ """Calcule les rayons de n cercles concentriques.
+
+ Args:
+ n: Nombre de cercles à générer
+ rayon_0: Rayon du premier cercle (le plus interne)
+ a: Liste des nombres de points/cellules par cercle
+ rapport_R_T: Liste des rapports entre rayon et longueur de corde
+ debug: Active/désactive l'affichage des informations de débogage
+
+ Returns:
+ Liste des rayons des cercles générés
+ """
+ if n <= 0:
+ return []
+
+ rayon_n_cercles = [rayon_0] # Initialisation avec le premier rayon
+
+ if debug:
+ print(f"cercle 0: rayon = {rayon_0}\n")
+
+ for i in range(1, n):
+ rayon_precedent = rayon_n_cercles[i - 1]
+
+ # Sélection de l'indice correct pour a
+ a_idx = i - 1 if i < n - 1 or len(a) <= i - 1 else i - 2
+
+ # Facteur multiplicatif pour calculer l'incrément de rayon
+
+ # Calcul du nouveau rayon
+ sin_term = math.sin(math.pi / a[a_idx])
+ increment = rapport_R_T[i - 1] * 2 * sin_term * rayon_precedent
+ nouveau_rayon = rayon_precedent + increment
+ rayon_n_cercles.append(nouveau_rayon)
+
+ if debug:
+ print(f"cercle {i}:")
+ print(f"rayon précédent = {rayon_precedent}")
+ print(f"nouveau rayon = {nouveau_rayon}")
+ print(f"incrément = {increment}")
+ if i < n - 1:
+ ratio_calcule = (nouveau_rayon - rayon_precedent) / (2 * sin_term * rayon_precedent)
+ print(f"ratio R/T calculé = {ratio_calcule}")
+ print(f"ratio R/T attendu = {rapport_R_T[i]}")
+ else:
+ ratio_calcule = (nouveau_rayon - rayon_precedent) / (sin_term * rayon_precedent)
+ print(f"ratio R/T = {ratio_calcule}")
+ print(f"a[{a_idx}] = {a[a_idx]}\n")
+
+ return rayon_n_cercles
+
+
+
+
+
+#----------------------------------------------------------------------------------------------------#
+#---------- CRÉATION DES NOEUDS INITIAUX ------------------------------------------------------------#
+#----------------------------------------------------------------------------------------------------#
+
+def creer_noeuds_initiaux(n, rayon_n_cercles, a):
+ """Crée les nœuds initiaux sans fusion.
+
+ Args:
+ n: Nombre de cercles
+ rayon_n_cercles: Liste des rayons de chaque cercle
+ a: Liste des nombres de points/cellules par cercle
+
+ Returns:
+ Tuple contenant:
+ - Liste des noeuds en coordonnées polaires pour chaque cercle
+ - Nombre total de noeuds créés
+ """
+ k_noeuds_n_cercle_polaire = []
+ index_noeud = 0
+
+ # Fonction auxiliaire pour créer un nœud
+ def creer_noeud(r, theta, boundary=False, fixed=False):
+ nonlocal index_noeud
+ noeud = {
+ "r": r,
+ "theta": theta,
+ "index": index_noeud,
+ "initial": True,
+ "sam": False,
+ "boundary": boundary,
+ "fixed": fixed
+ }
+ index_noeud += 1
+ return noeud
+
+ for i in range(n):
+ rayon = rayon_n_cercles[i]
+ cercle_noeuds = []
+
+ if i == 0:
+ # Premier cercle - tous les nœuds sont fixes
+ cercle_noeuds = [
+ creer_noeud(
+ r=rayon,
+ theta=2 * math.pi * j / a[i],
+ fixed=True
+ ) for j in range(a[i])
+ ]
+
+ elif 0 < i < n - 1:
+ # Cercles intermédiaires
+ # D'abord les points alignés avec le cercle précédent
+ cercle_noeuds.extend([
+ creer_noeud(
+ r=rayon,
+ theta=2 * math.pi * j / a[i-1]
+ ) for j in range(a[i-1])
+ ])
+
+ # Puis les points propres à ce cercle
+ cercle_noeuds.extend([
+ creer_noeud(
+ r=rayon,
+ theta=2 * math.pi * j / a[i]
+ ) for j in range(a[i])
+ ])
+
+ else:
+ # Dernier cercle - tous les points sont sur la frontière
+ cercle_noeuds = [
+ creer_noeud(
+ r=rayon,
+ theta=2 * math.pi * j / a[i-1],
+ boundary=True
+ ) for j in range(a[i-1])
+ ]
+
+ k_noeuds_n_cercle_polaire.append(cercle_noeuds)
+
+ return k_noeuds_n_cercle_polaire, index_noeud
+
+
+
+#----------------------------------------------------------------------------------------------------#
+#------------- FUSION DES NOEUDS PROCHES ------------------------------------------------------------#
+#----------------------------------------------------------------------------------------------------#
+
+def fusionner_noeuds(k_noeuds_n_cercle_polaire, n, index_noeud_depart=0, seuil_distance=5):
+ """ Fusionne les nœuds qui se chevauchent.
+
+ Args:
+ k_noeuds_n_cercle_polaire: Liste des noeuds en coordonnées polaires
+ n: Nombre de cercles
+ index_noeud_depart: Index de départ pour les nouveaux noeuds créés
+ seuil_distance: Distance minimale entre deux noeuds pour les considérer distincts
+
+ Returns:
+ Tuple contenant:
+ - Liste mise à jour des noeuds en coordonnées polaires
+ - Dictionnaire de correspondance des indices fusionnés """
+
+ index_noeud = index_noeud_depart
+
+ # Trier chaque sous-liste par ordre croissant de theta
+ for i in range(len(k_noeuds_n_cercle_polaire)):
+ k_noeuds_n_cercle_polaire[i].sort(key=lambda noeud: noeud["theta"])
+
+ # Collecter tous les nœuds avec leur cercle d'origine
+ tous_noeuds = []
+ for i, cercle in enumerate(k_noeuds_n_cercle_polaire):
+ for noeud in cercle:
+ r = noeud["r"]
+ theta = noeud["theta"]
+ idx = noeud["index"]
+ initial = noeud["initial"]
+ sam = noeud["sam"]
+ boundary = noeud["boundary"]
+ fixed = noeud["fixed"]
+ x = r * math.cos(theta)
+ y = r * math.sin(theta)
+ tous_noeuds.append((x, y, r, theta, idx, i, initial, sam,boundary,fixed))
+
+ # Identifier les paires de nœuds qui se chevauchent
+ map_indices = {}
+ noeuds_a_fusionner = []
+
+ for i in range(len(tous_noeuds)):
+ x1, y1, r1, theta1, idx1, cercle1, initial1,sam1,boundary1,fixed1 = tous_noeuds[i]
+
+ for j in range(i + 1, len(tous_noeuds)):
+ x2, y2, r2, theta2, idx2, cercle2, initial2,sam2,boundary2,fixed2 = tous_noeuds[j]
+
+ # Distance entre les nœuds
+ distance = math.sqrt((x2 - x1) ** 2 + (y2 - y1) ** 2)
+
+ if distance < seuil_distance:
+ print(f"Nœuds à fusionner : {idx1} et {idx2} (distance={distance:.3f})")
+ noeuds_a_fusionner.append((i, j))
+
+ # Création des nouveaux nœuds
+ nouveaux_noeuds = []
+ indices_a_supprimer = set()
+
+ for i, j in noeuds_a_fusionner:
+ x1, y1, r1, theta1, idx1, cercle1, initial1,sam1,boundary1,fixed1 = tous_noeuds[i]
+ x2, y2, r2, theta2, idx2, cercle2, initial2,sam2,boundary2,fixed2 = tous_noeuds[j]
+
+ # Créer le nœud entre les deux
+ x_nouveau = (x1 + x2) / 2
+ y_nouveau = (y1 + y2) / 2
+ r_nouveau = math.sqrt(x_nouveau ** 2 + y_nouveau ** 2)
+ theta_nouveau = math.atan2(y_nouveau, x_nouveau)
+
+ if theta_nouveau < 0:
+ theta_nouveau += 2 * math.pi
+
+ nouvel_indice = index_noeud
+ index_noeud += 1
+
+ # Un nœud est initial seulement si tous les nœuds fusionnés sont initiaux
+ initial_nouveau = initial1 and initial2
+ boundary_nouveau = boundary1 or boundary2
+ sam_nouveau = False
+ fixed_nouveau = False
+ # Création du nouveau nœud
+ nouveau_noeud = {
+ "r": r_nouveau,
+ "theta": theta_nouveau,
+ "index": nouvel_indice,
+ "initial": initial_nouveau,
+ "sam":sam_nouveau,
+ "boundary":boundary_nouveau,
+ "fixed": fixed_nouveau
+ }
+
+ nouveaux_noeuds.append((nouveau_noeud, cercle1, cercle2))
+
+ map_indices[idx1] = nouvel_indice
+ map_indices[idx2] = nouvel_indice
+
+ indices_a_supprimer.add(i)
+ indices_a_supprimer.add(j)
+
+ # Reconstruction des nœuds sans ceux qui sont supprimés
+ nouveau_k_noeuds_n_cercle_polaire = [[] for _ in range(n)]
+
+ # Ajouter les nœuds non supprimés
+ for i, (x, y, r, theta, idx, cercle, initial, sam,boundary, fixed) in enumerate(tous_noeuds):
+ if i not in indices_a_supprimer:
+ nouveau_k_noeuds_n_cercle_polaire[cercle].append({
+ "r": r,
+ "theta": theta,
+ "index": idx,
+ "initial": initial,
+ "sam": sam,
+ "boundary": boundary,
+ "fixed": fixed
+ })
+
+ # Ajouter les nouveaux nœuds
+ for nouveau_noeud, cercle1, cercle2 in nouveaux_noeuds:
+ nouveau_k_noeuds_n_cercle_polaire[cercle1].append(nouveau_noeud.copy())
+ if cercle1 != cercle2:
+ nouveau_k_noeuds_n_cercle_polaire[cercle2].append(nouveau_noeud.copy())
+
+ # Trier à nouveau
+ for i in range(len(nouveau_k_noeuds_n_cercle_polaire)):
+ nouveau_k_noeuds_n_cercle_polaire[i].sort(key=lambda noeud: noeud["theta"])
+
+ print(f"Nombre de nouveaux nœuds créés: {len(nouveaux_noeuds)}")
+
+ return nouveau_k_noeuds_n_cercle_polaire, map_indices
+
+
+
+# ----------------------------------------------------------------------------------------------------#
+# ------------ CRÉATION DES CELLULES AVEC NOEUDS INTERMÉDIAIRES ---------------------------------------#
+# ----------------------------------------------------------------------------------------------------#
+def creer_cellules(rayon_n_cercles, k_noeuds_n_cercle_polaire, n, a):
+
+ """Crée des cellules à 4 nœuds entre cercles consécutifs.
+
+ Args:
+ rayon_n_cercles: Liste des rayons des cercles
+ k_noeuds_n_cercle_polaire: Coordonnées polaires des nœuds pour chaque cercle
+ n: Nombre de cercles
+ a: Liste des nombres de cellules entre chaque paire de cercles consécutifs
+
+ Returns:
+ Liste des cellules, chaque cellule étant définie par une liste de noeuds (indices)
+ """
+ # Fonction auxiliaire pour la comparaison d'angles
+ def angles_equivalents(a1, a2, tolerance=0.001):
+ a1_norm = a1 % (2 * math.pi)
+ a2_norm = a2 % (2 * math.pi)
+ diff = min(abs(a1_norm - a2_norm), 2 * math.pi - abs(a1_norm - a2_norm))
+ return diff < tolerance
+
+ # Fonction pour vérifier si un angle est entre deux autres
+ def est_entre_angles(theta, debut, fin, tolerance=0.001):
+ theta_norm = theta % (2 * math.pi)
+ debut_norm = debut % (2 * math.pi)
+ fin_norm = fin % (2 * math.pi)
+
+ if debut_norm <= fin_norm:
+ return debut_norm - tolerance <= theta_norm <= fin_norm + tolerance
+ else:
+ return theta_norm >= debut_norm - tolerance or theta_norm <= fin_norm + tolerance
+
+ # Prétraitement : indexer et trier les nœuds par angle pour chaque cercle
+ noeuds_par_cercle = []
+ for i in range(n):
+ if i < len(k_noeuds_n_cercle_polaire):
+ noeuds_par_cercle.append(sorted(k_noeuds_n_cercle_polaire[i], key=lambda noeud: noeud["theta"]))
+ else:
+ noeuds_par_cercle.append([])
+
+ cellules_temp = [] # Liste temporaire pour les cellules
+
+ # Création de la cellule centrale (cercle 0)
+ if n > 0 and len(k_noeuds_n_cercle_polaire) > 0:
+ noeuds_cercle_0 = [noeud["index"] for noeud in noeuds_par_cercle[0]]
+
+ cellule_centrale = {
+ "index": 0,
+ "noeuds": noeuds_cercle_0,
+ "boundary": 0,
+ "cell_type": 1,
+ "target_area": 100.0,
+ "lambda_celllength": 0,
+ "at_boundary": True,
+ "dead": False,
+ "target_length": 0,
+ "stiffness": 1,
+ "source": False,
+ "pin_fixed": False,
+ "area": 0.0,
+ "fixed": False,
+ "div_counter": 0,
+ "cercle": 0,
+ "angle": 0
+ }
+
+ cellules_temp.append(cellule_centrale)
+ print(f"Cellule centrale créée avec {len(noeuds_cercle_0)} noeuds")
+
+ # Création des cellules entre les cercles
+ for i in range(n - 1):
+ nb_cellules = a[i] if i < len(a) else a[-1]
+
+ for j in range(nb_cellules):
+ angle_j = 2 * j * math.pi / nb_cellules
+ angle_j_moins_1 = 2 * (j - 1) * math.pi / nb_cellules
+ if angle_j_moins_1 < 0:
+ angle_j_moins_1 += 2 * math.pi
+
+ # Variables pour stocker les informations des nœuds trouvés
+ noeud1, noeud2, noeud3, noeud4 = None, None, None, None
+ angle1, angle2, angle3, angle4 = None, None, None, None
+ r1, r2, r3, r4 = None, None, None, None
+ tolerance = 0.001
+
+ # Recherche optimisée des nœuds aux angles spécifiques
+ for point in noeuds_par_cercle[i]:
+ theta = point["theta"]
+ if noeud1 is None and angles_equivalents(theta, angle_j, tolerance):
+ noeud1, angle1, r1 = point["index"], theta, point["r"]
+ elif noeud2 is None and angles_equivalents(theta, angle_j_moins_1, tolerance):
+ noeud2, angle2, r2 = point["index"], theta, point["r"]
+
+ # Si les deux nœuds sont trouvés, on peut passer au cercle suivant
+ if noeud1 is not None and noeud2 is not None:
+ break
+
+ for point in noeuds_par_cercle[i + 1]:
+ theta = point["theta"]
+ if noeud3 is None and angles_equivalents(theta, angle_j_moins_1, tolerance):
+ noeud3, angle3, r3 = point["index"], theta, point["r"]
+ elif noeud4 is None and angles_equivalents(theta, angle_j, tolerance):
+ noeud4, angle4, r4 = point["index"], theta, point["r"]
+
+ if noeud3 is not None and noeud4 is not None:
+ break
+
+ # Si tous les nœuds principaux sont trouvés
+ if noeud1 is not None and noeud2 is not None and noeud3 is not None and noeud4 is not None:
+ # Calculer le centre de la cellule
+ x1, y1 = r1 * math.cos(angle1), r1 * math.sin(angle1)
+ x2, y2 = r2 * math.cos(angle2), r2 * math.sin(angle2)
+ x3, y3 = r3 * math.cos(angle3), r3 * math.sin(angle3)
+ x4, y4 = r4 * math.cos(angle4), r4 * math.sin(angle4)
+
+ centre_x = (x1 + x2 + x3 + x4) / 4
+ centre_y = (y1 + y2 + y3 + y4) / 4
+ angle_centre = math.atan2(centre_y, centre_x)
+ if angle_centre < 0:
+ angle_centre += 2 * math.pi
+
+ # Recherche des nœuds intermédiaires
+ noeuds_arc_sup = []
+ for point in noeuds_par_cercle[i]:
+ theta, index = point["theta"], point["index"]
+ if index != noeud1 and index != noeud2:
+ if (est_entre_angles(theta, angle2, angle1, tolerance) or
+ angles_equivalents(theta, angle1, tolerance) or
+ angles_equivalents(theta, angle2, tolerance)):
+ noeuds_arc_sup.append((theta, index))
+
+ noeuds_arc_sup.sort(reverse=True)
+ noeuds_arc_sup = [idx for _, idx in noeuds_arc_sup]
+
+ noeuds_arc_inf = []
+ for point in noeuds_par_cercle[i + 1]:
+ theta, index = point["theta"], point["index"]
+ if index != noeud3 and index != noeud4:
+ if (est_entre_angles(theta, angle3, angle4, tolerance) or
+ angles_equivalents(theta, angle3, tolerance) or
+ angles_equivalents(theta, angle4, tolerance)):
+ noeuds_arc_inf.append((theta, index))
+
+ noeuds_arc_inf.sort()
+ noeuds_arc_inf = [idx for _, idx in noeuds_arc_inf]
+
+ # Construction des noeuds de la cellule dans l'ordre
+ tous_noeuds = [noeud1] + noeuds_arc_sup + [noeud2, noeud3] + noeuds_arc_inf + [noeud4]
+
+ cellule = {
+ "index": len(cellules_temp),
+ "noeuds": tous_noeuds,
+ "boundary": 0,
+ "cell_type": 0 if i == n - 2 else (3 if i == 0 else 0),
+ "target_area": 100.0,
+ "lambda_celllength": 0,
+ "at_boundary": True if i == n - 2 else False,
+ "dead": False,
+ "target_length": 0,
+ "stiffness": 1,
+ "source": False,
+ "pin_fixed": False,
+ "area": 0.0,
+ "fixed": False,
+ "div_counter": 0,
+ "cercle": i + 1,
+ "angle": angle_centre
+ }
+
+ cellules_temp.append(cellule)
+ else:
+ print(f"Impossible de créer la cellule à i={i}, j={j}: nœuds manquants")
+ print(f"Nœuds trouvés: {noeud1}, {noeud2}, {noeud3}, {noeud4}")
+
+ # Organiser les cellules par cercle puis par angle
+ cellules_par_cercle = {}
+ for cellule in cellules_temp:
+ cercle = cellule.get("cercle", 0)
+ if cercle not in cellules_par_cercle:
+ cellules_par_cercle[cercle] = []
+ cellules_par_cercle[cercle].append(cellule)
+
+ # Trier et réassembler les cellules
+ cellules_triees = []
+ for cercle in sorted(cellules_par_cercle.keys()):
+ cellules_par_cercle[cercle].sort(key=lambda c: c.get("angle", 0))
+ cellules_triees.extend(cellules_par_cercle[cercle])
+
+ # Réindexer les cellules triées
+ cellules = []
+ for i, cellule in enumerate(cellules_triees):
+ cellule_copy = cellule.copy()
+ cellule_copy["index"] = i
+ cellules.append(cellule_copy)
+
+ print("cellules", cellules)
+ return cellules
+
+
+# ----------------------------------------------------------------------------------------------------#
+# ---------- RAFFINNAGE DU MAILLAGE (AJOUT DE NOEUDS) --------------------------------------------------------------#
+# ----------------------------------------------------------------------------------------------------#
+
+def raffiner_maillage_separe(k_noeuds_n_cercle_polaire, n, cellules, longueur_seuil_cercle, longueur_seuil_radial,
+ rayons_n_cercles, seuil_proximite):
+ # Copier les données initiales
+ nouveau_k_noeuds_n_cercle_polaire = [[] for _ in range(n)]
+ for i in range(min(n, len(k_noeuds_n_cercle_polaire))):
+ for noeud in k_noeuds_n_cercle_polaire[i]:
+ nouveau_k_noeuds_n_cercle_polaire[i].append(noeud.copy())
+
+ nouvelles_cellules = [cellule.copy() for cellule in cellules]
+
+ # Tableau pour stocker les nœuds intermédiaires radiaux (qui ne sont pas sur les cercles)
+ noeuds_radiaux = []
+
+ # Identifier les noeuds avec tag spécial
+ noeuds_speciaux = {}
+ for i_cercle, cercle in enumerate(nouveau_k_noeuds_n_cercle_polaire):
+ for noeud in cercle:
+ if noeud.get("tag_special", False):
+ r = noeud["r"]
+ theta = noeud["theta"]
+ x = r * math.cos(theta)
+ y = r * math.sin(theta)
+ noeuds_speciaux[noeud["index"]] = (x, y, r, theta)
+
+ # Phase 1: Remaillage des cercles (segments circulaires)
+ iterations_cercles = 0
+ segments_cercles_raffines = True
+
+ while segments_cercles_raffines and iterations_cercles < 5:
+ iterations_cercles += 1
+ segments_cercles_raffines = False
+
+ # Convertir en coordonnées cartésiennes pour le calcul des distances
+ noeuds_cartesien = {}
+ for i_cercle in range(len(nouveau_k_noeuds_n_cercle_polaire)):
+ for noeud in nouveau_k_noeuds_n_cercle_polaire[i_cercle]:
+ r = noeud["r"]
+ theta = noeud["theta"]
+ index = noeud["index"]
+ initial = noeud["initial"]
+ boundary = noeud["boundary"]
+ x = r * math.cos(theta)
+ y = r * math.sin(theta)
+ noeuds_cartesien[index] = (x, y, r, theta, i_cercle, initial, boundary)
+
+ # Ajouter les noeuds radiaux à la liste des noeuds cartésiens
+ for noeud in noeuds_radiaux:
+ r = noeud["r"]
+ theta = noeud["theta"]
+ index = noeud["index"]
+ initial = noeud["initial"]
+ boundary = noeud["boundary"]
+ x = r * math.cos(theta)
+ y = r * math.sin(theta)
+ noeuds_cartesien[index] = (x, y, r, theta, -1, initial, boundary) # -1 indique un noeud radial
+
+ # Dictionnaire pour stocker les nouveaux noeuds à ajouter sur les cercles
+ segments_cercles_a_raffiner = {}
+
+ # Vérifier les segments sur un même cercle
+ for i_cercle in range(n):
+ if i_cercle >= len(nouveau_k_noeuds_n_cercle_polaire):
+ continue
+
+ cercle_noeuds = nouveau_k_noeuds_n_cercle_polaire[i_cercle]
+ nb_noeuds = len(cercle_noeuds)
+
+ for i in range(nb_noeuds):
+ idx1 = cercle_noeuds[i]["index"]
+ idx2 = cercle_noeuds[(i + 1) % nb_noeuds]["index"]
+
+ if idx1 in noeuds_cartesien and idx2 in noeuds_cartesien:
+ x1, y1, r1, theta1, _, _, boundary1 = noeuds_cartesien[idx1]
+ x2, y2, r2, theta2, _, _, boundary2 = noeuds_cartesien[idx2]
+
+ # Distance euclidienne entre les deux noeuds
+ distance = math.sqrt((x2 - x1) ** 2 + (y2 - y1) ** 2)
+
+ if distance > longueur_seuil_cercle:
+ # Gestion de l'interpolation angulaire
+ if theta1 < 0: theta1 += 2 * math.pi
+ if theta2 < 0: theta2 += 2 * math.pi
+
+ # Gérer le cas où l'arc traverse la ligne θ=0
+ if abs(theta1 - theta2) > math.pi:
+ if theta1 > theta2:
+ theta2 += 2 * math.pi
+ else:
+ theta1 += 2 * math.pi
+
+ # Interpolation angulaire en respectant le rayon du cercle
+ theta_new = (theta1 + theta2) / 2
+ r_new = rayons_n_cercles[i_cercle] # Utiliser le rayon exact du cercle
+
+ # Normaliser l'angle entre 0 et 2π
+ if theta_new >= 2 * math.pi:
+ theta_new -= 2 * math.pi
+
+ # Calculer les coordonnées cartésiennes
+ x_new = r_new * math.cos(theta_new)
+ y_new = r_new * math.sin(theta_new)
+
+ # Vérifier proximité avec noeuds spéciaux
+ trop_proche = False
+ for _, (x_special, y_special, _, _) in noeuds_speciaux.items():
+ dist_special = math.sqrt((x_new - x_special) ** 2 + (y_new - y_special) ** 2)
+ if dist_special < seuil_proximite:
+ trop_proche = True
+ break
+
+ if not trop_proche:
+ # Hériter le statut boundary si au moins un des nœuds est boundary
+ is_boundary = boundary1 or boundary2
+ segments_cercles_a_raffiner[tuple(sorted([idx1, idx2]))] = (x_new, y_new, r_new, theta_new, i_cercle, is_boundary)
+ segments_cercles_raffines = True
+
+ # Assigner des indices aux nouveaux noeuds
+ indices_max = [noeud["index"] for cercle in nouveau_k_noeuds_n_cercle_polaire for noeud in cercle]
+ indices_max.extend([noeud["index"] for noeud in noeuds_radiaux])
+ prochain_indice = max(indices_max) + 1 if indices_max else 0
+
+ # Ajouter les nouveaux noeuds aux cercles et créer le mappage
+ map_segments_cercles_indices = {}
+ for segment_key, (x_new, y_new, r_new, theta_new, cercle, is_boundary) in segments_cercles_a_raffiner.items():
+ idx1, idx2 = segment_key
+
+ nouveau_noeud = {
+ "r": r_new,
+ "theta": theta_new,
+ "index": prochain_indice,
+ "initial": False, # Nouveau nœud intermédiaire
+ "sam": False,
+ "boundary": is_boundary, # Hériter le statut boundary
+ "fixed": False
+ }
+
+ # Ajouter au cercle correspondant
+ nouveau_k_noeuds_n_cercle_polaire[cercle].append(nouveau_noeud)
+
+ # Mapper le segment au nouvel indice pour mise à jour des cellules
+ map_segments_cercles_indices[segment_key] = prochain_indice
+ prochain_indice += 1
+
+ # Trier les noeuds de chaque cercle par angle
+ for i in range(n):
+ if i < len(nouveau_k_noeuds_n_cercle_polaire):
+ nouveau_k_noeuds_n_cercle_polaire[i].sort(key=lambda point: point["theta"])
+
+ # Mettre à jour les cellules
+ maj_cellules = []
+ for cellule in nouvelles_cellules:
+ nouvelle_liste_noeuds = []
+ noeuds = cellule["noeuds"]
+
+ for i in range(len(noeuds)):
+ idx1 = noeuds[i]
+ idx2 = noeuds[(i + 1) % len(noeuds)]
+
+ nouvelle_liste_noeuds.append(idx1)
+
+ # Vérifier si ce segment a été raffiné (cercle)
+ segment_key = tuple(sorted([idx1, idx2]))
+ if segment_key in map_segments_cercles_indices:
+ nouvelle_liste_noeuds.append(map_segments_cercles_indices[segment_key])
+
+ nouvelle_cellule = cellule.copy()
+ nouvelle_cellule["noeuds"] = nouvelle_liste_noeuds
+ maj_cellules.append(nouvelle_cellule)
+
+ nouvelles_cellules = maj_cellules
+
+ # Phase 2: Remaillage des segments radiaux entre nœuds UNIQUEMENT où des segments radiaux existent déjà
+ iterations_radiaux = 0
+ segments_radiaux_raffines = True
+
+ while segments_radiaux_raffines and iterations_radiaux < 5:
+ iterations_radiaux += 1
+ segments_radiaux_raffines = False
+
+ # Convertir en coordonnées cartésiennes pour le calcul des distances
+ noeuds_cartesien = {}
+ for i_cercle in range(len(nouveau_k_noeuds_n_cercle_polaire)):
+ for noeud in nouveau_k_noeuds_n_cercle_polaire[i_cercle]:
+ r = noeud["r"]
+ theta = noeud["theta"]
+ index = noeud["index"]
+ initial = noeud["initial"]
+ boundary = noeud["boundary"]
+ x = r * math.cos(theta)
+ y = r * math.sin(theta)
+ noeuds_cartesien[index] = (x, y, r, theta, i_cercle, initial, boundary)
+
+ # Ajouter les noeuds radiaux à la liste des noeuds cartésiens
+ for noeud in noeuds_radiaux:
+ r = noeud["r"]
+ theta = noeud["theta"]
+ index = noeud["index"]
+ initial = noeud["initial"]
+ boundary = noeud["boundary"]
+ x = r * math.cos(theta)
+ y = r * math.sin(theta)
+ noeuds_cartesien[index] = (x, y, r, theta, -1, initial, boundary)
+
+ # Collecter les segments radiaux existants dans les cellules
+ segments_radiaux_existants = set()
+ for cellule in nouvelles_cellules:
+ noeuds = cellule["noeuds"]
+ for i in range(len(noeuds)):
+ idx1 = noeuds[i]
+ idx2 = noeuds[(i + 1) % len(noeuds)]
+
+ if idx1 in noeuds_cartesien and idx2 in noeuds_cartesien:
+ x1, y1, r1, theta1, cercle1, _, _ = noeuds_cartesien[idx1]
+ x2, y2, r2, theta2, cercle2, _, _ = noeuds_cartesien[idx2]
+
+ # Vérifier si c'est un segment radial (rayons différents)
+ if abs(r1 - r2) > 0.001: # Tolérance pour éviter erreurs d'arrondi
+ segments_radiaux_existants.add(tuple(sorted([idx1, idx2])))
+
+ # Dictionnaire pour stocker les nouveaux nœuds à ajouter
+ segments_radiaux_a_raffiner = {}
+
+ # Pour chaque segment radial existant
+ for segment in segments_radiaux_existants:
+ idx1, idx2 = segment
+
+ if idx1 in noeuds_cartesien and idx2 in noeuds_cartesien:
+ x1, y1, r1, theta1, cercle1, initial1, boundary1 = noeuds_cartesien[idx1]
+ x2, y2, r2, theta2, cercle2, initial2, boundary2 = noeuds_cartesien[idx2]
+
+ # Distance euclidienne entre les deux noeuds
+ distance = math.sqrt((x2 - x1)**2 + (y2 - y1)**2)
+
+ # Si la distance est supérieure au seuil, on ajoute un nœud intermédiaire
+ if distance > longueur_seuil_radial:
+ # Calculer la position du nouveau nœud intermédiaire
+ x_new = (x1 + x2) / 2
+ y_new = (y1 + y2) / 2
+ r_new = math.sqrt(x_new**2 + y_new**2)
+ theta_new = math.atan2(y_new, x_new)
+ if theta_new < 0:
+ theta_new += 2 * math.pi
+
+ # Hériter le statut boundary si l'un des nœuds est boundary
+ is_boundary = boundary1 or boundary2
+
+ # Sauvegarder les coordonnées du nouveau nœud
+ segments_radiaux_a_raffiner[segment] = (x_new, y_new, r_new, theta_new, is_boundary)
+ segments_radiaux_raffines = True
+
+ # Assigner des indices aux nouveaux noeuds radiaux
+ indices_max = [noeud["index"] for cercle in nouveau_k_noeuds_n_cercle_polaire for noeud in cercle]
+ indices_max.extend([noeud["index"] for noeud in noeuds_radiaux])
+ prochain_indice = max(indices_max) + 1 if indices_max else 0
+
+ # Créer les nouveaux noeuds radiaux
+ map_segments_radiaux_indices = {}
+ for segment_key, (x_new, y_new, r_new, theta_new, is_boundary) in segments_radiaux_a_raffiner.items():
+ idx1, idx2 = segment_key
+
+ nouveau_noeud = {
+ "r": r_new,
+ "theta": theta_new,
+ "index": prochain_indice,
+ "initial": False, # Nouveau nœud intermédiaire
+ "sam": False,
+ "boundary": False, # Hériter le statut boundary
+ "fixed": False
+ }
+
+ # Ajouter aux nœuds radiaux
+ noeuds_radiaux.append(nouveau_noeud)
+
+ # Mapper le segment au nouvel indice pour mise à jour des cellules
+ map_segments_radiaux_indices[segment_key] = prochain_indice
+ prochain_indice += 1
+
+ # Mettre à jour les cellules avec les nouveaux noeuds radiaux
+ maj_cellules = []
+ for cellule in nouvelles_cellules:
+ nouvelle_liste_noeuds = []
+ noeuds = cellule["noeuds"]
+
+ for i in range(len(noeuds)):
+ idx1 = noeuds[i]
+ idx2 = noeuds[(i + 1) % len(noeuds)]
+
+ nouvelle_liste_noeuds.append(idx1)
+
+ # Vérifier si ce segment a été raffiné (radialement)
+ segment_key = tuple(sorted([idx1, idx2]))
+ if segment_key in map_segments_radiaux_indices:
+ nouvelle_liste_noeuds.append(map_segments_radiaux_indices[segment_key])
+
+ nouvelle_cellule = cellule.copy()
+ nouvelle_cellule["noeuds"] = nouvelle_liste_noeuds
+ maj_cellules.append(nouvelle_cellule)
+
+ nouvelles_cellules = maj_cellules
+
+ k_noeuds_n_cercle_polaire_final = []
+ for cercle in nouveau_k_noeuds_n_cercle_polaire:
+ k_noeuds_n_cercle_polaire_final.append(cercle)
+
+ # Créer un cercle virtuel pour les noeuds radiaux (permet de rester compatible avec le format attendu)
+ if noeuds_radiaux:
+ k_noeuds_n_cercle_polaire_final.append(noeuds_radiaux)
+
+ return k_noeuds_n_cercle_polaire_final, nouvelles_cellules
+
+
+
+
+
+
+#----------------------------------------------------------------------------------------------------#
+#-------------------------------------walls-------------------------------------------#
+#----------------------------------------------------------------------------------------------------#
+
+def generer_walls_initiaux(k_noeuds_n_cercle_cartesien, cellules_list):
+ """
+ Génère les walls (parois) entre les cellules adjacentes.
+
+ Args:
+ k_noeuds_n_cercle_cartesien: Liste des noeuds en coordonnées cartésiennes
+ cellules_list: Liste des cellules
+
+ Returns:
+ Liste des walls générés
+ """
+ # Créer un dictionnaire pour accès rapide aux noeuds
+ noeuds_dict = {}
+ for noeud in k_noeuds_n_cercle_cartesien:
+ noeuds_dict[noeud["index"]] = (noeud["x"], noeud["y"], noeud.get("initial", False),
+ noeud.get("boundary", False))
+
+ # Identifier les segments et les cellules qui les partagent
+ segments_par_cellule = {}
+ for cellule in cellules_list:
+ noeuds = cellule["noeuds"]
+ cell_index = cellule["index"]
+
+ # Pour chaque paire de noeuds consécutifs
+ for i in range(len(noeuds)):
+ n1 = noeuds[i]
+ n2 = noeuds[(i + 1) % len(noeuds)]
+ segment = tuple(sorted([n1, n2]))
+
+ # Ajouter la cellule à ce segment
+ if segment not in segments_par_cellule:
+ segments_par_cellule[segment] = []
+ segments_par_cellule[segment].append(cell_index)
+
+ # Générer les walls uniquement pour les segments partagés par deux cellules
+ walls_liste = []
+ wall_index = 0
+
+ for segment, cellules in segments_par_cellule.items():
+ # Un wall ne peut exister qu'entre deux cellules
+ if len(cellules) == 2:
+ n1, n2 = segment
+ c1, c2 = sorted(cellules)
+
+ # Vérifier que les noeuds existent et sont initiaux
+ if n1 in noeuds_dict and n2 in noeuds_dict:
+ _, _, initial1, boundary1 = noeuds_dict[n1]
+ _, _, initial2, boundary2 = noeuds_dict[n2]
+
+ # Vérifier que les deux noeuds sont initiaux
+ if initial1 and initial2:
+ # Ne pas créer de wall si les deux noeuds sont sur la frontière
+ if boundary1 and boundary2:
+ continue
+
+ # Calculer la longueur du wall
+ (x1, y1, _, _), (x2, y2, _, _) = noeuds_dict[n1], noeuds_dict[n2]
+ longueur = math.sqrt((x2 - x1) ** 2 + (y2 - y1) ** 2)
+
+ # Créer le wall avec exactement la structure demandée
+ wall = {
+ "length": f"{longueur:.4f}",
+ "c1": str(c1),
+ "c2": str(c2),
+ "n1": str(n1),
+ "n2": str(n2),
+ "wall_type": "normal",
+ "viz_flux": "0",
+ "index": str(wall_index)
+ }
+
+ walls_liste.append(wall)
+ wall_index += 1
+
+ return walls_liste
+
+
+#----------------------------------------------------------------------------------------------------#
+#------------------------- Aire cellules ---------------------------------------------------------------------#
+#----------------------------------------------------------------------------------------------------#
+
+def shoelace_formula(cellules_list, noeuds_list, absoluteValue=True):
+ """
+ Calcule l'aire de chaque cellule en utilisant la formule de Shoelace (Gauss).
+
+ Args:
+ cellules_list: Liste des cellules à traiter
+ noeuds_list: Liste des noeuds avec leurs coordonnées
+ absoluteValue: Si True, retourne la valeur absolue de l'aire
+
+ Returns:
+ Liste des cellules avec l'aire calculée
+ """
+ # Optimisation par précalcul du dictionnaire de coordonnées
+ noeuds_dict = {}
+ for noeud in noeuds_list:
+ noeuds_dict[noeud["index"]] = (noeud["x"], noeud["y"])
+
+ # Préallocation de la liste de résultat
+ n_cellules = len(cellules_list)
+ cellules_avec_aire = [None] * n_cellules
+
+ # Traitement optimisé par cellule
+ for i, cellule in enumerate(cellules_list):
+ indices_noeuds = cellule["noeuds"]
+ nb_noeuds = len(indices_noeuds)
+
+ # Traitement rapide des polygones dégénérés
+ if nb_noeuds < 3:
+ cellule_maj = cellule.copy()
+ cellule_maj["area"] = 0.0
+ cellules_avec_aire[i] = cellule_maj
+ continue
+
+ # Extraction optimisée des coordonnées avec gestion d'erreur intégrée
+ try:
+ # Extraction en une seule fois pour éviter les accès répétés
+ coords = [noeuds_dict[idx] for idx in indices_noeuds]
+
+ # Boucle unifiée pour le calcul de l'aire (sans allocation supplémentaire)
+ somme = 0.0
+ for j in range(nb_noeuds):
+ k = (j + 1) % nb_noeuds
+ # Formule de Shoelace optimisée
+ somme += coords[j][0] * coords[k][1] - coords[k][0] * coords[j][1]
+
+ # Calcul final avec une seule multiplication
+ aire = abs(somme * 0.5) if absoluteValue else somme * 0.5
+
+ except KeyError:
+ # En cas d'indice invalide, attribuer une aire nulle
+ aire = 0.0
+
+ # Minimiser les copies en utilisant copy() au lieu de deepcopy()
+ cellule_maj = cellule.copy()
+ cellule_maj["area"] = aire
+ cellules_avec_aire[i] = cellule_maj
+
+ return cellules_avec_aire
+
+
+def calculer_aire_totale_boundary(noeuds_list, absoluteValue=True):
+ """
+ Calcule l'aire totale du tissu en utilisant uniquement les noeuds marqués comme boundary.
+ Version optimisée.
+
+ Args:
+ noeuds_list: Liste des noeuds avec leurs coordonnées
+ absoluteValue: Si True, retourne la valeur absolue de l'aire
+
+ Returns:
+ Aire totale du tissu délimité par les noeuds boundary
+ """
+ # Extraction directe des noeuds boundary (plus efficace qu'une compréhension de liste)
+ noeuds_boundary = []
+ for noeud in noeuds_list:
+ if noeud.get("boundary", False):
+ noeuds_boundary.append(noeud)
+
+ # Vérification rapide du nombre de noeuds
+ n_noeuds = len(noeuds_boundary)
+ if n_noeuds < 3:
+ return 0.0
+
+ # Calcul du véritable centroïde (dans la version originale, il était initialisé à 0,0)
+ centre_x = sum(noeud["x"] for noeud in noeuds_boundary) / n_noeuds
+ centre_y = sum(noeud["y"] for noeud in noeuds_boundary) / n_noeuds
+
+ # Pré-calcul des angles pour le tri (évite les calculs répétés)
+ noeuds_avec_angle = []
+ for noeud in noeuds_boundary:
+ dx = noeud["x"] - centre_x
+ dy = noeud["y"] - centre_y
+ angle = math.atan2(dy, dx)
+ if angle < 0:
+ angle += 2 * math.pi
+ noeuds_avec_angle.append((noeud, angle))
+
+ # Tri efficace
+ noeuds_avec_angle.sort(key=lambda x: x[1])
+
+ # Préextraction des coordonnées pour un accès plus rapide
+ coords_x = []
+ coords_y = []
+ for noeud, _ in noeuds_avec_angle:
+ coords_x.append(noeud["x"])
+ coords_y.append(noeud["y"])
+
+ # Formule de Shoelace optimisée en une seule passe
+ aire = 0.0
+ for i in range(n_noeuds):
+ j = (i + 1) % n_noeuds
+ # Version optimisée de la formule
+ aire += (coords_x[i] * coords_y[j]) - (coords_x[j] * coords_y[i])
+
+ # Division par 2 une seule fois à la fin
+ aire *= 0.5
+
+ return abs(aire) if absoluteValue else aire
+
+#----------------------------------------------------------------------------------------------------#
+#--------- VISUALISATION DES POINTS ET CERCLES ------------------------------------------------------#
+#----------------------------------------------------------------------------------------------------#
+
+def tracer_points_cercles(k_noeuds, n, a, cellules=None):
+ """ Visualise les noeuds, les cercles et les segments radiaux.
+
+ Args:
+ k_noeuds_n_cercle_polaire: Liste des noeuds en coordonnées polaires
+ n: Nombre de cercles
+ a: Liste des nombres de cellules/points par cercle
+
+ Returns:
+ None. Affiche un graphique avec matplotlib. """
+
+ plt.figure(figsize=(10, 10))
+
+ # Couleurs différentes pour chaque cercle
+ couleurs = ['r', 'g', 'b', 'm', 'c', 'y', 'k', 'orange', 'purple', 'brown']
+ couleur_radiale = 'gray' # Couleur pour les segments radiaux
+ est_format_cartesien = not isinstance(k_noeuds[0], list)
+ # Grouper les noeuds par rayon pour identifier les cercles
+ noeuds_par_rayon = {}
+ if est_format_cartesien:
+ # Traitement des noeuds cartésiens (liste plate)
+ for noeud in k_noeuds:
+ # Calculer r pour le groupement
+ if "r" in noeud:
+ r = noeud["r"]
+ else:
+ r = math.sqrt(noeud["x"] ** 2 + noeud["y"] ** 2)
+
+ if r not in noeuds_par_rayon:
+ noeuds_par_rayon[r] = []
+
+ # S'assurer que les coordonnées cartésiennes sont présentes
+ if "x" not in noeud or "y" not in noeud:
+ noeud["x"] = r * math.cos(noeud["theta"])
+ noeud["y"] = r * math.sin(noeud["theta"])
+
+ noeuds_par_rayon[r].append(noeud)
+ else:
+ # Traitement original pour les noeuds polaires (liste de listes)
+ for i_cercle in range(len(k_noeuds)):
+ for point in k_noeuds[i_cercle]:
+ r = point["r"]
+ if r not in noeuds_par_rayon:
+ noeuds_par_rayon[r] = []
+
+ # Ajouter les coordonnées cartésiennes calculées
+ x = r * math.cos(point["theta"])
+ y = r * math.sin(point["theta"])
+ point_avec_xy = point.copy()
+ point_avec_xy["x"] = x
+ point_avec_xy["y"] = y
+ noeuds_par_rayon[r].append(point_avec_xy)
+
+ # Dictionnaire pour accès rapide aux coordonnées
+ noeuds_dict = {}
+ for rayon, points in noeuds_par_rayon.items():
+ for point in points:
+ noeuds_dict[point["index"]] = (point["x"], point["y"], rayon)
+
+
+ # Segments déjà tracés (pour éviter les doublons)
+ segments_traces = set()
+
+ # Tracer chaque cercle et ses points
+ for i, (rayon, points) in enumerate(sorted(noeuds_par_rayon.items())):
+ # Séparer les nœuds initiaux des nœuds raffinés
+ points_initiaux = [point for point in points if point.get("initial", False)]
+ points_raffines = [point for point in points if not point.get("initial", False)]
+
+ # Tracer les points initiaux
+ x_init = [p["x"] for p in points_initiaux]
+ y_init = [p["y"] for p in points_initiaux]
+ indices_init = [p["index"] for p in points_initiaux]
+ if x_init:
+ plt.scatter(x_init, y_init, color=couleurs[i % len(couleurs)], marker='o',
+ label=f'Cercle {i} (initial)' if i == 0 else "")
+
+ # Tracer les points raffinés
+ x_raff = [p["x"] for p in points_raffines]
+ y_raff = [p["y"] for p in points_raffines]
+ indices_raff = [p["index"] for p in points_raffines]
+ if x_raff:
+ plt.scatter(x_raff, y_raff, color=couleurs[i % len(couleurs)], marker='x',
+ label=f'Cercle {i} (raffiné)' if i == 0 else "")
+
+ # Afficher les indices des nœuds
+ for j in range(len(x_init)):
+ plt.text(x_init[j] + 0.3, y_init[j] + 0.3, str(indices_init[j]), fontsize=8,
+ bbox=dict(facecolor='white', alpha=0.7, edgecolor='none'))
+ for j in range(len(x_raff)):
+ plt.text(x_raff[j] + 0.3, y_raff[j] + 0.3, str(indices_raff[j]), fontsize=8,
+ bbox=dict(facecolor='lightyellow', alpha=0.7, edgecolor='none'))
+
+ # Tracer les segments à partir des cellules
+ if cellules:
+ rayons_tries = sorted(noeuds_par_rayon.keys())
+ for cellule in cellules:
+ noeuds = cellule["noeuds"]
+ for i in range(len(noeuds)):
+ idx1 = noeuds[i]
+ idx2 = noeuds[(i + 1) % len(noeuds)]
+
+ segment_key = tuple(sorted([idx1, idx2]))
+ if segment_key in segments_traces:
+ continue
+
+ if idx1 in noeuds_dict and idx2 in noeuds_dict:
+ x1, y1, rayon1 = noeuds_dict[idx1]
+ x2, y2, rayon2 = noeuds_dict[idx2]
+
+ # Tracer le segment selon le type
+ if rayon1 == rayon2: # Segment sur le même cercle
+ i_couleur = rayons_tries.index(rayon1) % len(couleurs)
+ plt.plot([x1, x2], [y1, y2],
+ color=couleurs[i_couleur],
+ linestyle='-', linewidth=1)
+ else: # Segment radial
+ plt.plot([x1, x2], [y1, y2],
+ color=couleur_radiale,
+ linestyle='--', linewidth=0.8)
+
+ segments_traces.add(segment_key)
+
+ plt.grid(True)
+ plt.axis('equal')
+ plt.title('Visualisation des cercles (o=initial, x=raffiné)')
+ plt.xlabel('x')
+ plt.ylabel('y')
+ plt.show()
+
+
+
+
+#----------------------------------------------------------------------------------------------------#
+#---------- VISUALISATION DES CELLULES --------------------------------------------------------------#
+#----------------------------------------------------------------------------------------------------#
+def tracer_cellules(points, cellules):
+ """ Visualise les cellules avec leur indice au centre.
+
+ Args:
+ k_noeuds_n_cercle_cartesien: Liste des noeuds en coordonnées cartésiennes
+ cellules: Liste des cellules définies par leurs indices de noeuds
+
+ Returns:
+ None. Affiche un graphique avec matplotlib. """
+
+ plt.figure(figsize=(10, 10))
+
+ # Couleurs différentes pour colorer les cellules par groupe
+ couleurs = ['r', 'g', 'b', 'm', 'c', 'y', 'k', 'orange', 'purple', 'brown']
+
+
+ noeuds_dict = {} # Créer un dictionnaire pour accéder rapidement aux coordonnées des noeuds
+ noeuds_initiaux = set() # Pour distinguer les noeuds initiaux des noeuds raffinés
+
+ for point in points:
+ if isinstance(point, dict) and "index" in point:
+ # Récupérer les coordonnées cartésiennes du point
+ if "x" in point and "y" in point:
+ noeuds_dict[point["index"]] = (point["x"], point["y"])
+ elif "r" in point and "theta" in point:
+ # Convertir de polaire à cartésien
+ r = point["r"]
+ theta = point["theta"]
+ x = r * math.cos(theta)
+ y = r * math.sin(theta)
+ noeuds_dict[point["index"]] = (x, y)
+
+ # Marquer les noeuds initiaux
+ if point.get("initial", False):
+ noeuds_initiaux.add(point["index"])
+
+ # Identifier les rayons pour grouper les cellules (code existant)
+ rayons_cellules = {}
+ for cellule in cellules:
+ # Code de groupement inchangé
+ cell_type = cellule.get("cell_type", 0)
+ if cell_type not in rayons_cellules:
+ rayons_cellules[cell_type] = []
+ rayons_cellules[cell_type].append(cellule)
+
+ # Tracer les polygones des cellules
+ for i, (rayon, groupe_cellules) in enumerate(sorted(rayons_cellules.items())):
+ couleur = couleurs[i % len(couleurs)]
+ for cellule in groupe_cellules:
+ # Récupérer les coordonnées des noeuds de la cellule
+ coords = []
+ for noeud_idx in cellule["noeuds"]:
+ if noeud_idx in noeuds_dict:
+ coords.append(noeuds_dict[noeud_idx])
+
+ # Tracer le polygone
+ if len(coords) >= 3:
+ xs, ys = zip(*coords)
+ plt.fill(xs, ys, alpha=0.5, color=couleur, edgecolor='black')
+
+ # Ajouter l'indice de la cellule au centre
+ centre_x = sum(xs) / len(xs)
+ centre_y = sum(ys) / len(ys)
+ plt.text(centre_x, centre_y, str(cellule["index"]),
+ ha='center', va='center', fontweight='bold')
+
+ # Tracer tous les noeuds
+ for noeud_idx, (x, y) in noeuds_dict.items():
+ # Utiliser un marqueur différent selon le type de noeud
+ marker = 'o' if noeud_idx in noeuds_initiaux else 'x'
+ plt.scatter(x, y, color='black', marker=marker, s=30, zorder=3)
+ plt.text(x + 0.2, y + 0.2, str(noeud_idx), fontsize=8,
+ bbox=dict(facecolor='white', alpha=0.7, edgecolor='none'))
+
+ # Tracer les segments entre noeuds consécutifs de chaque cellule
+ segments_traces = set()
+ for cellule in cellules:
+ noeuds = cellule["noeuds"]
+ for i in range(len(noeuds)):
+ idx1 = noeuds[i]
+ idx2 = noeuds[(i + 1) % len(noeuds)]
+
+ segment_key = tuple(sorted([idx1, idx2]))
+ if segment_key not in segments_traces and idx1 in noeuds_dict and idx2 in noeuds_dict:
+ x1, y1 = noeuds_dict[idx1]
+ x2, y2 = noeuds_dict[idx2]
+ plt.plot([x1, x2], [y1, y2], 'k-', linewidth=1, alpha=0.7, zorder=2)
+ segments_traces.add(segment_key)
+
+ plt.grid(True)
+ plt.axis('equal')
+ plt.title('Visualisation des cellules avec noeuds intermédiaires')
+ plt.xlabel('x')
+ plt.ylabel('y')
+ plt.show()
+
+
+
+#----------------------------------------------------------------------------------------------------#
+#------------------------- MAIN ---------------------------------------------------------------------#
+#----------------------------------------------------------------------------------------------------#
+""" Programme principal. """
+
+
+def generer_donnees():
+ rayon_0 = 200
+ a = [25,25,30]
+ n = len(a)+1
+ rapport_R_T = [1,0.5,0.5]
+ seuil_proximite = 1
+ longueur_max_cercles = 10 # Seuil pour les segments circulaires
+ longueur_max_radiaux = 10 # Seuil pour les segments radiaux
+ maillage = True
+
+ rayons_n_cercles = n_cercles(n, rayon_0, a, rapport_R_T)
+ k_noeuds_n_cercle_polaire_initial, index_noeud_max = creer_noeuds_initiaux(n, rayons_n_cercles, a)
+ k_noeuds_n_cercle_polaire, map_indices = fusionner_noeuds(k_noeuds_n_cercle_polaire_initial, n, index_noeud_max)
+ cellules_list = creer_cellules(rayons_n_cercles, k_noeuds_n_cercle_polaire, n, a)
+ if not(maillage):
+
+ #Walls
+ k_noeuds_n_cercle_cartesien = polaire_vers_cartesien(k_noeuds_n_cercle_polaire)
+ liste_walls = generer_walls_initiaux(k_noeuds_n_cercle_cartesien, cellules_list)
+ cellules_finales = shoelace_formula(cellules_list, k_noeuds_n_cercle_cartesien)
+ basearea = calculer_aire_totale_boundary(k_noeuds_n_cercle_cartesien) / (len(cellules_finales))
+ #Tracé
+ # tracer_points_cercles(k_noeuds_n_cercle_polaire, n, a, cellules_list)
+ # tracer_cellules(polaire_vers_cartesien(k_noeuds_n_cercle_polaire, n, a), cellules_list)
+ #
+ # print(f"Aire totale du tissu : {basearea:.4f}")
+
+ return k_noeuds_n_cercle_cartesien, cellules_finales, liste_walls, basearea
+
+ else :
+ k_noeuds_n_cercle_polaire_raffine, cellules_list_raffine = raffiner_maillage_separe(
+ k_noeuds_n_cercle_polaire, n, cellules_list,
+ longueur_max_cercles, longueur_max_radiaux,
+ rayons_n_cercles, seuil_proximite
+ )
+
+ #Walls
+ k_noeuds_n_cercle_cartesien_raffine = polaire_vers_cartesien(k_noeuds_n_cercle_polaire_raffine)
+ liste_walls = generer_walls_initiaux(k_noeuds_n_cercle_cartesien_raffine, cellules_list_raffine)
+ cellules_finales = shoelace_formula(cellules_list_raffine, k_noeuds_n_cercle_cartesien_raffine)
+ basearea = calculer_aire_totale_boundary(k_noeuds_n_cercle_cartesien_raffine) / (len(cellules_finales))
+ print(f"Aire totale du tissu : {basearea:.4f}")
+
+ # Tracé
+ k_noeuds_n_cercle_cartesien_raffine = polaire_vers_cartesien(k_noeuds_n_cercle_polaire_raffine)
+ tracer_points_cercles(k_noeuds_n_cercle_polaire_raffine, n, a, cellules_list_raffine)
+ # tracer_cellules(polaire_vers_cartesien(k_noeuds_n_cercle_polaire_raffine, n, a), cellules_list_raffine)
+
+ return k_noeuds_n_cercle_cartesien_raffine, cellules_finales, liste_walls, basearea
+
+
+
+
+
+ # k_noeuds_renommes, cellules_renommees, walls_renommes = reindexer_noeuds_par_cellule(
+ # k_noeuds_n_cercle_cartesien_raffine,
+ # cellules_list_raffine,
+ # liste_walls
+ # )
+
+
+
+
+
+
+
+
+
+
+
+
+generer_donnees()
\ No newline at end of file
diff --git a/run_in_batch.py b/run_in_batch.py
new file mode 100644
index 00000000..6b286227
--- /dev/null
+++ b/run_in_batch.py
@@ -0,0 +1,120 @@
+import xml.etree.ElementTree as ET
+from pathlib import Path
+import subprocess
+import numpy as np
+import time
+
+class MyXML:
+ """Utility to clone a LeafML file and tweak simple entries."""
+
+ def __init__(self, templatefile: str):
+ self.tree = ET.parse(templatefile)
+ self.root = self.tree.getroot()
+ self.parameters = self.root.find("parameter")
+
+ def set_simple_param(self, name: str, value) -> None:
+ """Change the ‘val’ attribute of ."""
+ par = self.parameters.find(f"./par[@name='{name}']")
+ if par is None:
+ raise KeyError(f"Parameter '{name}' not found in XML")
+ par.set("val", str(value))
+ def set_setting(self, name: str, value) -> None:
+ """Change the 'val' attribute of ."""
+ settings = self.root.find("settings")
+ if settings is None:
+ raise KeyError("Settings section not found in XML")
+
+ setting = settings.find(f"./setting[@name='{name}']")
+ if setting is None:
+ raise KeyError(f"Setting '{name}' not found in XML")
+
+ # Convert boolean values to lowercase strings (true/false)
+ setting.set("val", str(value).lower() if isinstance(value, bool) else str(value))
+
+ def write(self, filename: str) -> None:
+ """Write a full XML document in UTF‑8."""
+ # ① simply pass the *path* to ElementTree; it opens the file in 'wb'
+ self.tree.write(filename, encoding="utf-8", xml_declaration=True)
+
+
+# -----------------------------------------------------------------------------
+simulation_start_time = time.time()
+leaf_in = Path("data/leaves/cambium.xml")
+model = "libcambium.so"
+# Fixed expansion rate and different elastic modulus values
+number_of_runs = np.arange(0,1)
+for r in number_of_runs:
+ # Create unique output names
+ output_suffix = f"Test_if_stiffness_is_beign_passed_{r}"
+ datadir = f"/home/ardati/Data_VirtualLeaf/Cambium_{output_suffix}"
+ leaf_out = leaf_in.with_name(leaf_in.stem + output_suffix + ".xml")
+
+ # Create and modify XML
+ xml = MyXML(leaf_in)
+ xml.set_simple_param("maxt", 5000)
+ xml.set_simple_param("datadir", datadir)
+ xml.set_simple_param("rseed", 1) #set seed to 1 for reproducibility
+ xml.set_simple_param("mc_stepsize", 0.2)
+ xml.set_simple_param("mc_cell_stepsize", 0.1)
+ xml.set_simple_param("compatibility_level", 1)
+ xml.set_setting("show_nodes", False)
+ xml.set_setting("show_node_numbers", False)
+ xml.set_setting("show_cell_numbers", False)
+ xml.set_setting("show_cell_centers", False)
+
+ # Write XML file
+ xml.write(leaf_out)
+
+ # Run simulation
+ print(f"Running simulation with number {r} and output {leaf_out}")
+ subprocess.run([
+ "./bin/VirtualLeaf",
+ "-b",
+ "-l", str(leaf_out),
+ "-m", model
+ ], check=True)
+
+ # here i want to ran this bash script in the same directory to animate the pngs
+ # Animate the PNGs generated in the simulation
+ animate_script = f"""#!/bin/bash
+ # Get directory name for the output file name
+ dir_name=$(basename "$(pwd)")
+
+ # 1. Make numbered links
+ i=0
+ for f in $(ls leaf.[0-9][0-9][0-9][0-9][0-9][0-9].png | sort); do
+ printf -v link "link_%06d.png" "$i"
+ ln -s "$f" "$link"
+ ((i++))
+ done
+
+ # 2. Encode
+ ffmpeg -framerate 25 -i link_%06d.png \\
+ -c:v libx264 -crf 18 -preset slow \\
+ -pix_fmt yuv420p -movflags +faststart \\
+ "$dir_name.mp4"
+
+ # 3. Clean up
+ rm link_*.png
+ """
+ # Create the script file in the data directory
+ import os
+
+ script_path = os.path.join(datadir, "animate.sh")
+
+ # Write the script
+ with open(script_path, 'w') as f:
+ f.write(animate_script)
+
+ # Make executable
+ os.chmod(script_path, 0o755)
+
+ # Run the animation script in the data directory
+ print(f"Animating PNGs in {datadir}")
+ subprocess.run(
+ [script_path],
+ cwd=datadir, # Run in the data directory
+ check=True
+ )
+
+print(f"This Simulation took {round((time.time() - simulation_start_time) / 60, 2)} minutes.")
diff --git a/src/GUI/GUI.pro b/src/GUI/GUI.pro
index 9063c85e..6625e602 100644
--- a/src/GUI/GUI.pro
+++ b/src/GUI/GUI.pro
@@ -21,6 +21,8 @@
CONFIG += release
CONFIG += debug
+QMAKE_CXXFLAGS_DEBUG += -g -O0
+QMAKE_LFLAGS += -rdynamic
CONFIG += qt
#CONFIG -= app_bundle
CONFIG+=sdk_no_version_check
diff --git a/src/GUI/VirtualLeaf.cpp b/src/GUI/VirtualLeaf.cpp
index 4ba2b3ea..0a71cf83 100755
--- a/src/GUI/VirtualLeaf.cpp
+++ b/src/GUI/VirtualLeaf.cpp
@@ -185,7 +185,7 @@ void MainBase::Plot(int resize_stride)
PNGname.width(6);
PNGname << count << ".png";
// Write high-res PNG snapshot every plot step
- Save(PNGname.str().c_str(), "PNG", 1024, 768);
+ Save(PNGname.str().c_str(), "PNG", 3072, 3072); //768
//}
}
diff --git a/src/GUI/cell.cpp b/src/GUI/cell.cpp
index a8efe353..18758d58 100755
--- a/src/GUI/cell.cpp
+++ b/src/GUI/cell.cpp
@@ -20,7 +20,6 @@
*/
#include
-
#include
#include "pi.h"
#include "cell.h"
@@ -32,6 +31,17 @@
#include "nodeitem.h"
#include "qcanvasarrow.h"
#include "parameter.h"
+//#define QDEBUG
+
+// Division type enumeration
+// enum DivisionType {
+// NO_DIVISION = 0,
+// RANDOM_DIVISION = 1,
+// MAX_STRESS_AXIS = 2,
+// SHORT_AXIS = 3,
+// LONG_AXIS = 4,
+// PERP_STRESS = 5
+// };
static const std::string _module_id("$Id$");
@@ -59,7 +69,7 @@ Cell::Cell(const Cell &src) : CellBase(src)
bool Cell::Cmp(Cell *c) const { return this->Index() < c->Index(); }
bool Cell::Eq(Cell *c) const { return this->Index() == c->Index(); }
-Cell Cell::operator=(const Cell &src)
+Cell Cell::operator=(const Cell &src)
{
CellBase::operator=(src);
m=src.m;
@@ -67,7 +77,7 @@ Cell Cell::operator=(const Cell &src)
}
//Cell(void) : CellBase() {}
-void Cell::DivideOverAxis(Vector axis)
+void Cell::DivideOverAxis(Vector axis)
{
// Build a wall
// -> find the position of the wall
@@ -75,28 +85,33 @@ void Cell::DivideOverAxis(Vector axis)
// better look for intersection with a simple line intersection algorithm as below?
// this leads to some exceptions: e.g. dividing a horizontal rectangle.
// leaving it like this for the time being
-
+#ifdef QDEBUG
+ qDebug() << "Dividing cell " << Index() << Qt::endl;
+ qDebug() << "Number of walls: " << walls.size() << Qt::endl;
+#endif
if (dead) return;
- Vector centroid=Centroid();
- double prev_cross_z=(axis * (centroid - *(nodes.back()) ) ).z ;
+ Vector centroid = Centroid();
+ double prev_cross_z = (axis * (centroid - *(nodes.back()))).z;
ItList new_node_locations;
for (list::iterator i=nodes.begin(); i!=nodes.end(); i++) {
-
// cross product to detect position of division
Vector cross = axis * (centroid - *(*i));
- if (cross.z * prev_cross_z < 0 ) {
+ if (cross.z * prev_cross_z < 0) {
new_node_locations.push_back(i);
-
- }
- prev_cross_z=cross.z;
+ }
+ prev_cross_z = cross.z;
}
DivideWalls(new_node_locations, centroid, centroid+axis);
+ #ifdef QDEBUG
+ qDebug() << "Dividing cell Finish" << Index() << Qt::endl;
+ qDebug() << "Number of walls: " << walls.size() << Qt::endl;
+#endif
}
double Cell::MeanArea(void)
@@ -109,13 +124,13 @@ void Cell::Apoptose(void)
{
// First kill walls
#ifdef QDEBUG
- qDebug() << "This is cell " << Index() << endl;
- qDebug() << "Number of walls: " << walls.size() << endl;
+ qDebug() << "This is cell " << Index() << Qt::endl;
+ qDebug() << "Number of walls: " << walls.size() << Qt::endl;
#endif
for (list::iterator w=walls.begin(); w!=walls.end(); w++) {
#ifdef QDEBUG
qDebug() << "Before apoptosis, wall " << (*w)->Index() << " says: c1 = "
- << (*w)->c1->Index() << ", c2 = " << (*w)->c2->Index() << endl;
+ << (*w)->c1->Index() << ", c2 = " << (*w)->c2->Index() << Qt::endl;
#endif
}
for (list::iterator w=walls.begin(); w!=walls.end(); w++) {
@@ -128,7 +143,7 @@ void Cell::Apoptose(void)
if ((*w)->c1 == this) {
// invert wall?
- (*w)->c1 = (*w)->c2;
+ (*w)->c1 = (*w)->c2;
(*w)->c2 = m->boundary_polygon;
Node *n1 = (*w)->n1;
@@ -141,7 +156,7 @@ void Cell::Apoptose(void)
#ifdef QDEBUG
if (illegal_flag && (*w)->c1==(*w)->c2) {
- qDebug() << "I created an illegal wall." << endl;
+ qDebug() << "I created an illegal wall." << Qt::endl;
}
#endif
@@ -149,22 +164,22 @@ void Cell::Apoptose(void)
((*w)->C1() == (*w)->C2() ) ){
// kill wall
#ifdef QDEBUG
- qDebug() << "Killing wall." << endl;
+ qDebug() << "Killing wall." << Qt::endl;
#endif
(*w)->Kill();
#ifdef QDEBUG
if ((*w)) {
- qDebug() << "Wall " << (*w)->Index() << " says: c1 = "
- << (*w)->c1->Index() << ", c2 = " << (*w)->c2->Index() << endl;
+ qDebug() << "Wall " << (*w)->Index() << " says: c1 = "
+ << (*w)->c1->Index() << ", c2 = " << (*w)->c2->Index() << Qt::endl;
}
#endif
(*w)=0;
} else {
#ifdef QDEBUG
- qDebug() << "Not killing wall." << endl;
- qDebug() << "Wall " << (*w)->Index() << " says: c1 = "
- << (*w)->c1->Index() << ", c2 = " << (*w)->c2->Index() << endl;
+ qDebug() << "Not killing wall." << Qt::endl;
+ qDebug() << "Wall " << (*w)->Index() << " says: c1 = "
+ << (*w)->c1->Index() << ", c2 = " << (*w)->c2->Index() << Qt::endl;
#endif
}
}
@@ -200,7 +215,7 @@ void Cell::Apoptose(void)
no.MarkDead();
} else {
// register node with outside world
- if (find_if( no.owners.begin(), no.owners.end(),
+ if (find_if( no.owners.begin(), no.owners.end(),
[this](auto neighbor){return neighbor.CellEquals(m->boundary_polygon->Index());} ) == no.owners.end() ) {
tmp.cell = m->boundary_polygon;
no.owners.push_back(tmp);
@@ -216,12 +231,12 @@ void Cell::ConstructConnections(void)
{
// Tie up the nodes of this cell, assuming they are correctly ordered
- //cerr << "Constructing connections of cell " << index << endl;
+ //cerr << "Constructing connections of cell " << index << Qt::endl;
for (list::iterator i=nodes.begin(); i!=nodes.end(); i++) {
- //cerr << "Connecting node " << *i << endl;
- //cerr << "Node " << *i << endl << " = " << *(*i) << endl;
+ //cerr << "Connecting node " << *i << Qt::endl;
+ //cerr << "Node " << *i << Qt::endl << " = " << *(*i) << Qt::endl;
// 1. Tidy up existing connections (which are part of this cell)
if ((*i)->owners.size()>0) {
list::iterator neighb_with_this_cell=
@@ -229,7 +244,7 @@ void Cell::ConstructConnections(void)
find_if((*i)->owners.begin(),
(*i)->owners.end(),
[this](auto neighbor){return neighbor.CellEquals(this->Index());});
- if (neighb_with_this_cell!=(*i)->owners.end())
+ if (neighb_with_this_cell!=(*i)->owners.end())
(*i)->owners.erase(neighb_with_this_cell);
}
@@ -262,7 +277,7 @@ bool Cell::DivideOverGivenLine(const Vector v1, const Vector v2, bool fix_cellwa
ItList new_node_locations;
#ifdef QDEBUG
- qDebug() << "Cell " << Index() << " is doing DivideOverGivenLine" << endl;
+ qDebug() << "Cell " << Index() << " is doing DivideOverGivenLine" << Qt::endl;
#endif
for (list::iterator i=nodes.begin(); i!=nodes.end(); i++) {
@@ -274,12 +289,12 @@ bool Cell::DivideOverGivenLine(const Vector v1, const Vector v2, bool fix_cellwa
}
Vector v4 = *(*nb);
- double denominator =
+ double denominator =
(v4.y - v3.y)*(v2.x - v1.x) - (v4.x - v3.x)*(v2.y - v1.y);
- double ua =
+ double ua =
((v4.x - v3.x)*(v1.y - v3.y) - (v4.y - v3.y)*(v1.x -v3.x))/denominator;
- double ub =
+ double ub =
((v2.x - v1.x)*(v1.y-v3.y) - (v2.y- v1.y)*(v1.x - v3.x))/denominator;
@@ -289,30 +304,30 @@ bool Cell::DivideOverGivenLine(const Vector v1, const Vector v2, bool fix_cellwa
// yes, intersection detected. Push the location to the list of iterators
new_node_locations.push_back(nb);
- }
+ }
}
#ifdef QDEBUG
- if (new_node_locations.size()<2) {
- qDebug() << "Line does not intersect with two edges of Cell " << Index() << endl;
- qDebug() << "new_node_locations.size() = " << new_node_locations.size() << endl;
+ if (new_node_locations.size()<2) {
+ qDebug() << "Line does not intersect with two edges of Cell " << Index() << Qt::endl;
+ qDebug() << "new_node_locations.size() = " << new_node_locations.size() << Qt::endl;
return false;
}
ItList::iterator i = new_node_locations.begin();
list< Node *>::iterator j;
- qDebug() << "-------------------------------" << endl;
+ qDebug() << "-------------------------------" << Qt::endl;
qDebug() << "Location of new nodes: " << (**i)->Index() << " and ";
++i;
- j = *i;
+ j = *i;
if (j==nodes.begin()) j=nodes.end(); j--;
- qDebug() << (*j)->Index() << endl;
- qDebug() << "-------------------------------" << endl;
+ qDebug() << (*j)->Index() << Qt::endl;
+ qDebug() << "-------------------------------" << Qt::endl;
if ( **new_node_locations.begin() == *j ) {
- qDebug() << "Rejecting proposed division (cutting off zero area)." << endl;
+ qDebug() << "Rejecting proposed division (cutting off zero area)." << Qt::endl;
return false;
}
#endif
@@ -467,10 +482,9 @@ void Cell::DivideWalls(ItList new_node_locations, const Vector from, const Vecto
ParentInfo parent_info;
parent_info.polarization = ReduceCellAndWalls( PINdir );
parent_info.polarization.Normalise();
- parent_info.PINmembrane = SumTransporters(1);
+// parent_info.PINmembrane = SumTransporters(1);
parent_info.PINendosome = Chemical(1);
-
- //cerr << "Parent polarization before division: " << parent_info.polarization << endl;
+// cerr << "Parent polarization before division: " << parent_info.polarization << Qt::endl;
// Step 1: create a daughter cell
Cell *daughter=m->AddCell(new Cell());
@@ -502,7 +516,7 @@ void Cell::DivideWalls(ItList new_node_locations, const Vector from, const Vecto
// cells, remember to update the code below. There are some
// fixed-size arrays over there!
- cerr << "Warning in Cell::Division: division of non-convex cells not fully implemented" << endl;
+ cerr << "Warning in Cell::Division: division of non-convex cells not fully implemented" << Qt::endl;
// Reject the daughter cell and decrement the amount of cells
// again. We can do this here because it is the last cell added.
@@ -512,9 +526,9 @@ void Cell::DivideWalls(ItList new_node_locations, const Vector from, const Vecto
// get totally messed up...! (e.g. the indices used in Nodes::cells)
#ifdef QDEBUG
- qDebug() << "new_node_locations.size() = " << new_node_locations.size() <index = " << daughter->index << endl;
- qDebug() << "cells.size() = " << m->cells.size() << endl;
+ qDebug() << "new_node_locations.size() = " << new_node_locations.size() <index = " << daughter->index << Qt::endl;
+ qDebug() << "cells.size() = " << m->cells.size() << Qt::endl;
#endif
m->cells.pop_back();
@@ -553,14 +567,14 @@ void Cell::DivideWalls(ItList new_node_locations, const Vector from, const Vecto
list::iterator nb=*i;
if (nb == nodes.begin()) {
nb = nodes.end();
- }
+ }
nb--;
- Vector v4=*( *nb );
+ Vector v4=*( *nb );
- double denominator =
+ double denominator =
(v4.y - v3.y)*(v2.x - v1.x) - (v4.x - v3.x)*(v2.y - v1.y);
- double ua =
+ double ua =
((v4.x - v3.x)*(v1.y - v3.y) - (v4.y - v3.y)*(v1.x -v3.x))/denominator;
double intersec_x = v1.x + ua*(v2.x-v1.x);
@@ -589,8 +603,8 @@ void Cell::DivideWalls(ItList new_node_locations, const Vector from, const Vecto
new_node_flag[nnc]=1;
new_node[nnc] = *(**i);
new_node_ind[nnc] = **i;
- //cerr << **i << endl ;
- } else
+ //cerr << **i << Qt::endl ;
+ } else
if ( (*(*nb) - *n).Norm() < collapse_node_threshold * elem_length ) {
new_node_flag[nnc]=2;
new_node[nnc] = *(*nb);
@@ -609,7 +623,7 @@ void Cell::DivideWalls(ItList new_node_locations, const Vector from, const Vecto
Cell *neighbor_cell=0; // we need this to split up the "Wall" objects.
- // for both divided edges:
+ // for both divided edges:
// insert its new node into all cells that own the divided edge
// but only if it really is a new node:
if (new_node_flag[i]!=0) {
@@ -622,14 +636,14 @@ void Cell::DivideWalls(ItList new_node_locations, const Vector from, const Vecto
boundary = SAM;
daughter->boundary = SAM;
boundary_touched_flag = true;
- */
+ */
}
} else {
// (Construct a list of all owners:)
// really construct the new node (if this is a new node)
- new_node_ind[i] =
+ new_node_ind[i] =
m->AddNode(new Node (new_node[i]) );
@@ -667,10 +681,10 @@ void Cell::DivideWalls(ItList new_node_locations, const Vector from, const Vecto
((m->findNextBoundaryNode(div_edges[i].first))->Index() == div_edges[i].second->Index())){ // The boundary proceeds from first to second.
#ifdef QDEBUG
- qDebug() << "Index of the first node: " << div_edges[i].first->Index() << endl;
- qDebug() << "Index of the second node: " << div_edges[i].second->Index() << endl;
- qDebug() << "Boundary proceeds from: " << div_edges[i].first->Index()
- << "to: " << (m->findNextBoundaryNode(div_edges[i].first))->Index() << endl << endl;
+ qDebug() << "Index of the first node: " << div_edges[i].first->Index() << Qt::endl;
+ qDebug() << "Index of the second node: " << div_edges[i].second->Index() << Qt::endl;
+ qDebug() << "Boundary proceeds from: " << div_edges[i].first->Index()
+ << "to: " << (m->findNextBoundaryNode(div_edges[i].first))->Index() << Qt::endl << Qt::endl;
#endif
new_node_ind[i]->SetBoundary();
@@ -695,7 +709,7 @@ void Cell::DivideWalls(ItList new_node_locations, const Vector from, const Vecto
} else {
// insert before second node, so leave ins_pos as it is,
// that is: incremented
- m->boundary_polygon->nodes.insert(ins_pos, new_node_ind[i]);
+ m->boundary_polygon->nodes.insert(ins_pos, new_node_ind[i]);
// .. set the neighbors of the new node ...
}
}
@@ -713,24 +727,24 @@ void Cell::DivideWalls(ItList new_node_locations, const Vector from, const Vecto
back_inserter(owners));
- // find first non-self duplicate in the owners:
+ // find first non-self duplicate in the owners:
// cells owning the same two nodes
// share an edge with me
owners.sort( [](auto neighbor_a, auto neighbor_b){return neighbor_a.Cmp(neighbor_b);} );
-#ifdef QDEBUG
+#ifdef QDEBUG
list unique_owners;
copy(owners.begin(), owners.end(), back_inserter(unique_owners));
unique_owners.unique( mem_fn( &Neighbor::Eq ) );
- qDebug() << "The dividing edge nodes: " << div_edges[i].first->Index()
+ qDebug() << "The dividing edge nodes: " << div_edges[i].first->Index()
<< " and " << div_edges[i].second->Index() << " are owned by cells: ";
// spit out each owners' cell index
foreach(Neighbor neighbor, unique_owners){
qDebug() << neighbor.cell->Index() << " ";
}
- qDebug() << endl;
+ qDebug() << Qt::endl;
#endif
// Search through the sorted list of edge node owners looking for duplicate pairs. Each pair represents an actual edge owner.
@@ -740,15 +754,15 @@ void Cell::DivideWalls(ItList new_node_locations, const Vector from, const Vecto
it = adjacent_find(it, owners.end(), neighbor_cell_eq);
if (it == owners.end()) break; // bail if reach the end of the list
#ifdef QDEBUG
- qDebug() << "Considering: " << it->cell->Index() << " as a possible edge owner." << endl;
+ qDebug() << "Considering: " << it->cell->Index() << " as a possible edge owner." << Qt::endl;
#endif
if (it->cell->Index() != this->Index()) {
#ifdef QDEBUG
- qDebug() << "Adding: " << it->cell->Index() << " to the list of edge owners." << endl;
+ qDebug() << "Adding: " << it->cell->Index() << " to the list of edge owners." << Qt::endl;
#endif
edge_owners.push_back(*it);
}
- }
+ }
if (edge_owners.size() > 1){
// Remove the boundary polygon - if its there
@@ -756,21 +770,21 @@ void Cell::DivideWalls(ItList new_node_locations, const Vector from, const Vecto
if ((it = find_if (edge_owners.begin(), edge_owners.end(), [](auto neighbor){return neighbor.CellEquals(-1);}))
!= edge_owners.end()) {
#ifdef QDEBUG
- qDebug() << "deleting: " << it->cell->Index() << " from the list of edge owners." << endl;
+ qDebug() << "deleting: " << it->cell->Index() << " from the list of edge owners." << Qt::endl;
#endif
edge_owners.erase(it);
}
}
#ifdef QDEBUG
- qDebug() << "The edge owners list has: " << edge_owners.size() << " elements" << endl;
+ qDebug() << "The edge owners list has: " << edge_owners.size() << " elements" << Qt::endl;
#endif
// Since the list should always contain exactly one element, pass it on as an iterator
list::iterator c = (edge_owners.size() != 0) ? edge_owners.begin() : edge_owners.end();
// (can we have more than one neighboring cell here??)
- if (c!=owners.end()) {
+ if (c!=owners.end()) {
neighbor_cell = c->cell;
if (c->cell == NULL) {
cout << "error";
@@ -811,7 +825,7 @@ void Cell::DivideWalls(ItList new_node_locations, const Vector from, const Vecto
back_inserter(owners));
- // find first non-self duplicate in the owners:
+ // find first non-self duplicate in the owners:
// cells owning the same two nodes
// share an edge with me
owners.sort( mem_fn ( &Neighbor::Cmp ) );
@@ -824,14 +838,14 @@ void Cell::DivideWalls(ItList new_node_locations, const Vector from, const Vecto
if (c!=owners.end())
neighbor_cell = c->cell;
- else
+ else
neighbor_cell = 0;
}
if (neighbor_cell /* && !neighbor_cell->BoundaryPolP() */) {
- //cerr << "Cell " << index << " says: neighboring cell is " << neighbor_cell->index << endl;
+// cerr << "Cell " << index << " says: neighboring cell is " << neighbor_cell->index << Qt::endl;
/*************** 1. Find the correct wall element ********************/
@@ -846,9 +860,9 @@ void Cell::DivideWalls(ItList new_node_locations, const Vector from, const Vecto
if (w == walls.end()) {
#ifdef QDEBUG
- qDebug() << "Whoops, wall element not found...!" << endl;
- qDebug() << "Cell ID: " << neighbor_cell->Index() << endl;
- qDebug() << "My cell ID: " << Index() << endl;
+ qDebug() << "Whoops, wall element not found...!" << Qt::endl;
+ qDebug() << "Cell ID: " << neighbor_cell->Index() << Qt::endl;
+ qDebug() << "My cell ID: " << Index() << Qt::endl;
#endif
} else {
@@ -863,14 +877,14 @@ void Cell::DivideWalls(ItList new_node_locations, const Vector from, const Vecto
// over the two daughter walls
(*w)->SetLength(); // make sure we've got the current length
orig_length[i] = (*w)->Length();
- //cerr << "Original length is " << orig_length[i] << endl;
+ //cerr << "Original length is " << orig_length[i] << Qt::endl;
if ((*w)->c1 == this ) {
- // cerr << "Cell " << (*w)->c1->Index() << " splits up wall " << *(*w) << ", into: " << endl;
+ // cerr << "Cell " << (*w)->c1->Index() << " splits up wall " << *(*w) << ", into: " << Qt::endl;
new_wall = new Wall( (*w)->n1, new_node_ind[i], this, neighbor_cell);
(*w)->n1 = new_node_ind[i];
- // cerr << "wall " << *(*w) << ", and new wall " << *new_wall << endl;
+ // cerr << "wall " << *(*w) << ", and new wall " << *new_wall << Qt::endl;
} else {
new_wall = new Wall( (*w)->n1, new_node_ind[i], neighbor_cell, this);
@@ -892,10 +906,10 @@ void Cell::DivideWalls(ItList new_node_locations, const Vector from, const Vecto
}
}
AddWall(new_wall);
- // cerr << "Building new wall: this=" << Index() << ", neighbor_cell = " << neighbor_cell->Index() << endl;
+ // cerr << "Building new wall: this=" << Index() << ", neighbor_cell = " << neighbor_cell->Index() << Qt::endl;
neighbor_cell->AddWall( new_wall);
- //cerr << "Existing wall: c1 = " << (*w)->c1->Index() << ", neighbor_cell = " << (*w)->c2->Index() << endl;
+ //cerr << "Existing wall: c1 = " << (*w)->c1->Index() << ", neighbor_cell = " << (*w)->c2->Index() << Qt::endl;
// Remember the addresses of the new walls
div_wall[2*i+0] = *w;
@@ -920,12 +934,12 @@ void Cell::DivideWalls(ItList new_node_locations, const Vector from, const Vecto
start=new_node_locations.front();
- //cerr << "*new_node_locations.front() = " << *new_node_locations.front() << endl;
+ //cerr << "*new_node_locations.front() = " << *new_node_locations.front() << Qt::endl;
if (new_node_flag[0]==1) {
start++;
if (start==nodes.end())
start=nodes.begin();
- }
+ }
stop=new_node_locations.back();
if (new_node_flag[1]==2) {
@@ -944,9 +958,8 @@ void Cell::DivideWalls(ItList new_node_locations, const Vector from, const Vecto
(*i)->owners.end(),
[this](auto neighbor){return neighbor.CellEquals(this->Index());});
if (neighb_with_this_cell==(*i)->owners.end()) {
-
#ifdef QDEBUG
- qDebug() << "not found" << endl;
+ qDebug() << "not found" << Qt::endl;
#endif
abort();
}
@@ -986,7 +999,7 @@ void Cell::DivideWalls(ItList new_node_locations, const Vector from, const Vecto
new_nodes_parent.push_back( *i );
i++;
- if (i==nodes.end())
+ if (i==nodes.end())
i = nodes.begin();
};
}
@@ -1057,8 +1070,8 @@ void Cell::DivideWalls(ItList new_node_locations, const Vector from, const Vecto
// move the new nodes to the parent
nodes.clear();
- copy( new_nodes_parent.begin(),
- new_nodes_parent.end(),
+ copy( new_nodes_parent.begin(),
+ new_nodes_parent.end(),
back_inserter(nodes) );
@@ -1068,7 +1081,7 @@ void Cell::DivideWalls(ItList new_node_locations, const Vector from, const Vecto
if (boundary_touched_flag) {
m->boundary_polygon->ConstructConnections();
- }
+ }
// collecting neighbors of divided cell
list broken_neighbors;
@@ -1096,18 +1109,18 @@ void Cell::DivideWalls(ItList new_node_locations, const Vector from, const Vecto
daughter->AddWall( wall );
- //cerr << "Correct walls of cell " << Index() << " and daughter " << daughter->Index() << endl;
+ //cerr << "Correct walls of cell " << Index() << " and daughter " << daughter->Index() << Qt::endl;
// Move Walls to daughter cell
list copy_walls = walls;
for (list::iterator w = copy_walls.begin(); w!=copy_walls.end(); w++) {
- //cerr << "Doing wall, before: " << **w << endl;
+ //cerr << "Doing wall, before: " << **w << Qt::endl;
// checks the nodes of the wall and gives it away if appropriate
(*w)->CorrectWall ( );
- //cerr << "and after: " << **w << endl;
+ //cerr << "and after: " << **w << Qt::endl;
}
@@ -1119,7 +1132,7 @@ void Cell::DivideWalls(ItList new_node_locations, const Vector from, const Vecto
}
}
- //cerr << "Cell " << index << " has been dividing, and gave birth to Cell " << daughter->index << endl;
+ //cerr << "Cell " << index << " has been dividing, and gave birth to Cell " << daughter->index << Qt::endl;
// now reconstruct neighbor list for all "broken" neighbors
@@ -1169,7 +1182,7 @@ void Cell::DivideWalls(ItList new_node_locations, const Vector from, const Vecto
daughter->div_counter=(++div_counter);
}
-
+//
void Cell::findBeforeAfter(Node * node, Node ** before, Node**after) {
for (list::iterator i=this->nodes.begin(); i!=this->nodes.end(); i++) {
list::const_iterator next=i;
@@ -1316,7 +1329,7 @@ double Cell::Displace(double dx, double dy, double dh)
// Displace whole cell, add resulting energy to dh,
// and accept displacement if energetically favorable
- //
+ //
// Method is called if a "fixed" node is displaced
// Warning: length constraint not yet CORRECTLY implemented for this function
@@ -1343,7 +1356,7 @@ double Cell::Displace(double dx, double dy, double dh)
if (n->getCell()!=this) {
length_edges.push_back( pair (*i, n->nb1) );
length_edges.push_back( pair (*i, n->nb2) );
- old_length +=
+ old_length +=
DSQR(Node::target_length-(*(*i)-*(n->nb1)).Norm())+
DSQR(Node::target_length-(*(*i)-*(n->nb2)).Norm());
}
@@ -1383,10 +1396,10 @@ double Cell::Displace(double dx, double dy, double dh)
list::const_iterator nb_it = neighbors.begin();
for (vector::const_iterator ar_it = cellareas.begin(); ar_it!=cellareas.end(); ( ar_it++, nb_it++) ) {
((Cell *)(*nb_it))->area = *ar_it;
- (*nb_it)->SetIntegrals();
+ (*nb_it)->SetIntegrals();
}
- //cerr << endl;
+ //cerr << Qt::endl;
} else {
@@ -1412,7 +1425,7 @@ double Cell::Energy(void) const
for (list::const_iterator i=nodes.begin(); i!=nodes.end(); i++) {
for (list::const_iterator n=(*i)->owners.begin(); n!=(*i)->owners.end(); n++) {
if (n->getCell()==this) {
- length_contribution +=
+ length_contribution +=
DSQR(Node::target_length-(*(*i)-*(n->nb1)).Norm()) +
DSQR(Node::target_length-(*(*i)-*(n->nb2)).Norm());
}
@@ -1451,37 +1464,37 @@ bool Cell::SelfIntersect(void)
for (list::const_iterator i=nodes.begin(); i!=nodes.end(); i++) {
- list::const_iterator j=i;
+ list::const_iterator j=i;
++j;
- for (; j!=nodes.end(); j++)
+ for (; j!=nodes.end(); j++)
{
-
+
Vector v1 = *(*i);
list::const_iterator nb=i;
nb++;
if (nb == nodes.end()) {
nb = nodes.begin();
- }
+ }
Vector v2 = *(*nb);
Vector v3 = *(*j);
nb=j;
nb++;
if (nb == nodes.end()) {
nb = nodes.begin();
- }
- Vector v4=*( *nb );
+ }
+ Vector v4=*( *nb );
- double denominator =
+ double denominator =
(v4.y - v3.y)*(v2.x - v1.x) - (v4.x - v3.x)*(v2.y - v1.y);
- double ua =
+ double ua =
((v4.x - v3.x)*(v1.y - v3.y) - (v4.y - v3.y)*(v1.x -v3.x))/denominator;
- double ub =
+ double ub =
((v2.x - v1.x)*(v1.y-v3.y) - (v2.y- v1.y)*(v1.x - v3.x))/denominator;
if ( ( TINY < ua && ua < 1.-TINY ) && ( TINY < ub && ub < 1.-TINY ) ) {
- //cerr << "ua = " << ua << ", ub = " << ub << endl;
+ //cerr << "ua = " << ua << ", ub = " << ub << Qt::endl;
return true;
}
}
@@ -1495,7 +1508,7 @@ bool Cell::SelfIntersect(void)
bool Cell::MoveSelfIntersectsP(Node *moving_node_ind, Vector new_pos)
{
- // Check whether the polygon will self-intersect if moving_node_ind
+ // Check whether the polygon will self-intersect if moving_node_ind
// were displaced to new_pos
// Compare the two new edges against each other edge
@@ -1515,9 +1528,9 @@ bool Cell::MoveSelfIntersectsP(Node *moving_node_ind, Vector new_pos)
nb++;
if (nb == nodes.end()) {
nb = nodes.begin();
- }
+ }
- neighbor_of_moving_node[0]=*(*nb);
+ neighbor_of_moving_node[0]=*(*nb);
nb=moving_node_ind_pos;
if (nb == nodes.begin()) {
@@ -1525,7 +1538,7 @@ bool Cell::MoveSelfIntersectsP(Node *moving_node_ind, Vector new_pos)
}
nb--;
- neighbor_of_moving_node[1]=*( *nb );
+ neighbor_of_moving_node[1]=*( *nb );
for (list::const_iterator i=nodes.begin(); i!=nodes.end(); i++) {
@@ -1534,7 +1547,7 @@ bool Cell::MoveSelfIntersectsP(Node *moving_node_ind, Vector new_pos)
nb++;
if (nb == nodes.end()) {
nb = nodes.begin();
- }
+ }
if (*i == moving_node_ind || *nb == moving_node_ind) {
// do not compare to self
continue;
@@ -1543,16 +1556,16 @@ bool Cell::MoveSelfIntersectsP(Node *moving_node_ind, Vector new_pos)
Vector v3 = *(*i);
Vector v4 = *(*nb);
- double denominator =
+ double denominator =
(v4.y - v3.y)*(neighbor_of_moving_node[j].x - new_pos.x) - (v4.x - v3.x)*(neighbor_of_moving_node[j].y - new_pos.y);
- double ua =
+ double ua =
((v4.x - v3.x)*(new_pos.y - v3.y) - (v4.y - v3.y)*(new_pos.x -v3.x))/denominator;
- double ub =
+ double ub =
((neighbor_of_moving_node[j].x - new_pos.x)*(new_pos.y-v3.y) - (neighbor_of_moving_node[j].y- new_pos.y)*(new_pos.x - v3.x))/denominator;
if ( ( TINY < ua && ua < 1.-TINY ) && ( TINY < ub && ub < 1.-TINY ) ) {
- //cerr << "ua = " << ua << ", ub = " << ub << endl;
+ //cerr << "ua = " << ua << ", ub = " << ub << Qt::endl;
return true;
}
}
@@ -1566,40 +1579,40 @@ bool Cell::MoveSelfIntersectsP(Node *moving_node_ind, Vector new_pos)
bool Cell::MoveSelfIntersectsP(Node *moving_node_ind, Vector new_pos)
{
-
+
// Check whether the polygon will self-intersect if moving_node_ind
// were displaced to new_pos
-
+
// Compare the two new edges against each other edge
-
+
// O(2*N)
-
+
// method used for segment intersection:
// http://astronomy.swin.edu.au/~pbourke/geometry/lineline2d/
-
+
Vector neighbor_of_moving_node[2];
-
+
//cerr << "list::const_iterator moving_node_ind_pos = find (nodes.begin(),nodes.end(),moving_node_ind);\n";
list::const_iterator moving_node_ind_pos = find (nodes.begin(),nodes.end(),moving_node_ind);
-
+
list::const_iterator nb = moving_node_ind_pos;
//cerr << "Done\n";
nb++;
if (nb == nodes.end()) {
nb = nodes.begin();
}
-
+
neighbor_of_moving_node[0]=*(*nb);
-
+
nb=moving_node_ind_pos;
if (nb == nodes.begin()) {
nb = nodes.end();
}
nb--;
-
+
neighbor_of_moving_node[1]=*( *nb );
-
-
+
+
for (list::const_iterator i=nodes.begin(); i!=nodes.end(); i++) {
for (int j=0;j<2;j++) { // loop over the two neighbors of moving node
list::const_iterator nb=i;
@@ -1611,13 +1624,13 @@ bool Cell::MoveSelfIntersectsP(Node *moving_node_ind, Vector new_pos)
// do not compare to self
continue;
}
-
+
Vector v3 = *(*i);
Vector v4 = *(*nb);
-
+
double denominator =
(v4.y - v3.y)*(neighbor_of_moving_node[j].x - new_pos.x) - (v4.x - v3.x)*(neighbor_of_moving_node[j].y - new_pos.y);
-
+
// double ua =
// ((v4.x - v3.x)*(new_pos.y - v3.y) - (v4.y - v3.y)*(new_pos.x -v3.x))/denominator;
// double ub =
@@ -1625,23 +1638,23 @@ bool Cell::MoveSelfIntersectsP(Node *moving_node_ind, Vector new_pos)
double numera = ((v4.x - v3.x)*(new_pos.y - v3.y) - (v4.y - v3.y)*(new_pos.x -v3.x));
double numerb = ((neighbor_of_moving_node[j].x - new_pos.x)*(new_pos.y-v3.y) - (neighbor_of_moving_node[j].y- new_pos.y)*(new_pos.x - v3.x));
-
+
// Are the wall elements coincident?
if (fabs(numera) < TINY && fabs(numerb) < TINY && fabs(denominator) < TINY) {
return true;
}
-
+
// Are the wall elements parallel?
if (fabs(denominator) < TINY) {
continue;
}
double ua = numera / denominator;
double ub = numerb / denominator;
-
-
+
+
//if ( ( TINY < ua && ua < 1.-TINY ) && ( TINY < ub && ub < 1.-TINY ) ) {
if ( ( 0 < ua && ua < 1. ) && ( 0 < ub && ub < 1.) ) {
- //cerr << "ua = " << ua << ", ub = " << ub << endl;
+ //cerr << "ua = " << ua << ", ub = " << ub << Qt::endl;
return true;
}
}
@@ -1654,84 +1667,84 @@ bool Cell::MoveSelfIntersectsP(Node *moving_node_ind, Vector new_pos)
bool Cell::LinePieceIntersectsP(const Vector n1, const Vector n2) const
{
-
+
// Check whether the polygon will self-intersect if moving_node_ind
// were displaced to new_pos
-
+
// Compare the two new edges against each other edge
-
+
// O(2*N)
-
+
// method used for segment intersection:
// http://astronomy.swin.edu.au/~pbourke/geometry/lineline2d/
-
+
/*Vector neighbor_of_moving_node[2];
-
+
//cerr << "list::const_iterator moving_node_ind_pos = find (nodes.begin(),nodes.end(),moving_node_ind);\n";
list::const_iterator moving_node_ind_pos = find (nodes.begin(),nodes.end(),moving_node_ind);
-
+
list::const_iterator nb = moving_node_ind_pos;
//cerr << "Done\n";
nb++;
if (nb == nodes.end()) {
nb = nodes.begin();
}
-
+
neighbor_of_moving_node[0]=*(*nb);
-
+
nb=moving_node_ind_pos;
if (nb == nodes.begin()) {
nb = nodes.end();
}
nb--;
-
+
neighbor_of_moving_node[1]=*( *nb );
*/
-
+
for (list::const_iterator i=nodes.begin(); i!=nodes.end(); i++) {
list::const_iterator nb=i;
nb++;
if (nb == nodes.end()) {
nb = nodes.begin();
}
-
+
/* if (*i == moving_node_ind || *nb == moving_node_ind) {
// do not compare to self
continue;
}*/
-
+
Vector v3 = *(*i);
Vector v4 = *(*nb);
-
+
double denominator =
(v4.y - v3.y)*(n1.x - n2.x) - (v4.x - v3.x)*(n1.y - n2.y);
-
+
/* double ua =
((v4.x - v3.x)*(new_pos.y - v3.y) - (v4.y - v3.y)*(new_pos.x -v3.x))/denominator;
double ub =
((neighbor_of_moving_node[j].x - new_pos.x)*(new_pos.y-v3.y) - (neighbor_of_moving_node[j].y- new_pos.y)*(new_pos.x - v3.x))/denominator;*/
double numera = ((v4.x - v3.x)*(n1.y - v3.y) - (v4.y - v3.y)*(n1.x -v3.x));
double numerb = ((n2.x - n1.x)*(n1.y-v3.y) - (n2.y- n1.y)*(n1.x - v3.x));
-
+
/* Are the wall elements coincident? */
if (fabs(numera) < TINY && fabs(numerb) < TINY && fabs(denominator) < TINY) {
return true;
}
-
+
/* Are the wall elements parallel? */
if (fabs(denominator) < TINY) {
continue;
}
double ua = numera / denominator;
double ub = numerb / denominator;
-
-
+
+
//if ( ( TINY < ua && ua < 1.-TINY ) && ( TINY < ub && ub < 1.-TINY ) ) {
if ( ( 0 < ua && ua < 1. ) && ( 0 < ub && ub < 1.) ) {
- //cerr << "ua = " << ua << ", ub = " << ub << endl;
+ //cerr << "ua = " << ua << ", ub = " << ub << Qt::endl;
return true;
}
-
+
}
return false;
}
@@ -1744,7 +1757,7 @@ bool Cell::IntersectsWithLineP(const Vector v1, const Vector v2)
// Compare the line against each edge
// method used: http://astronomy.swin.edu.au/~pbourke/geometry/lineline2d/
- for (list::const_iterator i=nodes.begin(); i!=nodes.end(); i++)
+ for (list::const_iterator i=nodes.begin(); i!=nodes.end(); i++)
{
Vector v3 = *(*i);
list::const_iterator nb=i;
@@ -1754,12 +1767,12 @@ bool Cell::IntersectsWithLineP(const Vector v1, const Vector v2)
}
Vector v4 = *(*nb);
- double denominator =
+ double denominator =
(v4.y - v3.y)*(v2.x - v1.x) - (v4.x - v3.x)*(v2.y - v1.y);
- double ua =
+ double ua =
((v4.x - v3.x)*(v1.y - v3.y) - (v4.y - v3.y)*(v1.x -v3.x))/denominator;
- double ub =
+ double ub =
((v2.x - v1.x)*(v1.y-v3.y) - (v2.y- v1.y)*(v1.x - v3.x))/denominator;
if ( ( TINY < ua && ua < 1.-TINY ) && ( TINY < ub && ub < 1.-TINY ) ) {
@@ -1802,7 +1815,7 @@ void Cell::ConstructWalls(void)
// previous one in list
list::const_iterator nb = (--corner_points.end());
- // loop over list,
+ // loop over list,
for (list::const_iterator i=corner_points.begin(); i!=corner_points.end(); ( i++, nb++) ) {
if (nb==corner_points.end()) nb=corner_points.begin();
@@ -1828,13 +1841,13 @@ void Cell::ConstructWalls(void)
for (list::const_iterator j=owning_cells.begin(); j!=owning_cells.end(); ( j++, prevj++) ) {
if (prevj==owning_cells.end())
prevj=owning_cells.begin();
- if (*j==*prevj)
+ if (*j==*prevj)
duplicates.push_back(*j);
}
if (duplicates.size()==3) { // ignore cell boundary (this occurs only after the first division, I think)
vector| ::iterator dup_it = find_if(duplicates.begin(),duplicates.end(),mem_fn(&Cell::BoundaryPolP) );
- if (dup_it!=duplicates.end())
+ if (dup_it!=duplicates.end())
duplicates.erase(dup_it);
else {
return;
@@ -1907,12 +1920,12 @@ void Cell::Flux(double *flux, double *D)
#ifdef QDEBUG
if ((*i)->c1!=this) {
- qDebug() << "Warning, bad cells boundary: " << (*i)->c1->Index() << ", " << index << endl;
+ qDebug() << "Warning, bad cells boundary: " << (*i)->c1->Index() << ", " << index << Qt::endl;
}
#endif
flux[c] += phi;
- }
+ }
}
}
@@ -1927,9 +1940,9 @@ void Cell::Draw(QGraphicsScene *c, bool showStiffness, QString tooltip)
// Draw the cell on a QCanvas object
- if (DeadP()) {
+ if (DeadP()) {
#ifdef QDEBUG
- qDebug() << "Cell " << index << " not drawn, because dead." << endl;
+ qDebug() << "Cell " << index << " not drawn, because dead." << Qt::endl;
#endif
return;
}
@@ -2052,7 +2065,7 @@ void Cell::DrawNodes(QGraphicsScene *c) const {
item ->setPos(((offset[0]+i->x)*factor), ((offset[1]+i->y)*factor) );
c->addItem(item);
item->show();
-
+
}
}
@@ -2063,19 +2076,19 @@ void Cell::DrawIndex(QGraphicsScene *c) const {
// Draw any text in the cell's center
void Cell::DrawText(QGraphicsScene *c, const QString &text) const {
-
+
Vector centroid = Centroid();
QGraphicsSimpleTextItem *ctext = new QGraphicsSimpleTextItem ( text, 0);
// ctext->setPen( QPen(QColor(par.textcolor)) );
ctext->setBrush( QBrush(QColor(par.textcolor)) );
ctext->setZValue(20);
ctext->setFont( QFont( "Helvetica", par.cellnumsize, QFont::Normal) );
-
+
ctext ->setPos(((offset[0]+centroid.x)*factor),
((offset[1]+centroid.y)*factor) );
c->addItem(ctext);
ctext->show();
-
+
}
@@ -2085,7 +2098,7 @@ void Cell::DrawAxis(QGraphicsScene *c) const {
double width;
Length(&long_axis, &width);
- //cerr << "Length is " << length << endl;
+ //cerr << "Length is " << length << Qt::endl;
long_axis.Normalise();
Vector short_axis=long_axis.Perp2D();
@@ -2100,13 +2113,13 @@ void Cell::DrawAxis(QGraphicsScene *c) const {
line->setZValue(2);
line->setLine( ( (offset[0]+from.x)*factor ),
- ( (offset[1]+from.y)*factor ),
+ ( (offset[1]+from.y)*factor ),
( (offset[0]+to.x)*factor ),
( (offset[1]+to.y)*factor ) );
line->setZValue(10);
c->addItem(line);
line->show();
-
+
}
void Cell::DrawStrain(QGraphicsScene *c) const {
@@ -2135,7 +2148,7 @@ void Cell::DrawFluxes(QGraphicsScene *c, double arrowsize)
arrow->setZValue(2);
arrow->setLine( ( (offset[0]+from.x)*factor ),
- ( (offset[1]+from.y)*factor ),
+ ( (offset[1]+from.y)*factor ),
( (offset[0]+to.x)*factor ),
( (offset[1]+to.y)*factor ) );
arrow->setZValue(10);
@@ -2183,22 +2196,22 @@ void Cell::SetWallLengths(void)
// Now, walk to the second node of the edge in the list of nodes
for (list::const_iterator n=++first_node_edge; n!=second_node_edge_plus_1; ++n ) {
if (n==nodes.end())
- n=nodes.begin(); /* wrap around */
- list::const_iterator prev_n = n;
+ n=nodes.begin(); /* wrap around */
+ list::const_iterator prev_n = n;
if (prev_n==nodes.begin())
prev_n=nodes.end();
--prev_n;
- // Note that Node derives from a Vector, so we can do vector calculus as defined in vector.h
- sum_length += (*(*prev_n) - *(*n)).Norm();
+ // Note that Node derives from a Vector, so we can do vector calculus as defined in vector.h
+ sum_length += (*(*prev_n) - *(*n)).Norm();
- //cerr << "Node " << *prev_n << " to " << *n << ", cumulative length = " << sum_length << endl;
+ //cerr << "Node " << *prev_n << " to " << *n << ", cumulative length = " << sum_length << Qt::endl;
}
// We got the total length of the Wall now, store it:
(*de)->length = sum_length;
- //cerr << endl;
+ //cerr << Qt::endl;
// goto next de
}
}
@@ -2241,7 +2254,7 @@ void Cell::AddWall( Wall *w )
// if necessary, we could try later inserting it at the correct position
#ifdef QDEBUG
if (w->c1 == w->c2 ){
- qDebug() << "Wall between identical cells: " << w->c1->Index()<< endl;
+ qDebug() << "Wall between identical cells: " << w->c1->Index()<< Qt::endl;
}
#endif
@@ -2267,7 +2280,7 @@ list::iterator Cell::RemoveWall( Wall *w )
void Cell::EmitValues(double t)
{
- // cerr << "Attempting to emit " << t << ", " << chem[0] << ", " << chem[1] << endl;
+ // cerr << "Attempting to emit " << t << ", " << chem[0] << ", " << chem[1] << Qt::endl;
emit ChemMonValue(t, chem);
}
@@ -2307,4 +2320,102 @@ double Cell::elastic_limit() {
return this->m->elastic_limit;
}
+
+
+Vector Cell::CalculateDivisionPlane()
+{
+ Vector div_vec;
+
+ switch (division_type) {
+ case NO_DIVISION:
+ // No division, return empty vector
+ return Vector(0, 0, 0);
+
+ case RANDOM_DIVISION:
+ // Random division vector
+ div_vec = Vector(RANDOM() - 0.5, RANDOM() - 0.5, 0);
+ div_vec.Normalise();
+ return div_vec;
+
+ case MAX_STRESS_AXIS: {
+ // Calculate principal stress axis for this cell
+ Vector max_stress_axis = CalculatePrincipalStressAxis();
+
+ return max_stress_axis;
+ }
+
+ case SHORT_AXIS: {
+ // Use the short axis of the cell for division
+ Vector long_axis;
+ double width;
+ Length(&long_axis, &width);
+ return long_axis.Perp2D(); // Perpendicular to long axis = short axis
+ }
+
+ case LONG_AXIS: {
+ // Use the long axis of the cell for division
+ Vector long_axis;
+ double width;
+ Length(&long_axis, &width);
+ return long_axis;
+ }
+
+ case PERP_STRESS: {
+ // Calculate principal stress axis and return its perpendicular
+ Vector max_stress_axis = CalculatePrincipalStressAxis();
+ return max_stress_axis.Perp2D();
+ }
+
+ default:
+ // Default to random division
+ div_vec = Vector(RANDOM() - 0.5, RANDOM() - 0.5, 0);
+ div_vec.Normalise();
+ return div_vec;
+ }
+}
+
+// Matrix Cell::CalculateStressTensor()
+// {
+// // Initialize stress tensor
+// Matrix stress(2,2);
+//
+// // Calculate stress for each wall element
+// for (list::const_iterator i=nodes.begin(); i!=nodes.end(); i++) {
+// list::const_iterator next = i;
+// next++;
+// if (next == nodes.end()) {
+// next = nodes.begin();
+// }
+//
+// // Calculate wall element vector
+// Vector wall_vec = *(*next) - *(*i);
+// double length = wall_vec.Norm();
+// wall_vec.Normalise();
+//
+// // Get wall stiffness and strain
+// WallElementInfo element;
+// fillWallElementInfo(&element, *i, *next);
+// double stiffness = element.stiffness();
+// if (std::isnan(stiffness)) {
+// stiffness = 1.0;
+// }
+//
+// double rest_length = element.restLength();
+// if (std::isnan(rest_length) || rest_length <= 0) {
+// rest_length = length;
+// }
+//
+// double strain = (length - rest_length) / rest_length;
+// double tension = stiffness * strain;
+//
+// // Add contribution to stress tensor
+// stress(0,0) += tension * wall_vec.x * wall_vec.x;
+// stress(0,1) += tension * wall_vec.x * wall_vec.y;
+// stress(1,0) += tension * wall_vec.y * wall_vec.x;
+// stress(1,1) += tension * wall_vec.y * wall_vec.y;
+// }
+//
+// return stress;
+// }
+
/* finis */
diff --git a/src/GUI/cell.h b/src/GUI/cell.h
index 2851ebd0..878ba3ad 100755
--- a/src/GUI/cell.h
+++ b/src/GUI/cell.h
@@ -34,6 +34,8 @@
#include "warning.h"
#include "cellbase.h"
#include "Neighbor.h"
+#include "random.h"
+#include "pi.h"
//#include "cell.h"
#include
@@ -94,11 +96,70 @@ class Cell : public CellBase
// divide over the line (if line and cell intersect)
bool DivideOverGivenLine(const Vector v1, const Vector v2, bool wall_fixed = false, NodeSet *node_set = 0);
- void Divide(void) { // Divide cell over short axis
-
- Vector long_axis;
- Length(&long_axis);
- DivideOverAxis(long_axis.Perp2D());
+ void Divide(void) { // Divide cell based on division_type
+ std::cout << "Cell " << index << ": Starting division process" << std::endl;
+ Vector axis;
+ Length(&axis); // Get the long axis
+ std::cout << "Cell " << index << ": Long axis = (" << axis.x << ", " << axis.y << ", " << axis.z << ")" << std::endl;
+
+ switch (division_type) {
+ case NO_DIVISION:
+ std::cout << "Cell " << index << ": Division type = NO_DIVISION, skipping" << std::endl;
+ return;
+ case RANDOM_DIVISION:
+ {
+ std::cout << "Cell " << index << ": Division type = RANDOM_DIVISION" << std::endl;
+ // Random angle between 0 and π
+ double orientation = Pi*RANDOM();
+ Vector divAxis(sin(orientation), cos(orientation), 0.);
+ std::cout << "Cell " << index << ": Random division axis = (" << divAxis.x << ", " << divAxis.y << ", " << divAxis.z << "), orientation = " << orientation << std::endl;
+ DivideOverAxis(divAxis);
+ }
+ break;
+ case MAX_STRESS_AXIS:
+ std::cout << "Cell " << index << ": Division type = MAX_STRESS_AXIS" << std::endl;
+ // Calculate principal stress axis and divide along it
+ {
+ Vector stressAxis = CalculateDivisionPlane();
+ std::cout << "Cell " << index << ": Stress division axis = (" << stressAxis.x << ", " << stressAxis.y << ", " << stressAxis.z << ")" << std::endl;
+ DivideOverAxis(stressAxis);
+ }
+ break;
+ case SHORT_AXIS:
+ std::cout << "Cell " << index << ": Division type = SHORT_AXIS" << std::endl;
+ // Divide over short axis (perpendicular to long axis)
+ {
+ Vector shortAxis = axis.Perp2D();
+ std::cout << "Cell " << index << ": Short axis = (" << shortAxis.x << ", " << shortAxis.y << ", " << shortAxis.z << ")" << std::endl;
+ DivideOverAxis(shortAxis);
+ }
+ break;
+ case LONG_AXIS:
+ std::cout << "Cell " << index << ": Division type = LONG_AXIS" << std::endl;
+ // Divide over long axis
+ std::cout << "Cell " << index << ": Using long axis for division" << std::endl;
+ DivideOverAxis(axis);
+ break;
+ case PERP_STRESS:
+ std::cout << "Cell " << index << ": Division type = PERP_STRESS" << std::endl;
+ // Divide perpendicular to principal stress
+ {
+ Vector perpStressAxis = CalculateDivisionPlane();
+ std::cout << "Cell " << index << ": Perpendicular stress axis = (" << perpStressAxis.x << ", " << perpStressAxis.y << ", " << perpStressAxis.z << ")" << std::endl;
+ DivideOverAxis(perpStressAxis);
+ }
+ break;
+ default:
+ std::cout << "Cell " << index << ": Division type = UNKNOWN (" << division_type << "), defaulting to SHORT_AXIS" << std::endl;
+ // Default to short axis division
+ {
+ Vector shortAxis = axis.Perp2D();
+ std::cout << "Cell " << index << ": Default short axis = (" << shortAxis.x << ", " << shortAxis.y << ", " << shortAxis.z << ")" << std::endl;
+ DivideOverAxis(shortAxis);
+ }
+ break;
+ }
+ std::cout << "Cell " << index << ": Division complete" << std::endl;
}
//void CheckForGFDrivenDivision(void);
@@ -179,6 +240,7 @@ class Cell : public CellBase
void findBeforeAfter(Node * node, Node ** before, Node**after);
Cell* findOtherCell(Cell*other, Node * node, Node * node2);
Cell* findNeighbourCellOnDivide(Cell* daughter,Node* node,Node * before1,Node * after1 ,Node * before2,Node * after2);
+ Vector CalculateDivisionPlane();
};
diff --git a/src/GUI/mesh.cpp b/src/GUI/mesh.cpp
index feb81a16..811c130c 100755
--- a/src/GUI/mesh.cpp
+++ b/src/GUI/mesh.cpp
@@ -50,6 +50,7 @@
#include
static const std::string _module_id("$Id$");
+int Mesh::cell_to_debug = 1000;
extern Parameter par;
@@ -654,6 +655,7 @@ double getStiffness(CellBase* c,NodeBase* n1) {
}
void Mesh::RemodelWallElement(vector & curves,CellBase* c,Node* w0,Node* w1,Node* w2,Node* w3,Node* w4) {
+// qDebug() << "DisplaceNodes - elastic_modulus: " << elastic_modulus;
Node * o0;
Node * o1;
@@ -1102,7 +1104,12 @@ double Mesh::DisplaceNodes(void) {
double cell_w = c.GetWallStiffness();
w1 = w1*cell_w;
w2 = w2*cell_w;
-
+ // Debug output for cell #28
+ if (c.Index() == cell_to_debug) {
+ qDebug() << "Cell: "<< cell_to_debug <<" - Wall Stiffness Debug:";
+ qDebug() << " Base stiffness:" << cell_w;
+ qDebug() << " w1:" << w1 << " w2:" << w2;
+ }
double w_w1 = 1;
double w_w2 = 1;
@@ -1110,26 +1117,50 @@ double Mesh::DisplaceNodes(void) {
double bl_plus_1 = 0.0;
if (activateWallStiffnessHamiltonian()) {
- calculateWallStiffness(&c, *i, &w_w1, &w_w2, &bl_minus_1, &bl_plus_1);
+ calculateWallStiffness(&c, *i, &w_w1, &w_w2, &bl_minus_1, &bl_plus_1);
+}
+if (bl_minus_1>0 && bl_plus_1>0) {
+ w1 = cell_w * (w_w1);
+ w2 = cell_w * (w_w2);
+ //check if wall elements are defined and pick the appropriate length_dh
+
+ double old_length_dh = length_dh;
+ double term1 = elastic_modulus * w1 * bl_minus_1 * (DSQR(new_l1/bl_minus_1 - 1) - DSQR(old_l1/bl_minus_1 - 1));
+ double term2 = elastic_modulus * w2 * bl_plus_1 * (DSQR(new_l2/bl_plus_1 - 1) - DSQR(old_l2/bl_plus_1 - 1));
+ length_dh += term1 + term2;
+
+ if (c.Index() == cell_to_debug) {
+ std::cout << "Debug [Cell " << c.index
+ << "]: Wall elastic terms - term1: " << term1 << ", term2: " << term2
+ << ", length_dh delta: " << (length_dh - old_length_dh)
+ << "\n w1: " << w1 << ", w2: " << w2
+ << "\n elastic modulus: " << elastic_modulus
+ << "\n bl_minus_1: " << bl_minus_1 << ", bl_plus_1: " << bl_plus_1
+ << "\n new_l1: " << new_l1 << ", old_l1: " << old_l1
+ << "\n new_l2: " << new_l2 << ", old_l2: " << old_l2
+ << "\n length_dh: " << length_dh
+ << std::endl;
}
- if (bl_minus_1>0 && bl_plus_1>0) {
- w1 = cell_w * (w_w1);
- w2 = cell_w * (w_w2);
- //check if wall elements are defined and pick the appropriate length_dh
-
- length_dh +=
- elastic_modulus * w1 *
- bl_minus_1 *(DSQR(new_l1/bl_minus_1 - 1)-DSQR(old_l1/bl_minus_1 - 1)) +
- elastic_modulus * w2 *
- bl_plus_1 *(DSQR(new_l2/bl_plus_1 - 1)-DSQR(old_l2/bl_plus_1 - 1));
+}
+else {
+ double old_length_dh = length_dh;
+ double term1 = 2 * Node::target_length * (w1 * (old_l1 - new_l1) + w2 * (old_l2 - new_l2));
+ double term2 = w1 * (DSQR(new_l1) - DSQR(old_l1)) + w2 * (DSQR(new_l2) - DSQR(old_l2));
+ length_dh += term1 + term2;
+
+ if (c.Index() == cell_to_debug) {
+ std::cout << "Debug [Cell " << c.index
+ << "]: Default elastic terms - term1: " << term1 << ", term2: " << term2
+ << ", length_dh delta: " << (length_dh - old_length_dh)
+ << "\n w1: " << w1 << ", w2: " << w2
+ << "\n elastic modulus: " << elastic_modulus
+ << "\n target_length: " << Node::target_length
+ << "\n new_l1: " << new_l1 << ", old_l1: " << old_l1
+ << "\n new_l2: " << new_l2 << ", old_l2: " << old_l2
+ << "\n length_dh: " << length_dh
+ << std::endl;
}
- else {
- length_dh +=2*Node::target_length * (
- w1*(old_l1 - new_l1) +
- w2*(old_l2 - new_l2) ) +
- w1*(DSQR(new_l1) - DSQR(old_l1)) +
- w2*(DSQR(new_l2) - DSQR(old_l2));
- }
+}
// cout << node << "\t" << bl_minus_1 << "\t" << bl_plus_1 << "\t" << w_w1 << "\t" << w_w2 << "\n";
}
@@ -1198,36 +1229,85 @@ void Mesh::WallRelaxation(void) {
}
}
-void extractWallData(WallElementInfo* wallElementInfo,double *w,double* bl){
+void extractWallData(WallElementInfo* wallElementInfo, double *w, double *bl){
double stiffness=.0;
double base_length=.0;
+ int cell_to_debug = 1000; // Set the cell index to debug
+
+ bool debugCell = (wallElementInfo->getCell()->Index() == cell_to_debug);
+
+ if (debugCell) {
+ qDebug() << "extractWallData called with wallElementInfo:" << wallElementInfo;
+ }
+
if (wallElementInfo->hasWallElement()) {
stiffness = wallElementInfo->getWallElement()->getStiffness();
base_length = wallElementInfo->getBaseLength();
+ if (debugCell) {
+ qDebug() << " Has WallElement - Stiffness:" << stiffness << "Base Length:" << base_length;
+ }
} else {
stiffness = wallElementInfo->getCell()->GetWallStiffness();
+ if (debugCell) {
+ qDebug() << " No WallElement - Using cell wall stiffness:" << stiffness;
+ }
}
+
+ double old_w = *w;
+ double old_bl = *bl;
if (!std::isnan(stiffness)){
(*w) += stiffness;
(*bl) += base_length;
+ if (debugCell) {
+ qDebug() << " Updated values - w:" << old_w << "->" << *w << "bl:" << old_bl << "->" << *bl;
+ }
+ } else if (debugCell) {
+ qDebug() << " Skipped update due to NaN stiffness";
}
}
-
void Mesh::calculateWallStiffness(CellBase* c, Node* node, double *w_p1,double *w_p2, double* bl_minus_1, double* bl_plus_1) {
- c->LoopWallElements([node,w_p1,w_p2,bl_minus_1,bl_plus_1](auto wallElementInfo){
- int points = 0;
- if (wallElementInfo->isTo(node)) {
+ bool debugCell = (c->Index() == cell_to_debug);
+
+ if (debugCell) {
+ qDebug() << "calculateWallStiffness called for Cell 1 and Node" << node->Index();
+ qDebug() << " Initial values - w_p1:" << *w_p1 << "w_p2:" << *w_p2
+ << "bl_minus_1:" << *bl_minus_1 << "bl_plus_1:" << *bl_plus_1;
+ }
+
+ c->LoopWallElements([node,w_p1,w_p2,bl_minus_1,bl_plus_1,debugCell](auto wallElementInfo){
+ int points = 0;
+ if (wallElementInfo->isTo(node)) {
+ if (debugCell) {
+ qDebug() << " Found wall element TO node" << node->Index() << "- Before extraction w_p1:" << *w_p1 << "bl_minus_1:" << *bl_minus_1;
+ }
extractWallData(wallElementInfo,w_p1,bl_minus_1);
+ if (debugCell) {
+ qDebug() << " After extraction w_p1:" << *w_p1 << "bl_minus_1:" << *bl_minus_1;
+ }
points++;
- } else if (wallElementInfo->isFrom(node)) {
+ } else if (wallElementInfo->isFrom(node)) {
+ if (debugCell) {
+ qDebug() << " Found wall element FROM node" << node->Index() << "- Before extraction w_p2:" << *w_p2 << "bl_plus_1:" << *bl_plus_1;
+ }
extractWallData(wallElementInfo,w_p2,bl_plus_1);
+ if (debugCell) {
+ qDebug() << " After extraction w_p2:" << *w_p2 << "bl_plus_1:" << *bl_plus_1;
+ }
points++;
}
- if (points == 2) {
+ if (points == 2) {
+ if (debugCell) {
+ qDebug() << " Found both connections, stopping loop";
+ }
//stop the loop, as we do not need to go further.
- wallElementInfo->stopLoop();
- }
- });
+ wallElementInfo->stopLoop();
+ }
+ });
+
+ if (debugCell) {
+ qDebug() << " Final values - w_p1:" << *w_p1 << "w_p2:" << *w_p2
+ << "bl_minus_1:" << *bl_minus_1 << "bl_plus_1:" << *bl_plus_1;
+ }
}
diff --git a/src/GUI/mesh.h b/src/GUI/mesh.h
index 17b42aae..fdb89c84 100755
--- a/src/GUI/mesh.h
+++ b/src/GUI/mesh.h
@@ -86,7 +86,7 @@ class Mesh {
friend class Node;
friend class FigureEditor;
- public:
+public:
Mesh(void) {
// Make sure the reserved value is large enough if a cell is added
// in "Divide" when the capacity is insufficient, "cells" might be
@@ -333,7 +333,6 @@ class Mesh {
}
return sum/(double)NCells();
}
-
void SetBaseArea(void);
int NCells(void) const {
return cells.size();
@@ -466,6 +465,8 @@ class Mesh {
double time;
SimPluginInterface *plugin;
+ static int cell_to_debug;
+
// Private member functions
double CellSpecificStiffnessOneSide(Node *nb,set &nodeown);
void AddNodeToCell(Cell *c, Node *n, Node *nb1 , Node *nb2);
diff --git a/src/Library/cellbase.cpp b/src/Library/cellbase.cpp
index f574c713..a87705c9 100755
--- a/src/Library/cellbase.cpp
+++ b/src/Library/cellbase.cpp
@@ -701,4 +701,94 @@ void CellBase::correctNeighbors() {}
double CellBase::elastic_limit() {
return std::nan("1");
}
+
+double CellBase::SetInitialArea(void) {
+ InitialArea = this->CalcArea();
+ return InitialArea;
+}
+Vector CellBase::CalculatePrincipalStressAxis() {
+ cout << "CalculatePrincipalStressAxis" << endl; // Calculate cell centroid
+ Vector centroid(0, 0, 0);
+ int n = nodes.size();
+ for (auto it = nodes.begin(); it != nodes.end(); it++) {
+ centroid += Vector((*it)->x, (*it)->y, (*it)->z);
+ }
+ centroid = centroid * (1.0 / n);
+
+ // Construct stress tensor
+ double stress_tensor[2][2] = {{0, 0}, {0, 0}};
+
+ // Calculate stress contribution from each wall
+ for (auto wall_it = walls.begin(); wall_it != walls.end(); ++wall_it) {
+ Wall* wall = *wall_it;
+ Vector wall_vec = Vector(wall->n2->x - wall->n1->x, wall->n2->y - wall->n1->y, wall->n2->z - wall->n1->z);
+ double wall_length = wall_vec.Norm();
+
+ if (wall_length > 0) {
+ // Normalize wall vector
+ wall_vec = wall_vec * (1.0 / wall_length);
+
+ // Get wall tension (stress)
+ double wall_stiffness;
+ if (std::isnan(wall->c1WallStiffness)) {
+ wall_stiffness = std::max(wall->c1->GetWallStiffness(), wall->c2WallStiffness);
+ } else if (std::isnan(wall->c2WallStiffness)) {
+ wall_stiffness = std::max(wall->c2->GetWallStiffness(), wall->c1WallStiffness);
+ } else {
+ wall_stiffness = std::max(wall->c1WallStiffness, wall->c2WallStiffness);
+ }
+ double wall_length_original = wall_vec.Norm();
+ double tension = wall_stiffness * (wall_length - wall_length_original) / wall_length_original;
+ // Add contribution to stress tensor (outer product)
+ stress_tensor[0][0] += tension * wall_vec.x * wall_vec.x;
+ stress_tensor[0][1] += tension * wall_vec.x * wall_vec.y;
+ stress_tensor[1][0] += tension * wall_vec.y * wall_vec.x;
+ stress_tensor[1][1] += tension * wall_vec.y * wall_vec.y;
+ }
+ }
+
+ // Calculate eigenvalues and eigenvectors to find principal stress
+ double trace = stress_tensor[0][0] + stress_tensor[1][1];
+ double det = stress_tensor[0][0] * stress_tensor[1][1] - stress_tensor[0][1] * stress_tensor[1][0];
+
+ // Eigenvalues
+ double lambda1 = (trace + sqrt(trace * trace - 4 * det)) / 2;
+ double lambda2 = (trace - sqrt(trace * trace - 4 * det)) / 2;
+
+ // Eigenvector for the larger eigenvalue is the principal stress direction
+ Vector principal_stress;
+ if (fabs(lambda1) >= fabs(lambda2)) {
+ // Calculate eigenvector for lambda1
+ if (fabs(stress_tensor[0][1]) > 1e-10) {
+ principal_stress = Vector(stress_tensor[0][1], lambda1 - stress_tensor[0][0], 0);
+ } else if (fabs(stress_tensor[1][0]) > 1e-10) {
+ principal_stress = Vector(lambda1 - stress_tensor[1][1], stress_tensor[1][0], 0);
+ } else {
+ // Diagonal matrix - eigenvectors are axis-aligned
+ principal_stress = (fabs(stress_tensor[0][0]) > fabs(stress_tensor[1][1])) ?
+ Vector(1, 0, 0) : Vector(0, 1, 0);
+ }
+ } else {
+ // Calculate eigenvector for lambda2
+ if (fabs(stress_tensor[0][1]) > 1e-10) {
+ principal_stress = Vector(stress_tensor[0][1], lambda2 - stress_tensor[0][0], 0);
+ } else if (fabs(stress_tensor[1][0]) > 1e-10) {
+ principal_stress = Vector(lambda2 - stress_tensor[1][1], stress_tensor[1][0], 0);
+ } else {
+ // Diagonal matrix - eigenvectors are axis-aligned
+ principal_stress = (fabs(stress_tensor[0][0]) < fabs(stress_tensor[1][1])) ?
+ Vector(1, 0, 0) : Vector(0, 1, 0);
+ }
+ }
+
+ // Normalize the principal stress vector
+ principal_stress.Normalise();
+
+ std::cout << "Cell " << index << ": Calculated principal stress axis = ("
+ << principal_stress.x << ", " << principal_stress.y << ", "
+ << principal_stress.z << ")" << std::endl;
+
+ return principal_stress;
+}
+
/* finis*/
diff --git a/src/Library/cellbase.h b/src/Library/cellbase.h
index e3d954bd..8a56cea6 100755
--- a/src/Library/cellbase.h
+++ b/src/Library/cellbase.h
@@ -44,6 +44,18 @@
//#include "wallelementinfo.h"
+
+// Division type enumeration
+enum DivisionType {
+ NO_DIVISION,
+ RANDOM_DIVISION,
+ MAX_STRESS_AXIS,
+ SHORT_AXIS,
+ LONG_AXIS,
+ PERP_STRESS
+};
+
+
extern Parameter par;
using namespace std;
@@ -101,6 +113,7 @@ class CellBase : public QObject, public Vector
public:
CellBase(QObject *parent=0);
CellBase(double x,double y,double z=0); // constructor
+ double InitialArea = 0.0; // Initialize to zero
virtual ~CellBase() {
delete[] chem;
@@ -112,6 +125,7 @@ class CellBase : public QObject, public Vector
CellBase(const CellBase &src); // copy constructor
virtual bool BoundaryPolP(void) const { return false; }
+ const list& getNodes() const { return nodes; } // Ajout Rouges 2025
CellBase operator=(const CellBase &src); // assignment operator
CellBase operator=(const Vector &src);
@@ -199,12 +213,14 @@ class CellBase : public QObject, public Vector
inline int Index(void) const { return index; }
+ double SetInitialArea(void); // Calculate and store the initial area
+ double GetInitialArea(void) const { return InitialArea; } // Getter method
void SetTargetArea(double tar_ar) { target_area=tar_ar; }
inline void SetTargetLength(double tar_l) { target_length=tar_l; }
inline void SetLambdaLength(double lambda_length) { lambda_celllength = lambda_length; }
-
+ inline double GetLambdaLength(void) const { return lambda_celllength; }
inline double TargetArea(void) { return target_area; }
inline double EnlargeTargetArea(double da) { return target_area+=da; }
@@ -244,6 +260,10 @@ class CellBase : public QObject, public Vector
virtual void InsertWall( WallBase *w );
virtual CellBase* getOtherWallElementSide(NodeBase * spikeEnd,NodeBase * over);
virtual double elastic_limit();
+ void SetDivisionType(DivisionType type) { division_type = type; }
+ DivisionType GetDivisionType() const { return division_type; }
+ DivisionType division_type;
+ virtual Vector CalculatePrincipalStressAxis();
QList getWalls(void) {
QList wall_list;
@@ -584,7 +604,9 @@ inline Vector PINdir(CellBase *here, CellBase *nb, Wall *w)
{
return w->getTransporter( here, 1) * w->getInfluxVector(here);
}
-
#endif
+
+
+
/* finis*/
diff --git a/src/Library/parameter.cpp b/src/Library/parameter.cpp
index db9d9cda..ed27647a 100644
--- a/src/Library/parameter.cpp
+++ b/src/Library/parameter.cpp
@@ -1935,6 +1935,10 @@ if (!strcmp(namec, "elastic_limit")) {
elastic_limit = standardlocale.toDouble(valc, &ok);
if (!ok) { MyWarning::error("Read error: cannot convert string \"%s\" to double while reading parameter 'elastic_limit' from XML file.",valc); }
}
+if (!strcmp(namec, "elastic_modulus")) {
+ elastic_modulus = standardlocale.toDouble(valc, &ok);
+ if (!ok) { MyWarning::error("Read error: cannot convert string \"%s\" to double while reading parameter 'elastic_modulus' from XML file.",valc); }
+}
if (!strcmp(namec, "movie")) {
movie = strtobool(valc);
}
diff --git a/src/Models/Cambium/Makefile b/src/Models/Cambium/Makefile
index b7a3fbd6..69ca93ed 100644
--- a/src/Models/Cambium/Makefile
+++ b/src/Models/Cambium/Makefile
@@ -1111,7 +1111,7 @@ moc_cambium.cpp: cambium.h \
/home/ardati/anaconda3/include/qt/QtGui/QColor \
moc_predefs.h \
/home/ardati/anaconda3/bin/moc
- /home/ardati/anaconda3/bin/moc $(DEFINES) --include /home/ardati/PycharmProjects/VirtualLeaf2021/src/Models/Cambium/moc_predefs.h -I/home/ardati/anaconda3/mkspecs/linux-g++ -I/home/ardati/PycharmProjects/VirtualLeaf2021/src/Models/Cambium -I/home/ardati/PycharmProjects/VirtualLeaf2021/src/Library -I/home/ardati/PycharmProjects/VirtualLeaf2021/src/GUI -I/home/ardati/PycharmProjects/VirtualLeaf2021/include -I/home/ardati/anaconda3/include/qt -I/home/ardati/anaconda3/include/qt/QtWidgets -I/home/ardati/anaconda3/include/qt/QtGui -I/home/ardati/anaconda3/include/qt/QtXml -I/home/ardati/anaconda3/include/qt/QtCore -I/usr/include/c++/11 -I/usr/include/x86_64-linux-gnu/c++/11 -I/usr/include/c++/11/backward -I/usr/lib/gcc/x86_64-linux-gnu/11/include -I/usr/local/include -I/usr/include/x86_64-linux-gnu -I/usr/include cambium.h -o moc_cambium.cpp
+ /home/ardati/anaconda3/bin/moc $(DEFINES) --include /home/ardati/PycharmProjects/VirtualLeaf2021/src/Models/Cambium/moc_predefs.h -I/home/ardati/anaconda3/mkspecs/linux-g++ -I/home/ardati/PycharmProjects/VirtualLeaf2021/src/Models/Cambium -I/home/ardati/PycharmProjects/VirtualLeaf2021/src/Library -I/home/ardati/PycharmProjects/VirtualLeaf2021/src/GUI -I/home/ardati/PycharmProjects/VirtualLeaf2021/include -I/home/ardati/anaconda3/include/qt -I/home/ardati/anaconda3/include/qt/QtWidgets -I/home/ardati/anaconda3/include/qt/QtGui -I/home/ardati/anaconda3/include/qt/QtXml -I/home/ardati/anaconda3/include/qt/QtCore -I/usr/local/hdf5/include -I. -I/usr/include/c++/11 -I/usr/include/x86_64-linux-gnu/c++/11 -I/usr/include/c++/11/backward -I/usr/lib/gcc/x86_64-linux-gnu/11/include -I/usr/local/include -I/usr/include/x86_64-linux-gnu -I/usr/include cambium.h -o moc_cambium.cpp
compiler_moc_objc_header_make_all:
compiler_moc_objc_header_clean:
diff --git a/src/Models/Cambium/Makefile.cambium b/src/Models/Cambium/Makefile.cambium
deleted file mode 100644
index 6964f3df..00000000
--- a/src/Models/Cambium/Makefile.cambium
+++ /dev/null
@@ -1,1010 +0,0 @@
-#############################################################################
-# Makefile for building: libcambium.dylib
-# Generated by qmake (3.1) (Qt 5.12.1)
-# Project: cambium.pro
-# Template: lib
-# Command: /opt/Qt/5.12.1/clang_64/bin/qmake -o Makefile.cambium cambium.pro
-#############################################################################
-
-MAKEFILE = Makefile.cambium
-
-EQ = =
-
-####### Compiler, tools and options
-
-CC = /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang
-CXX = /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang++
-DEFINES = -DQTGRAPHICS -DQT_NO_DEBUG -DQT_PLUGIN -DQT_WIDGETS_LIB -DQT_GUI_LIB -DQT_CORE_LIB
-CFLAGS = -pipe -O2 $(EXPORT_ARCH_ARGS) -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.14.sdk -mmacosx-version-min=10.12 -Wall -W -fPIC $(DEFINES)
-CXXFLAGS = -pipe -stdlib=libc++ -Wno-write-strings -Wno-unused-parameter -fPIC -I/usr/include/libxml2 -O2 -std=gnu++11 $(EXPORT_ARCH_ARGS) -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.14.sdk -mmacosx-version-min=10.12 -Wall -W -fPIC $(DEFINES)
-INCPATH = -I. -I../../Library -I../../GUI -I/opt/Qt/5.12.1/clang_64/lib/QtWidgets.framework/Headers -I/opt/Qt/5.12.1/clang_64/lib/QtGui.framework/Headers -I/opt/Qt/5.12.1/clang_64/lib/QtCore.framework/Headers -I. -I/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.14.sdk/Applications/Xcode10.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.14.sdk/System/Library/Frameworks/OpenGL.framework/Headers -I/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.14.sdk/Applications/Xcode10.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.14.sdk/System/Library/Frameworks/AGL.framework/Headers/ -I/opt/Qt/5.12.1/clang_64/mkspecs/macx-clang -F/opt/Qt/5.12.1/clang_64/lib
-QMAKE = /opt/Qt/5.12.1/clang_64/bin/qmake
-DEL_FILE = rm -f
-CHK_DIR_EXISTS= test -d
-MKDIR = mkdir -p
-COPY = cp -f
-COPY_FILE = cp -f
-COPY_DIR = cp -f -R
-INSTALL_FILE = install -m 644 -p
-INSTALL_PROGRAM = install -m 755 -p
-INSTALL_DIR = cp -f -R
-QINSTALL = /opt/Qt/5.12.1/clang_64/bin/qmake -install qinstall
-QINSTALL_PROGRAM = /opt/Qt/5.12.1/clang_64/bin/qmake -install qinstall -exe
-DEL_FILE = rm -f
-SYMLINK = ln -f -s
-DEL_DIR = rmdir
-MOVE = mv -f
-TAR = tar -cf
-COMPRESS = gzip -9f
-DISTNAME = cambium1.0.0
-DISTDIR = /Users/roel/Documents/GitHub/VirtualLeaf/src/Models/cambium/.tmp/cambium1.0.0
-LINK = /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang++
-LFLAGS = -stdlib=libc++ -fPIC -headerpad_max_install_names $(EXPORT_ARCH_ARGS) -Wl,-syslibroot,/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.14.sdk -mmacosx-version-min=10.12 -Wl,-rpath,@executable_path/Frameworks -Wl,-rpath,/opt/Qt/5.12.1/clang_64/lib -single_module -dynamiclib
-LIBS = $(SUBLIBS) -F/opt/Qt/5.12.1/clang_64/lib -L../../../lib -lvleaf -framework QtWidgets -framework QtGui -framework QtCore -framework DiskArbitration -framework IOKit -framework OpenGL -framework AGL
-AR = /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/ar cq
-RANLIB = /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/ranlib -s
-SED = sed
-STRIP = strip
-
-####### Output directory
-
-OBJECTS_DIR = ./
-
-####### Files
-
-SOURCES = cambium.cpp moc_cambium.cpp
-OBJECTS = cambium.o \
- moc_cambium.o
-DIST = /opt/Qt/5.12.1/clang_64/mkspecs/features/spec_pre.prf \
- /opt/Qt/5.12.1/clang_64/mkspecs/qdevice.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/features/device_config.prf \
- /opt/Qt/5.12.1/clang_64/mkspecs/common/unix.conf \
- /opt/Qt/5.12.1/clang_64/mkspecs/common/mac.conf \
- /opt/Qt/5.12.1/clang_64/mkspecs/common/macx.conf \
- /opt/Qt/5.12.1/clang_64/mkspecs/common/sanitize.conf \
- /opt/Qt/5.12.1/clang_64/mkspecs/common/gcc-base.conf \
- /opt/Qt/5.12.1/clang_64/mkspecs/common/gcc-base-mac.conf \
- /opt/Qt/5.12.1/clang_64/mkspecs/common/clang.conf \
- /opt/Qt/5.12.1/clang_64/mkspecs/common/clang-mac.conf \
- /opt/Qt/5.12.1/clang_64/mkspecs/qconfig.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_3danimation.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_3danimation_private.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_3dcore.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_3dcore_private.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_3dextras.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_3dextras_private.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_3dinput.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_3dinput_private.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_3dlogic.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_3dlogic_private.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_3dquick.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_3dquick_private.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_3dquickanimation.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_3dquickanimation_private.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_3dquickextras.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_3dquickextras_private.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_3dquickinput.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_3dquickinput_private.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_3dquickrender.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_3dquickrender_private.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_3dquickscene2d.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_3dquickscene2d_private.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_3drender.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_3drender_private.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_accessibility_support_private.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_bluetooth.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_bluetooth_private.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_bootstrap_private.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_charts.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_charts_private.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_clipboard_support_private.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_concurrent.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_concurrent_private.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_core.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_core_private.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_datavisualization.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_datavisualization_private.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_dbus.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_dbus_private.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_designer.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_designer_private.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_designercomponents_private.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_devicediscovery_support_private.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_edid_support_private.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_eventdispatcher_support_private.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_fb_support_private.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_fontdatabase_support_private.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_gamepad.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_gamepad_private.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_graphics_support_private.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_gui.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_gui_private.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_help.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_help_private.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_location.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_location_private.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_macextras.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_macextras_private.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_multimedia.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_multimedia_private.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_multimediawidgets.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_multimediawidgets_private.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_network.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_network_private.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_networkauth.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_networkauth_private.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_nfc.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_nfc_private.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_opengl.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_opengl_private.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_openglextensions.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_openglextensions_private.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_packetprotocol_private.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_platformcompositor_support_private.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_positioning.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_positioning_private.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_positioningquick.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_positioningquick_private.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_printsupport.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_printsupport_private.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_purchasing.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_purchasing_private.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_qml.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_qml_private.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_qmldebug_private.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_qmldevtools_private.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_qmltest.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_qmltest_private.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_qtmultimediaquicktools_private.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_quick.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_quick_private.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_quickcontrols2.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_quickcontrols2_private.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_quickparticles_private.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_quickshapes_private.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_quicktemplates2_private.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_quickwidgets.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_quickwidgets_private.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_remoteobjects.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_remoteobjects_private.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_repparser.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_repparser_private.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_script.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_script_private.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_scripttools.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_scripttools_private.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_scxml.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_scxml_private.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_sensors.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_sensors_private.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_serialbus.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_serialbus_private.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_serialport.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_serialport_private.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_service_support_private.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_sql.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_sql_private.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_svg.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_svg_private.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_testlib.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_testlib_private.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_texttospeech.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_texttospeech_private.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_theme_support_private.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_uiplugin.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_uitools.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_uitools_private.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_virtualkeyboard.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_virtualkeyboard_private.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_webchannel.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_webchannel_private.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_webengine.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_webengine_private.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_webenginecore.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_webenginecore_private.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_webenginecoreheaders_private.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_webenginewidgets.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_webenginewidgets_private.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_websockets.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_websockets_private.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_webview.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_webview_private.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_widgets.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_widgets_private.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_xml.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_xml_private.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_xmlpatterns.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_xmlpatterns_private.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_zlib_private.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/features/qt_functions.prf \
- /opt/Qt/5.12.1/clang_64/mkspecs/features/qt_config.prf \
- /opt/Qt/5.12.1/clang_64/mkspecs/macx-clang/qmake.conf \
- /opt/Qt/5.12.1/clang_64/mkspecs/features/spec_post.prf \
- ../../.qmake.stash \
- /opt/Qt/5.12.1/clang_64/mkspecs/features/exclusive_builds.prf \
- /opt/Qt/5.12.1/clang_64/mkspecs/features/mac/sdk.prf \
- /opt/Qt/5.12.1/clang_64/mkspecs/features/toolchain.prf \
- /opt/Qt/5.12.1/clang_64/mkspecs/features/mac/toolchain.prf \
- /opt/Qt/5.12.1/clang_64/mkspecs/features/default_pre.prf \
- /opt/Qt/5.12.1/clang_64/mkspecs/features/mac/default_pre.prf \
- /opt/Qt/5.12.1/clang_64/mkspecs/features/resolve_config.prf \
- /opt/Qt/5.12.1/clang_64/mkspecs/features/default_post.prf \
- /opt/Qt/5.12.1/clang_64/mkspecs/features/mac/default_post.prf \
- /opt/Qt/5.12.1/clang_64/mkspecs/features/mac/objective_c.prf \
- /opt/Qt/5.12.1/clang_64/mkspecs/features/mac/mac.prf \
- /opt/Qt/5.12.1/clang_64/mkspecs/features/warn_on.prf \
- /opt/Qt/5.12.1/clang_64/mkspecs/features/qt.prf \
- /opt/Qt/5.12.1/clang_64/mkspecs/features/resources.prf \
- /opt/Qt/5.12.1/clang_64/mkspecs/features/moc.prf \
- /opt/Qt/5.12.1/clang_64/mkspecs/features/unix/opengl.prf \
- /opt/Qt/5.12.1/clang_64/mkspecs/features/uic.prf \
- /opt/Qt/5.12.1/clang_64/mkspecs/features/unix/thread.prf \
- /opt/Qt/5.12.1/clang_64/mkspecs/features/qmake_use.prf \
- /opt/Qt/5.12.1/clang_64/mkspecs/features/file_copies.prf \
- /opt/Qt/5.12.1/clang_64/mkspecs/features/mac/rez.prf \
- /opt/Qt/5.12.1/clang_64/mkspecs/features/mac/asset_catalogs.prf \
- /opt/Qt/5.12.1/clang_64/mkspecs/features/testcase_targets.prf \
- /opt/Qt/5.12.1/clang_64/mkspecs/features/exceptions.prf \
- /opt/Qt/5.12.1/clang_64/mkspecs/features/yacc.prf \
- /opt/Qt/5.12.1/clang_64/mkspecs/features/lex.prf \
- cambium.pro cambium.h cambium.cpp
-QMAKE_TARGET = cambium
-DESTDIR = ../../../bin/models/
-TARGET = libcambium.dylib
-TARGETD = libcambium.dylib
-
-####### Custom Variables
-EXPORT_VALID_ARCHS = x86_64
-EXPORT_ACTIVE_ARCHS = $(filter $(EXPORT_VALID_ARCHS), $(ARCHS))
-EXPORT_ARCH_ARGS = $(foreach arch, $(if $(EXPORT_ACTIVE_ARCHS), $(EXPORT_ACTIVE_ARCHS), $(EXPORT_VALID_ARCHS)), -arch $(arch))
-EXPORT__PRO_FILE_ = /Users/roel/Documents/GitHub/VirtualLeaf/src/Models/cambium/cambium.pro
-
-
-first: all
-####### Build rules
-
-../../../bin/models/libcambium.dylib: $(OBJECTS) $(SUBLIBS) $(OBJCOMP)
- @test -d ../../../bin/models/ || mkdir -p ../../../bin/models/
- -$(DEL_FILE) $(TARGET)
- $(LINK) $(LFLAGS) -o $(TARGET) $(OBJECTS) $(LIBS) $(OBJCOMP)
- -$(MOVE) $(TARGET) ../../../bin/models/$(TARGET)
-
-
-
-Makefile.cambium: cambium.pro /opt/Qt/5.12.1/clang_64/mkspecs/macx-clang/qmake.conf /opt/Qt/5.12.1/clang_64/mkspecs/features/spec_pre.prf \
- /opt/Qt/5.12.1/clang_64/mkspecs/qdevice.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/features/device_config.prf \
- /opt/Qt/5.12.1/clang_64/mkspecs/common/unix.conf \
- /opt/Qt/5.12.1/clang_64/mkspecs/common/mac.conf \
- /opt/Qt/5.12.1/clang_64/mkspecs/common/macx.conf \
- /opt/Qt/5.12.1/clang_64/mkspecs/common/sanitize.conf \
- /opt/Qt/5.12.1/clang_64/mkspecs/common/gcc-base.conf \
- /opt/Qt/5.12.1/clang_64/mkspecs/common/gcc-base-mac.conf \
- /opt/Qt/5.12.1/clang_64/mkspecs/common/clang.conf \
- /opt/Qt/5.12.1/clang_64/mkspecs/common/clang-mac.conf \
- /opt/Qt/5.12.1/clang_64/mkspecs/qconfig.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_3danimation.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_3danimation_private.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_3dcore.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_3dcore_private.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_3dextras.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_3dextras_private.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_3dinput.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_3dinput_private.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_3dlogic.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_3dlogic_private.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_3dquick.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_3dquick_private.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_3dquickanimation.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_3dquickanimation_private.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_3dquickextras.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_3dquickextras_private.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_3dquickinput.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_3dquickinput_private.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_3dquickrender.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_3dquickrender_private.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_3dquickscene2d.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_3dquickscene2d_private.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_3drender.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_3drender_private.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_accessibility_support_private.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_bluetooth.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_bluetooth_private.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_bootstrap_private.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_charts.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_charts_private.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_clipboard_support_private.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_concurrent.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_concurrent_private.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_core.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_core_private.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_datavisualization.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_datavisualization_private.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_dbus.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_dbus_private.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_designer.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_designer_private.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_designercomponents_private.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_devicediscovery_support_private.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_edid_support_private.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_eventdispatcher_support_private.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_fb_support_private.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_fontdatabase_support_private.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_gamepad.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_gamepad_private.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_graphics_support_private.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_gui.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_gui_private.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_help.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_help_private.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_location.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_location_private.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_macextras.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_macextras_private.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_multimedia.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_multimedia_private.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_multimediawidgets.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_multimediawidgets_private.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_network.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_network_private.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_networkauth.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_networkauth_private.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_nfc.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_nfc_private.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_opengl.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_opengl_private.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_openglextensions.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_openglextensions_private.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_packetprotocol_private.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_platformcompositor_support_private.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_positioning.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_positioning_private.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_positioningquick.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_positioningquick_private.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_printsupport.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_printsupport_private.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_purchasing.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_purchasing_private.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_qml.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_qml_private.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_qmldebug_private.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_qmldevtools_private.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_qmltest.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_qmltest_private.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_qtmultimediaquicktools_private.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_quick.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_quick_private.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_quickcontrols2.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_quickcontrols2_private.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_quickparticles_private.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_quickshapes_private.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_quicktemplates2_private.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_quickwidgets.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_quickwidgets_private.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_remoteobjects.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_remoteobjects_private.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_repparser.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_repparser_private.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_script.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_script_private.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_scripttools.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_scripttools_private.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_scxml.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_scxml_private.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_sensors.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_sensors_private.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_serialbus.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_serialbus_private.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_serialport.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_serialport_private.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_service_support_private.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_sql.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_sql_private.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_svg.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_svg_private.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_testlib.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_testlib_private.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_texttospeech.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_texttospeech_private.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_theme_support_private.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_uiplugin.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_uitools.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_uitools_private.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_virtualkeyboard.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_virtualkeyboard_private.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_webchannel.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_webchannel_private.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_webengine.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_webengine_private.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_webenginecore.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_webenginecore_private.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_webenginecoreheaders_private.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_webenginewidgets.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_webenginewidgets_private.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_websockets.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_websockets_private.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_webview.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_webview_private.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_widgets.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_widgets_private.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_xml.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_xml_private.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_xmlpatterns.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_xmlpatterns_private.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_zlib_private.pri \
- /opt/Qt/5.12.1/clang_64/mkspecs/features/qt_functions.prf \
- /opt/Qt/5.12.1/clang_64/mkspecs/features/qt_config.prf \
- /opt/Qt/5.12.1/clang_64/mkspecs/macx-clang/qmake.conf \
- /opt/Qt/5.12.1/clang_64/mkspecs/features/spec_post.prf \
- ../../.qmake.stash \
- /opt/Qt/5.12.1/clang_64/mkspecs/features/exclusive_builds.prf \
- /opt/Qt/5.12.1/clang_64/mkspecs/features/mac/sdk.prf \
- /opt/Qt/5.12.1/clang_64/mkspecs/features/toolchain.prf \
- /opt/Qt/5.12.1/clang_64/mkspecs/features/mac/toolchain.prf \
- /opt/Qt/5.12.1/clang_64/mkspecs/features/default_pre.prf \
- /opt/Qt/5.12.1/clang_64/mkspecs/features/mac/default_pre.prf \
- /opt/Qt/5.12.1/clang_64/mkspecs/features/resolve_config.prf \
- /opt/Qt/5.12.1/clang_64/mkspecs/features/default_post.prf \
- /opt/Qt/5.12.1/clang_64/mkspecs/features/mac/default_post.prf \
- /opt/Qt/5.12.1/clang_64/mkspecs/features/mac/objective_c.prf \
- /opt/Qt/5.12.1/clang_64/mkspecs/features/mac/mac.prf \
- /opt/Qt/5.12.1/clang_64/mkspecs/features/warn_on.prf \
- /opt/Qt/5.12.1/clang_64/mkspecs/features/qt.prf \
- /opt/Qt/5.12.1/clang_64/mkspecs/features/resources.prf \
- /opt/Qt/5.12.1/clang_64/mkspecs/features/moc.prf \
- /opt/Qt/5.12.1/clang_64/mkspecs/features/unix/opengl.prf \
- /opt/Qt/5.12.1/clang_64/mkspecs/features/uic.prf \
- /opt/Qt/5.12.1/clang_64/mkspecs/features/unix/thread.prf \
- /opt/Qt/5.12.1/clang_64/mkspecs/features/qmake_use.prf \
- /opt/Qt/5.12.1/clang_64/mkspecs/features/file_copies.prf \
- /opt/Qt/5.12.1/clang_64/mkspecs/features/mac/rez.prf \
- /opt/Qt/5.12.1/clang_64/mkspecs/features/mac/asset_catalogs.prf \
- /opt/Qt/5.12.1/clang_64/mkspecs/features/testcase_targets.prf \
- /opt/Qt/5.12.1/clang_64/mkspecs/features/exceptions.prf \
- /opt/Qt/5.12.1/clang_64/mkspecs/features/yacc.prf \
- /opt/Qt/5.12.1/clang_64/mkspecs/features/lex.prf \
- cambium.pro \
- /opt/Qt/5.12.1/clang_64/lib/QtWidgets.framework/QtWidgets.prl \
- /opt/Qt/5.12.1/clang_64/lib/QtGui.framework/QtGui.prl \
- /opt/Qt/5.12.1/clang_64/lib/QtCore.framework/QtCore.prl
- $(QMAKE) -o Makefile.cambium cambium.pro
-/opt/Qt/5.12.1/clang_64/mkspecs/features/spec_pre.prf:
-/opt/Qt/5.12.1/clang_64/mkspecs/qdevice.pri:
-/opt/Qt/5.12.1/clang_64/mkspecs/features/device_config.prf:
-/opt/Qt/5.12.1/clang_64/mkspecs/common/unix.conf:
-/opt/Qt/5.12.1/clang_64/mkspecs/common/mac.conf:
-/opt/Qt/5.12.1/clang_64/mkspecs/common/macx.conf:
-/opt/Qt/5.12.1/clang_64/mkspecs/common/sanitize.conf:
-/opt/Qt/5.12.1/clang_64/mkspecs/common/gcc-base.conf:
-/opt/Qt/5.12.1/clang_64/mkspecs/common/gcc-base-mac.conf:
-/opt/Qt/5.12.1/clang_64/mkspecs/common/clang.conf:
-/opt/Qt/5.12.1/clang_64/mkspecs/common/clang-mac.conf:
-/opt/Qt/5.12.1/clang_64/mkspecs/qconfig.pri:
-/opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_3danimation.pri:
-/opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_3danimation_private.pri:
-/opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_3dcore.pri:
-/opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_3dcore_private.pri:
-/opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_3dextras.pri:
-/opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_3dextras_private.pri:
-/opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_3dinput.pri:
-/opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_3dinput_private.pri:
-/opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_3dlogic.pri:
-/opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_3dlogic_private.pri:
-/opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_3dquick.pri:
-/opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_3dquick_private.pri:
-/opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_3dquickanimation.pri:
-/opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_3dquickanimation_private.pri:
-/opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_3dquickextras.pri:
-/opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_3dquickextras_private.pri:
-/opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_3dquickinput.pri:
-/opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_3dquickinput_private.pri:
-/opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_3dquickrender.pri:
-/opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_3dquickrender_private.pri:
-/opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_3dquickscene2d.pri:
-/opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_3dquickscene2d_private.pri:
-/opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_3drender.pri:
-/opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_3drender_private.pri:
-/opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_accessibility_support_private.pri:
-/opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_bluetooth.pri:
-/opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_bluetooth_private.pri:
-/opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_bootstrap_private.pri:
-/opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_charts.pri:
-/opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_charts_private.pri:
-/opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_clipboard_support_private.pri:
-/opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_concurrent.pri:
-/opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_concurrent_private.pri:
-/opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_core.pri:
-/opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_core_private.pri:
-/opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_datavisualization.pri:
-/opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_datavisualization_private.pri:
-/opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_dbus.pri:
-/opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_dbus_private.pri:
-/opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_designer.pri:
-/opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_designer_private.pri:
-/opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_designercomponents_private.pri:
-/opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_devicediscovery_support_private.pri:
-/opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_edid_support_private.pri:
-/opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_eventdispatcher_support_private.pri:
-/opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_fb_support_private.pri:
-/opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_fontdatabase_support_private.pri:
-/opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_gamepad.pri:
-/opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_gamepad_private.pri:
-/opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_graphics_support_private.pri:
-/opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_gui.pri:
-/opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_gui_private.pri:
-/opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_help.pri:
-/opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_help_private.pri:
-/opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_location.pri:
-/opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_location_private.pri:
-/opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_macextras.pri:
-/opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_macextras_private.pri:
-/opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_multimedia.pri:
-/opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_multimedia_private.pri:
-/opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_multimediawidgets.pri:
-/opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_multimediawidgets_private.pri:
-/opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_network.pri:
-/opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_network_private.pri:
-/opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_networkauth.pri:
-/opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_networkauth_private.pri:
-/opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_nfc.pri:
-/opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_nfc_private.pri:
-/opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_opengl.pri:
-/opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_opengl_private.pri:
-/opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_openglextensions.pri:
-/opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_openglextensions_private.pri:
-/opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_packetprotocol_private.pri:
-/opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_platformcompositor_support_private.pri:
-/opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_positioning.pri:
-/opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_positioning_private.pri:
-/opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_positioningquick.pri:
-/opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_positioningquick_private.pri:
-/opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_printsupport.pri:
-/opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_printsupport_private.pri:
-/opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_purchasing.pri:
-/opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_purchasing_private.pri:
-/opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_qml.pri:
-/opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_qml_private.pri:
-/opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_qmldebug_private.pri:
-/opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_qmldevtools_private.pri:
-/opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_qmltest.pri:
-/opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_qmltest_private.pri:
-/opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_qtmultimediaquicktools_private.pri:
-/opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_quick.pri:
-/opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_quick_private.pri:
-/opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_quickcontrols2.pri:
-/opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_quickcontrols2_private.pri:
-/opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_quickparticles_private.pri:
-/opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_quickshapes_private.pri:
-/opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_quicktemplates2_private.pri:
-/opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_quickwidgets.pri:
-/opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_quickwidgets_private.pri:
-/opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_remoteobjects.pri:
-/opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_remoteobjects_private.pri:
-/opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_repparser.pri:
-/opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_repparser_private.pri:
-/opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_script.pri:
-/opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_script_private.pri:
-/opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_scripttools.pri:
-/opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_scripttools_private.pri:
-/opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_scxml.pri:
-/opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_scxml_private.pri:
-/opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_sensors.pri:
-/opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_sensors_private.pri:
-/opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_serialbus.pri:
-/opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_serialbus_private.pri:
-/opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_serialport.pri:
-/opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_serialport_private.pri:
-/opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_service_support_private.pri:
-/opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_sql.pri:
-/opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_sql_private.pri:
-/opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_svg.pri:
-/opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_svg_private.pri:
-/opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_testlib.pri:
-/opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_testlib_private.pri:
-/opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_texttospeech.pri:
-/opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_texttospeech_private.pri:
-/opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_theme_support_private.pri:
-/opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_uiplugin.pri:
-/opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_uitools.pri:
-/opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_uitools_private.pri:
-/opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_virtualkeyboard.pri:
-/opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_virtualkeyboard_private.pri:
-/opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_webchannel.pri:
-/opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_webchannel_private.pri:
-/opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_webengine.pri:
-/opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_webengine_private.pri:
-/opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_webenginecore.pri:
-/opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_webenginecore_private.pri:
-/opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_webenginecoreheaders_private.pri:
-/opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_webenginewidgets.pri:
-/opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_webenginewidgets_private.pri:
-/opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_websockets.pri:
-/opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_websockets_private.pri:
-/opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_webview.pri:
-/opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_webview_private.pri:
-/opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_widgets.pri:
-/opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_widgets_private.pri:
-/opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_xml.pri:
-/opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_xml_private.pri:
-/opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_xmlpatterns.pri:
-/opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_xmlpatterns_private.pri:
-/opt/Qt/5.12.1/clang_64/mkspecs/modules/qt_lib_zlib_private.pri:
-/opt/Qt/5.12.1/clang_64/mkspecs/features/qt_functions.prf:
-/opt/Qt/5.12.1/clang_64/mkspecs/features/qt_config.prf:
-/opt/Qt/5.12.1/clang_64/mkspecs/macx-clang/qmake.conf:
-/opt/Qt/5.12.1/clang_64/mkspecs/features/spec_post.prf:
-../../.qmake.stash:
-/opt/Qt/5.12.1/clang_64/mkspecs/features/exclusive_builds.prf:
-/opt/Qt/5.12.1/clang_64/mkspecs/features/mac/sdk.prf:
-/opt/Qt/5.12.1/clang_64/mkspecs/features/toolchain.prf:
-/opt/Qt/5.12.1/clang_64/mkspecs/features/mac/toolchain.prf:
-/opt/Qt/5.12.1/clang_64/mkspecs/features/default_pre.prf:
-/opt/Qt/5.12.1/clang_64/mkspecs/features/mac/default_pre.prf:
-/opt/Qt/5.12.1/clang_64/mkspecs/features/resolve_config.prf:
-/opt/Qt/5.12.1/clang_64/mkspecs/features/default_post.prf:
-/opt/Qt/5.12.1/clang_64/mkspecs/features/mac/default_post.prf:
-/opt/Qt/5.12.1/clang_64/mkspecs/features/mac/objective_c.prf:
-/opt/Qt/5.12.1/clang_64/mkspecs/features/mac/mac.prf:
-/opt/Qt/5.12.1/clang_64/mkspecs/features/warn_on.prf:
-/opt/Qt/5.12.1/clang_64/mkspecs/features/qt.prf:
-/opt/Qt/5.12.1/clang_64/mkspecs/features/resources.prf:
-/opt/Qt/5.12.1/clang_64/mkspecs/features/moc.prf:
-/opt/Qt/5.12.1/clang_64/mkspecs/features/unix/opengl.prf:
-/opt/Qt/5.12.1/clang_64/mkspecs/features/uic.prf:
-/opt/Qt/5.12.1/clang_64/mkspecs/features/unix/thread.prf:
-/opt/Qt/5.12.1/clang_64/mkspecs/features/qmake_use.prf:
-/opt/Qt/5.12.1/clang_64/mkspecs/features/file_copies.prf:
-/opt/Qt/5.12.1/clang_64/mkspecs/features/mac/rez.prf:
-/opt/Qt/5.12.1/clang_64/mkspecs/features/mac/asset_catalogs.prf:
-/opt/Qt/5.12.1/clang_64/mkspecs/features/testcase_targets.prf:
-/opt/Qt/5.12.1/clang_64/mkspecs/features/exceptions.prf:
-/opt/Qt/5.12.1/clang_64/mkspecs/features/yacc.prf:
-/opt/Qt/5.12.1/clang_64/mkspecs/features/lex.prf:
-cambium.pro:
-/opt/Qt/5.12.1/clang_64/lib/QtWidgets.framework/QtWidgets.prl:
-/opt/Qt/5.12.1/clang_64/lib/QtGui.framework/QtGui.prl:
-/opt/Qt/5.12.1/clang_64/lib/QtCore.framework/QtCore.prl:
-qmake: FORCE
- @$(QMAKE) -o Makefile.cambium cambium.pro
-
-qmake_all: FORCE
-
-
-all: Makefile.cambium ../../../bin/models/libcambium.dylib
-
-dist: distdir FORCE
- (cd `dirname $(DISTDIR)` && $(TAR) $(DISTNAME).tar $(DISTNAME) && $(COMPRESS) $(DISTNAME).tar) && $(MOVE) `dirname $(DISTDIR)`/$(DISTNAME).tar.gz . && $(DEL_FILE) -r $(DISTDIR)
-
-distdir: FORCE
- @test -d $(DISTDIR) || mkdir -p $(DISTDIR)
- $(COPY_FILE) --parents $(DIST) $(DISTDIR)/
- $(COPY_FILE) --parents /opt/Qt/5.12.1/clang_64/mkspecs/features/data/dummy.cpp $(DISTDIR)/
- $(COPY_FILE) --parents cambium.h $(DISTDIR)/
- $(COPY_FILE) --parents cambium.cpp $(DISTDIR)/
-
-
-clean: compiler_clean
- -$(DEL_FILE) $(OBJECTS)
- -$(DEL_FILE) *~ core *.core
-
-
-distclean: clean
- -$(DEL_FILE) ../../../bin/models/$(TARGET)
- -$(DEL_FILE) Makefile.cambium
-
-
-####### Sub-libraries
-
-xcodeproj:
- @$(QMAKE) -spec macx-xcode $(EXPORT__PRO_FILE_)
-
-mocclean: compiler_moc_header_clean compiler_moc_objc_header_clean compiler_moc_source_clean
-
-mocables: compiler_moc_header_make_all compiler_moc_objc_header_make_all compiler_moc_source_make_all
-
-check: first
-
-benchmark: first
-
-compiler_rcc_make_all:
-compiler_rcc_clean:
-compiler_moc_predefs_make_all: moc_predefs.h
-compiler_moc_predefs_clean:
- -$(DEL_FILE) moc_predefs.h
-moc_predefs.h: /opt/Qt/5.12.1/clang_64/mkspecs/features/data/dummy.cpp
- /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang++ -pipe -stdlib=libc++ -Wno-write-strings -Wno-unused-parameter -fPIC -I/usr/include/libxml2 -O2 -std=gnu++11 $(EXPORT_ARCH_ARGS) -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.14.sdk -mmacosx-version-min=10.12 -Wall -W -dM -E -o moc_predefs.h /opt/Qt/5.12.1/clang_64/mkspecs/features/data/dummy.cpp
-
-compiler_moc_header_make_all: moc_cambium.cpp
-compiler_moc_header_clean:
- -$(DEL_FILE) moc_cambium.cpp
-moc_cambium.cpp: cambium.h \
- /opt/Qt/5.12.1/clang_64/lib/QtCore.framework/Headers/QObject \
- /opt/Qt/5.12.1/clang_64/lib/QtCore.framework/Headers/qobject.h \
- /opt/Qt/5.12.1/clang_64/lib/QtGui.framework/Headers/QtGui \
- /opt/Qt/5.12.1/clang_64/lib/QtGui.framework/Headers/qtguiglobal.h \
- /opt/Qt/5.12.1/clang_64/lib/QtGui.framework/Headers/qabstracttextdocumentlayout.h \
- /opt/Qt/5.12.1/clang_64/lib/QtGui.framework/Headers/qaccessible.h \
- /opt/Qt/5.12.1/clang_64/lib/QtGui.framework/Headers/qaccessiblebridge.h \
- /opt/Qt/5.12.1/clang_64/lib/QtGui.framework/Headers/qaccessibleobject.h \
- /opt/Qt/5.12.1/clang_64/lib/QtGui.framework/Headers/qaccessibleplugin.h \
- /opt/Qt/5.12.1/clang_64/lib/QtGui.framework/Headers/qbackingstore.h \
- /opt/Qt/5.12.1/clang_64/lib/QtGui.framework/Headers/qbitmap.h \
- /opt/Qt/5.12.1/clang_64/lib/QtGui.framework/Headers/qbrush.h \
- /opt/Qt/5.12.1/clang_64/lib/QtGui.framework/Headers/qclipboard.h \
- /opt/Qt/5.12.1/clang_64/lib/QtGui.framework/Headers/qcolor.h \
- /opt/Qt/5.12.1/clang_64/lib/QtGui.framework/Headers/qcursor.h \
- /opt/Qt/5.12.1/clang_64/lib/QtGui.framework/Headers/qdesktopservices.h \
- /opt/Qt/5.12.1/clang_64/lib/QtGui.framework/Headers/qdrag.h \
- /opt/Qt/5.12.1/clang_64/lib/QtGui.framework/Headers/qevent.h \
- /opt/Qt/5.12.1/clang_64/lib/QtGui.framework/Headers/qfont.h \
- /opt/Qt/5.12.1/clang_64/lib/QtGui.framework/Headers/qfontdatabase.h \
- /opt/Qt/5.12.1/clang_64/lib/QtGui.framework/Headers/qfontinfo.h \
- /opt/Qt/5.12.1/clang_64/lib/QtGui.framework/Headers/qfontmetrics.h \
- /opt/Qt/5.12.1/clang_64/lib/QtGui.framework/Headers/qgenericmatrix.h \
- /opt/Qt/5.12.1/clang_64/lib/QtGui.framework/Headers/qgenericplugin.h \
- /opt/Qt/5.12.1/clang_64/lib/QtGui.framework/Headers/qgenericpluginfactory.h \
- /opt/Qt/5.12.1/clang_64/lib/QtGui.framework/Headers/qglyphrun.h \
- /opt/Qt/5.12.1/clang_64/lib/QtGui.framework/Headers/qguiapplication.h \
- /opt/Qt/5.12.1/clang_64/lib/QtGui.framework/Headers/qicon.h \
- /opt/Qt/5.12.1/clang_64/lib/QtGui.framework/Headers/qiconengine.h \
- /opt/Qt/5.12.1/clang_64/lib/QtGui.framework/Headers/qiconengineplugin.h \
- /opt/Qt/5.12.1/clang_64/lib/QtGui.framework/Headers/qimage.h \
- /opt/Qt/5.12.1/clang_64/lib/QtGui.framework/Headers/qimageiohandler.h \
- /opt/Qt/5.12.1/clang_64/lib/QtGui.framework/Headers/qimagereader.h \
- /opt/Qt/5.12.1/clang_64/lib/QtGui.framework/Headers/qimagewriter.h \
- /opt/Qt/5.12.1/clang_64/lib/QtGui.framework/Headers/qinputmethod.h \
- /opt/Qt/5.12.1/clang_64/lib/QtGui.framework/Headers/qkeysequence.h \
- /opt/Qt/5.12.1/clang_64/lib/QtGui.framework/Headers/qmatrix.h \
- /opt/Qt/5.12.1/clang_64/lib/QtGui.framework/Headers/qmatrix4x4.h \
- /opt/Qt/5.12.1/clang_64/lib/QtGui.framework/Headers/qmovie.h \
- /opt/Qt/5.12.1/clang_64/lib/QtGui.framework/Headers/qoffscreensurface.h \
- /opt/Qt/5.12.1/clang_64/lib/QtGui.framework/Headers/qopengl.h \
- /opt/Qt/5.12.1/clang_64/lib/QtGui.framework/Headers/qopenglbuffer.h \
- /opt/Qt/5.12.1/clang_64/lib/QtGui.framework/Headers/qopenglcontext.h \
- /opt/Qt/5.12.1/clang_64/lib/QtGui.framework/Headers/qopengldebug.h \
- /opt/Qt/5.12.1/clang_64/lib/QtGui.framework/Headers/qopenglextrafunctions.h \
- /opt/Qt/5.12.1/clang_64/lib/QtGui.framework/Headers/qopenglframebufferobject.h \
- /opt/Qt/5.12.1/clang_64/lib/QtGui.framework/Headers/qopenglfunctions.h \
- /opt/Qt/5.12.1/clang_64/lib/QtGui.framework/Headers/qopenglpaintdevice.h \
- /opt/Qt/5.12.1/clang_64/lib/QtGui.framework/Headers/qopenglpixeltransferoptions.h \
- /opt/Qt/5.12.1/clang_64/lib/QtGui.framework/Headers/qopenglshaderprogram.h \
- /opt/Qt/5.12.1/clang_64/lib/QtGui.framework/Headers/qopengltexture.h \
- /opt/Qt/5.12.1/clang_64/lib/QtGui.framework/Headers/qopengltextureblitter.h \
- /opt/Qt/5.12.1/clang_64/lib/QtGui.framework/Headers/qopengltimerquery.h \
- /opt/Qt/5.12.1/clang_64/lib/QtGui.framework/Headers/qopenglversionfunctions.h \
- /opt/Qt/5.12.1/clang_64/lib/QtGui.framework/Headers/qopenglvertexarrayobject.h \
- /opt/Qt/5.12.1/clang_64/lib/QtGui.framework/Headers/qopenglwindow.h \
- /opt/Qt/5.12.1/clang_64/lib/QtGui.framework/Headers/qpagedpaintdevice.h \
- /opt/Qt/5.12.1/clang_64/lib/QtGui.framework/Headers/qpagelayout.h \
- /opt/Qt/5.12.1/clang_64/lib/QtGui.framework/Headers/qpagesize.h \
- /opt/Qt/5.12.1/clang_64/lib/QtGui.framework/Headers/qpaintdevice.h \
- /opt/Qt/5.12.1/clang_64/lib/QtGui.framework/Headers/qpaintdevicewindow.h \
- /opt/Qt/5.12.1/clang_64/lib/QtGui.framework/Headers/qpaintengine.h \
- /opt/Qt/5.12.1/clang_64/lib/QtGui.framework/Headers/qpainter.h \
- /opt/Qt/5.12.1/clang_64/lib/QtGui.framework/Headers/qpainterpath.h \
- /opt/Qt/5.12.1/clang_64/lib/QtGui.framework/Headers/qpalette.h \
- /opt/Qt/5.12.1/clang_64/lib/QtGui.framework/Headers/qpdfwriter.h \
- /opt/Qt/5.12.1/clang_64/lib/QtGui.framework/Headers/qpen.h \
- /opt/Qt/5.12.1/clang_64/lib/QtGui.framework/Headers/qpicture.h \
- /opt/Qt/5.12.1/clang_64/lib/QtGui.framework/Headers/qpictureformatplugin.h \
- /opt/Qt/5.12.1/clang_64/lib/QtGui.framework/Headers/qpixelformat.h \
- /opt/Qt/5.12.1/clang_64/lib/QtGui.framework/Headers/qpixmap.h \
- /opt/Qt/5.12.1/clang_64/lib/QtGui.framework/Headers/qpixmapcache.h \
- /opt/Qt/5.12.1/clang_64/lib/QtGui.framework/Headers/qpolygon.h \
- /opt/Qt/5.12.1/clang_64/lib/QtGui.framework/Headers/qquaternion.h \
- /opt/Qt/5.12.1/clang_64/lib/QtGui.framework/Headers/qrasterwindow.h \
- /opt/Qt/5.12.1/clang_64/lib/QtGui.framework/Headers/qrawfont.h \
- /opt/Qt/5.12.1/clang_64/lib/QtGui.framework/Headers/qregion.h \
- /opt/Qt/5.12.1/clang_64/lib/QtGui.framework/Headers/qrgb.h \
- /opt/Qt/5.12.1/clang_64/lib/QtGui.framework/Headers/qrgba64.h \
- /opt/Qt/5.12.1/clang_64/lib/QtGui.framework/Headers/qscreen.h \
- /opt/Qt/5.12.1/clang_64/lib/QtGui.framework/Headers/qsessionmanager.h \
- /opt/Qt/5.12.1/clang_64/lib/QtGui.framework/Headers/qstandarditemmodel.h \
- /opt/Qt/5.12.1/clang_64/lib/QtGui.framework/Headers/qstatictext.h \
- /opt/Qt/5.12.1/clang_64/lib/QtGui.framework/Headers/qstylehints.h \
- /opt/Qt/5.12.1/clang_64/lib/QtGui.framework/Headers/qsurface.h \
- /opt/Qt/5.12.1/clang_64/lib/QtGui.framework/Headers/qsurfaceformat.h \
- /opt/Qt/5.12.1/clang_64/lib/QtGui.framework/Headers/qsyntaxhighlighter.h \
- /opt/Qt/5.12.1/clang_64/lib/QtGui.framework/Headers/qtextcursor.h \
- /opt/Qt/5.12.1/clang_64/lib/QtGui.framework/Headers/qtextdocument.h \
- /opt/Qt/5.12.1/clang_64/lib/QtGui.framework/Headers/qtextdocumentfragment.h \
- /opt/Qt/5.12.1/clang_64/lib/QtGui.framework/Headers/qtextdocumentwriter.h \
- /opt/Qt/5.12.1/clang_64/lib/QtGui.framework/Headers/qtextformat.h \
- /opt/Qt/5.12.1/clang_64/lib/QtGui.framework/Headers/qtextlayout.h \
- /opt/Qt/5.12.1/clang_64/lib/QtGui.framework/Headers/qtextlist.h \
- /opt/Qt/5.12.1/clang_64/lib/QtGui.framework/Headers/qtextobject.h \
- /opt/Qt/5.12.1/clang_64/lib/QtGui.framework/Headers/qtextoption.h \
- /opt/Qt/5.12.1/clang_64/lib/QtGui.framework/Headers/qtexttable.h \
- /opt/Qt/5.12.1/clang_64/lib/QtGui.framework/Headers/qtouchdevice.h \
- /opt/Qt/5.12.1/clang_64/lib/QtGui.framework/Headers/qtransform.h \
- /opt/Qt/5.12.1/clang_64/lib/QtGui.framework/Headers/qvalidator.h \
- /opt/Qt/5.12.1/clang_64/lib/QtGui.framework/Headers/qvector2d.h \
- /opt/Qt/5.12.1/clang_64/lib/QtGui.framework/Headers/qvector3d.h \
- /opt/Qt/5.12.1/clang_64/lib/QtGui.framework/Headers/qvector4d.h \
- /opt/Qt/5.12.1/clang_64/lib/QtGui.framework/Headers/qwindow.h \
- /opt/Qt/5.12.1/clang_64/lib/QtGui.framework/Headers/qwindowdefs.h \
- /opt/Qt/5.12.1/clang_64/lib/QtGui.framework/Headers/qtguiversion.h \
- /opt/Qt/5.12.1/clang_64/lib/QtCore.framework/Headers/QString \
- /opt/Qt/5.12.1/clang_64/lib/QtCore.framework/Headers/qstring.h \
- ../../Library/simplugin.h \
- /opt/Qt/5.12.1/clang_64/lib/QtCore.framework/Headers/QtPlugin \
- /opt/Qt/5.12.1/clang_64/lib/QtCore.framework/Headers/qplugin.h \
- /opt/Qt/5.12.1/clang_64/lib/QtCore.framework/Headers/QMetaType \
- /opt/Qt/5.12.1/clang_64/lib/QtCore.framework/Headers/qmetatype.h \
- ../../Library/cellbase.h \
- /opt/Qt/5.12.1/clang_64/lib/QtCore.framework/Headers/QDebug \
- /opt/Qt/5.12.1/clang_64/lib/QtCore.framework/Headers/qdebug.h \
- ../../Library/vector.h \
- ../../GUI/sqr.h \
- /opt/Qt/5.12.1/clang_64/lib/QtCore.framework/Headers/QPointF \
- /opt/Qt/5.12.1/clang_64/lib/QtCore.framework/Headers/qpoint.h \
- ../../Library/parameter.h \
- ../../GUI/wall.h \
- ../../Library/wallbase.h \
- /opt/Qt/5.12.1/clang_64/lib/QtWidgets.framework/Headers/QGraphicsScene \
- /opt/Qt/5.12.1/clang_64/lib/QtWidgets.framework/Headers/qgraphicsscene.h \
- ../../Library/warning.h \
- /opt/Qt/5.12.1/clang_64/lib/QtGui.framework/Headers/QColor \
- moc_predefs.h \
- /opt/Qt/5.12.1/clang_64/bin/moc
- /opt/Qt/5.12.1/clang_64/bin/moc $(DEFINES) --include /Users/roel/Documents/GitHub/VirtualLeaf/src/Models/cambium/moc_predefs.h -I/opt/Qt/5.12.1/clang_64/mkspecs/macx-clang -I/Users/roel/Documents/GitHub/VirtualLeaf/src/Models/cambium -I/Users/roel/Documents/GitHub/VirtualLeaf/src/Library -I/Users/roel/Documents/GitHub/VirtualLeaf/src/GUI -I/opt/Qt/5.12.1/clang_64/lib/QtWidgets.framework/Headers -I/opt/Qt/5.12.1/clang_64/lib/QtGui.framework/Headers -I/opt/Qt/5.12.1/clang_64/lib/QtCore.framework/Headers -I/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include/c++/v1 -I/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/clang/10.0.0/include -I/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include -I/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.14.sdk/usr/include -F/opt/Qt/5.12.1/clang_64/lib cambium.h -o moc_cambium.cpp
-
-compiler_moc_objc_header_make_all:
-compiler_moc_objc_header_clean:
-compiler_moc_source_make_all:
-compiler_moc_source_clean:
-compiler_uic_make_all:
-compiler_uic_clean:
-compiler_rez_source_make_all:
-compiler_rez_source_clean:
-compiler_yacc_decl_make_all:
-compiler_yacc_decl_clean:
-compiler_yacc_impl_make_all:
-compiler_yacc_impl_clean:
-compiler_lex_make_all:
-compiler_lex_clean:
-compiler_clean: compiler_moc_predefs_clean compiler_moc_header_clean
-
-####### Compile
-
-cambium.o: cambium.cpp /opt/Qt/5.12.1/clang_64/lib/QtCore.framework/Headers/QObject \
- /opt/Qt/5.12.1/clang_64/lib/QtCore.framework/Headers/qobject.h \
- /opt/Qt/5.12.1/clang_64/lib/QtGui.framework/Headers/QtGui \
- /opt/Qt/5.12.1/clang_64/lib/QtGui.framework/Headers/qtguiglobal.h \
- /opt/Qt/5.12.1/clang_64/lib/QtGui.framework/Headers/qabstracttextdocumentlayout.h \
- /opt/Qt/5.12.1/clang_64/lib/QtGui.framework/Headers/qaccessible.h \
- /opt/Qt/5.12.1/clang_64/lib/QtGui.framework/Headers/qaccessiblebridge.h \
- /opt/Qt/5.12.1/clang_64/lib/QtGui.framework/Headers/qaccessibleobject.h \
- /opt/Qt/5.12.1/clang_64/lib/QtGui.framework/Headers/qaccessibleplugin.h \
- /opt/Qt/5.12.1/clang_64/lib/QtGui.framework/Headers/qbackingstore.h \
- /opt/Qt/5.12.1/clang_64/lib/QtGui.framework/Headers/qbitmap.h \
- /opt/Qt/5.12.1/clang_64/lib/QtGui.framework/Headers/qbrush.h \
- /opt/Qt/5.12.1/clang_64/lib/QtGui.framework/Headers/qclipboard.h \
- /opt/Qt/5.12.1/clang_64/lib/QtGui.framework/Headers/qcolor.h \
- /opt/Qt/5.12.1/clang_64/lib/QtGui.framework/Headers/qcursor.h \
- /opt/Qt/5.12.1/clang_64/lib/QtGui.framework/Headers/qdesktopservices.h \
- /opt/Qt/5.12.1/clang_64/lib/QtGui.framework/Headers/qdrag.h \
- /opt/Qt/5.12.1/clang_64/lib/QtGui.framework/Headers/qevent.h \
- /opt/Qt/5.12.1/clang_64/lib/QtGui.framework/Headers/qfont.h \
- /opt/Qt/5.12.1/clang_64/lib/QtGui.framework/Headers/qfontdatabase.h \
- /opt/Qt/5.12.1/clang_64/lib/QtGui.framework/Headers/qfontinfo.h \
- /opt/Qt/5.12.1/clang_64/lib/QtGui.framework/Headers/qfontmetrics.h \
- /opt/Qt/5.12.1/clang_64/lib/QtGui.framework/Headers/qgenericmatrix.h \
- /opt/Qt/5.12.1/clang_64/lib/QtGui.framework/Headers/qgenericplugin.h \
- /opt/Qt/5.12.1/clang_64/lib/QtGui.framework/Headers/qgenericpluginfactory.h \
- /opt/Qt/5.12.1/clang_64/lib/QtGui.framework/Headers/qglyphrun.h \
- /opt/Qt/5.12.1/clang_64/lib/QtGui.framework/Headers/qguiapplication.h \
- /opt/Qt/5.12.1/clang_64/lib/QtGui.framework/Headers/qicon.h \
- /opt/Qt/5.12.1/clang_64/lib/QtGui.framework/Headers/qiconengine.h \
- /opt/Qt/5.12.1/clang_64/lib/QtGui.framework/Headers/qiconengineplugin.h \
- /opt/Qt/5.12.1/clang_64/lib/QtGui.framework/Headers/qimage.h \
- /opt/Qt/5.12.1/clang_64/lib/QtGui.framework/Headers/qimageiohandler.h \
- /opt/Qt/5.12.1/clang_64/lib/QtGui.framework/Headers/qimagereader.h \
- /opt/Qt/5.12.1/clang_64/lib/QtGui.framework/Headers/qimagewriter.h \
- /opt/Qt/5.12.1/clang_64/lib/QtGui.framework/Headers/qinputmethod.h \
- /opt/Qt/5.12.1/clang_64/lib/QtGui.framework/Headers/qkeysequence.h \
- /opt/Qt/5.12.1/clang_64/lib/QtGui.framework/Headers/qmatrix.h \
- /opt/Qt/5.12.1/clang_64/lib/QtGui.framework/Headers/qmatrix4x4.h \
- /opt/Qt/5.12.1/clang_64/lib/QtGui.framework/Headers/qmovie.h \
- /opt/Qt/5.12.1/clang_64/lib/QtGui.framework/Headers/qoffscreensurface.h \
- /opt/Qt/5.12.1/clang_64/lib/QtGui.framework/Headers/qopengl.h \
- /opt/Qt/5.12.1/clang_64/lib/QtGui.framework/Headers/qopenglbuffer.h \
- /opt/Qt/5.12.1/clang_64/lib/QtGui.framework/Headers/qopenglcontext.h \
- /opt/Qt/5.12.1/clang_64/lib/QtGui.framework/Headers/qopengldebug.h \
- /opt/Qt/5.12.1/clang_64/lib/QtGui.framework/Headers/qopenglextrafunctions.h \
- /opt/Qt/5.12.1/clang_64/lib/QtGui.framework/Headers/qopenglframebufferobject.h \
- /opt/Qt/5.12.1/clang_64/lib/QtGui.framework/Headers/qopenglfunctions.h \
- /opt/Qt/5.12.1/clang_64/lib/QtGui.framework/Headers/qopenglpaintdevice.h \
- /opt/Qt/5.12.1/clang_64/lib/QtGui.framework/Headers/qopenglpixeltransferoptions.h \
- /opt/Qt/5.12.1/clang_64/lib/QtGui.framework/Headers/qopenglshaderprogram.h \
- /opt/Qt/5.12.1/clang_64/lib/QtGui.framework/Headers/qopengltexture.h \
- /opt/Qt/5.12.1/clang_64/lib/QtGui.framework/Headers/qopengltextureblitter.h \
- /opt/Qt/5.12.1/clang_64/lib/QtGui.framework/Headers/qopengltimerquery.h \
- /opt/Qt/5.12.1/clang_64/lib/QtGui.framework/Headers/qopenglversionfunctions.h \
- /opt/Qt/5.12.1/clang_64/lib/QtGui.framework/Headers/qopenglvertexarrayobject.h \
- /opt/Qt/5.12.1/clang_64/lib/QtGui.framework/Headers/qopenglwindow.h \
- /opt/Qt/5.12.1/clang_64/lib/QtGui.framework/Headers/qpagedpaintdevice.h \
- /opt/Qt/5.12.1/clang_64/lib/QtGui.framework/Headers/qpagelayout.h \
- /opt/Qt/5.12.1/clang_64/lib/QtGui.framework/Headers/qpagesize.h \
- /opt/Qt/5.12.1/clang_64/lib/QtGui.framework/Headers/qpaintdevice.h \
- /opt/Qt/5.12.1/clang_64/lib/QtGui.framework/Headers/qpaintdevicewindow.h \
- /opt/Qt/5.12.1/clang_64/lib/QtGui.framework/Headers/qpaintengine.h \
- /opt/Qt/5.12.1/clang_64/lib/QtGui.framework/Headers/qpainter.h \
- /opt/Qt/5.12.1/clang_64/lib/QtGui.framework/Headers/qpainterpath.h \
- /opt/Qt/5.12.1/clang_64/lib/QtGui.framework/Headers/qpalette.h \
- /opt/Qt/5.12.1/clang_64/lib/QtGui.framework/Headers/qpdfwriter.h \
- /opt/Qt/5.12.1/clang_64/lib/QtGui.framework/Headers/qpen.h \
- /opt/Qt/5.12.1/clang_64/lib/QtGui.framework/Headers/qpicture.h \
- /opt/Qt/5.12.1/clang_64/lib/QtGui.framework/Headers/qpictureformatplugin.h \
- /opt/Qt/5.12.1/clang_64/lib/QtGui.framework/Headers/qpixelformat.h \
- /opt/Qt/5.12.1/clang_64/lib/QtGui.framework/Headers/qpixmap.h \
- /opt/Qt/5.12.1/clang_64/lib/QtGui.framework/Headers/qpixmapcache.h \
- /opt/Qt/5.12.1/clang_64/lib/QtGui.framework/Headers/qpolygon.h \
- /opt/Qt/5.12.1/clang_64/lib/QtGui.framework/Headers/qquaternion.h \
- /opt/Qt/5.12.1/clang_64/lib/QtGui.framework/Headers/qrasterwindow.h \
- /opt/Qt/5.12.1/clang_64/lib/QtGui.framework/Headers/qrawfont.h \
- /opt/Qt/5.12.1/clang_64/lib/QtGui.framework/Headers/qregion.h \
- /opt/Qt/5.12.1/clang_64/lib/QtGui.framework/Headers/qrgb.h \
- /opt/Qt/5.12.1/clang_64/lib/QtGui.framework/Headers/qrgba64.h \
- /opt/Qt/5.12.1/clang_64/lib/QtGui.framework/Headers/qscreen.h \
- /opt/Qt/5.12.1/clang_64/lib/QtGui.framework/Headers/qsessionmanager.h \
- /opt/Qt/5.12.1/clang_64/lib/QtGui.framework/Headers/qstandarditemmodel.h \
- /opt/Qt/5.12.1/clang_64/lib/QtGui.framework/Headers/qstatictext.h \
- /opt/Qt/5.12.1/clang_64/lib/QtGui.framework/Headers/qstylehints.h \
- /opt/Qt/5.12.1/clang_64/lib/QtGui.framework/Headers/qsurface.h \
- /opt/Qt/5.12.1/clang_64/lib/QtGui.framework/Headers/qsurfaceformat.h \
- /opt/Qt/5.12.1/clang_64/lib/QtGui.framework/Headers/qsyntaxhighlighter.h \
- /opt/Qt/5.12.1/clang_64/lib/QtGui.framework/Headers/qtextcursor.h \
- /opt/Qt/5.12.1/clang_64/lib/QtGui.framework/Headers/qtextdocument.h \
- /opt/Qt/5.12.1/clang_64/lib/QtGui.framework/Headers/qtextdocumentfragment.h \
- /opt/Qt/5.12.1/clang_64/lib/QtGui.framework/Headers/qtextdocumentwriter.h \
- /opt/Qt/5.12.1/clang_64/lib/QtGui.framework/Headers/qtextformat.h \
- /opt/Qt/5.12.1/clang_64/lib/QtGui.framework/Headers/qtextlayout.h \
- /opt/Qt/5.12.1/clang_64/lib/QtGui.framework/Headers/qtextlist.h \
- /opt/Qt/5.12.1/clang_64/lib/QtGui.framework/Headers/qtextobject.h \
- /opt/Qt/5.12.1/clang_64/lib/QtGui.framework/Headers/qtextoption.h \
- /opt/Qt/5.12.1/clang_64/lib/QtGui.framework/Headers/qtexttable.h \
- /opt/Qt/5.12.1/clang_64/lib/QtGui.framework/Headers/qtouchdevice.h \
- /opt/Qt/5.12.1/clang_64/lib/QtGui.framework/Headers/qtransform.h \
- /opt/Qt/5.12.1/clang_64/lib/QtGui.framework/Headers/qvalidator.h \
- /opt/Qt/5.12.1/clang_64/lib/QtGui.framework/Headers/qvector2d.h \
- /opt/Qt/5.12.1/clang_64/lib/QtGui.framework/Headers/qvector3d.h \
- /opt/Qt/5.12.1/clang_64/lib/QtGui.framework/Headers/qvector4d.h \
- /opt/Qt/5.12.1/clang_64/lib/QtGui.framework/Headers/qwindow.h \
- /opt/Qt/5.12.1/clang_64/lib/QtGui.framework/Headers/qwindowdefs.h \
- /opt/Qt/5.12.1/clang_64/lib/QtGui.framework/Headers/qtguiversion.h \
- ../../Library/parameter.h \
- ../../Library/vector.h \
- ../../GUI/sqr.h \
- /opt/Qt/5.12.1/clang_64/lib/QtCore.framework/Headers/QPointF \
- /opt/Qt/5.12.1/clang_64/lib/QtCore.framework/Headers/qpoint.h \
- ../../Library/wallbase.h \
- ../../Library/cellbase.h \
- /opt/Qt/5.12.1/clang_64/lib/QtCore.framework/Headers/QString \
- /opt/Qt/5.12.1/clang_64/lib/QtCore.framework/Headers/qstring.h \
- /opt/Qt/5.12.1/clang_64/lib/QtCore.framework/Headers/QDebug \
- /opt/Qt/5.12.1/clang_64/lib/QtCore.framework/Headers/qdebug.h \
- ../../GUI/wall.h \
- /opt/Qt/5.12.1/clang_64/lib/QtWidgets.framework/Headers/QGraphicsScene \
- /opt/Qt/5.12.1/clang_64/lib/QtWidgets.framework/Headers/qgraphicsscene.h \
- ../../Library/warning.h \
- cambium.h \
- ../../Library/simplugin.h \
- /opt/Qt/5.12.1/clang_64/lib/QtCore.framework/Headers/QtPlugin \
- /opt/Qt/5.12.1/clang_64/lib/QtCore.framework/Headers/qplugin.h \
- /opt/Qt/5.12.1/clang_64/lib/QtCore.framework/Headers/QMetaType \
- /opt/Qt/5.12.1/clang_64/lib/QtCore.framework/Headers/qmetatype.h \
- /opt/Qt/5.12.1/clang_64/lib/QtGui.framework/Headers/QColor
- $(CXX) -c $(CXXFLAGS) $(INCPATH) -o cambium.o cambium.cpp
-
-moc_cambium.o: moc_cambium.cpp
- $(CXX) -c $(CXXFLAGS) $(INCPATH) -o moc_cambium.o moc_cambium.cpp
-
-####### Install
-
-install: FORCE
-
-uninstall: FORCE
-
-FORCE:
-
diff --git a/src/Models/Cambium/cambium.cpp b/src/Models/Cambium/cambium.cpp
index e6fd8575..ac67b843 100755
--- a/src/Models/Cambium/cambium.cpp
+++ b/src/Models/Cambium/cambium.cpp
@@ -37,7 +37,7 @@ Cell Types and Their Behavior:
CellType(0) : Bark Cells
- Can grow slightly (prevents potential bugs if restricted completely).
- Cannot divide.
-- Stiffness = 10 × Cambium stiffness.
+- Stiffness = 5 × Cambium stiffness.
CellType(1) : Cambium Cells
- Can grow until a specific threshold is reached.
@@ -52,7 +52,7 @@ CellType(2) : Growing Xylem Cells
CellType(3) : Mature Xylem Cells
- Cannot grow or divide.
-- Stiffness = 100 × Cambium stiffness.
+- Stiffness = 5 × Cambium stiffness.
*/
@@ -78,28 +78,76 @@ void cambium::AfficherNoeuds(CellBase *c) {
// Node operations can be added here if needed
}
}
+void PrintWallStiffness(CellBase *c) {
+ qDebug() << "Cell" << c->Index() << "wall stiffness values:";
+ int wall_count = 0;
+
+ c->LoopWallElements([&wall_count](auto wallElementInfo){
+ double stiffness = wallElementInfo->getWallElement()->getStiffness();
+ qDebug() << " Wall element" << wall_count++ << "stiffness:" << stiffness;
+ });
+}
void cambium::SetCellTypeProperties(CellBase *c) { // Set cell properties
/* SetLambdaLength property notes:
+ - Default value 0 for all cell mode 0
- High values (>2) cause cells to "flow"
- Very low values (<0.01) for bark prevent cells from moving between bark cells
- This is the elasticity coefficient of the wall, allowing it to extend to lambda * initial value
*/
- if (c->CellType()==0){
- c-> SetWallStiffness(1);
- c-> SetLambdaLength(0);
+ // Define stiffness parameters for different cell types
+ const double cambium_added_stiffness = 0; // Base stiffness (used by cambium)
+ const double bark_added_stiffness = 0; // Additional stiffness for bark cells
+ const double mature_xylem_added_stiffness = 0; // Additional stiffness for mature xylem
+
+ if (c->CellType()==0) { // Bark Cells
+ c->SetLambdaLength(0);
+
+ // Set stiffness to default + added stiffness for bark
+ double stiffness = bark_added_stiffness;
+ double* p_stiffness = &stiffness;
+
+ c->LoopWallElements([p_stiffness](auto wallElementInfo){
+ wallElementInfo->getWallElement()->setStiffness(*p_stiffness);
+ });
}
- else if (c->CellType()==1){
- c-> SetWallStiffness(1);
- c-> SetLambdaLength(0);
+ else if (c->CellType()==1) { // Cambium Cells
+ c->SetLambdaLength(0);
+
+ // Set stiffness to default (no modification)
+ double stiffness = cambium_added_stiffness;
+ double* p_stiffness = &stiffness;
+
+ c->LoopWallElements([p_stiffness](auto wallElementInfo){
+ wallElementInfo->getWallElement()->setStiffness(*p_stiffness);
+ });
}
- else if (c->CellType()==2){
- c-> SetWallStiffness(1);
- c-> SetLambdaLength(0);
+ else if (c->CellType()==2) { // Growing Xylem Cells
+ c->SetLambdaLength(0);
+
+ // Calculate growth progress (0.0 to 1.0)
+ double progress = (c->Area() - c->BaseArea()) / (2.0 * c->BaseArea());
+ progress = std::min(1.0, std::max(0.0, progress)); // Clamp between 0 and 1
+
+ // Gradually increase stiffness from default to higher values as the cell grows
+ // Add up to 0.5 additional stiffness as the cell reaches full growth
+ double stiffness = mature_xylem_added_stiffness * progress;
+ double* p_stiffness = &stiffness;
+
+ c->LoopWallElements([p_stiffness](auto wallElementInfo){
+ wallElementInfo->getWallElement()->setStiffness(*p_stiffness);
+ });
}
- else {
- c-> SetWallStiffness(1);
- c-> SetLambdaLength(0);
+ else { // Mature Xylem Cells (Type 3)
+ c->SetLambdaLength(0);
+
+ // Set stiffness to default + added stiffness for mature xylem
+ double stiffness = mature_xylem_added_stiffness;
+ double* p_stiffness = &stiffness;
+
+ c->LoopWallElements([p_stiffness](auto wallElementInfo){
+ wallElementInfo->getWallElement()->setStiffness(*p_stiffness);
+ });
}
}
@@ -223,10 +271,21 @@ void cambium::OnDivide(ParentInfo *parent_info, CellBase *daughter1, CellBase *d
// }
//}
-void cambium::CellHouseKeeping(CellBase *c) { // How cells behave after division
- qDebug() << "Cell elastic limit :" << c->elastic_limit() ;
- SetCellTypeProperties(c);
+// void cambium::CellHouseKeeping(CellBase *c) { // How cells behave after division
+// if (c->Index()==1) {
+// c->EnlargeTargetArea(par->cell_expansion_rate);
+// }
+// }
+void cambium::CellHouseKeeping(CellBase *c) {
+ c->SetDivisionType(PERP_STRESS);
+ // Set initial area on first call to this function for each cell
+ static std::set initialized_cells;
+ if (initialized_cells.find(c->Index()) == initialized_cells.end()) {
+ c->SetInitialArea();
+ initialized_cells.insert(c->Index());
+ }
+ // SetCellTypeProperties(c);
// Check if a cambium cell is no longer adjacent to the bark, if not it has to be transformed into a Growing Xylem cell
if (c->CellType() == 1) {
@@ -268,55 +327,8 @@ void cambium::CellHouseKeeping(CellBase *c) { // How cells behave after division
else if (c->CellType() == 0) {
/* If the cell is a bark cell (type 0), we need to slightly enlarge it to prevent excessive stretching,
which could cause issues in the simulation. This adjustment ensures stability during runtime. */
-
- // Get current area values
- double area = c->Area();
- double baseArea = c->BaseArea();
-
- // Use static maps to store growth data for each cell by its index
- static std::map growth_additions;
- static std::map last_growth_step;
- static int current_step = 0;
-
- // Increment step counter each time function is called (simulation step)
- current_step++;
-
- // Initialize growth addition for this cell if not present
- if (growth_additions.find(c->Index()) == growth_additions.end()) {
- growth_additions[c->Index()] = 0.0;
- last_growth_step[c->Index()] = 0;
- }
-
- // Check if we need to increase the growth_addition (every 500 simulation steps)
- if (current_step - last_growth_step[c->Index()] >= 200) {
- // Increase growth_addition by 5% of baseArea
- growth_additions[c->Index()] += baseArea * 0.15;
- // Update last growth step
- last_growth_step[c->Index()] = current_step;
-
- if (c->Index() == 28) {
- qDebug() << "Cell 28 - GROWTH UPDATE - Step:" << current_step
- << "New Growth Addition:" << growth_additions[c->Index()];
- }
- }
-
- // Use effective base area (original baseArea + growth_addition)
- double effective_base_area = baseArea + growth_additions[c->Index()];
-
- // Maintain effective base area if cell has shrunk
- if (area < effective_base_area) {
- // Gradually increase target area to reach effective base area
- c->EnlargeTargetArea(par->cell_expansion_rate);
-
- if (c->Index() == 28) {
- qDebug() << "Cell 28 - ENLARGING TARGET AREA - Step:" << current_step
- << "Effective base area:" << effective_base_area
- << "Current area:" << area
- << "Target area:" << c->TargetArea()
- << "Rate:" << par->cell_expansion_rate;
- }
- }
-}
+ c->EnlargeTargetArea(0.5 * par->cell_expansion_rate);
+ }
}
diff --git a/src/Models/Cambium/moc_predefs.h b/src/Models/Cambium/moc_predefs.h
index 6f841a0b..aacf77f0 100644
--- a/src/Models/Cambium/moc_predefs.h
+++ b/src/Models/Cambium/moc_predefs.h
@@ -65,7 +65,6 @@
#define __linux 1
#define __DEC32_EPSILON__ 1E-6DF
#define __FLT_EVAL_METHOD_TS_18661_3__ 0
-#define __OPTIMIZE__ 1
#define __unix 1
#define __UINT32_MAX__ 0xffffffffU
#define __GXX_EXPERIMENTAL_CXX0X__ 1
@@ -79,7 +78,6 @@
#define __WCHAR_MIN__ (-__WCHAR_MAX__ - 1)
#define __INT64_C(c) c ## L
#define __GCC_ATOMIC_POINTER_LOCK_FREE 2
-#define _FORTIFY_SOURCE 2
#define __FLT32X_MANT_DIG__ 53
#define __GCC_ATOMIC_CHAR16_T_LOCK_FREE 2
#define __cpp_aligned_new 201606L
@@ -194,6 +192,7 @@
#define __FLT32_MIN__ 1.17549435082228750796873653722224568e-38F32
#define __UINT8_TYPE__ unsigned char
#define __FLT_DIG__ 6
+#define __NO_INLINE__ 1
#define __DEC_EVAL_METHOD__ 2
#define __DEC128_MAX__ 9.999999999999999999999999999999999E6144DL
#define __FLT_MANT_DIG__ 24
@@ -307,6 +306,7 @@
#define __UINTPTR_MAX__ 0xffffffffffffffffUL
#define __INT_FAST64_WIDTH__ 64
#define __cpp_decltype 200707L
+#define QDEBUG 1
#define __INT_FAST64_MAX__ 0x7fffffffffffffffL
#define __GCC_ATOMIC_TEST_AND_SET_TRUEVAL 1
#define __FLT_NORM_MAX__ 3.40282346638528859811704183484516925e+38F
diff --git a/src/Models/Tutorial1A/tutorial1A.cpp b/src/Models/Tutorial1A/tutorial1A.cpp
index 970c89d4..2e35040b 100755
--- a/src/Models/Tutorial1A/tutorial1A.cpp
+++ b/src/Models/Tutorial1A/tutorial1A.cpp
@@ -53,6 +53,13 @@ void Tutorial1A::SetCellColor(CellBase *c, QColor *color) {
void Tutorial1A::CellHouseKeeping(CellBase *c) {
// add cell behavioral rules here
+ cout << "Cell base Area: " << c->BaseArea() << endl;
+ cout << "Cell current Area: " << c->Area() << endl;
+ cout << "Cell Target Area: " << c->TargetArea() << endl;
+ c->SetLambdaLength(1);
+ cout << "Cell lambda length: " << c->GetLambdaLength() << endl;
+
+
c->EnlargeTargetArea(par->cell_expansion_rate);
}
diff --git a/src/Models/Tutorial1C/tutorial1C.cpp b/src/Models/Tutorial1C/tutorial1C.cpp
index bc88ef84..60044a74 100755
--- a/src/Models/Tutorial1C/tutorial1C.cpp
+++ b/src/Models/Tutorial1C/tutorial1C.cpp
@@ -29,6 +29,8 @@
#include "cellbase.h"
#include "tutorial1C.h"
+#include "mesh.h"
+
static const std::string _module_id("$Id$");
QString Tutorial1C::ModelID(void) {
@@ -43,6 +45,22 @@ int Tutorial1C::NChem(void) { return 0; }
void Tutorial1C::OnDivide(ParentInfo *parent_info, CellBase *daughter1, CellBase *daughter2) {
// rules to be executed after cell division go here
// (e.g., cell differentiation rules)
+
+ // double stiffness = 2;
+ // double* p_stiffness= &stiffness;
+ // if (daughter1->AtBoundaryP()) {
+ // // Apply to both daughter cells
+ // daughter1->LoopWallElements([p_stiffness](auto wallElementInfo){
+ // wallElementInfo->getWallElement()->setStiffness(*p_stiffness);
+ // (*p_stiffness)+=0.1;
+ // });
+ // }
+ // if (daughter2->AtBoundaryP()) {
+ // daughter2->LoopWallElements([p_stiffness](auto wallElementInfo){
+ // wallElementInfo->getWallElement()->setStiffness(*p_stiffness);
+ // (*p_stiffness)+=0.1;
+ // });
+ // }
}
void Tutorial1C::SetCellColor(CellBase *c, QColor *color) {
@@ -50,20 +68,38 @@ void Tutorial1C::SetCellColor(CellBase *c, QColor *color) {
}
void Tutorial1C::CellHouseKeeping(CellBase *c) {
+ c->SetDivisionType(SHORT_AXIS);
+ cout << "Cell " << c->Index() << " at boundary : " << c->AtBoundaryP() << endl;
+ // Count total cells in the tissue
+ // int totalCells = CountCells();
+ // cout << "Cell " << c->Index() << " at boundary: " << c->AtBoundaryP()
+ // << ", Total cells: " << totalCells << endl;
+ // cout << "Cell lambda length: " << c->GetLambdaLength() << endl;
+ double lambda = 0.1;
+ double lambda_ext = 0.5;
+ // Only set high stiffness for boundary cells
+ if (c->AtBoundaryP()) {
+ c->SetLambdaLength(lambda_ext);
+ // double stiffness = 2;
+ // double* p_stiffness = &stiffness;
+ //
+ // c->LoopWallElements([p_stiffness](auto wallElementInfo){
+ // wallElementInfo->getWallElement()->setStiffness(*p_stiffness);
+ // (*p_stiffness)+=0.1;
+ // });
+ } else {
+ // Set uniform stiffness for non-boundary cells
+ c->SetLambdaLength(lambda);
+ // c->LoopWallElements([](auto wallElementInfo){
+ // wallElementInfo->getWallElement()->setStiffness(1);
+ // });
+ }
-
- double stiffness = 2;
- double* p_stiffness= &stiffness;
-
- c->LoopWallElements([c,p_stiffness](auto wallElementInfo){
- wallElementInfo->getWallElement()->setStiffness(*p_stiffness);
- (*p_stiffness)+=0.1;
- });
// add cell behavioral rules here
- c->EnlargeTargetArea(par->cell_expansion_rate);
- if (c->Area() > par->rel_cell_div_threshold * c->BaseArea()) {
- c->Divide();
- }
+ c->EnlargeTargetArea(par->cell_expansion_rate);
+ if (c->Area() > par->rel_cell_div_threshold * c->BaseArea()) {
+ c->Divide();
+ }
}
void Tutorial1C::CelltoCellTransport(Wall *w, double *dchem_c1, double *dchem_c2) {
diff --git a/src/Models/Tutorial1C/tutorial1C.h b/src/Models/Tutorial1C/tutorial1C.h
index 8596c487..098a784a 100755
--- a/src/Models/Tutorial1C/tutorial1C.h
+++ b/src/Models/Tutorial1C/tutorial1C.h
@@ -31,10 +31,9 @@ class Tutorial1C : public QObject, SimPluginInterface {
Q_OBJECT
Q_INTERFACES(SimPluginInterface);
Q_PLUGIN_METADATA(IID "org.virtualleaf.tutorial1c")
-
public:
virtual QString ModelID(void);
-
+
// Executed after the cellular mechanics steps have equillibrized
virtual void CellHouseKeeping (CellBase *c);
// Differential equations describing transport of chemicals from cell to cell
diff --git a/src/VirtualLeaf.pro b/src/VirtualLeaf.pro
index 60c4866e..863560be 100755
--- a/src/VirtualLeaf.pro
+++ b/src/VirtualLeaf.pro
@@ -1,8 +1,16 @@
TEMPLATE = subdirs
-CONFIG+=ordered
+
+# Ensure we build in debug (no stripping, full symbols, zero optimization):
+CONFIG += ordered debug
+QMAKE_CXXFLAGS_DEBUG += -g -O0
+
+# On Linux, generate a symbol table for backtrace_symbols()
+QMAKE_LFLAGS += -rdynamic
+
+# C++ standard
CONFIG += c++14
-SUBDIRS = \
-Library \ # relative paths
-GUI \
-Models
+SUBDIRS += \
+ Library \
+ GUI \
+ Models
diff --git a/structure_n_cercles.xml b/structure_n_cercles.xml
new file mode 100644
index 00000000..88a308ed
--- /dev/null
+++ b/structure_n_cercles.xml
@@ -0,0 +1,806 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+ |
+ | |
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/structure_vierge.xml b/structure_vierge.xml
new file mode 100644
index 00000000..a6434c34
--- /dev/null
+++ b/structure_vierge.xml
@@ -0,0 +1,194 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/virtualleaf_xml_model.py b/virtualleaf_xml_model.py
index 71f0d2bb..5a6805f9 100644
--- a/virtualleaf_xml_model.py
+++ b/virtualleaf_xml_model.py
@@ -196,7 +196,7 @@ class NodeSection:
def __post_init__(self):
self.nodes = [
Node(
- nr=int(n.attrib["nr"]),
+ nr=int(n.attrib.get("nr", 0)),
x=float(n.attrib["x"]),
y=float(n.attrib["y"]),
sam=_to_bool(n.attrib.get("sam")),
@@ -232,6 +232,9 @@ def area(self) -> float:
@property
def cell_type(self) -> int:
return int(self.attributes.get("cell_type", 0))
+ @property
+ def target_area(self) -> float:
+ return float(self.attributes.get("target_area", 0.0))
@dataclass
| |