//*************************************************************** // Copyright 2008 Centre For Advanced Spatial Analysis, UCL // // Author: Joel Dearden, University College London // // Contact: j.dearden@ucl.ac.uk // // Joel Dearden, // Centre for Advanced Spatial Analysis, // University College London, // 1-19 Torrington Place, // London, // WC1E 7HB // // // This file is part of SLSegregationModel. // // SLSegregationModel is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // SLSegregationModel is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with SLSegregationModel. If not, see . // //*************************************************************** integer totalAgentsOfEachType = 48; integer currentHappyRed = totalAgentsOfEachType; //agents all start happy integer currentHappyBlue = totalAgentsOfEachType; //agents all start happy integer totalAgentMoves = 0; integer maxVisibleAgentMoves = 200; //any moves after this will not be drawn integer talkToGrapher = -77662; integer talkToLineSegments = -88821; //total happy agents (vertical) axis is POSITIVE Z float oneVerticalUnit = 0.143; //total agent moves (horizontal) axis is NEGATIVE Y float oneHorizontalUnit = 0.071; vector previousBlueLineSegmentPosition; vector previousRedLineSegmentPosition; integer firstRedLineSegment = TRUE; integer firstBlueLineSegment = TRUE; //to cope with large graph sizes (e.g. 16m wide) the grapher is positioned half way along the graph //so that line segments can still be rezzed within the 10m range limit vector calculateFirstHalfSegmentPos( vector horizontalUnitVector, integer horizontalValue, vector verticalUnitVector, integer verticalValue ) { vector segmentPos = llGetPos(); //first half position = (totalAgentMoves * horizontal unit) - (maxMoves/2 * horizontal unit) segmentPos += verticalUnitVector * verticalValue; segmentPos += (horizontalValue * horizontalUnitVector) - ((maxVisibleAgentMoves/2) * horizontalUnitVector); return segmentPos; } vector calculateSecondHalfSegmentPos( vector horizontalUnitVector, integer horizontalValue, vector verticalUnitVector, integer verticalValue ) { vector segmentPos = llGetPos(); //second half position = (totalAgentMoves * horizontal unit) segmentPos += verticalUnitVector * verticalValue; segmentPos += (horizontalValue * horizontalUnitVector); return segmentPos; } buildNextBlueLineSegment() { if(firstBlueLineSegment == TRUE) { //nothing to draw //just calculate position and save it for second line segment vector worldPositiveZ = <0,0,1>; vector localPositiveZ = worldPositiveZ * llGetRot(); vector worldNegativeY = <0,-1,0>; vector localNegativeY = worldNegativeY * llGetRot(); //calculate segment position - must be in first half of graph vector segmentPos = calculateFirstHalfSegmentPos( (localNegativeY * oneHorizontalUnit), totalAgentMoves, (localPositiveZ * oneVerticalUnit), currentHappyBlue ); //save current position for next time previousBlueLineSegmentPosition = segmentPos; firstBlueLineSegment = FALSE; } else { //calculate position for next line segment end... vector worldPositiveZ = <0,0,1>; vector localPositiveZ = worldPositiveZ * llGetRot(); vector worldNegativeY = <0,-1,0>; vector localNegativeY = worldNegativeY * llGetRot(); //rez next part of blue line at line segment end //(it will adjust its own position, scale and rotation to fit the line) vector segmentPos; if(totalAgentMoves < (maxVisibleAgentMoves/2)) { segmentPos = calculateFirstHalfSegmentPos( (localNegativeY * oneHorizontalUnit), totalAgentMoves, (localPositiveZ * oneVerticalUnit), currentHappyBlue ); } else { segmentPos = calculateSecondHalfSegmentPos( (localNegativeY * oneHorizontalUnit), totalAgentMoves, (localPositiveZ * oneVerticalUnit), currentHappyBlue ); } llRezObject("blueLineSegment", segmentPos, <0,0,0>, llGetRot(), 0); //send previous line segment position to new line segment by chat message llSay(talkToLineSegments, "pbp:" + (string) previousBlueLineSegmentPosition); //save current position for next time previousBlueLineSegmentPosition = segmentPos; } } buildNextRedLineSegment() { if(firstRedLineSegment == TRUE) { //nothing to draw //just calculate position and save it for second line segment vector worldPositiveZ = <0,0,1>; vector localPositiveZ = worldPositiveZ * llGetRot(); vector worldNegativeY = <0,-1,0>; vector localNegativeY = worldNegativeY * llGetRot(); //calculate segment position - must be in first half of graph vector segmentPos = calculateFirstHalfSegmentPos( (localNegativeY * oneHorizontalUnit), totalAgentMoves, (localPositiveZ * oneVerticalUnit), currentHappyRed ); //save current position for next time previousRedLineSegmentPosition = segmentPos; firstRedLineSegment = FALSE; } else { //calculate position for next line segment end... vector worldPositiveZ = <0,0,1>; vector localPositiveZ = worldPositiveZ * llGetRot(); vector worldNegativeY = <0,-1,0>; vector localNegativeY = worldNegativeY * llGetRot(); //rez next part of red line at line segment end //(it will adjust its own position, scale and rotation to fit the line) vector segmentPos; if(totalAgentMoves < (maxVisibleAgentMoves/2)) { segmentPos = calculateFirstHalfSegmentPos( (localNegativeY * oneHorizontalUnit), totalAgentMoves, (localPositiveZ * oneVerticalUnit), currentHappyRed ); } else { segmentPos = calculateSecondHalfSegmentPos( (localNegativeY * oneHorizontalUnit), totalAgentMoves, (localPositiveZ * oneVerticalUnit), currentHappyRed ); } llRezObject("redLineSegment", segmentPos, <0,0,0>, llGetRot(), 0); //send previous line segment position to new line segment by chat message llSay(talkToLineSegments, "prp:" + (string) previousRedLineSegmentPosition); //save current position for next time previousRedLineSegmentPosition = segmentPos; } } default { state_entry() { state new_graph; } } state new_graph { state_entry() { llOwnerSay("clearing any old lines away...."); //clear red and blue line segments llSay(talkToLineSegments, "die"); llSleep(1.0); //tell them twice in case they didn't hear the first time llSay(talkToLineSegments, "die"); currentHappyRed = totalAgentsOfEachType; currentHappyBlue = totalAgentsOfEachType; totalAgentMoves = 0; firstBlueLineSegment = TRUE; firstRedLineSegment = TRUE; llOwnerSay("ready to construct new graph"); state building_graph; } } state building_graph { state_entry() { llOwnerSay("building graph..."); //listen for controller and agents llListen(talkToGrapher, "", NULL_KEY, ""); } listen(integer channel, string name, key id, string message) { llOwnerSay("got message:" + message); if(channel == talkToGrapher) { //controller new-grid message if(message == "NEW") { state new_graph; } //controller total-agent-moves message if(llGetSubString(message, 0, 2) == "TM:") { totalAgentMoves = (integer) llGetSubString(message, 3, -1); llOwnerSay("DEBUG: totalAgentMoves=" + (string)totalAgentMoves); //any more line left to build? if(totalAgentMoves <= maxVisibleAgentMoves) { llOwnerSay("DEBUG: more lines left to build..."); //do we need to visualise this move? if(totalAgentMoves % 5 == 0) { llOwnerSay("DEBUG: building new line segments"); //yes buildNextBlueLineSegment(); buildNextRedLineSegment(); } } } //agent state change message if(message == "bhs") { //blue-happy-to-sad currentHappyBlue--; } if(message == "bsh") { //blue-sad-to-happy currentHappyBlue++; } if(message == "rhs") { //red-happy-to-sad currentHappyRed--; } if(message == "rsh") { //red-sad-to-happy currentHappyRed++; } } } }