internal string getInternalName(string actionName, string exceptionStackTrace, bool processLinks = true, params string[] linksConcerned) { TransitionLink transitionLink = getTransitionLinkByTransitionLabel(actionName); if (transitionLink != null) { string logic = transitionLink.logic; // Check logic expression if (ExpressionParser.isValid(transitionLink)) { List <List <string> > groupAndByOr = getPossibleSetOfLinks(actionName, exceptionStackTrace); // If we have to process links and linksConcerned is empty and we have at least one OR statement into logic expression (i.e. at least 2 AND groups) => problem, developer has to specify the set of links concerned by this transition. if (processLinks && linksConcerned.Length == 0 && groupAndByOr.Count > 1) { string availableCombination = "\nAvailable combination of links:\n"; foreach (List <string> ands in groupAndByOr) { availableCombination = availableCombination + " -"; foreach (string token in ands) { availableCombination = availableCombination + " " + token; } availableCombination = availableCombination + "\n"; } throw new TraceAborted("Distributed logic expression for \"" + actionName + "\" action in \"" + this.gameObject.name + "\" Game Object contains \"+\" operator. You have to specify which links are concerned to perform this game action. " + availableCombination, exceptionStackTrace); } else { string prefix = this.gameObject.name + "_"; bool linksFound = false; if (groupAndByOr.Count <= 1) { // If logic expression is empty or contains only AND operators, linksConcerned parameter is not useful because there is no ambiguity on this transition. linksFound = true; if (linksConcerned.Length > 0) { WarningException we = new WarningException("Because logic expression includes only \"*\" operators, \"linksConcerned\" parameters are ignored. You can remove them to the call.", exceptionStackTrace); Debug.LogException(we); } } else { if (!processLinks) { // Developer wants to ignore linksConcerned. So we trace the first one (From Laalys point of view this is not a problem because all or actions have the same public name). prefix = "or0_" + prefix; linksFound = true; } else { // Look for links concerned into distributed logic expression List <string> linksConcerned_sorted = linksConcerned.ToList(); linksConcerned_sorted.Sort(); for (int i = 0; i < groupAndByOr.Count; i++) { groupAndByOr [i].Sort(); if (groupAndByOr [i].SequenceEqual(linksConcerned_sorted)) { if (i > 0) { prefix = "or" + (i - 1) + "_" + prefix; } linksFound = true; break; } } } } if (linksFound) { return(prefix + actionName + "_" + this.id); } else { string debug = ""; foreach (string link in linksConcerned) { debug = debug + " \"" + link + "\""; } string availableCombination = "\nAvailable combination of links:\n"; foreach (List <string> ands in groupAndByOr) { availableCombination = availableCombination + " -"; foreach (string token in ands) { availableCombination = availableCombination + " " + token; } availableCombination = availableCombination + "\n"; } throw new TraceAborted(debug + " not found into distributed logic expression for \"" + actionName + "\" action in \"" + this.gameObject.name + "\" Game Object. " + availableCombination, exceptionStackTrace); } } } else { throw new TraceAborted("Logic expression for \"" + actionName + "\" action in \"" + this.gameObject.name + "\" Game Object is not valid.", exceptionStackTrace); } } else { throw new TraceAborted("Action \"" + actionName + "\" is not monitored by \"" + this.gameObject.name + "\" Game Object.", exceptionStackTrace); } }
private void GeneratePNandFeatures() { // List of full Petri nets // Key => Petri net name defined inside monitor.fullPn // Value => Pair <PetriNet, offsetX> Dictionary <string, KeyValuePair <PetriNet, float> > petriNets = new Dictionary <string, KeyValuePair <PetriNet, float> >(); bool abort = false; MonitoringManager mm = (MonitoringManager)target; // Fill final PN foreach (ComponentMonitoring monitor in Resources.FindObjectsOfTypeAll <ComponentMonitoring> ()) { // Get full Petri net for this monitor if (monitor.fullPnSelected >= mm.PetriNetsName.Count) { monitor.fullPnSelected = 0; } string fullName = mm.PetriNetsName[monitor.fullPnSelected]; if (!petriNets.ContainsKey(fullName)) { petriNets[fullName] = new KeyValuePair <PetriNet, float>(new PetriNet(), 0); } PetriNet fullPn = petriNets[fullName].Key; float offsetX = petriNets[fullName].Value; // Check if PN exists if (monitor.PetriNet != null && !abort) { // Make a copy of local PN in order to organise it spatially without changing original PN PetriNet tmpPN = new PetriNet(monitor.PetriNet, monitor.gameObject.name); tmpPN.addWidth(offsetX); fullPn.addSubNet(tmpPN); // Process links foreach (TransitionLink transitionLink in monitor.transitionLinks) { // Check if all links target the same fullPn foreach (Link curLink in transitionLink.links) { if (!curLink.isCompatibleWithPnName(monitor.fullPnSelected)) { abort = true; EditorUtility.DisplayDialog("Error, building aborted", "The action \"" + transitionLink.transition.label + "\" of monitor \"" + monitor.gameObject.name + " (ref: " + monitor.id + ")\" is linked with GameObject \"" + curLink.linkedObject.name + "\" (label: \"" + curLink.label + "\"). But these two elements are not affected to the same full Petri net.\n\nPlease review your configurations and try again.", "Close"); } } // Make a copy of current transition and prefix its name with its game object name Node curTransition_copy = new Node(transitionLink.transition); string publicLabel = curTransition_copy.label + " "; if (curTransition_copy.overridedLabel != null && !curTransition_copy.overridedLabel.Equals("")) { publicLabel = curTransition_copy.overridedLabel + " "; } if (monitor is FamilyMonitoring) { publicLabel = publicLabel + ((FamilyMonitoring)monitor).equivalentName; } else { publicLabel = publicLabel + monitor.gameObject.name; } curTransition_copy.label = monitor.gameObject.name + "_" + curTransition_copy.label; // Add this transition to Features XmlHandler.addFeature(fullName, curTransition_copy.label + "_" + monitor.id, publicLabel, transitionLink.isSystemAction, transitionLink.isEndAction); Node oldTransition = curTransition_copy; if (isNullOrWhiteSpace(transitionLink.logic)) { // Default : And of all link foreach (Link curLink in transitionLink.links) { if (curLink.linkedObject != null) { // Make a copy of linked place and prefix its name with its game object name Node linkedPlace = curLink.getPlace(); if (linkedPlace != null) { Node linkedPlace_copy = new Node(linkedPlace); linkedPlace_copy.label = curLink.linkedObject.name + "_" + linkedPlace_copy.label; // Define arc type ArcType arcType = curLink.type == 2 ? Arc.stringToArcType(Arc.optType.ElementAt(curLink.flagsType)) : ArcType.regular; // Create arc between Transition and linked place (depends on Get/Produce/Require diffusion state) fullPn.arcs.Add(curLink.type != 1 ? new Arc(linkedPlace_copy, curTransition_copy, arcType, curLink.weight) : new Arc(curTransition_copy, linkedPlace_copy, arcType, curLink.weight)); } } } } else { if (ExpressionParser.isValid(transitionLink)) { // Logic expression is valid // Distribute expression string[] exp = ExpressionParser.getDistribution(transitionLink.logic); int or = 0; // Parse distributed expression foreach (string token in exp) { // Check if current token is an operator if (!token.Equals("+") && !token.Equals("*")) { // It's not an operator => we load the link Link curLink = transitionLink.getLabeledLink(token); if (curLink.linkedObject != null) { // Make a copy of linked place and prefix its name with its game object name Node linkedPlace = curLink.getPlace(); if (linkedPlace != null) { Node linkedPlace_copy = new Node(linkedPlace); linkedPlace_copy.label = curLink.linkedObject.name + "_" + linkedPlace_copy.label; // Define arc type ArcType arcType = curLink.type == 2 ? Arc.stringToArcType(Arc.optType.ElementAt(curLink.flagsType)) : ArcType.regular; // Create arc between Transition and linked place (depends on Get/Produce/Require diffusion state) fullPn.arcs.Add(curLink.type != 1 ? new Arc(linkedPlace_copy, curTransition_copy, arcType, curLink.weight) : new Arc(curTransition_copy, linkedPlace_copy, arcType, curLink.weight)); } } } else if (token.Equals("+")) { // We detect OR operator => add a new transition and set it as current node // Build new transition, we keep old transition to build links after // Add offset to position curTransition_copy.position.x += offsetX; curTransition_copy.position.y += 50; curTransition_copy = new Node("or" + (or++) + "_" + oldTransition.label, curTransition_copy.id, curTransition_copy.offset, curTransition_copy.initialMarking, curTransition_copy.position); // Add this new transition to PN fullPn.transitions.Add(curTransition_copy); // and to features XmlHandler.addFeature(fullName, curTransition_copy.label + "_" + monitor.id, publicLabel, transitionLink.isSystemAction, transitionLink.isEndAction); // Duplicate arcs from old transition foreach (Arc a in tmpPN.getConcernedArcs(oldTransition)) { if (a.target.label.Equals(oldTransition.label)) { fullPn.arcs.Add(new Arc(a.source, curTransition_copy, a.type, a.weight)); } else if (a.source.label.Equals(oldTransition.label)) { fullPn.arcs.Add(new Arc(curTransition_copy, a.target, a.type, a.weight)); } } } } } else { UnityEngine.Debug.LogError("Petri Net Building aborted: Logic expression of \"" + transitionLink.transition.label + "\" action from \"" + monitor.gameObject.name + "\" is not valid => \"" + transitionLink.logic + "\". Please check it from Monitor edit view."); } } } petriNets[fullName] = new KeyValuePair <PetriNet, float>(fullPn, offsetX + monitor.PetriNet.getWidth() + 50); // Add spaces between PN } } if (!abort) { // Save all Petri nets foreach (KeyValuePair <string, KeyValuePair <PetriNet, float> > pn in petriNets) { PnmlParser.SaveAtPath(pn.Value.Key, pn.Key + ".pnml"); } // and features XmlHandler.saveFeatures(); EditorUtility.DisplayDialog("Files built", "Files have been saved into \"completeNets\" and \"features\" folders of this Unity project", "Close"); } }