# HG changeset patch # User veltr # Date 1352910366 -3600 # Node ID 4baa7530912cc4cb143b5328a0188e9e094a41a5 # Parent e05da377a27e8caa624f715ba5a86f488e630699 Corrected MDP Embed diff -r e05da377a27e -r 4baa7530912c src/hp/settings.py --- a/src/hp/settings.py Wed Nov 14 16:35:12 2012 +0100 +++ b/src/hp/settings.py Wed Nov 14 17:26:06 2012 +0100 @@ -163,8 +163,8 @@ } } -LDT_DOMAIN = 'http://localhost' -LDT_BASE_URL = LDT_DOMAIN + '/~ymh/hp_ldt/' +LDT_DOMAIN = 'http://capsicum' +LDT_BASE_URL = LDT_DOMAIN + '/pf/' LDT_URL = LDT_BASE_URL + "ldtplatform/" LDT_API_URL = LDT_URL + 'api/ldt/1.0/' LDT_STATIC_URL = LDT_BASE_URL + "static/site/" diff -r e05da377a27e -r 4baa7530912c src/hp/static/hp/css/player.css --- a/src/hp/static/hp/css/player.css Wed Nov 14 16:35:12 2012 +0100 +++ b/src/hp/static/hp/css/player.css Wed Nov 14 17:26:06 2012 +0100 @@ -11,39 +11,3 @@ .right-column h2 { text-align: right; } - -.related-video { - width: 235px; float: left; margin-bottom: 10px; -} - -.related-video:nth-child(even) { - margin-left: 10px; -} - -.related-video a { - display: block; clear: both; text-decoration: none; -} - -.related-video img { - max-width: 120px; max-height: 90px; float: left; -} - -.related-video h3, p { - margin: 0 0 5px 125px; -} - -.related-video h3 { - font-size: 14px; font-weight: 600; color: #330099; -} - -.related-video h3:hover { - text-decoration: underline; -} - -.related-video p { - font-size: 12px; -} - -.video-duration { - color: #c00000; -} diff -r e05da377a27e -r 4baa7530912c src/hp/static/hp/tmgraph/constants.pde --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/hp/static/hp/tmgraph/constants.pde Wed Nov 14 17:26:06 2012 +0100 @@ -0,0 +1,266 @@ +////////// CONSTANTS ////////// +static final int LABEL_LENGTH = 24; +static final float GAP = 8; +static final float sigma = 0.01; +static final float FRAME = 24; +static final float TICK = 1;//0.5f; +static final float SPRING_LENGTH = 100; +static final float SPRING_STRENGTH = 0.4; // 0.2; +static final float SPRING_DAMPING = 0.4; // 0.2; +static final float SPACER_STRENGTH = 2000; +static final float DRAGFACTOR = 0.2; //0.2 +static final float REDUCE = 1; +static final float MAX_DISTANCE = 600; +static final float MIN_DISTANCE = 24;//6; +static final float MAX_VELOCITY = 48;//20; //8; + +// mouse event +static final int MOVED = 1, + DRAGGED = 2, + CLICKED = 3, + RELEASED = 4; +// touch event +static final int MOVE = 6, + START = 7, + END = 8; +// motion +static final int HALT = 11, + MOVING = 12, + DRAGGING = 13, + DRAG = 14, + UP = 15; +// action +static final int NOOP = 20, + CLICK = 21, + RELEASE = 22, + DOUBLECLICK = 23, + HOLDING = 24, + HOLDED = 25; +// node menu +static final int EXPND = 31, + ROOT = 32, + FIX = 33, + FREE = 34, + HIDE = 35, + INFO = 36, + NEWREL = 37, + NEWREL2 = 30, + SQUEEZE = 38, + TOPIC = 39; +// application menu +static final int FITALL = 41, + ALLFIX = 42, + ALLFREE = 43, + GROUPSHAPE = 44, + ALLSAVE = 45, + ALLRETRIEVE = 46, + NEWTOPIC = 47, + MODE = 48, + PEDIA = 49; +// edge menu +static final int HIDEEDGE = 51, + EDITEDGE = 52, + DELETEEDGE = 53; + +static final int AliceBlue = #F0F8FF; +static final int AntiqueWhite = #FAEBD7; +static final int Aqua = #00FFFF; +static final int Aquamarine = #7FFFD4; +static final int Azure = #F0FFFF; +static final int Beige = #F5F5DC; +static final int Bisque = #FFE4C4; +static final int Black = #000000; +static final int BlanchedAlmond = #FFEBCD; +static final int Blue = #0000FF; +static final int BlueViolet = #8A2BE2; +static final int Brown = #A52A2A; +static final int BurlyWood = #DEB887; +static final int CadetBlue = #5F9EA0; +static final int Chartreuse = #7FFF00; +static final int Chocolate = #D2691E; +static final int Coral = #FF7F50; +static final int CornflowerBlue = #6495ED; +static final int Cornsilk = #FFF8DC; +static final int Crimson = #DC143C; +static final int Cyan = #00FFFF; +static final int DarkBlue = #00008B; +static final int DarkCyan = #008B8B; +static final int DarkGoldenRod = #B8860B; +static final int DarkGray = #A9A9A9; +static final int DarkGrey = #A9A9A9; +static final int DarkGreen = #006400; +static final int DarkKhaki = #BDB76B; +static final int DarkMagenta = #8B008B; +static final int DarkOliveGreen = #556B2F; +static final int Darkorange = #FF8C00; +static final int DarkOrchid = #9932CC; +static final int DarkRed = #8B0000; +static final int DarkSalmon = #E9967A; +static final int DarkSeaGreen = #8FBC8F; +static final int DarkSlateBlue = #483D8B; +static final int DarkSlateGray = #2F4F4F; +static final int DarkSlateGrey = #2F4F4F; +static final int DarkTurquoise = #00CED1; +static final int DarkViolet = #9400D3; +static final int DeepPink = #FF1493; +static final int DeepSkyBlue = #00BFFF; +static final int DimGray = #696969; +static final int DimGrey = #696969; +static final int DodgerBlue = #1E90FF; +static final int FireBrick = #B22222; +static final int FloralWhite = #FFFAF0; +static final int ForestGreen = #228B22; +static final int Fuchsia = #FF00FF; +static final int Gainsboro = #DCDCDC; +static final int GhostWhite = #F8F8FF; +static final int Gold = #FFD700; +static final int GoldenRod = #DAA520; +static final int Gray = #808080; +static final int Grey = #808080; +static final int Green = #008000; +static final int GreenYellow = #ADFF2F; +static final int HoneyDew = #F0FFF0; +static final int HotPink = #FF69B4; +static final int IndianRed = #CD5C5C; +static final int Indigo = #4B0082; +static final int Ivory = #FFFFF0; +static final int Khaki = #F0E68C; +static final int Lavender = #E6E6FA; +static final int LavenderBlush = #FFF0F5; +static final int LawnGreen = #7CFC00; +static final int LemonChiffon = #FFFACD; +static final int LightBlue = #ADD8E6; +static final int LightCoral = #F08080; +static final int LightCyan = #E0FFFF; +static final int LightGoldenRodYellow = #FAFAD2; +static final int LightGray = #D3D3D3; +static final int LightGrey = #D3D3D3; +static final int LightGreen = #90EE90; +static final int LightPink = #FFB6C1; +static final int LightSalmon = #FFA07A; +static final int LightSeaGreen = #20B2AA; +static final int LightSkyBlue = #87CEFA; +static final int LightSlateGray = #778899; +static final int LightSlateGrey = #778899; +static final int LightSteelBlue = #B0C4DE; +static final int LightYellow = #FFFFE0; +static final int Lime = #00FF00; +static final int LimeGreen = #32CD32; +static final int Linen = #FAF0E6; +static final int Magenta = #FF00FF; +static final int Maroon = #800000; +static final int MediumAquaMarine = #66CDAA; +static final int MediumBlue = #0000CD; +static final int MediumOrchid = #BA55D3; +static final int MediumPurple = #9370D8; +static final int MediumSeaGreen = #3CB371; +static final int MediumSlateBlue = #7B68EE; +static final int MediumSpringGreen = #00FA9A; +static final int MediumTurquoise = #48D1CC; +static final int MediumVioletRed = #C71585; +static final int MidnightBlue = #191970; +static final int MintCream = #F5FFFA; +static final int MistyRose = #FFE4E1; +static final int Moccasin = #FFE4B5; +static final int NavajoWhite = #FFDEAD; +static final int Navy = #000080; +static final int OldLace = #FDF5E6; +static final int Olive = #808000; +static final int OliveDrab = #6B8E23; +static final int Orange = #FFA500; +static final int OrangeRed = #FF4500; +static final int Orchid = #DA70D6; +static final int PaleGoldenRod = #EEE8AA; +static final int PaleGreen = #98FB98; +static final int PaleTurquoise = #AFEEEE; +static final int PaleVioletRed = #D87093; +static final int PapayaWhip = #FFEFD5; +static final int PeachPuff = #FFDAB9; +static final int Peru = #CD853F; +static final int Pink = #FFC0CB; +static final int Plum = #DDA0DD; +static final int PowderBlue = #B0E0E6; +static final int Purple = #800080; +static final int Red = #FF0000; +static final int RosyBrown = #BC8F8F; +static final int RoyalBlue = #4169E1; +static final int SaddleBrown = #8B4513; +static final int Salmon = #FA8072; +static final int SandyBrown = #F4A460; +static final int SeaGreen = #2E8B57; +static final int SeaShell = #FFF5EE; +static final int Sienna = #A0522D; +static final int Silver = #C0C0C0; +static final int SkyBlue = #87CEEB; +static final int SlateBlue = #6A5ACD; +static final int SlateGray = #708090; +static final int SlateGrey = #708090; +static final int Snow = #FFFAFA; +static final int SpringGreen = #00FF7F; +static final int SteelBlue = #4682B4; +static final int Tan = #D2B48C; +static final int Teal = #008080; +static final int Thistle = #D8BFD8; +static final int Tomato = #FF6347; +static final int Turquoise = #40E0D0; +static final int Violet = #EE82EE; +static final int Wheat = #F5DEB3; +static final int White = #FFFFFF; +static final int WhiteSmoke = #F5F5F5; +static final int Yellow = #FFFF00; +static final int YellowGreen = #9ACD32; + +static final color nodeColor = LightYellow; +static final color selectColor = Gold; +static final color selectedColor = SpringGreen; +static final color rootColor = Darkorange; +static final color fixedColor = HotPink; +static final color edgeColor = 0xFF80A0A0; + +////////// TO STRING /////////////////////////////////////////////// +String toStr(int i) { + switch(i) { +// Event + case MOVED: return "MOVED"; + case DRAGGED: return "DRAGGED"; + case CLICKED: return "CLICKED"; + case RELEASED: return "RELEASED"; + case START: return "START"; + case MOVE: return "MOVE"; + case END: return "END"; +// Motion + case HALT: return "HALT"; + case MOVING: return "MOVING"; + case DRAGGING: return "DRAGGING"; + case DRAG: return "DRAG"; +// Action + case NOOP: return "NOOP"; + case CLICK: return "CLICK"; + case RELEASE: return "RELEASE"; + case DOUBLECLICK: return "DOUBLECLICK"; + case HOLDING: return "HOLDING"; + case HOLDED: return "HOLDED"; + default: return ""; +// menu + case EXPND: return "EXPAND"; + case ROOT: return "ROOT"; + case FIX: return "FIX"; + case FREE: return "FREE"; + case HIDE: return "HIDE"; + case INFO: return "INFO"; + case NEWREL: return "NEWREL"; + case NEWREL2: return "NEWREL2"; + case SQUEEZE: return "SQUEEZE"; + case TOPIC: return "TOPIC"; +// apmenu + case FITALL: return "FITALL"; + case ALLFIX: return "ALLFIX"; + case ALLFREE: return "ALLFREE"; + case GROUPSHAPE: return "GROUPSHAPE"; + case ALLSAVE: return "ALLSAVE"; + case ALLRETRIEVE: return "ALLRETRIEVE"; + case NEWTOPIC: return "NEWTOPIC"; + } +} + + diff -r e05da377a27e -r 4baa7530912c src/hp/static/hp/tmgraph/event.pde --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/hp/static/hp/tmgraph/event.pde Wed Nov 14 17:26:06 2012 +0100 @@ -0,0 +1,437 @@ +boolean isMouse=true; +int mouse_event=0, + mouse_motion=HALT, + mouse_action=NOOP; +int touch_event=0, + touch_motion=UP, + touch_action=NOOP; +int touch_count; +boolean is_down; +boolean touchedH, touchedC, touchedD; +float startH, startC, startD; +float elapsedTimeHold, elapsedTimeClick, elapsedTimeDoubleClick; +float holdX, holdY; + +////////// EVENT ACTION ///////////////////////////// +void doMove(float x, float y) { + event = "Move"; + if (menu_active || apmenu_active || edgmenu_active) return; + adjustCoordinates(Math.round(x), Math.round(y)); + pressStartX = pointX; + pressStartY = pointY; + doSelectEdge(); + doSelectNode(); +} + +void doClick(float x, float y) { + event = "Click"; + adjustCoordinates(Math.round(x), Math.round(y)); + pressStartX = pointX; + pressStartY = pointY; + doSelectEdge(); + doSelectNode(); + if (mouseButton == RIGHT) { + if (selection != null && selected == null && !menu_active) + doBeginMenu(); + else if (sel_edge != null && !edgmenu_active) + doBeginEdgMenu(); + else if (selection == null && !apmenu_active) + doBeginApMenu(); + } + else if (from_node == null && selection != null && selected == null) { + if (debug) println("doExpandNode"); + doExpandNode(selection); + } + else if (from_node != null) { + if (debug) println("new_relation("+from_node.name+", "+selection.name+")"); + String id = from_node.id; + String name = from_node.name; + String grp = from_node.grp; + String proj = from_node.proj; + if (grp==null) grp=""; + String to_id, to_name, to_grp, to_proj; + if (selection != null) { + to_node = selection; + to_id = to_node.id; + to_name = to_node.name; + to_grp = to_node.grp; + to_proj = to_node.proj; + if (to_grp==null) to_grp=""; + to_node = null; + } + else { + to_id = ""; + to_name = ""; + to_grp = ""; + to_proj = ""; + } + from_node = null; + if (debug) println("javascript.new_relation2("+id+", "+name+", "+grp+", "+proj+", "+to_id+", "+to_name+", "+to_grp+", "+to_proj+")"); + javascript.new_relation(id, name, grp, proj, to_id, to_name, to_grp, to_proj); + } + else if (menu_active && selected != null) { + if (debug) println("doMenu " + nls(menu,ln) ); + doMenu(); + } + else if (edgmenu_active && sel_edge != null) { + doEdgMenu(); + } + else if (apmenu_active) { + doApMenu(); + } + dragging = false; +} + +void doDoubleClick(float x, float y) { + event = "DoubleClick"; + if (selection != null && selected == null) { + rootNode(selection); + } +} + +void doHold(float x, float y) { + event = "Hold"; + if (selection != null && selected == null) { + doBeginMenu(); + } + else if (sel_edge != null) { + doBeginEdgMenu(); + } + else if (selection == null) { + doBeginApMenu(); + } +} + +void doDrag(float x, float y) { + event = "Drag"; + adjustCoordinates(Math.round(x), Math.round(y)); + if (menu_active == false && apmenu_active == false) { + if (selection != null) { + doDragNode(); + dragging = false; + } + else { + dragging = true; + } + } +} + +void doReleased(float x, float y) { + event = "Released"; + adjustCoordinates(Math.round(x), Math.round(y)); + if (dragging) { + doUpdateNodePosition(); + } + dragging = false; + menu = 0; + selection = null; + previous_selection = null; + //javascript.end_select(); +} + +////////// MOUSE EVENT DETECTION /////////////////////////////////// +void mouseMoved() { + //if (debug) print("\tmouseMoved"); + is_down = false; + if (!isMouse) return; + mouse_event = MOVED; + mouse_motion = MOVING; + doEvent(mouseX, mouseY); +} + +void mouseDragged() { + //if (debug) print("\tmouseDragged"); + is_down = true; + if (!isMouse) return; + if (mouse_action==HOLDED) { //Handling wrong dragging status after holding + //if (debug) print("\tMoved"); + is_down = false; + mouse_event = MOVED; + mouse_motion = MOVING; + } else { + //if (debug) print("\tDragged"); + mouse_event = DRAGGED; + mouse_motion = DRAGGING; + } + doEvent(mouseX, mouseY); +} +void mouseClicked() { + //if (debug) print("\nmouseClicked"); + is_down = true; + if (!isMouse) return; + mouse_event = CLICKED; + doEvent(mouseX, mouseY); +} +void mouseReleased() { + //if (debug) print("\nmouseReleased"); + is_down = false; + if (!isMouse) return; + mouse_event = RELEASED; + doEvent(mouseX, mouseY); +} + +////////// MOUSE EVENT HANDLING //////////////////////////// +void doEvent(float x, float y) { + //if (debug) print( "\ndoEvent event=" + toStr(mouse_event) + "\taction=" + toStr(mouse_action) + "\tmotion=" + toStr(mouse_motion) ); + switch (mouse_event) { + case CLICKED: + //if (debug) print("\nCLICKED"); + checkClickTimer(x, y); + checkDoubleClickTimer(x, y); + break; + case RELEASED: + //if (debug) print("\nRELEASED"); + checkClickTimer(x, y); + if (mouse_motion == DRAGGING) { // TO DETECT RELEASE AFTER DRAGGINNG + mouse_action = RELEASE; + doReleased(x, y); + stopClickTimer(); + stopDoubleClickTimer(); + stopHoldTimer(); + } else if (mouse_motion == MOVING) { // TO CATCH CLICK DUE TO NO CLICKED AFTER HOLDING + mouse_action = CLICK; + doClick(x, y); + stopClickTimer(); + stopDoubleClickTimer(); + stopHoldTimer(); + } + break; + case MOVED: + //if (debug) print("\nMOVED"); + mouse_motion = MOVING; + doMove(x, y); + stopClickTimer(); + stopDoubleClickTimer(); + stopHoldTimer(); + break; + case DRAGGED: + //if (debug) print("\nDRAGGED"); + mouse_motion = DRAGGING; + doDrag(x, y); + stopClickTimer(); + stopDoubleClickTimer(); + stopHoldTimer(); + break; + default: + } +} +////////// TOUCH EVENT DETECTION /////////////////////////////////// +// Following functions are used for iPad(iOS) + +void touchMove(TouchEvent touchEvent) { //Comment out while debugging. These routines are for iPad. + //if (debug) print("\ttouchMove"); + isMouse=false; + is_down = true; + touch_event = MOVE; + // draw circles at where fingers touch + touch_count = touchEvent.touches.length; + for (int i = 0; i < touch_count; i++) { + int x = touchEvent.touches[i].offsetX; + int y = touchEvent.touches[i].offsetY; + fill(128,128,128); + ellipse(x, y, 10, 10); + } + if (touch_count > 1) { + currtXa = touchEvent.touches[0].offsetX; + currtYa = touchEvent.touches[0].offsetY; + currtXb = touchEvent.touches[1].offsetX; + currtYb = touchEvent.touches[1].offsetY; + currt_dist = Math.sqrt((currtXa - currtXb)*(currtXa - currtXb) + (currtYa - currtYb)*(currtYa - currtYb)); + scl = currt_dist / start_dist; + zoom(scl); + javascript.setscale(scl); + } + if (touch_count==1) { + touchX = touchEvent.touches[0].offsetX; + touchY = touchEvent.touches[0].offsetY; + fill(128,64,64); + ellipse(touchX, touchY, 10, 10); + doTouch(touchX, touchY); + } +} + +void touchEnd(TouchEvent touchEvent) { + //if (debug) print("\ttouchEnd"); + touch_event = END; + isMouse=false; + is_down = false; + if (touch_count==1) { + doTouch(touchX, touchY); + } +} + +void touchStart(TouchEvent touchEvent) { + //if (debug) print("\ttouchStart"); + isMouse=false; + is_down = true; + // draw circles at where fingers touch + touch_count = touchEvent.touches.length; + for (int i = 0; i < touch_count; i++) { + int x = touchEvent.touches[i].offsetX; + int y = touchEvent.touches[i].offsetY; + fill(0,128,64); + ellipse(x, y, 10, 10); + } + if (touch_count > 1) { + startXa = touchEvent.touches[0].offsetX; + startYa = touchEvent.touches[0].offsetY; + startXb = touchEvent.touches[1].offsetX; + startYb = touchEvent.touches[1].offsetY; + start_dist = Math.sqrt((startXa - startXb)*(startXa - startXb) + (startYa - startYb)*(startYa - startYb)); + } + touchX = touchEvent.touches[0].offsetX; + touchY = touchEvent.touches[0].offsetY; + fill(64,128,255); + ellipse(touchX, touchY, 10, 10); + touch_event = START; + doTouch(touchX, touchY); +} + +////////// TOUCH EVENT HANDLING //////////////////////////////// +void doTouch(float x, float y) { + //if (debug) print("\ndoTouch event=" + toStr(touch_event)); + switch (touch_event) { + case START: + dragmode = !dragmode; + checkClickTimer(x, y); + checkDoubleClickTimer(x, y); + break; + case END: + mouse_motion = (mouse_motion==DRAGGING)? DRAG:UP; + checkClickTimer(x, y); + if (mouse_motion == DRAG) { // TO DETECT RELEASE AFTER DRAGGINNG + mouse_action = RELEASE; + doReleased(x, y); + } + stopClickTimer(); + stopDoubleClickTimer(); + stopHoldTimer(); + break; + case MOVE: + if (dragmode && selection==null) { + mouse_motion = MOVING; + doMove(x, y); + } + else { + mouse_motion = DRAGGING; + doDrag(x, y); + } + stopClickTimer(); + stopDoubleClickTimer(); + stopHoldTimer(); + break; + default: + } +} + +////////// TIMER /////////////////////////////////////////////// +void checkClickTimer(float x, float y) { + float current = millis()/1000F; + elapsedTimeClick = current - startC; // Get elapsed time in seconds + //if (debug) print("\n"+current+"\tCheck\tClick\ttouched="+touchedC+"\tstart="+startC+"\telapsed="+elapsedTimeClick); + if ( !touchedC ) { // IF Not touched + startClickTimer(); + } + else if ( touchedC ) { + if ( elapsedTimeClick < 1 ) { + //if (debug) print("\nCLICK"); + mouse_motion = HALT; + mouse_action = CLICK; + if (isMouse) doClick(mouseX, mouseY); + else doClick(touchX, touchY); + stopClickTimer(); + } + } +} +void startClickTimer() { + float current = millis()/1000F; + touchedC = true; + startC = millis()/1000F; // Get current time + elapsedTimeClick = 0; + //if (debug) print("\n"+current+"\tStart\tClick"); +} + +void stopClickTimer() { + touchedC = false; + elapsedTimeClick = 0; +} + +void checkDoubleClickTimer(float x, float y) { // This routine works only under PC Firefox. Other environment doesn't work. + float current = millis()/1000F; + elapsedTimeDoubleClick = current - startD; // Get elapsed time in seconds + //if (debug) print("\n"+current+"\tCheck\tDoubleClick\ttouched="+touchedD+"\tstart="+startD+"\telapsed="+elapsedTimeDoubleClick); + if ( !touchedD ) { // IF Not touched + startDoubleClickTimer(); + } + else if ( touchedD ) { + if ( elapsedTimeDoubleClick < 1 ) { + //if (debug) print("\nDOUBLE CLICK"); + mouse_motion = HALT; + mouse_action = DOUBLECLICK; + if (isMouse) doDoubleClick(mouseX, mouseY); + else doDoubleClick(touchX, touchY); + stopDoubleClickTimer(); + } + } +} + +void startDoubleClickTimer() { + float current = millis()/1000F; + touchedD = true; + startD = millis()/1000F; // Get current time + elapsedTimeDoubleClick = 0; + //if (debug) print("\n"+current+"\tStart\tDoubleClick"); +} + +void stopDoubleClickTimer() { // ditto. + touchedD = false; + elapsedTimeDoubleClick = 0; +} + +void checkHoldTimer() { + float current = millis()/1000F; + elapsedTimeHold = current - startH; // Get elapsed time in seconds + /*if (Math.round(elapsedTimeHold*10)%10==0) + if (debug) print("\n"+current+"\tCheck\tHold\ttouched="+touchedH+"\tstart="+startH+"\telapsed="+elapsedTimeHold); + */ + if ((isMouse && mousePressed && !(mouse_motion==MOVING && mouse_action==HOLDED)) + || (!isMouse && is_down)) { + if ( !touchedH ) { // IF Not touched + startHoldTimer(); + holdX = (isMouse)? mouseX:touchX; + holdY = (isMouse)? mouseY:touchY; + } + else if ( touchedH ) { + float currentX = (isMouse)? mouseX:touchX; + float currentY = (isMouse)? mouseY:touchY; + float dist2 = (currentX - holdX)*(currentX - holdX) + (currentY - holdY)*(currentY - holdY); + if ( dist2 < 16 && elapsedTimeHold > 0.5 ) { + //if (debug) print("\nHOLD"); + mouse_motion = HALT; + mouse_action = HOLDING; + if (isMouse) doHold(mouseX, mouseY); + else doHold(touchX, touchY); + mouse_action = HOLDED; + stopHoldTimer(); + } + } + } + else { + stopHoldTimer(); + } +} + +void startHoldTimer() { + touchedH = true; + float current = millis()/1000F; + startH = current; // Get current time + elapsedTimeHold = 0; + //if (debug) print("\n"+current+"\tStart\tHold"); +} + +void stopHoldTimer() { + touchedH = false; + elapsedTimeHold = 0; +} + + diff -r e05da377a27e -r 4baa7530912c src/hp/static/hp/tmgraph/initialdata.pde --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/hp/static/hp/tmgraph/initialdata.pde Wed Nov 14 17:26:06 2012 +0100 @@ -0,0 +1,10 @@ +//////// LOAD DATA /////////////////////////////////////////////////////////// +void loadData() { + +} + +void setNodeShapes() { + +} + + diff -r e05da377a27e -r 4baa7530912c src/hp/static/hp/tmgraph/javascript.pde --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/hp/static/hp/tmgraph/javascript.pde Wed Nov 14 17:26:06 2012 +0100 @@ -0,0 +1,27 @@ +//////// JAVASCRIPT ////////////////////////////////////////////////////////// +interface JavaScript { + void adjacentnodes(String id, String pj, String adj, String bd); + void selectnode(String id, String pj); + void selectedge(String s); + void topicnode(String s); + void setscale(float s); + void group_shapes(); + void allbackup(String s); + void allretrieve(String s); + void new_topic(); + void pedia(); + void set_mode(String lang, boolean d, boolean p, boolean u, String b, boolean ed); + void countassoc(String id, String pj); + void new_relation(String id, String name, String grp, String proj, String to_id, String to_name, String to_grp, String to_proj); + void new_select(String id, String proj); + void startexpand(); + void endexpand(); + void username(String uid); +} + +void bindJavascript(JavaScript js) { + javascript = js; +} + +JavaScript javascript; + diff -r e05da377a27e -r 4baa7530912c src/hp/static/hp/tmgraph/menu.pde --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/hp/static/hp/tmgraph/menu.pde Wed Nov 14 17:26:06 2012 +0100 @@ -0,0 +1,646 @@ +//////// USER INTERFACE ///////////////////////////////////////////////// +void adjustCoordinates(int x, int y) { + scrnX = Math.round( x - WORLD_SIZE_W/2 ); + scrnY = Math.round( y - WORLD_SIZE_H/2 ); + pointX = Math.round( scrnX/factor ); + pointY = Math.round( scrnY/factor ); +} + +void doSelectNode() { + //func = "select node"; + Iterator it = nodes.entrySet().iterator(); + selection = null; + while (it.hasNext ()) { + Map.Entry e = (Map.Entry)it.next(); + String k = (String) e.getKey(); + Node n = (Node) e.getValue(); + //if (debug) print(n.name + "\t"); + if ( (! "MARK".equals(n.shape)) && pointerOverRect(n.x, n.y, n.w, n.h) || + "MARK".equals(n.shape) && pointerOverRect(n.x + n.w/factor/2, n.y, n.w, n.h) ) { + //func = "select node"; + sel_edge = null; + selection = n; + if ( selection == null || + previous_selection == null || + ! previous_selection.id.equals(selection.id) ) { + if (nodetrace) println("NEW SELECTION "+ selection.name); + previous_selection = selection; + if (javascript != null) javascript.new_select(selection.id, selection.proj); + } + //sel_edge = null; + selectNode(selection); + //selected = null; + } + } +} + +void doSelectEdge() { + //func = "select edge"; + if (selection == null) { + Iterator it = edges.entrySet().iterator(); + sel_edge = null; + while (it.hasNext ()) { + Map.Entry ie = (Map.Entry)it.next(); + String k = (String) ie.getKey(); + Edge e = (Edge) ie.getValue(); + if (pointerOverLine(e.from, e.to) && e.dup==0) { + //func = "select edge"; + //if (debug) println("select edge line "+e.asc_id); + sel_edge = e; + } + else if (pointerOverArc( e )) { + //func = "select edge"; + //if (debug) println("select edge arc "+e.asc_id); + sel_edge = e; + } + } + } +} + +void move_vizgroup(int dx, int dy) { + if (vizgroup!=null){ + for (int i = 0; i < vizgroup.size(); i++) { + Node n = (Node) vizgroup.get(i); + int originalX = n.x; + int originalY = n.y; + n.position(originalX + dx, originalY + dy); + } + } +} + +void doUpdateNodePosition() { + //func = "update node position"; + Iterator it = nodes.entrySet().iterator(); + while (it.hasNext ()) { + Map.Entry e = (Map.Entry)it.next(); + String k = (String) e.getKey(); + Node n = (Node) e.getValue(); + n.x += pointX - pressStartX; + n.y += pointY - pressStartY; + n.position(n.x, n.y); + } +} + +boolean pointerOverRect( float x, float y, float w, float h ) { + int pX, pY; + if (!isMouse) { + pX = touchX; + pY = touchY; + } + else { + pX = mouseX; + pY = mouseY; + } + adjustCoordinates(pX, pY); + boolean isOver = false; + if ( pointX >= x - w/factor/2 && pointX <= x + w/factor/2 && + pointY >= y - h/factor/2 && pointY <= y + h/factor/2 ) { + isOver = true; + } + return isOver; +} + +boolean pointerOverLine( Node from, Node to ) { + int pX, pY; + if (!isMouse) { + pX = touchX; + pY = touchY; + } + else { + pX = mouseX; + pY = mouseY; + } + adjustCoordinates( pX, pY ); + boolean isOver = false; + Vector2D pFrom = new Vector2D(from.x, from.y); + Vector2D pTo = new Vector2D(to.x, to.y); + Vector2D pointer = new Vector2D(pointX, pointY); + float distance = pointer.distance(pFrom, pTo); + if (distance < 2) { + isOver = true; + } + return isOver; +} + +boolean pointerOverArc( Edge e ) { + //if (e.dup==0) return false; + boolean isOver = false; + int ptX, ptY; + float sigma = 0.1; + if (!isMouse) { + ptX = touchX; + ptY = touchY; + } + else { + ptX = mouseX; + ptY = mouseY; + } + adjustCoordinates( ptX, ptY ); + // based on screen coordination. center(0,0) rightbottom(WoORLD_SIZE_W/2, WORLD_SIZE_H/2) + if (e.from==null || e.to==null || e.centr==null) return false; + fromX = factor * (e.from.x); + fromY = factor * (e.from.y); + toX = factor * (e.to.x); + toY = factor * (e.to.y); + cX = factor * (e.centr.x); + cY = factor * (e.centr.y); + PVector P = new PVector(scrnX, scrnY); + PVector Cntr = new PVector(cX, cY); + if (P != null) phai = e.theta(Cntr, P); + PVector P1 = new PVector(fromX, fromY); + if (P1 != null) theta1 = e.theta(Cntr, P1); + PVector P2 = new PVector(toX, toY); + if (P2 != null) theta2 = e.theta(Cntr, P2); + PVector T = PVector.sub(P, Cntr); + float D = dist(P1.x, P1.y, Cntr.x, Cntr.y); + T.normalize(); + T.mult(D); + T.add(Cntr); + T.sub(P); + float w = 0; + if (sqrt(sq(T.x) + sq(T.y)) < 3) { + if (edgetrace) println("initial theta1="+round(degrees(theta1))+" phai="+round(degrees(phai))+" theta2="+round(degrees(theta2))); + if (-TWO_PI PI) { + w = theta2; + theta2 = theta1; + theta1 = w; + } + if((( -TWO_PI < phai-theta1 && phai-theta1 < -PI) || + ( 0 < phai-theta1 && phai-theta1 < PI)) && + (( -TWO_PI < theta2-phai && theta2-phai < -PI) || + ( 0 < theta2-phai && theta2-phai < PI))) + isOver = true; + } + return isOver; +} + +void doBeginMenu() { + //func = "begin menu"; + menu_active = true; + menuX = scrnX; + menuY = scrnY; + selected = selection; + selection = null; + previous_selection = null; + //javascript.end_select(); +} + +void doMenu() { + if (debug) println( "menu=" + nls(menu,ln) ); + switch (menu) { + case ROOT: + rootNode(selected); + break; + case HIDE: + if (!selected.root) hideNode(selected); + break; + case INFO: + infoNode(selected); + break; + case NEWREL: + newRelation(selected); + break; + case SQUEEZE: + squeezeNode(selected); + } + menu_active = false; + selected = null; + dragging = false; +} + +void doBeginEdgMenu() { + //func = "begin edge menu"; + edgmenu_active = true; + menuX = scrnX; + menuY = scrnY; + selected_edge = sel_edge; +} + +void doEdgMenu() { + if (edgetrace) println( "edge menu=" + nls(edgmenu,ln) ); + switch (edgmenu) { + case HIDEEDGE: + hideEdge(sel_edge); + break; + case EDITEDGE: + infoEdge(sel_edge); + } + edgmenu_active = false; + sel_edge = null; + dragging = false; +} + +void doBeginApMenu() { + //func = "begin ap menu"; + apmenu_active = true; + menuX = scrnX; + menuY = scrnY; +} + +void doApMenu() { + //func = "execute ap menu"; + switch (apmenu) { + case FITALL: + fitAll(); + break; + case ALLFIX: + allFix(); + break; + case ALLFREE: + allFree(); + break; + case GROUPSHAPE: + groupShape(); + break; + case ALLSAVE: + allSave(); + break; + case ALLRETRIEVE: + allRetrieve(); + break; + case NEWTOPIC: + newTopic(); + break; + case PEDIA: + pedia(); + break; + case MODE: + setMode(); + } + apmenu_active = false; +} + +void setMode() { + if (debug) println("setMode"); + if (javascript!=null) { + String lang = ln; + boolean d = debug, + p = personal, + u = showusername, + ed = editmode; + String b = both; + javascript.set_mode( lang, d, p, u, b, ed ); + } +} + +void saveMode(String lang, String d, String p, String u, String b, String ed){ + if (debug) println("\t"+lang+" "+d+" "+p+" "+u+" "+b+" "+ed); + if (lang!=null) ln = lang; + if ("debug".equals(d)) { + debug=true; + nodetrace=true; + edgetrace=true; + } + else { + debug=false; + nodetrace=false; + edgetrace=false; + } + if ("personal".equals(p)) + personal=true; else personal=false; + if ("showusername".equals(u)) + showusername=true; else showusername=false; + if ("edit".equals(ed)) { + editmode=true; + } + else { + editmode=false; + } + both = b; + if (debug) println("\tdebug="+debug+" personal="+personal+" showusername="+showusername+" both="+both+" editmode="+editmode); +} + +void doExpandNode(Node node) { +// funcTrace("Expandng..."); + boolean isfree=true; + if(node.fixed) isfree=false; + node.fix(); + expandNode(node, both); // "" means one direction "both" means bidirection expansion + selection = null; + previous_selection = null; +} + +void doFixNode(Node node) { + if (debug) println("doFixNode " + node.name); + //func = "fix node"; + node.fix(); + selection = null; + previous_selection = null; +} + +void doFreeNode(Node node) { + if (debug) println("doFreeNode " + node.name); + //func = "free node"; + node.free(); + selection = null; + previous_selection = null; +} + +void doDragNode() { + //func = "drag node"; + draggingnode = true; + int dx = pointX - selection.x; + int dy = pointY - selection.y; + selection.fix(); + //if (debug) println("mouseDragged " + selection.name + "\t(" + originalX + ",\t" + originalY + ") to (" + pointX + ",\t" + pointY + ")"); + if (selection.vizgroup == null) { + selection.position(pointX, pointY); + } else { + move_vizgroup(dx, dy); + } + damper = 1.0; +} + +//////// MENU /////////////////////////////////////////////////////////// +boolean isOverMenu(float x, float y, int w, int h) { + int pX, pY; + if (!isMouse) { + pX = touchX; + pY = touchY; + } + else { + pX = mouseX; + pY = mouseY; + } + adjustCoordinates(pX, pY); + if ((scrnX) >= x - w/2 && (scrnX) <= x + w/2 && + (scrnY) >= y - h/2 && (scrnY) <= y + h/2) { + return true; + } + else { + return false; + } +} + +Vector2D adjustMenuPosition(int x, int y, int w, int h, int rows) { + float WORLD_HALF_SIZE_W = (WORLD_SIZE_W - w)/2; + float WORLD_HALF_SIZE_H = (WORLD_SIZE_H - h)/2; + float new_x = x; + float new_y = y; + if ( x < -WORLD_HALF_SIZE_W ) new_x = -WORLD_HALF_SIZE_W; + if ( x > WORLD_HALF_SIZE_W ) new_x = WORLD_HALF_SIZE_W; + if ( y < -WORLD_HALF_SIZE_H ) new_y = -WORLD_HALF_SIZE_H; + if ( y > WORLD_HALF_SIZE_H - rows * h ) new_y = WORLD_HALF_SIZE_H - rows * h; + Vector2D newPosition = new Vector2D(new_x, new_y); + return newPosition; +} + +void showMenu() { + stroke(Silver); + strokeWeight(0.1); + int w = 100; + int h = 25; + Vector2D menuPosition; + float x0, y0; + if (editmode) { + menuPosition = adjustMenuPosition( menuX, menuY, w, h, 5); + x0 = menuPosition.x; + y0 = menuPosition.y; + int i = 0; + menuItem(x0, y0 + h*i++, w, h, nls(INFO,ln) ); + menuItem(x0, y0 + h*i++, w, h, nls(ROOT,ln) ); + menuItem(x0, y0 + h*i++, w, h, nls(SQUEEZE,ln) ); + menuItem(x0, y0 + h*i++, w, h, nls(HIDE,ln) ); + menuItem(x0, y0 + h*i++, w, h, nls(NEWREL,ln) ); + if (isOverMenu(x0, y0, w, h)) { + menuHighlite( x0, y0, w, h, nls(INFO,ln) ); menu = INFO; } + else if (isOverMenu(x0, y0 + h, w, h)) { + menuHighlite( x0, y0 + h, w, h, nls(ROOT,ln) ); menu = ROOT; } + else if (isOverMenu(x0, y0 + h*2, w, h)) { + menuHighlite( x0, y0 + h*2, w, h, nls(SQUEEZE,ln) ); menu = SQUEEZE; } + else if (isOverMenu(x0, y0 + h*3, w, h)) { + menuHighlite( x0, y0 + h*3, w, h, nls(HIDE,ln) ); menu = HIDE; } + else if (isOverMenu(x0, y0 + h*4, w, h)) { + menuHighlite( x0, y0 + h*4, w, h, nls(NEWREL,ln) ); menu = NEWREL; } + else { + menu = 0; menu_active = false; selected = null; } + } + else { + menuPosition = adjustMenuPosition( menuX, menuY, w, h, 2); + x0 = menuPosition.x; + y0 = menuPosition.y; + int i = 0; + menuItem(x0, y0 + h*i++, w, h, nls(INFO,ln) ); + menuItem(x0, y0 + h*i++, w, h, nls(ROOT,ln) ); + if (isOverMenu( x0, y0, w, h)) { + menuHighlite( x0, y0, w, h, nls(INFO,ln) ); menu = INFO; } + else if (isOverMenu(x0, y0 + h*1, w, h)) { + menuHighlite( x0, y0 + h*1, w, h, nls(ROOT,ln) ); menu = ROOT; } + else { + menu = 0; menu_active = false; selected = null; } + } +} + +void showEdgMenu() { + if (menu_active || apmenu_active) return; + stroke(Silver); + strokeWeight(0.1); + int w = 100; + int h = 25; + Vector2D menuPosition; + float x0, y0; + if (editmode) { + menuPosition = adjustMenuPosition( menuX, menuY, w, h, 2 ); + x0 = menuPosition.x; + y0 = menuPosition.y; + menuItem(x0, y0, w, h, nls(EDITEDGE,ln) ); + //menuItem(x0, y0 + h, w, h, nls(HIDEEDGE,ln) ); + if (isOverMenu( x0, y0, w, h)) { + menuHighlite( x0, y0, w, h, nls(EDITEDGE,ln) ); edgmenu = EDITEDGE; } + /* + else if (isOverMenu(x0, y0 + h, w, h)) { + menuHighlite( x0, y0 + h, w, h, nls(HIDEEDGE,ln) ); edgmenu = HIDEEDGE; } + */ + else { + edgmenu = 0; edgmenu_active = false; selected_edge = null; + } + } +} + +void showApMenu() { + if (menu_active) return; + stroke(Silver); + strokeWeight(0.1); + int w = 100; + int h = 25; + Vector2D menuPosition; + float x0, y0; + if (editmode) { + menuPosition = adjustMenuPosition( menuX, menuY, w, h, 9 ); + x0 = menuPosition.x; + y0 = menuPosition.y; + int i = 0; + menuItem(x0, y0 + h*i++, w, h, nls(FITALL,ln) ); + menuItem(x0, y0 + h*i++, w, h, nls(NEWTOPIC,ln) ); + menuItem(x0, y0 + h*i++, w, h, nls(PEDIA,ln) ); + menuItem(x0, y0 + h*i++, w, h, nls(ALLFREE,ln) ); + menuItem(x0, y0 + h*i++, w, h, nls(ALLFIX,ln) ); + menuItem(x0, y0 + h*i++, w, h, nls(GROUPSHAPE,ln) ); + menuItem(x0, y0 + h*i++, w, h, nls(ALLSAVE,ln) ); + menuItem(x0, y0 + h*i++, w, h, nls(ALLRETRIEVE,ln) ); + menuItem(x0, y0 + h*i++, w, h, nls(MODE,ln) ); + if (isOverMenu( x0, y0 + h*0, w, h)) { + menuHighlite( x0, y0 + h*0, w, h, nls(FITALL,ln) ); apmenu = FITALL; } + else if (isOverMenu(x0, y0 + h*1, w, h)) { + menuHighlite( x0, y0 + h*1, w, h, nls(NEWTOPIC,ln) ); apmenu = NEWTOPIC; } + else if (isOverMenu(x0, y0 + h*2, w, h)) { + menuHighlite( x0, y0 + h*2, w, h, nls(PEDIA,ln) ); apmenu = PEDIA; } + else if (isOverMenu(x0, y0 + h*3, w, h)) { + menuHighlite( x0, y0 + h*3, w, h, nls(ALLFREE,ln) ); apmenu = ALLFREE; } + else if (isOverMenu(x0, y0 + h*4, w, h)) { + menuHighlite( x0, y0 + h*4, w, h, nls(ALLFIX,ln) ); apmenu = ALLFIX; } + else if (isOverMenu(x0, y0 + h*5, w, h)) { + menuHighlite( x0, y0 + h*5, w, h, nls(GROUPSHAPE,ln) ); apmenu = GROUPSHAPE; } + else if (isOverMenu(x0, y0 + h*6, w, h)) { + menuHighlite( x0, y0 + h*6, w, h, nls(ALLSAVE,ln) ); apmenu = ALLSAVE; } + else if (isOverMenu(x0, y0 + h*7, w, h)) { + menuHighlite( x0, y0 + h*7, w, h, nls(ALLRETRIEVE,ln)); apmenu = ALLRETRIEVE; } + else if (isOverMenu(x0, y0 + h*8, w, h)) { + menuHighlite( x0, y0 + h*8, w, h, nls(MODE,ln)); apmenu = MODE; } + else { + apmenu = 0; apmenu_active = false; } + } + else { + menuPosition = adjustMenuPosition( menuX, menuY, w, h, 3 ); + x0 = menuPosition.x; + y0 = menuPosition.y; + int i = 0; + menuItem(x0, y0 + h*i++, w, h, nls(FITALL,ln) ); + menuItem(x0, y0 + h*i++, w, h, nls(PEDIA,ln) ); + menuItem(x0, y0 + h*i++, w, h, nls(MODE,ln) ); + if (isOverMenu( x0, y0 + h*0, w, h)) { + menuHighlite( x0, y0 + h*0, w, h, nls(FITALL,ln) ); apmenu = FITALL; } + else if (isOverMenu(x0, y0 + h*1, w, h)) { + menuHighlite( x0, y0 + h*1, w, h, nls(PEDIA,ln) ); apmenu = PEDIA; } + else if (isOverMenu(x0, y0 + h*2, w, h)) { + menuHighlite( x0, y0 + h*2, w, h, nls(MODE,ln)); apmenu = MODE; } + else { + apmenu = 0; apmenu_active = false; } + } +} + +void menuItem(float x, float y, int w, int h, String name) { + fill(White); + rectMode(CENTER); + rect(x, y, w, h); + fill(0); + textAlign(CENTER, CENTER); + textSize(12); + text(name, x, y); +} + +void menuHighlite(float x, float y, int w, int h, String name) { + fill(192); + rectMode(CENTER); + rect(x, y, w, h); + fill(White); + textAlign(CENTER, CENTER); + textSize(12); + text(name, x, y); +} + +void fitAll() { + //func = "fit all"; + float minX=width/2, maxX=-width/2, minY=height/2, maxY=-height/2; + float area_width, area_height, area_centerX, area_centerY; + selection = null; + previous_selection = null; + //javascript.end_select(); + Iterator it = nodes.entrySet().iterator(); + while (it.hasNext ()) { + Map.Entry e = (Map.Entry)it.next(); + String k = (String) e.getKey(); + Node n = (Node) e.getValue(); + if (n.x < minX) minX = n.x; + if (n.x > maxX) maxX = n.x; + if (n.y < minY) minY = n.y; + if (n.y > maxY) maxY = n.y; + } + area_width = maxX - minX; + area_height = maxY - minY; + area_centerX = minX + area_width/2; + area_centerY = minY + area_height/2; + //if (debug) print("width=" + width + "\theight=" + height + "\tX\tmin=" + minX + "\tmax=" + maxX + "\tY\tmin=" + minY + "\tmax=" + maxY + "\n"); + //if (debug) print("Area\twidth=" + area_width + "\theight=" + area_height + "\tcentr\tx=" + area_centerX + "\ty=" + area_centerY + "\n"); + + Iterator it2 = nodes.entrySet().iterator(); + while (it2.hasNext ()) { + Map.Entry e = (Map.Entry)it2.next(); + String k = (String) e.getKey(); + Node n = (Node) e.getValue(); + n.x -= area_centerX; + n.y -= area_centerY; + n.position(n.x, n.y); + } + pressStartX = 0; + pressStartY = 0; + float sw = width/area_width, sh = height/area_height; + float smin = (sw 4) scl = 3.2; + else scl *= 0.8; + if (debug) print("scl="+scl+"\tmin="+smin+"\tmax="+smax+"\n"); + zoom(scl); + if (javascript != null) javascript.setscale(scl); +} + +String nls(int i, String ln) { + if (ln.equals("ja")){ + switch(i) { + // menu + case EXPND: return "展開"; + case ROOT: return "中心ノード"; + case HIDE: return "非表示"; + case INFO: return "情報"; + case NEWREL: return "関係定義"; + case SQUEEZE: return "折りたたみ"; + // apmenu + case FITALL: return "全体表示"; + case ALLFIX: return "全粘着"; + case ALLFREE: return "全開放"; + case GROUPSHAPE: return "グループの形"; + case ALLSAVE: return "退避"; + case ALLRETRIEVE: return "回復"; + case NEWTOPIC: return "新規トピック"; + case MODE: return "実行モード"; + case PEDIA: return "世界大百科事典"; + // edgemenu + case HIDEEDGE: return "非表示"; + case EDITEDGE: return "情報"; + case DELETEEDGE: return "削除"; + } + } + else { + switch(i) { + // menu + case EXPND: return "EXPAND"; + case ROOT: return "ROOT"; + case HIDE: return "HIDE"; + case INFO: return "INFO"; + case NEWREL: return "NEWREL"; + case SQUEEZE: return "SQUEEZE"; + // apmenu + case FITALL: return "FIT ALL"; + case ALLFIX: return "ALL FIX"; + case ALLFREE: return "ALL FREE"; + case GROUPSHAPE: return "GROUP SHAPE"; + case ALLSAVE: return "SAVE"; + case ALLRETRIEVE: return "RETRIEVE"; + case NEWTOPIC: return "NEW TOPIC"; + case MODE: return "MODE"; + case PEDIA: return "ENCYCLOPEDIA"; + // edgemenu + case HIDEEDGE: return "HIDE EDGE"; + case EDITEDGE: return "EDGE INFO"; + case DELETEEDGE: return "DELETE EDGE"; + } + } + return null; +} + diff -r e05da377a27e -r 4baa7530912c src/hp/static/hp/tmgraph/model.pde --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/hp/static/hp/tmgraph/model.pde Wed Nov 14 17:26:06 2012 +0100 @@ -0,0 +1,2058 @@ +HashMap usercolors = new HashMap(); +HashMap nodes = new HashMap(); +HashMap edges = new HashMap(); +HashMap nodeshapes = new HashMap(); +HashMap edgeshapes = new HashMap(); +HashMap thumbs = new HashMap(); +HashMap connected_edges = new HashMap(); +HashMap imageMaps = new HashMap(); +ArrayList vizgroup = new ArrayList(); +PImage img; +int bgColor = White; +int u_clr; //user color + +// ADDED BY IRI TO ACCESS NODES AND EDGES FROM JS + +HashMap getNodes() { + return nodes; +} + +HashMap getEdges() { + return edges; +} + +//////// SAVE & LOAD NODES, EDGED //////////////////////////////////////////// +void allSave() { + String proj, asc_id, a_proj, id, from_proj, name, grp, to_id, to_proj, r_name, r_from, r_to; + boolean root, fixed; + int x, y, assoc; + Node node; + Edge edge; + String root_str = ""; + Iterator it = nodes.entrySet().iterator(); + while (it.hasNext ()) { + Map.Entry e = (Map.Entry)it.next(); + String k = (String) e.getKey(); + node = (Node) e.getValue(); + if (node!=null) { + id = node.id; + proj = node.proj; + name = node.name; + grp = node.grp; + assoc = node.assoc; + x = node.x; + y = node.y; + root = node.root; + fixed = node.fixed; + if (root) + root_str = "\"root\":[{ \"id\":\"" + id + "\", \"proj\":\""+ proj + "\", " + + "\"name\":\""+ name + "\", \"grp\":\""+ grp + "\", " + + "\"assoc\":" + assoc + ", \"x\":" + x + ", \"y\":" + y +" }]"; + } + } + //if (debug) println(root_str); + String nodes_str = "\"node\":[ "; + it = nodes.entrySet().iterator(); + while (it.hasNext ()) { + Map.Entry e = (Map.Entry)it.next(); + String k = (String) e.getKey(); + node = (Node) e.getValue(); + if (node!=null) { + id = node.id; + proj = node.proj; + name = node.name; + grp = node.grp; + assoc = node.assoc; + x = node.x; + y = node.y; + root = node.root; + fixed = node.fixed; + nodes_str += "{ \"id\":\"" + id + "\", \"proj\":\"" + proj + "\", " + + "\"name\":\""+ name + "\", \"grp\":\""+ grp + "\", " + + "\"assoc\":" + assoc + ", \"x\":" + x + ", \"y\":" + y +" },"; + } + } + //nodes_str += " {} ]"; + nodes_str = nodes_str.substring(0, nodes_str.length()-1) + " ]"; + //if (debug) println(nodes_str); + String edges_str = "\"edge\":[ "; + it = edges.entrySet().iterator(); + while (it.hasNext ()) { + Map.Entry e = (Map.Entry)it.next(); + String k = (String) e.getKey(); + edge = (Edge) e.getValue(); + asc_id = edge.asc_id; + a_proj = edge.proj; + id = edge.from.id; + from_proj = edge.from.proj; + to_id = edge.to.id; + to_proj = edge.to.proj; + r_name = edge.r_name; + r_from = edge.r_from; + r_to = edge.r_to; + edges_str += "{ \"asc_id\":\"" + asc_id + "\", \"a_proj\":\""+ a_proj +"\"," + + " \"id\":\"" + id + "\", \"from_proj\":\""+ from_proj +"\"," + + " \"to_id\":\"" + to_id + "\", \"to_proj\":\"" + to_proj + "\"," + + " \"r_name\":\"" + r_name +"\", \"r_from\":\"" + r_from + "\", \"r_to\":\"" + r_to + "\" },"; + } + //edges_str += " {} ]"; + edges_str = edges_str.substring(0, edges_str.length()-1) + " ]"; + if (debug) + println("{" + root_str + ", " + nodes_str + ", " + edges_str + "}"); + if (null != javascript) javascript.allbackup("{" + root_str + ", " + nodes_str + ", " + edges_str + "}"); +} + +void allRetrieve() { + physics.clear(); + nodes.clear(); + edges.clear(); + connected_edges.clear(); + javascript.allretrieve(""); +} + +int cvalue(int hex) { + int r = (hex & 0xff0000)>>16; + int g = (hex & 0xff00)>>8; + int b = hex & 0xff; + return r+g+b; +} + +int toInt(String s) { + int i = 0; + if ("0".equals(s)) i = 0; + else if ("1".equals(s)) i = 1; + else if ("2".equals(s)) i = 2; + else if ("3".equals(s)) i = 3; + else if ("4".equals(s)) i = 4; + else if ("5".equals(s)) i = 5; + else if ("6".equals(s)) i = 6; + else if ("7".equals(s)) i = 7; + else if ("8".equals(s)) i = 8; + else if ("9".equals(s)) i = 9; + else if ("a".equals(s)) i = 10; + else if ("A".equals(s)) i = 10; + else if ("b".equals(s)) i = 11; + else if ("B".equals(s)) i = 11; + else if ("c".equals(s)) i = 12; + else if ("C".equals(s)) i = 12; + else if ("d".equals(s)) i = 13; + else if ("D".equals(s)) i = 13; + else if ("e".equals(s)) i = 14; + else if ("E".equals(s)) i = 14; + else if ("f".equals(s)) i = 15; + else if ("F".equals(s)) i = 15; + return i; +} + +int hex2int(String s) { + String a = s.substring(0, 1); + String b = s.substring(1, 2); + int ret = 16 * toInt(a) + toInt(b); + //if (debug) println(s + " " + a + " " + b + " " + ret); + return ret; +} + +int str2color(String str) { + int c; + int r = hex2int(str.substring(0, 2)); + int g = hex2int(str.substring(2, 4)); + int b = hex2int(str.substring(4, 6)); + //if (debug) println(str + " " + r + " " + g + " " + b); + c = color(r, g, b); + return c; +} + +void initNode(String id, String name, String grp, String uid, String proj) { + if (debug) println("initNode(id=" + id + " name=" + name + " grp=" + grp + " uid=" + uid + " proj=" + proj + ")"); + //name = unescapeSTR( name ); + Node n = findNode(id, proj); + if (n == null) n = new Node(id, name, grp, uid, proj); + rootNode(n); +} + +//////// GROUP SHAPE & COLOR ///////////////////////////////////////////////// +void groupShape() { + if (nodetrace) print("groupShape"); + javascript.group_shapes(); +} + +int hexToColor(String clr) { + String s = clr.replaceFirst("^#", ""); + int c = str2color( s ); + return c; +} + +int color2int(String clr) { + int c = 0; + if ( "#".equals(clr.substring(0, 1))) { + c = hexToColor(clr); + } + else if ( "AliceBlue".equals(clr) ) c = AliceBlue; + else if ( "AntiqueWhite".equals(clr) ) c = AntiqueWhite; + else if ( "Aqua".equals(clr) ) c = Aqua; + else if ( "Aquamarine".equals(clr) ) c = Aquamarine; + else if ( "Azure".equals(clr) ) c = Azure; + else if ( "Beige".equals(clr) ) c = Beige; + else if ( "Bisque".equals(clr) ) c = Bisque; + else if ( "Black".equals(clr) ) c = Black; + else if ( "BlanchedAlmond".equals(clr) ) c = BlanchedAlmond; + else if ( "Blue".equals(clr) ) c = Blue; + else if ( "BlueViolet".equals(clr) ) c = BlueViolet; + else if ( "Brown".equals(clr) ) c = Brown; + else if ( "BurlyWood".equals(clr) ) c = BurlyWood; + else if ( "CadetBlue".equals(clr) ) c = CadetBlue; + else if ( "Chartreuse".equals(clr) ) c = Chartreuse; + else if ( "Chocolate".equals(clr) ) c = Chocolate; + else if ( "Coral".equals(clr) ) c = Coral; + else if ( "CornflowerBlue".equals(clr) ) c = CornflowerBlue; + else if ( "Cornsilk".equals(clr) ) c = Cornsilk; + else if ( "Crimson".equals(clr) ) c = Crimson; + else if ( "Cyan".equals(clr) ) c = Cyan; + else if ( "DarkBlue".equals(clr) ) c = DarkBlue; + else if ( "DarkCyan".equals(clr) ) c = DarkCyan; + else if ( "DarkGoldenRod".equals(clr) ) c = DarkGoldenRod; + else if ( "DarkGray".equals(clr) ) c = DarkGray; + else if ( "DarkGrey".equals(clr) ) c = DarkGrey; + else if ( "DarkGreen".equals(clr) ) c = DarkGreen; + else if ( "DarkKhaki".equals(clr) ) c = DarkKhaki; + else if ( "DarkMagenta".equals(clr) ) c = DarkMagenta; + else if ( "DarkOliveGreen".equals(clr) ) c = DarkOliveGreen; + else if ( "Darkorange".equals(clr) ) c = Darkorange; + else if ( "DarkOrchid".equals(clr) ) c = DarkOrchid; + else if ( "DarkRed".equals(clr) ) c = DarkRed; + else if ( "DarkSalmon".equals(clr) ) c = DarkSalmon; + else if ( "DarkSeaGreen".equals(clr) ) c = DarkSeaGreen; + else if ( "DarkSlateBlue".equals(clr) ) c = DarkSlateBlue; + else if ( "DarkSlateGray".equals(clr) ) c = DarkSlateGray; + else if ( "DarkSlateGrey".equals(clr) ) c = DarkSlateGrey; + else if ( "DarkTurquoise".equals(clr) ) c = DarkTurquoise; + else if ( "DarkViolet".equals(clr) ) c = DarkViolet; + else if ( "DeepPink".equals(clr) ) c = DeepPink; + else if ( "DeepSkyBlue".equals(clr) ) c = DeepSkyBlue; + else if ( "DimGray".equals(clr) ) c = DimGray; + else if ( "DimGrey".equals(clr) ) c = DimGrey; + else if ( "DodgerBlue".equals(clr) ) c = DodgerBlue; + else if ( "FireBrick".equals(clr) ) c = FireBrick; + else if ( "FloralWhite".equals(clr) ) c = FloralWhite; + else if ( "ForestGreen".equals(clr) ) c = ForestGreen; + else if ( "Fuchsia".equals(clr) ) c = Fuchsia; + else if ( "Gainsboro".equals(clr) ) c = Gainsboro; + else if ( "GhostWhite".equals(clr) ) c = GhostWhite; + else if ( "Gold".equals(clr) ) c = Gold; + else if ( "GoldenRod".equals(clr) ) c = GoldenRod; + else if ( "Gray".equals(clr) ) c = Gray; + else if ( "Grey".equals(clr) ) c = Grey; + else if ( "Green".equals(clr) ) c = Green; + else if ( "GreenYellow".equals(clr) ) c = GreenYellow; + else if ( "HoneyDew".equals(clr) ) c = HoneyDew; + else if ( "HotPink".equals(clr) ) c = HotPink; + else if ( "IndianRed ".equals(clr) ) c = IndianRed ; + else if ( "Indigo ".equals(clr) ) c = Indigo ; + else if ( "Ivory".equals(clr) ) c = Ivory; + else if ( "Khaki".equals(clr) ) c = Khaki; + else if ( "Lavender".equals(clr) ) c = Lavender; + else if ( "LavenderBlush".equals(clr) ) c = LavenderBlush; + else if ( "LawnGreen".equals(clr) ) c = LawnGreen; + else if ( "LemonChiffon".equals(clr) ) c = LemonChiffon; + else if ( "LightBlue".equals(clr) ) c = LightBlue; + else if ( "LightCoral".equals(clr) ) c = LightCoral; + else if ( "LightCyan".equals(clr) ) c = LightCyan; + else if ( "LightGoldenRodYellow".equals(clr) ) c = LightGoldenRodYellow; + else if ( "LightGray".equals(clr) ) c = LightGray; + else if ( "LightGrey".equals(clr) ) c = LightGrey; + else if ( "LightGreen".equals(clr) ) c = LightGreen; + else if ( "LightPink".equals(clr) ) c = LightPink; + else if ( "LightSalmon".equals(clr) ) c = LightSalmon; + else if ( "LightSeaGreen".equals(clr) ) c = LightSeaGreen; + else if ( "LightSkyBlue".equals(clr) ) c = LightSkyBlue; + else if ( "LightSlateGray".equals(clr) ) c = LightSlateGray; + else if ( "LightSlateGrey".equals(clr) ) c = LightSlateGrey; + else if ( "LightSteelBlue".equals(clr) ) c = LightSteelBlue; + else if ( "LightYellow".equals(clr) ) c = LightYellow; + else if ( "Lime".equals(clr) ) c = Lime; + else if ( "LimeGreen".equals(clr) ) c = LimeGreen; + else if ( "Linen".equals(clr) ) c = Linen; + else if ( "Magenta".equals(clr) ) c = Magenta; + else if ( "Maroon".equals(clr) ) c = Maroon; + else if ( "MediumAquaMarine".equals(clr) ) c = MediumAquaMarine; + else if ( "MediumBlue".equals(clr) ) c = MediumBlue; + else if ( "MediumOrchid".equals(clr) ) c = MediumOrchid; + else if ( "MediumPurple".equals(clr) ) c = MediumPurple; + else if ( "MediumSeaGreen".equals(clr) ) c = MediumSeaGreen; + else if ( "MediumSlateBlue".equals(clr) ) c = MediumSlateBlue; + else if ( "MediumSpringGreen".equals(clr) ) c = MediumSpringGreen; + else if ( "MediumTurquoise".equals(clr) ) c = MediumTurquoise; + else if ( "MediumVioletRed".equals(clr) ) c = MediumVioletRed; + else if ( "MidnightBlue".equals(clr) ) c = MidnightBlue; + else if ( "MintCream".equals(clr) ) c = MintCream; + else if ( "MistyRose".equals(clr) ) c = MistyRose; + else if ( "Moccasin".equals(clr) ) c = Moccasin; + else if ( "NavajoWhite".equals(clr) ) c = NavajoWhite; + else if ( "Navy".equals(clr) ) c = Navy; + else if ( "OldLace".equals(clr) ) c = OldLace; + else if ( "Olive".equals(clr) ) c = Olive; + else if ( "OliveDrab".equals(clr) ) c = OliveDrab; + else if ( "Orange".equals(clr) ) c = Orange; + else if ( "OrangeRed".equals(clr) ) c = OrangeRed; + else if ( "Orchid".equals(clr) ) c = Orchid; + else if ( "PaleGoldenRod".equals(clr) ) c = PaleGoldenRod; + else if ( "PaleGreen".equals(clr) ) c = PaleGreen; + else if ( "PaleTurquoise".equals(clr) ) c = PaleTurquoise; + else if ( "PaleVioletRed".equals(clr) ) c = PaleVioletRed; + else if ( "PapayaWhip".equals(clr) ) c = PapayaWhip; + else if ( "PeachPuff".equals(clr) ) c = PeachPuff; + else if ( "Peru".equals(clr) ) c = Peru; + else if ( "Pink".equals(clr) ) c = Pink; + else if ( "Plum".equals(clr) ) c = Plum; + else if ( "PowderBlue".equals(clr) ) c = PowderBlue; + else if ( "Purple".equals(clr) ) c = Purple; + else if ( "Red".equals(clr) ) c = Red; + else if ( "RosyBrown".equals(clr) ) c = RosyBrown; + else if ( "RoyalBlue".equals(clr) ) c = RoyalBlue; + else if ( "SaddleBrown".equals(clr) ) c = SaddleBrown; + else if ( "Salmon".equals(clr) ) c = Salmon; + else if ( "SandyBrown".equals(clr) ) c = SandyBrown; + else if ( "SeaGreen".equals(clr) ) c = SeaGreen; + else if ( "SeaShell".equals(clr) ) c = SeaShell; + else if ( "Sienna".equals(clr) ) c = Sienna; + else if ( "Silver".equals(clr) ) c = Silver; + else if ( "SkyBlue".equals(clr) ) c = SkyBlue; + else if ( "SlateBlue".equals(clr) ) c = SlateBlue; + else if ( "SlateGray".equals(clr) ) c = SlateGray; + else if ( "SlateGrey".equals(clr) ) c = SlateGrey; + else if ( "Snow".equals(clr) ) c = Snow; + else if ( "SpringGreen".equals(clr) ) c = SpringGreen; + else if ( "SteelBlue".equals(clr) ) c = SteelBlue; + else if ( "Tan".equals(clr) ) c = Tan; + else if ( "Teal".equals(clr) ) c = Teal; + else if ( "Thistle".equals(clr) ) c = Thistle; + else if ( "Tomato".equals(clr) ) c = Tomato; + else if ( "Turquoise".equals(clr) ) c = Turquoise; + else if ( "Violet".equals(clr) ) c = Violet; + else if ( "Wheat".equals(clr) ) c = Wheat; + else if ( "White".equals(clr) ) c = White; + else if ( "WhiteSmoke".equals(clr) ) c = WhiteSmoke; + else if ( "Yellow".equals(clr) ) c = Yellow; + else if ( "YellowGreen".equals(clr) ) c = YellowGreen; + return c; +} + +void newUserColor(String uid, int c, String show) { + if (debug) println("newUserColor(" + uid + "," + c + "," + show + ")"); + boolean s =("show".equals(show))? true:false; + UserColor usercolor = new UserColor(uid, uid, c, s); + usercolors.put( uid, usercolor ); + if (javascript != null) javascript.username(uid); +} + +void setUserColor(String uid, String uname) { + if (debug) println("setUserColor(" + uid + "," + uname + ")"); + UserColor usercolor = (UserColor) usercolors.get(uid); + if (usercolor != null) { + usercolor.uid = uid; + usercolor.name = uname; + usercolors.put( uid, usercolor ); + } +} + +public class UserColor { + String uid; + String name; + int c; + boolean show; + + UserColor(String uid, String name, int c, boolean show) { + this.uid = uid; + this.name = name; + this.c = c; + this.show = show; + } +} +// NodeShape +void newNodeShape(String grp, String s, String clr) { + if (debug || nodetrace) println("newNodeshape(" + grp + "," + s + "," + clr + ")"); + int c = color2int(clr); + NodeShape nodeshape = new NodeShape(grp, s, c); + addNodeShape(nodeshape); +} + +void addNodeShape(NodeShape nodeshape) { + if (nodetrace) print("addNodeShape("+nodeshape.grp+","+nodeshape.s+","+hex(nodeshape.c,6)+")"); + String grp = nodeshape.grp; + /*if (nodeshapes.containsKey( grp )) { + nodeshapes.remove( grp ); + } */ + nodeshapes.put( grp, nodeshape ); +} + +NodeShape findNodeShape(String grp) { + NodeShape node_shape = (NodeShape) nodeshapes.get(grp); + if (nodetrace) { + if(node_shape==null) + println("\tfindNodeShape grp="+grp+" shape undefined."); + else + println("\tfindNodeShape grp="+grp+" shape="+node_shape.s+" color="+hex(node_shape.c,6)); + } + return node_shape; +} + +public class NodeShape { + String grp; + String s; + int c; + + NodeShape(String grp, String s, int c) { + this.grp = grp; + this.s = s; + this.c = c; + } +} + +// EdgeShape +void newEdgeShape(String r_name, String s, String clr) { + if (edgetrace) println("newEdgeShape(" + r_name + "," + s + "," + clr + ")"); + int c = color2int(clr); + EdgeShape edgeshape = new EdgeShape(r_name, s, c); + addEdgeShape(edgeshape); +} + +void addEdgeShape(EdgeShape edgeshape) { + if (edgetrace) println("addEdgeShape edgeshape=("+edgeshape.r_name+","+edgeshape.s+","+hex(edgeshape.c,6)+") "); + String r_name = edgeshape.r_name; + /*if (edgeshapes.containsKey( r_name )) { + edgeshapes.remove( r_name ); + } */ + edgeshapes.put( r_name, edgeshape ); +} + +EdgeShape findEdgeShape(String r_name) { + if (edgetrace) println("\tfindEdgeShape("+r_name+")"); + if (r_name==null || r_name.equals("")) return null; + EdgeShape edgeshape = (EdgeShape) edgeshapes.get(r_name); + return edgeshape; +} + +public class EdgeShape { + String r_name; + String s; + int c; + + EdgeShape(String r_name, String s, int c) { + this.r_name = r_name; + this.s = s; + this.c = c; + } +} + +//////// IMAGE MAP MODEL /////////////////////////////////////////////// +ImageMap newImageMap(String url) { + //if (debug) println("newImageMap(" + url + ")"); + ImageMap imap = findImageMap(url); + if (imap == null) { + imap = new ImageMap(url); + addImageMap(imap); + } + return imap; +} + +ImageMap findImageMap(String url) { + //if (debug) println("\tfindImageMap("+url+")"); + if (url==null || url.equals("")) return null; + ImageMap imap = (ImageMap) imageMaps.get(url); + return imap; +} + +void addImageMap(ImageMap imap) { + //if (debug) println("addImage imap=("+imap.url+") "); + String url = imap.url; + /*if (imageMaps.containsKey( url )) { + imageMaps.remove( url ); + } */ + imageMaps.put( url, imap ); +} + +class ImageMap { + String url; + PImage img; + int w,h; + + ImageMap(String url) { + this.url = url; + int siz = 80; + w = h = 0; + this.img = loadImage(url); + if(this.img != null) { + w = img.width; + h = img.height; + if (w > h) { + h = round(siz * h / w); + w = siz; + } else { + w = round(siz * w / h); + h = siz; + } + img.resize(w, h); + } + } + + void show(int x, int y) { + image(this.img, x - this.w, y - this.h/2); + } +} + +//////// THUMBNAIL MODEL /////////////////////////////////////////////// +void newThumb(String id, int start, int end) { + if (debug) println("newThumb(" + id + "," + start + "," + end + ")"); + Thumb thumb = new Thumb(id, start, end); + addThumb(thumb); +} + +void addThumb(Thumb thumb) { + if (debug) println("addThumb thumb=("+thumb.start+","+thumb.end+") "); + String id = thumb.id; + /*if (thumbs.containsKey( id )) { + thumbs.remove( id ); + } */ + thumbs.put( id, thumb ); +} + +Thumb findThumb(String id) { + //if (debug) println("\tfindThumb("+id+")"); + if (id==null || id.equals("")) return null; + Thumb thumb = (Thumb) thumbs.get(id); + return thumb; +} + +class Thumb { + String id; + String prefix; + int start; + int end; + String postfix; + PImage image; + + Thumb(String id, int start, int end) { + this.id = id; + this.prefix = "thumbs/"; + this.start = start; + this.end = end; + this.postfix = "_in.jpg"; + } +} + +//////// GRAPH DATA MODEL /////////////////////////////////////////////// +public class Node { + Particle p; + int x, y; + int mass; + String id, proj, uid; + String name, grp, abst; + String url; + String shape; + int c; + int size; + int w, h; + //String hide; + boolean checked; + boolean fixed; + boolean root; + String isa; + int count; + int assoc; + String freeDirection; + String vizgroup; + + Node(String _id, String _name, String _grp, String _uid, String _proj) { + this.id = _id; + this.name = _name; + this.grp = _grp; + this.uid = _uid; + this.proj = _proj; + this.size = 18; + this.mass = 1;// MASS; + this.x = Math.round( random(-128, 128) ); + this.y = Math.round( random(-128, 128) ); + this.p = physics.makeParticle(this.mass, this.x, this.y /*, 0*/); + this.checked = false; + this.fixed = false; + this.root = false; + this.isa = ""; + this.count = 0; + this.assoc = 0; + String s = "RECTANGLE"; // Default + int c = LightSlateGray; // Default + NodeShape node_shape = findNodeShape( grp ); + if (node_shape != null) { + s = node_shape.s; + c = node_shape.c; + } + this.shape = s; + this.c = c; + this.w = 10; + this.h = 12; + if (nodetrace) println( "\tDEFINE Node( " + id + ", " + name + ", " + grp + ", " + uid + ", " + proj +" )" ); + } + + void increment() { + mass++; + } + + void setURL(String url) { + this.url = url; + } + + void fix() { + this.fixed = true; + this.p.makeFixed(); + } + + void free() { + this.fixed = false; + this.p.makeFree(); + } + + void position(int x, int y) { + this.x = x; + this.y = y; + this.p.position.x = x; + this.p.position.y = y; + } + + void update() { + this.x = Math.round( p.position.x ); + this.y = Math.round( p.position.y ); + } + + void move(float mx, float my) { + this.x += mx; + this.y += my; + this.position(this.x, this.y); + damper = 1.0; + } + + void affix(int diff, float x, float y, float w, float h, int s) { + if (diff > 0) { + if (diff>1000) s *= 2; + else if (diff>100) s *= 1.5; + String unopen = "" + diff; + stroke(White); + strokeWeight(1); + //stroke(edgeColor); + stroke(DeepPink); + fill(DeepPink); + rect(x + w/2, y - h/2, s, s); + fill(White); + textSize(8); + text(unopen, x + w/2, y - h/2); + textSize(12); + } + } + + void drawShape(String label, float dispX, float dispY, boolean highlite) { + float sf = sqrt(mass); + sf = 1 + (sf-1)/8; // scale factor of each node + int tsize = round(10*sf); + if (tsize > 48) { + textSize(48); + } else if (tsize > 12) { + textSize(tsize); + } else { + textSize(12); + } + w = round( textWidth(label) + 30 ); + h = round( sf * this.size ); + if (this.root) fill(rootColor); + if ("".equals(this.shape)) { + rectMode(CENTER); + rect(dispX, dispY, w, h); + } + else if ("CIRCLE".equals(this.shape)) { + ellipseMode(CENTER); + ellipse(dispX, dispY, w, w); + } + else if ("ELLIPSE".equals(this.shape)) { + ellipseMode(CENTER); + ellipse(dispX, dispY, w + 4, h + 4); + } + else if ("ROUNDED".equals(this.shape)) { + rectMode(CENTER); + ellipseMode(CENTER); + roundedRect(dispX, dispY, w, h, h/2); + } + else if ("MARK".equals(this.shape)) { + int radius = 18; + fill(bgColor, 10); + stroke(bgColor, 10); + rectMode(CENTER); + rect(dispX + w*sf/2 + radius, dispY, w, h); + fill(this.c); + stroke( (highlite)? selectColor:u_clr ); + ellipseMode(CENTER); + //ellipse(dispX, dispY, h*sf, h*sf); + ellipse(dispX, dispY, radius, radius); + } + else {//Default shape is RECTANGLE + rectMode(CENTER); + rect(dispX, dispY, w, h); + } + + int diff = this.assoc - this.count; + String unopen = ""; + if ( diff > 0 ) unopen += diff; + textAlign(CENTER, CENTER); + if ("MARK".equals(this.shape)) { + fill(Black); + text(label, dispX + w*sf/2, dispY); + affix(diff, dispX - w*sf/2 + h*sf/2, dispY, w*sf, h*sf, 9); + } + else { + fill(Black); + if ( cvalue(this.c) < cvalue(#A0A0A0) ) fill(White); + text(label, dispX, dispY); + affix(diff, dispX, dispY, w*sf, h*sf, 9); + } + if (url!=null) { + ImageMap imap = newImageMap(url); + imap.show(round(dispX - w*sf/2), round(dispY)); + } + } + + void show() { + Particle p = this.p; + update(); + if (p!=null) { + float dispX = factor * p.position.x; + float dispY = factor * p.position.y; + String s = "RECTANGLE"; // Default + int c = LightSlateGray; // Default + NodeShape node_shape = findNodeShape( grp ); + if (node_shape != null) { + s = node_shape.s; + c = node_shape.c; + } + this.shape = s; + this.c = c; + fill(this.c); + UserColor usercolor = (UserColor) usercolors.get(this.uid); + strokeWeight(1.5); + if (usercolor!=null) { + u_clr = usercolor.c; + stroke(u_clr); + } + else { + u_clr = color(32*int(random(255)/32), 32*int(random(255)/32), 32*int(random(255)/32)); + while (u_clr == selectColor){ + u_clr = color(32*int(random(255)/32), 32*int(random(255)/32), 32*int(random(255)/32)); + } + newUserColor(uid, u_clr, "show"); + stroke(u_clr); + } + //textSize(12); + String topicname = unescapeSTR(this.name); + UserColor uc = (UserColor) usercolors.get(uid); + String label = (showusername && uc.name!=null)? "["+uc.name+"] "+topicname:topicname; + if ( label.length() > LABEL_LENGTH ) label = label.substring(0, LABEL_LENGTH) + "..."; + this.drawShape(label, dispX, dispY, false); + } + } + + void highlight() { + Particle p = this.p; + float dispX=0, dispY=0; + int seq = 0; + if (p!=null) { + dispX = factor * p.position.x; + dispY = factor * p.position.y; + stroke(selectColor); + strokeWeight(2.0); + fill(this.c); + //textSize(12); + UserColor uc = (UserColor) usercolors.get(uid); + String topicname = unescapeSTR(this.name); + String label = (showusername && uc.name!=null)? "["+uc.name+"] "+topicname:topicname; + this.drawShape(label, dispX, dispY, true); + stroke(bgColor); + strokeWeight(0.1); + /*Thumb thumb = findThumb(id); + if (thumb!=null) { + int num = thumb.end-thumb.start; + num=(num>0)?num:1; + String filename = + thumb.prefix + + (thumb.start + (seq++ / 30) % num) + + thumb.postfix; + if (debug) println(filename); + img = loadImage(filename); + if (img!=null) image(img, dispX - 16, dispY + 4); + } + */ + } + if (nodetrace) { + fill(Gray); + text(isa, dispX - 30, dispY + 12); + text("assoc="+assoc+" count="+count, dispX - 30, dispY + 24); + text("fixed="+fixed+" root="+root, dispX - 30, dispY + 36); + text(id+"@"+proj+" grp="+grp+" url="+url, dispX - 30, dispY + 48); + } + } +} + +void roundedRect(float x, float y, float w, float h, float r) { + pushMatrix(); + translate(x, y); + beginShape(); + vertex( w/2 - r, -h/2 ); + bezierVertex( w/2 - r, -h/2, w/2, -h/2, w/2, -h/2 + r); + vertex( w/2, h/2 - r ); + bezierVertex( w/2, h/2, w/2 - r, h/2, w/2 - r, h/2); + vertex( -w/2 + r, h/2 ); + bezierVertex( - w/2, h/2, -w/2, h/2 - r, -w/2, h/2 - r ); + vertex( -w/2, -h/2 + r ); + bezierVertex( -w/2, -h/2, -w/2 + r, -h/2, -w/2 + r, -h/2 ); + endShape(CLOSE); + popMatrix(); +} + +public class Edge { + Spring s; + Node from; + Node to; + String from_is; + String to_is; + String proj, uid; + String asc_id; + String id, to_id, to_name; + String r_name, r_from, r_to; + float len; + int count; + int dup; //number of the same node pair + String shape; + int c; + int size; + PVector centr, V1, V2, V3; + float R; + char dir; + + Edge(Node from, Node to, String uid, String proj) { + if (edgetrace) print("\tDEFINE Edge("+from.name+", "+to.name+")"); + if (from==null || to==null) return; + this.uid = uid; + this.proj = proj; + this.from = from; + this.to = to; + Particle a = from.p; + Particle b = to.p; + if (a!=null && b!=null) this.s = physics.makeSpring(a, b, SPRING_STRENGTH, SPRING_DAMPING, SPRING_LENGTH); + this.id = from.id; + this.to_id = to.id; + this.len = SPRING_LENGTH; + this.count = 0; + } + + void setID( String asc_id ) { + this.asc_id = asc_id; + } + + void setRole( String R, String F, String T ) { + this.r_name = R; + this.r_from = F; + this.r_to = T; + String s = "ARROW"; // Default edge shape + int c = Silver; // Default edge color + EdgeShape edge_shape = findEdgeShape(this.r_name); + if (edge_shape != null) { + s = edge_shape.s; + c = edge_shape.c; + } + this.shape = s; + this.c = c; + if (edgetrace) println("\tshape="+s+" color="+hex(c,6)); + } + + void increment() { + count++; + } + + PVector vRotate(PVector To, PVector From, float theta, float r) { + PVector P = new PVector(From.x, From.y); + P.sub(To); + float x = cos(theta)*P.x - sin(theta)*P.y; + float y = sin(theta)*P.x + cos(theta)*P.y; + PVector Q = new PVector(x, y); + Q.normalize(); + Q.mult(r); + Q.add(To); + return Q; + } + + float theta(PVector P, PVector Q) { + //float sigma = 0.1; + float theta = 0; + if (P==null || Q==null) return 0; + float deltax = Q.x - P.x; + float deltay = Q.y - P.y; + float tan = deltay/deltax; + theta = atan(tan); + if (0 <= deltay) { + if (sigma < deltax) theta = theta; + if (-sigma <= deltax && deltax <= sigma) theta = HALF_PI; + if (deltax < -sigma) theta = PI + theta; + } + else { + if (deltax < -sigma) theta = PI + theta; + if (-sigma <= deltax && deltax <= sigma) theta = PI + HALF_PI; + if (sigma < deltax) theta = TWO_PI + theta; + } + return theta; + } + + void drawLine(PVector P, PVector Q) { + line(P.x, P.y, Q.x, Q.y); + } +/* + void fatLine(PVector P, PVector Q, float thickness) { + float x1 = P.x, y1 = P.y; + float x2 = Q.x, y2 = Q.y; + float distance = dist(x1, y1, x2, y2); + float angle = 360-atan2((y2-y1),x2-x1) ; + pushMatrix(); + rectMode(CORNER); + translate(x1,y1); + rotate(360 - angle); + rect(0, - (thickness / 2 ), distance, thickness); + rectMode(CENTER); + popMatrix(); + } +*/ + PVector calcCoord(PVector P) { + if (P==null) return null; + float x = factor*P.x; //WORLD_SIZE_W/2 + factor*P.x; //Math.round( (P.x - WORLD_SIZE_W/2)/factor ); + float y = factor*P.y; //WORLD_SIZE_H/2 + factor*P.y; //Math.round( (P.y - WORLD_SIZE_H/2)/factor ); + PVector Q = new PVector(x, y); + return Q; + } + + void drawArrow(/*Node from, Node to, int dup*/) { + PVector From = new PVector(this.from.x, this.from.y); + From.mult(factor); + PVector To = new PVector(this.to.x, this.to.y); + To.mult(factor); + //float sigma = 0.1; + int m = 4; // number of control vertex for edge + float w = 0.7; // width of arrow + float phai = 0; + float psi = 0; + float L = dist(From.x, From.y, To.x, To.y)/2; + PVector Q1; + PVector M = new PVector( (To.x + From.x)/2, (To.y + From.y)/2 ); + this.centr = M; + PVector Start, Terminate, P_i, Vi; + PVector Outer[] = new PVector[m]; + PVector Inner[] = new PVector[m]; + int N = 8; + int n = (dup%2==0)? dup/2 : -1*(dup/2)-1; + if ( (From.x - To.x < -sigma) || + (-sigma <= From.x - To.x && From.x - To.x < sigma && + From.y - To.y < -sigma) ) + n *= -1; + if (n < 0) + Q1 = vRotate(M, From, -HALF_PI, -n*L/N); + else + Q1 = vRotate(M, From, HALF_PI, n*L/N); + float a = dist(M.x, M.y, Q1.x, Q1.y)/L; + float b = (1-a*a)/(2*a); + if (n < 0) { + this.centr = vRotate(M, From, HALF_PI, b*L); + psi = theta(centr, To) - theta(centr, From); + if (PI < psi) psi -= TWO_PI; + if (psi< -PI) psi += TWO_PI; + phai = psi/m; + } + else if (n == 0){ + this.centr = vRotate(From, M, -HALF_PI, 1); + } + else if (0 < n){ + this.centr = vRotate(M,From, -HALF_PI, b*L); + psi = theta(centr, To) - theta(centr, From); + if (PI < psi) psi -= TWO_PI; + if (psi< -PI) psi += TWO_PI; + phai = psi/m; + } + R = dist(centr.x, centr.y, From.x, From.y); + if (n == 0) { + P_i = vRotate(From, M, 0, GAP); + To = vRotate(To, M, 0, GAP); + } + else { + if (0 < phai) { + P_i = vRotate(centr, From, GAP/R, R); + To = vRotate(centr, To, -GAP/R, R); + } + else { + P_i = vRotate(centr, From, -GAP/R, R); + To = vRotate(centr, To, GAP/R, R); + } + } + Vi = new PVector(From.x - centr.x, From.y - centr.y); + Vi.normalize(); + Vi.mult( m*w ); + Start = PVector.add(P_i, Vi); + Terminate = PVector.sub(P_i, Vi); + if (m==2) { + P_i = Q1; + Vi = new PVector(P_i.x - centr.x, P_i.y - centr.y); + Vi.normalize(); + Vi.mult( w ); + Outer[1]= PVector.add(P_i, Vi); + Inner[1]= PVector.sub(P_i, Vi); + } + else { + for (int i=1; i < m; i++) { + P_i = vRotate(centr, From, i*phai, R); + Vi = new PVector(P_i.x - centr.x, P_i.y - centr.y); + Vi.normalize(); + Vi.mult( (m-i)*w ); + Outer[i]= PVector.add(P_i, Vi); + Inner[i]= PVector.sub(P_i, Vi); + } + } + this.V1 = Outer[1]; + this.V2 = Q1; + this.V3 = Outer[m-1]; + //strokeJoin(MITER); + if (this.shape==null || "ARROW".equals(this.shape)) { + beginShape(); + if ( n == 0 ) { + vertex(Start.x, Start.y); + vertex(To.x, To.y); + vertex(Terminate.x, Terminate.y); + vertex(Start.x, Start.y); + } + else { + curveVertex(Start.x, Start.y); + curveVertex(Start.x, Start.y); + for (int j =1; j < m; j++) { + curveVertex(Outer[j].x, Outer[j].y); + } + curveVertex(To.x, To.y); + for (int k = m-1; k > 0; k--) { + curveVertex(Inner[k].x, Inner[k].y); + } + curveVertex(Terminate.x, Terminate.y); + curveVertex(Start.x, Start.y); + } + endShape(); + } + else if ("LINE".equals(this.shape)) { + noFill(); + strokeWeight(4); + if ( n == 0 ) { + drawLine(From, To); + } + else { + beginShape(); + curveVertex(From.x, From.y); + curveVertex(From.x, From.y); + for (int j =1; j < m; j++) { + curveVertex((Outer[j].x+Inner[j].x)/2,( Outer[j].y+Inner[j].y)/2); + } + curveVertex(To.x, To.y); + curveVertex(To.x, To.y); + endShape(); + } + } + this.centr.mult(1/factor); + this.V1.mult(1/factor); + this.V2.mult(1/factor); + this.V3.mult(1/factor); + // draw edge degug info + strokeWeight(0.5); + if (debug) { + fill(Pink); + if (from_is !=null) text(this.from_is, From.x+20, From.y-30); + if (to_is!=null) text(this.to_is, To.x+20, To.y-30); + } + if (edgetrace) { + fill(Red); + float pX = factor * (pointX); + float pY = factor * (pointY); + if (!dragging) ellipse(pX, pY, GAP, GAP); + + fromX = factor * (from.x); + fromY = factor * (from.y); + toX = factor * (to.x); + toY = factor * (to.y); + if (dup>0) { + cX = factor * (this.centr.x); + cY = factor * (this.centr.y); + } + else { + cX = M.x; + cY = M.y; + } + fill(Gray); + stroke(Gray); + line(cX, cY, fromX, fromY); + line(cX, cY, toX, toY); + textAlign(CORNER, CENTER); + text(asc_id+" dup="+dup+" shape="+this.shape+" color="+hex(c,6), cX, cY); + PVector P = new PVector(scrnX, scrnY); + PVector Cntr = new PVector(cX, cY); + if (P != null) phai = theta(Cntr, P); + PVector P1 = new PVector(fromX, fromY); + if (P1 != null) theta1 = theta(Cntr, P1); + PVector P2 = new PVector(toX, toY); + if (P2 != null) theta2 = theta(Cntr, P2); + if (dup>0) { + text("center x="+round(cX)+" y="+round(cY), cX, cY+10); + text("theta1="+round(degrees(theta1))+" theta2="+round(degrees(theta2))+" phai="+round(degrees(phai)), cX, cY+20); + } + } + } + + void show() { + UserColor usercolor = (UserColor) usercolors.get(this.uid); + strokeWeight(1.5); + if (usercolor!=null) { + u_clr = usercolor.c; + stroke(u_clr); + } + else { + u_clr = color(32*int(random(255)/32), 32*int(random(255)/32), 32*int(random(255)/32)); + while (u_clr == selectColor){ + u_clr = color(32*int(random(255)/32), 32*int(random(255)/32), 32*int(random(255)/32)); + } + newUserColor(uid, u_clr, "show"); + stroke(u_clr); + } + strokeWeight(0.6); + fill(this.c); + drawArrow(); + } + + void highlight() { + Node from = this.from; + Node to = this.to; + if (from==null || to==null) return; + float dx = to.x - from.x; + float dy = to.y - from.y; + float len = sqrt( dx*dx + dy*dy ); + float cs = GAP * dx/len; + float sn = GAP * dy/len; + float d = 2; + fromX = centerX + factor * (from.x - centerX); + fromY = centerY + factor * (from.y - centerX); + toX = centerX + factor * (to.x - centerX); + toY = centerY + factor * (to.y - centerX); + // draw highlighted edge + strokeWeight(0.5); + if (debug || edgetrace) { + fill(Red); + float pX = centerX + factor * (pointX - centerX); + float pY = centerY + factor * (pointY - centerX); + ellipse(pX, pY, GAP, GAP); + fill(Gray); + stroke(Gray); + cX = centerX + factor * (this.centr.x - centerX); + cY = centerY + factor * (this.centr.y - centerX); + line(cX, cY, fromX, fromY); + line(cX, cY, toX, toY); + textAlign(CORNER, CENTER); + if (dup==0) + text(asc_id+" dup="+dup+" shape="+this.shape+" color="+hex(c,6), 20 + (fromX + toX )/2, 10 + (fromY + toY )/2); + else + text(asc_id+" dup="+dup+" shape="+this.shape+" color="+hex(c,6), cX, cY); + } + stroke(selectColor); + fill(selectColor); + drawArrow(); + //draw label of roles + fill(Red); + textAlign(CENTER, CENTER); + float diffY = toY - fromY; + float D = 10; + float dY = 0; + if ( -D < diffY && diffY <= 0) dY = -D; + if ( 0 < diffY && diffY < D ) dY = D; + if (dup==0){ + if (sel_edge.r_from != null) + text( sel_edge.r_from, (3*fromX + toX )/4, (3*fromY + toY )/4 - dY ); + if (sel_edge.r_name != null) + text( sel_edge.r_name, (fromX + toX )/2, (fromY + toY )/2 ); + if (sel_edge.r_to != null) + text( sel_edge.r_to, (fromX + 3*toX)/4, (fromY + 3*toY)/4 + dY ); + } + else { + text(sel_edge.r_from, factor*V1.x, factor*V1.y); + text(sel_edge.r_name, factor*V2.x, factor*V2.y); + text(sel_edge.r_to, factor*V3.x, factor*V3.y); + } + } +} + +void allUpdate() { + Iterator itv = nodes.keySet().iterator(); + while (itv.hasNext ()) { + String key = (String) itv.next(); + Node node = (Node) nodes.get(key); + node.update(); + } +} + +void allFix() { + Iterator it = nodes.keySet().iterator(); + while (it.hasNext ()) { + String key = (String) it.next(); + Node node = (Node) nodes.get(key); + node.fix(); + } +} + +void allFree() { + Iterator it = nodes.keySet().iterator(); + while (it.hasNext ()) { + String key = (String) it.next(); + Node node = (Node) nodes.get(key); + if (!node.root) + node.free(); + } + damper = 1.0; +} + +void allMove(float mx, float my) { + Iterator it = nodes.keySet().iterator(); + while (it.hasNext ()) { + String key = (String) it.next(); + Node node = (Node) nodes.get(key); + node.move(mx, my); + } +} + +void setEdgeValue(String asc_id, String r_name, String r_from, String r_to, String s, String clr) { + if (edgetrace) println("setEdgeValue("+asc_id+","+r_name+","+r_from+","+r_to+","+s+","+clr+") "); + Edge e = edges.get(asc_id); + if (e!=null) { + e.r_name = r_name; + e.r_from = r_from; + e.r_to = r_to; + if (s!=null && !"".equals(s)) e.shape = s; + if (clr!=null && !"".equals(clr)) e.c = hexToColor(clr); + if (edgetrace) println("\tEdge UPDATED"); + } +} + +Edge findEdge(String asc_id, String proj) { + if (debug) print("\n\tfindEdge asc_id=" + asc_id + " proj=" + proj); + Edge e = null; + Iterator it = edges.keySet().iterator(); + while (it.hasNext ()) { + String k = (String) it.next(); + e = (Edge) edges.get(k); + asc_id = asc_id.trim(); + proj = proj.trim(); + if(k.equals(asc_id) && e.proj.equals(proj)) { + if (debug) { + if (debug) println("\tedge FOUND."); + } + return e; + } + } + if (debug) println("\tedge NOT found."); + return null; +} + +void addEdge(String asc_id, String fromId, String fromProj, String toId, String toProj, + String r_name, String r_from, String r_to, String uid, String proj) { + if (edgetrace) println("================\naddEdge asc_id=" + asc_id + + " from id=" + fromId + " proj="+fromProj+" to id=" + toId +" proj="+toProj+ " uid=" + uid+ " proj=" + proj ); + if("".equals(fromId) || fromId == null || "".equals(toId) || toId == null) return; + boolean newedge = false; + char dir; + String pair, reverse_pair; + Node from = findNode(fromId, fromProj); + if (from==null) from = newNode(fromId, fromId, "", uid, fromProj); + Node to = findNode(toId, toProj); + if (to==null) to = newNode(toId, toId, "", uid, toProj); + if (edgetrace) println("\tfromId="+fromId+" toId="+toId); + if(fromId.hashCode() < toId.hashCode()) { + pair = fromId+"#"+toId; + reverse_pair = toId+"#"+fromId; + } + else { + pair = toId+"#"+fromId; + reverse_pair = fromId+"#"+toId; + } + if (edgetrace) println("\tpair="+pair+"\tasc_id="+asc_id); + from.update(); + to.update(); + if ("".equals(asc_id)){ + newedge = true; + asc_id = fromId+"#"+toId; + Edge e = findEdge(asc_id, proj); + if (e!=null) return; + } + Edge the_edge = new Edge(from, to, uid, proj); + the_edge.asc_id = asc_id; + int count_connection = 0; + Iterator it = connected_edges.keySet().iterator(); + while (it.hasNext ()) { + String k = (String) it.next(); + if ( k.indexOf(pair)==0 || k.indexOf(reverse_pair)==0 ) count_connection++; + } + if (newedge) the_edge.dup = 0; else the_edge.dup = count_connection; + the_edge.setRole(r_name, r_from, r_to); + if (edgetrace) println("\tthe_edge.setRole("+r_name+","+ r_from+","+ r_to+")"); + if (edgetrace) println("\taddEdge edges put\t" + asc_id + "\t" + the_edge.from.name + "\t" + the_edge.to.name); + edges.put(asc_id, the_edge); + if (edgetrace) println("\taddEdge connected_edges put\t" + pair + ":" + count_connection +"\t"+ asc_id); + connected_edges.put(pair + ":" + count_connection, asc_id); + if (edgetrace) { + println("\tconnected_edges size=" + connected_edges.size()); + it = connected_edges.keySet().iterator(); + while (it.hasNext()) { + String k = (String) it.next(); + println("\t\tlist\t" + k + "\t" + connected_edges.get(k)); + } + } + if (edgetrace) println("================ addEdge"); +} + +void addSpacersToNode( Node node ) { + Iterator it = nodes.keySet().iterator(); + while (it.hasNext ()) { + String key = (String) it.next(); + Node n = (Node) nodes.get(key); + Particle q = n.p; + if ( node.p != q ) { + physics.makeAttraction( q, node.p, -SPACER_STRENGTH, MIN_DISTANCE ); + } + } +} + +Node newNode(String id, String name, String grp, String uid, String proj) { + if (nodetrace) print("----------------\nnewNode\tdefine\tid=" + id + " name=" + name + " grp=" + grp); + if (id == null || id.equals("")) return null; + if (name == null || name.equals("")) return null; + String label = name;//unescapeSTR(name); + Node node = findNode(id, proj); + if (node == null) node = new Node(id, label, grp, uid, proj); + node.name = label; + node.grp = grp; + if (nodetrace) println("\tdefined\tid=" + node.id + " name=" + node.name + " grp=" + node.grp); + addNode(node); + if (nodetrace) println("---------------- newNode"); + return node; +} + +void urlNode(String url, String id, String proj) { + if (nodetrace) println("node="+id+" url="+url); + Node node = findNode(id, proj); + if (node != null && url != null) node.setURL(url); +} +void addNode(Node node) { + if (nodetrace) print("\t--------\n\taddNode id=" + node.id + " name=" + node.name); + String the_id = node.id; + String proj = node.proj; + Node the_node = findNode( the_id, proj ); + if (the_node!=null) { // increment used count + if (nodetrace) println("\taddNode node Exists."); + the_node.count += 1; + } + else { // add new node + if (nodetrace) println("\taddNode ADD node."); + nodes.put( the_id, node ); + addSpacersToNode( node ); + } + if (nodetrace) { + println("\tnodes size=" + nodes.size() ); + Iterator it = nodes.keySet().iterator(); + while (it.hasNext ()) { + String key = (String) it.next(); + Node n = (Node) nodes.get(key); + println("\t\tlist\t" + key + "\t" + n.name); + } + println("\t-------- addNode"); + } +} + +void printHex(String str) { + char chr; + int i; + println(str); + println("length="+str.length()); + for (i = 0; i < str.length(); i++) { + chr = str.charAt(i) ; + print(" " + hex((int)chr,4)); + } + print("\n"); +} + +Node findNode(String id, String proj) { + if (nodetrace) print("\n\tfindNode id=" + id + " proj=" + proj); + Node n = null; + Iterator it = nodes.keySet().iterator(); + while (it.hasNext ()) { + String k = (String) it.next(); + n = (Node) nodes.get(k); + id = id.trim(); + proj=proj.trim(); + if(k.equals(id) && n.proj.equals(proj)) { + if (nodetrace) { + println("\tnode FOUND."); + } + return n; + } + } + if (nodetrace) println("\tnode NOT found."); + return null; +} + +void selectNode(Node node) { + if (nodetrace) println("selectNode(" + node.id + ")"); + String the_id = node.id; + topicX = Math.round( node.p.position.x ); + topicY = Math.round( node.p.position.y ); + if (node.vizgroup == null) + vizgroup.clear(); + else + vizgroupNodes(node); +} + +void infoNode(Node node) { + //func = "info node"; + String the_id = node.id; + String the_proj = node.proj; + if (nodetrace) println("infoNode name=" + node.name + " id=" + the_id + " proj=" + the_proj); + if ( javascript != null ) { + javascript.selectnode(the_id, the_proj); + } +} + +void topicNode(Node node) { + //func = "topic node"; + String the_id = node.id; + if ( javascript != null ) { + if (nodetrace) println("topicNode " + node.name + " (" + node.id + ")"); + javascript.topicnode(the_id); + } +} + +void setNodePosition(String id, String proj, int x, int y) { + if (nodetrace) println("setNodePosition id=" + id + " proj=" + proj); + Node node = findNode(id, proj); + if (node!=null) node.position(x, y); +} + +void fixNode(String id, String proj) { + if (nodetrace) println("fixNode id=" + id + " proj=" + proj); + Node node = findNode(id, proj); + if (node!=null) node.fix(); +} + +void setNodeValue(String id, String proj, String name, String grp, String abst, String uid) { + if (nodetrace) println("setNodeValue id=" + id + " proj=" + proj); + Node node = findNode(id, proj); + if ( node != null ) { + if ( uid != null && !uid.equals("") ) node.uid = uid; + if ( name != null && !name.equals("") ) node.name = name; + if ( grp != null && !grp.equals("") ) node.grp = grp; + if ( abst != null && !abst.equals("") ) node.abst = abst; + } +} + +void setNodeName(String id, String proj, String name) { + if (nodetrace) println("setNodeName id=" + id + " proj=" + proj + " name=" + name); + Node node = findNode(id, proj); + if ( node != null ) { + if ( name != null && !name.equals("") ) node.name = name; + } +} + +void setNodeAssoc(String id, String proj, int assoc) { + if (nodetrace) println("setNodeAssoc id=" + id + " proj=" + proj); + Node node = findNode(id, proj); + if ( node!=null ) node.assoc = assoc; + if ( nodetrace ) println("\tset node "+node.name+"("+id+")"+"\tassoc="+node.assoc); +} + +void setNodeCount(String id, String proj, int count) { + if (nodetrace) println("setNodeCount id=" + id + " proj=" + proj); + Node node = findNode(id, proj); + if ( node!=null ) node.count = count; + if (nodetrace) println("\tset node "+node.name+"("+id+")"+"\tcount="+node.count); +} + +void setNodeMass(String id, String proj, int mass) { + if (nodetrace) println("setNodeMass id=" + id + " proj=" + proj); + Node node = findNode(id, proj); + if (node!=null) node.mass = mass; + if (nodetrace) println("\tset node "+node.name+"("+id+")"+"\tmass="+node.mass); +} + +void setNodeFreeDirection(String id, String proj, String d) { + if (nodetrace) println("setNodeFreeDirection id=" + id + " proj=" + proj); + Node node = findNode(id, proj); + if ( node!=null ) { + node.freeDirection = d; + node.p.freeDirection = d; + } +} + +void setNodeVizgroup(String id, String proj, String g) { + if (nodetrace) println("setNodeVizgroup id=" + id + " proj=" + proj); + Node node = findNode(id, proj); + if ( node!=null ) { + node.vizgroup = g; + } +} + +void setNodeSize(String id, String proj, int size) { + if (nodetrace) println("setNodeSize id=" + id + " proj=" + proj); + Node node = findNode(id, proj); + if ( node!=null ) node.size = size; +} + +void newTopic() { + if (debug) println("newTopic"); + if (javascript!=null) { + javascript.new_topic(); + } +} + +void pedia() { + if (debug) println("pedia"); + if (javascript!=null) { + javascript.pedia(); + } +} +/* +void setTopic(String oldid, String id, String name, String grp) { + if (debug) println("setTopic oldid="+oldid+" id=" + id + " name=" + name + " grp=" + grp); + //if (debug) println("setTopic id=" + id + " name=" + name + " grp=" + grp); + name = name; //unescapeSTR( name ); + oldid = oldid; + id = id; + Node n = findNode(id); + if (n == null) n = newNode(id, name, grp); + if (debug) println( n.id ); + n.name = name; + n.grp = grp; + n.fix(); + n.position(0, 0); + ArrayList connected = new ArrayList(); + Node oldnode = findNode(oldid); + if (oldnode!=null) { + connected = connectedEdges(oldnode); + for (int i = 0; i < connected.size(); i++) { + Edge e = (Edge) connected.get(i); + if (debug) println("\told:" + oldnode.name + " relation:" + e.from.name + " " + e.to.name); + if ( oldnode.id.equals(e.from.id) ) { + if (debug) println("\tnew:" + name + " relation:" + name + " " + e.to.name); + e.from.id = id; + e.from.name = name; + e.from.grp = grp; + } + else if (oldnode.id.equals(e.to.id) ) { + if (debug) println("\tnew:" + name + " relation:" + e.from.name + " " + name); + e.to.id = id; + e.to.name = name; + e.to.grp = grp; + } + } + } + hideNode(oldnode); +} +*/ +void newRelation(Node n) { + if (debug) println("newRelation"); + //func = "new relation"; + from_node = selected; + selection = null; + damper = 1.0; +} + +void expandNode(Node node, String both) { + //func = "expand node"; + free = true; + connected_edges.clear(); + String the_id = node.id; + String the_proj = node.proj; + fixNode(the_id, the_proj); + if (javascript!=null) { + javascript.startexpand(); + ArrayList connected = new ArrayList(); + connected = connectedEdges(node); + the_adjacents = "(''"; + for (int i = 0; i < connected.size(); i++) { + Edge e = (Edge) connected.get(i); + String ajacent_id = ""; + if ( node.id.equals(e.from.id) ) { + ajacent_id = e.to.id; + } + else if ( node.id.equals(e.to.id) ) { + ajacent_id = e.from.id; + } + the_adjacents += ",'"+ajacent_id+"'"; + } + the_adjacents += ")"; + if (debug) println("expandNode name="+node.name+" id="+node.id+" proj="+node.proj+" ajacents="+the_adjacents); + javascript.adjacentnodes(the_id, the_proj, the_adjacents, both); + javascript.endexpand(); + } + damper = 1.0; +} + +void squeezeNode(Node node) { + //func = "squeeze node"; + ArrayList connected = new ArrayList(); + String from_is, to_is; + from_is = to_is = ""; + String the_id = node.id; + Node self, other; + self = other = null; + if (debug) println("squeezeNode " + the_id + " " + node.isa); + if (!node.isa.equals("leaf")) { + connected = connectedEdges(node); + if (debug) println(connected.size() + " connected edge(s)"); + for (int i = 0; i < connected.size(); i++) { + Edge e = (Edge) connected.get(i); + if (the_id.equals(e.from.id)) { + self = e.from; + from_is = e.from_is; + other = e.to; + to_is = e.to_is; + } + else if (the_id.equals(e.to.id)) { + self = e.to; + from_is = e.to_is; + other = e.from; + to_is = e.from_is; + } + if (debug) println("self=" + self.id + ":" + self.isa + "(" + from_is + ")\t" + + "other=" + other.id + ":" + other.isa + "(" + to_is + ")"); + if ( to_is != null && to_is.equals("leaf") ) { + if (other.isa.equals("leaf")) { + if (debug) println("remove edge " + e.asc_id + " leaf " + other.id); + edges.remove(e.asc_id); + nodes.remove(other.id); + for (int j = 0; j < physics.numberOfAttractions(); j++) { + Attraction attraction = physics.getAttraction(j); + if (attraction.getOneEnd() == other.p || attraction.getTheOtherEnd() == other.p) { + attraction.turnOff(); + } + } + for (int j = 0; j < physics.numberOfAttractions(); j++) { + Attraction attraction = physics.getAttraction(j); + if ( attraction.isOff() ) physics.removeAttraction(j); + } + } + else if (other.isa.equals("branch")) { + if (debug) println("squeeze branch " + other.id); + squeezeNode(other); + edges.remove(e.asc_id); + nodes.remove(other.id); + for (int j = 0; j < physics.numberOfAttractions(); j++) { + Attraction attraction = physics.getAttraction(j); + if (attraction.getOneEnd() == other.p || attraction.getTheOtherEnd() == other.p) { + attraction.turnOff(); + } + } + for (int j = 0; j < physics.numberOfAttractions(); j++) { + Attraction attraction = physics.getAttraction(j); + if ( attraction.isOff() ) physics.removeAttraction(j); + } + } + } + } + } +} + +void deleteTopic(String id, String proj) { + if (debug) println("deleteTopic " + id); + Node node = findNode(id, proj); + if (node!=null) hideNode(node); +} + +void hideNode(Node node) { + if (debug) println("hideNode " + node.id + " " + node.isa); + //func = "hide node"; + if (node.vizgroup!=null) return; + ArrayList connected = new ArrayList(); + connected = connectedEdges(node); + //if (!node.root) { + if (connected.size() > 0) squeezeNode(node); + String the_id = node.id; + if (debug) println(connected.size() + " connected edge(s)"); + if (connected !=null) { + for (int i=0; i < connected.size(); i++) { + Edge e = connected.get(i); + edges.remove(e.asc_id); + } + } + + if (debug) println("\tRemove " + node.id + " " + node.name); + nodes.remove(node.id); + + for (int i = 0; i < physics.numberOfAttractions(); i++) { + Attraction attraction = physics.getAttraction(i); + if (attraction.getOneEnd() == node.p || attraction.getTheOtherEnd() == node.p) { + attraction.turnOff(); + } + } + for (int i = 0; i < physics.numberOfAttractions(); i++) { + Attraction attraction = physics.getAttraction(i); + if ( attraction.isOff() ) physics.removeAttraction(i); + } + //} +} + +void markNode() { + //Object k; + String k; + String key; + Node node; + Edge edge; + int count; + Iterator it; + ArrayList adjacent = new ArrayList(); + // clear node isa status + it = nodes.keySet().iterator(); + while (it.hasNext ()) { + key = (String) it.next(); + node = (Node) nodes.get(key); + node.isa = ""; + node.count = 0; + nodes.put(key, node); + } + // reset node conecctioncounts + it = edges.keySet().iterator(); + while (it.hasNext ()) { + k = (String) it.next(); + edge = (Edge) edges.get(k); + key = edge.from.id; + node = (Node) nodes.get(key); + node.count += 1; + key = edge.to.id; + node = (Node) nodes.get(key); + node.count += 1; + } + it = nodes.keySet().iterator(); + while (it.hasNext ()) { + key = (String) it.next(); + node = (Node) nodes.get(key); + // A node is leaf iff a node is connected to one edge. + count = node.count; + if (!node.root && node.isa.equals("") && count == 1) { + node.isa = "leaf"; + //if (debug) print(key + " is leaf.\n"); + nodes.put(key, node); + } + // A node is trunk iff a node is root. + if (node.root) { + node.isa = "trunk"; + //if (debug) print(key + " is trunk.\n"); + nodes.put(key, node); + // A node is trunk iff a node is connected directry to root node. + adjacent = adjacentNodes(node); + for (int i = 0; i < adjacent.size(); i++) { + Node n = (Node) adjacent.get(i); + key = n.id; + n.isa = "trunk"; + //if (debug) print(key + " is trunk connected to root.\n"); + nodes.put(key, n); + } + } + } + // repeat 3 times + int repeat = 0; + while (repeat++ <= 3) { + it = nodes.keySet().iterator(); + while (it.hasNext ()) { + key = (String) it.next(); + node = (Node) nodes.get(key); + if (node.isa.equals("")); + { + // A node is branch iff a node is connected directry to n-1 leaf and/or branch nodes. + // A node is trunk iff a node is connected directry to more than 2 trunk nodes. + adjacent = adjacentNodes(node); + int branch_count, trunc_count; + branch_count = trunc_count = 0; + for (int i = 0; i < adjacent.size(); i++) { + Node n = (Node) adjacent.get(i); + if (n.isa.equals("leaf") || n.isa.equals("branch")) branch_count++; + else if (n.isa.equals("trunk")) trunc_count++; + } + if (node.isa.equals("") && branch_count == adjacent.size() - 1) { + node.isa = "branch"; + //if (debug) print(key + " is branch.(Step2)\n"); + nodes.put(key, node); + } + else if (node.isa.equals("") && trunc_count >= 2) { + node.isa = "trunk"; + //if (debug) print(key + " is trunk.(Step2)\n"); + nodes.put(key, node); + } + } + } + } + // A node is trunk if a node is neigther leaf nor branch i.e. "". + it = nodes.keySet().iterator(); + while (it.hasNext ()) { + key = (String) it.next(); + node = (Node) nodes.get(key); + if (node.isa.equals("")) { + node.isa = "trunk"; + //if (debug) print(key + " is trunk.(Step3)\n"); + nodes.put(key, node); + } + } +} + +ArrayList adjacentNodes(Node node) { + ArrayList adjacent = new ArrayList(); + String the_id = node.id; + Iterator it = edges.keySet().iterator(); + while (it.hasNext ()) { + Object k = it.next(); + Edge e = (Edge) edges.get(k); + Node other = null; + if (the_id.equals(e.from.id)) { + other = e.to; + } + else if (the_id.equals(e.to.id)) { + other = e.from; + } + if (other != null) adjacent.add(other); + } + return adjacent; +} + +void vizgroupNodes(Node node) { + vizgroup.clear(); + String the_vizgroup = node.vizgroup; + Iterator it = nodes.keySet().iterator(); + while (it.hasNext ()) { + String key = (String) it.next(); + Node n = (Node) nodes.get(key); + if (the_vizgroup.equals(n.vizgroup)) { + if (n != null) vizgroup.add(n); + } + } +} + +void rootNode(Node node) { + if (node == null) { + if (debug) println("EMPTY node"); + return; + } + if (debug) { + println("rootNode " + node.name); + } + physics.clear(); + edges.clear(); + nodes.clear(); + usercolors.clear(); + node.root = true; + node.fix(); + node.position(0, 0); + node.c = rootColor; + addNode(node); + if ( javascript != null ) { + //javascript.countassoc(node.id, node.proj); + } +} + +void markEdge() { + Iterator it; + Object k; + Edge edge; + Node node; + String key; + ArrayList connected = new ArrayList(); + int count; + // clear node isa status + it = edges.keySet().iterator(); + while (it.hasNext ()) { + key = (String) it.next(); + edge = (Edge) edges.get(key); + edge.from_is = ""; + edge.to_is = ""; + edges.put(key, edge); + } + it = nodes.keySet().iterator(); + while (it.hasNext ()) { + k = it.next(); + node = (Node) nodes.get(k); + String the_id = node.id; + if (node.isa.equals("leaf")) { + checkEdges(node); + } + } + it = nodes.keySet().iterator(); + while (it.hasNext ()) { + k = it.next(); + node = (Node) nodes.get(k); + String the_id = node.id; + if (!node.isa.equals("leaf")) { + checkEdges(node); + } + } +} + +void checkEdges(Node node) { + String the_id = node.id; + ArrayList connected = new ArrayList(); + connected = connectedEdges(node); + for (int i = 0; i < connected.size(); i++) { + Edge edge = (Edge) connected.get(i); + Node from = edge.from; + Node to = edge.to; + if (the_id.equals(from.id) && edge.from_is.equals("")) { + if (from.isa.equals("leaf")) { + edge.from_is = "leaf"; + edge.to_is = "trunk"; + } + else if (from.isa.equals("branch") && + (to.isa.equals("trunk") || to.isa.equals("root")) ) { + edge.from_is = "leaf"; + edge.to_is = "trunk"; + } + } + else if (the_id.equals(to.id) && edge.to_is.equals("")) { + if (to.isa.equals("leaf")) { + edge.to_is = "leaf"; + edge.from_is = "trunk"; + } + else if (to.isa.equals("branch") && + (from.isa.equals("trunk") || from.isa.equals("root")) ) { + edge.to_is = "leaf"; + edge.from_is = "trunk"; + } + } + } + boolean found_trunk = false; + boolean found_leaf = false; + for (int i = 0; i < connected.size(); i++) { + Edge edge = (Edge) connected.get(i); + Node from = edge.from; + Node to = edge.to; + if ( (the_id.equals(from.id) && edge.from_is.equals("leaf")) || + (the_id.equals(to.id) && edge.to_is.equals("leaf")) ) { + found_trunk = true; + } + if ( (the_id.equals(from.id) && edge.from_is.equals("trunk")) || + (the_id.equals(to.id) && edge.to_is.equals("trunk")) ) { + found_leaf = true; + } + } + for (int i = 0; i < connected.size(); i++) { + Edge edge = (Edge) connected.get(i); + Node from = edge.from; + Node to = edge.to; + if (the_id.equals(from.id) && edge.from_is.equals("")) { + if (from.isa.equals("branch") && to.isa.equals("branch")) { + if (found_leaf) { + edge.from_is = "leaf"; + edge.to_is = "trunk"; + } + if (found_trunk) { + edge.from_is = "trunk"; + edge.to_is = "leaf"; + } + } + } + else if (the_id.equals(to.id) && edge.to_is.equals("")) { + if (to.isa.equals("branch") && from.isa.equals("branch")) { + if (found_leaf) { + edge.to_is = "leaf"; + edge.from_is = "trunk"; + } + if (found_trunk) { + edge.to_is = "trunk"; + edge.from_is = "leaf"; + } + } + } + } +} + +void infoEdge(Edge e) { + if (debug) println("infoEdge " + e.asc_id); + //func = "info edge"; + String asc_id = e.asc_id; + if ( javascript != null ) { + javascript.selectedge(asc_id); + } +} + +void removeEdge(String asc_id) { + Edge e = edges.get(asc_id); + hideEdge(e); +} + +void hideEdge(Edge e) { //TODO renumber duplicate eges between the same node pair. + if (debug) println("hideEdge " + e.asc_id); + String asc_id = e.asc_id; + Node from = e.from; + Node to = e.to; + edges.remove(asc_id); + Iterator it = edges.keySet().iterator(); + int count_from=0; + int count_to=0; + while (it.hasNext ()) { + Object k = it.next(); + Edge edge = (Edge) edges.get(k); + if (edge.from.id.equals(from.id) || edge.to.id.equals(from.id)) { + count_from++; + } + if (edge.from.id.equals(to.id) || edge.to.id.equals(to.id)) { + count_to++; + } + } + if (count_from == 0) { + squeezeNode(from); + hideNode(from); + } + else { + from.count = count_from; + from.assoc -= 1; + } + if (count_to == 0) { + squeezeNode(to); + hideNode(to); + } + else { + to.count = count_to; + to.assoc -= 1; + } +} + +ArrayList connectedEdges(Node node) { + ArrayList connected = new ArrayList(); + String the_id = node.id; + Iterator it = edges.keySet().iterator(); + while (it.hasNext ()) { + Object k = it.next(); + Edge edge = (Edge) edges.get(k); + if (the_id.equals(edge.from.id) || the_id.equals(edge.to.id)) { + connected.add(edge); + } + } + return connected; +} + +ArrayList connectedNodes(Node node) { + ArrayList connected = new ArrayList(); + String the_id = node.id; + Iterator it = edges.keySet().iterator(); + while (it.hasNext ()) { + Object k = it.next(); + Edge e = (Edge) edges.get(k); + if ( the_id.equals(e.from.id) ) + connected.add(e.to); + else if ( the_id.equals(e.to.id) ) + connected.add(e.from); + } + return connected; +} + diff -r e05da377a27e -r 4baa7530912c src/hp/static/hp/tmgraph/physics.pde --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/hp/static/hp/tmgraph/physics.pde Wed Nov 14 17:26:06 2012 +0100 @@ -0,0 +1,1162 @@ +/* +This is a cached copy of http://geoviz.googlecode.com/svn +Search all code Search in http://geoviz.googlecode.com/svn +http://geoviz.googlecode.com/svn/trunk/touchgraph/src/main/java/geovista/touchgraph/TGLayout.java + */ +/* + * TouchGraph LLC. Apache-Style Software License + * + * + * Copyright (c) 2002 Alexander Shapiro. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The end-user documentation included with the redistribution, + * if any, must include the following acknowledgment: + * "This product includes software developed by + * TouchGraph LLC (http://www.touchgraph.com/)." + * Alternately, this acknowledgment may appear in the software itself, + * if and wherever such third-party acknowledgments normally appear. + * + * 4. The names "TouchGraph" or "TouchGraph LLC" must not be used to endorse + * or promote products derived from this software without prior written + * permission. For written permission, please contact + * alex@touchgraph.com + * + * 5. Products derived from this software may not be called "TouchGraph", + * nor may "TouchGraph" appear in their name, without prior written + * permission of alex@touchgraph.com. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL TOUCHGRAPH OR ITS CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * Following codes EulerIntegrator are inspired by TGLayout.java. + * http://geoviz.googlecode.com/svn/trunk/touchgraph/src/main/java/geovista/touchgraph/TGLayout.java + */ +// PHYSICS //////////////////////////////////////////// +/* +* May 29, 2005 +* @author jeffrey traer bernstein +* moified by ns 2012 +*/ +public interface Force { + public void turnOn(); + public void turnOff(); + public boolean isOn(); + public boolean isOff(); + public void apply(); +} + +public interface Integrator { + public void step( float t ); +} + +public class EulerIntegrator implements Integrator { + ParticleSystem s; + + public EulerIntegrator( ParticleSystem s ) { + this.s = s; + } + + public void step( float t ) { + s.clearForces(); + s.applyForces(); + + for ( int i = 0; i < s.numberOfParticles(); i++ ) { + float lastMaxMotion = maxMotion; + maxMotion = 0; + motionRatio = 1.0; + Particle p = (Particle)s.getParticle( i ); + if ( p.isFree() ) { + p.velocity.add( p.force.x/(p.mass * t), p.force.y/(p.mass * t) ); + + float squared = p.velocity.x*p.velocity.x + p.velocity.y*p.velocity.y; + float len = (float) sqrt( squared ); + maxMotion = max( maxMotion, len ); + if (maxMotion>0) motionRatio = lastMaxMotion/maxMotion - 1; //subtract 1 to make a positive value mean that + else motionRatio = 0; //things are moving faster + if ( motionRatio <= 0.001 ) { + if ((maxMotion<0.2 || (maxMotion>1 && damper<0.9)) && damper > 0.01) damper -= 0.005; + //If we've slowed down significanly, damp more aggresively (then the line two below) + else if (maxMotion<0.4 && damper > 0.003) damper -= 0.003; + //If max motion is pretty high, and we just started damping, then only damp slightly + else if (damper>0.0001) damper -=0.0001; + } + if ( maxMotion<0.001 ) { + damper=0; + } + p.velocity.multiplyBy( damper ); + + float dx = p.velocity.x/t; + float dy = p.velocity.y/t; + dx = max(-MAX_VELOCITY, min(MAX_VELOCITY, dx)); + dy = max(-MAX_VELOCITY, min(MAX_VELOCITY, dy)); + p.position.add(dx, dy ); + } + } + } +} + +public class RungeKuttaIntegrator implements Integrator { + ArrayList originalPositions; + ArrayList originalVelocities; + ArrayList k1Forces; + ArrayList k1Velocities; + ArrayList k2Forces; + ArrayList k2Velocities; + ArrayList k3Forces; + ArrayList k3Velocities; + ArrayList k4Forces; + ArrayList k4Velocities; + + ParticleSystem s; + + public RungeKuttaIntegrator( ParticleSystem s ) { + this.s = s; + + originalPositions = new ArrayList(); + originalVelocities = new ArrayList(); + k1Forces = new ArrayList(); + k1Velocities = new ArrayList(); + k2Forces = new ArrayList(); + k2Velocities = new ArrayList(); + k3Forces = new ArrayList(); + k3Velocities = new ArrayList(); + k4Forces = new ArrayList(); + k4Velocities = new ArrayList(); + } + + final void allocateParticles() { + while ( s.particles.size () > originalPositions.size() ) { + originalPositions.add( new Vector2D() ); + originalVelocities.add( new Vector2D() ); + k1Forces.add( new Vector2D() ); + k1Velocities.add( new Vector2D() ); + k2Forces.add( new Vector2D() ); + k2Velocities.add( new Vector2D() ); + k3Forces.add( new Vector2D() ); + k3Velocities.add( new Vector2D() ); + k4Forces.add( new Vector2D() ); + k4Velocities.add( new Vector2D() ); + } + } + + public final void step( float deltaT ) { + allocateParticles(); + ///////////////////////////////////////////////////////// + // save original position and velocities + for ( int i = 0; i < s.particles.size(); ++i ) { + Particle p = (Particle)s.particles.get( i ); + if ( p.isFree() ) { + ((Vector2D)originalPositions.get( i )).set( p.position ); + ((Vector2D)originalVelocities.get( i )).set( p.velocity ); + } + p.force.clear(); // and clear the forces + } + + //////////////////////////////////////////////////////////// + // get all the k1 values + s.applyForces(); + + // save the intermediate forces + for ( int i = 0; i < s.particles.size(); ++i ) { + Particle p = (Particle)s.particles.get( i ); + if ( p.isFree() ) { + ((Vector2D)k1Forces.get( i )).set( p.force ); + ((Vector2D)k1Velocities.get( i )).set( p.velocity ); + } + p.force.clear(); + } + + //////////////////////////////////////////////////////////// + // get k2 values + for ( int i = 0; i < s.particles.size(); ++i ) { + Particle p = (Particle)s.particles.get( i ); + String freeDirection = p.freeDirection; + if ( p.isFree() ) { + Vector2D originalPosition = (Vector2D)originalPositions.get( i ); + Vector2D k1Velocity = (Vector2D)k1Velocities.get( i ); + + if(freeDirection.indexOf("x")>=0) + p.position.x = originalPosition.x + k1Velocity.x * deltaT; + if(freeDirection.indexOf("y")>=0) + p.position.y = originalPosition.y + k1Velocity.y * deltaT; + //p.position.z = originalPosition.z + k1Velocity.z * deltaT; + + Vector2D originalVelocity = (Vector2D)originalVelocities.get( i ); + Vector2D k1Force = (Vector2D)k1Forces.get( i ); + + if(freeDirection.indexOf("x")>=0) + p.velocity.x = originalVelocity.x + k1Force.x * deltaT / p.mass; + if(freeDirection.indexOf("y")>=0) + p.velocity.y = originalVelocity.y + k1Force.y * deltaT / p.mass; + // p.velocity.z = originalVelocity.z + k1Force.z * deltaT / p.mass; + } + } + + s.applyForces(); + + // save the intermediate forces + for ( int i = 0; i < s.particles.size(); ++i ) { + Particle p = (Particle)s.particles.get( i ); + if ( p.isFree() ) { + ((Vector2D)k2Forces.get( i )).set( p.force ); + ((Vector2D)k2Velocities.get( i )).set( p.velocity ); + } + p.force.clear(); // and clear the forces now that we are done with them + } + + ///////////////////////////////////////////////////// + // get k3 values + for ( int i = 0; i < s.particles.size(); ++i ) { + Particle p = (Particle)s.particles.get( i ); + String freeDirection = p.freeDirection; + if ( p.isFree() ) { + Vector2D originalPosition = (Vector2D)originalPositions.get( i ); + Vector2D k2Velocity = (Vector2D)k2Velocities.get( i ); + + if(freeDirection.indexOf("x")>=0) + p.position.x = originalPosition.x + k2Velocity.x * deltaT; + if(freeDirection.indexOf("y")>=0) + p.position.y = originalPosition.y + k2Velocity.y * deltaT; + //p.position.z = originalPosition.z + k2Velocity.z * deltaT; + + Vector2D originalVelocity = (Vector2D)originalVelocities.get( i ); + Vector2D k2Force = (Vector2D)k2Forces.get( i ); + + if(freeDirection.indexOf("x")>=0) + p.velocity.x = originalVelocity.x + k2Force.x * deltaT / p.mass; + if(freeDirection.indexOf("y")>=0) + p.velocity.y = originalVelocity.y + k2Force.y * deltaT / p.mass; + //p.velocity.z = originalVelocity.z + k2Force.z * deltaT / p.mass; + } + } + + s.applyForces(); + + // save the intermediate forces + for ( int i = 0; i < s.particles.size(); ++i ) { + Particle p = (Particle)s.particles.get( i ); + if ( p.isFree() ) { + ((Vector2D)k3Forces.get( i )).set( p.force ); + ((Vector2D)k3Velocities.get( i )).set( p.velocity ); + } + p.force.clear(); // and clear the forces now that we are done with them + } + + ////////////////////////////////////////////////// + // get k4 values + for ( int i = 0; i < s.particles.size(); ++i ) { + Particle p = (Particle)s.particles.get( i ); + String freeDirection = p.freeDirection; + if ( p.isFree() ) { + Vector2D originalPosition = (Vector2D)originalPositions.get( i ); + Vector2D k3Velocity = (Vector2D)k3Velocities.get( i ); + + if(freeDirection.indexOf("x")>=0) + p.position.x = originalPosition.x + k3Velocity.x * deltaT; + if(freeDirection.indexOf("y")>=0) + p.position.y = originalPosition.y + k3Velocity.y * deltaT; + //p.position.z = originalPosition.z + k3Velocity.z * deltaT; + + Vector2D originalVelocity = (Vector2D)originalVelocities.get( i ); + Vector2D k3Force = (Vector2D)k3Forces.get( i ); + + if(freeDirection.indexOf("x")>=0) + p.velocity.x = originalVelocity.x + k3Force.x * deltaT / p.mass; + if(freeDirection.indexOf("y")>=0) + p.velocity.y = originalVelocity.y + k3Force.y * deltaT / p.mass; + //p.velocity.z = originalVelocity.z + k3Force.z * deltaT / p.mass; + } + } + + s.applyForces(); + + // save the intermediate forces + for ( int i = 0; i < s.particles.size(); ++i ) { + Particle p = (Particle)s.particles.get( i ); + if ( p.isFree() ) { + ((Vector2D)k4Forces.get( i )).set( p.force ); + ((Vector2D)k4Velocities.get( i )).set( p.velocity ); + } + } + + ///////////////////////////////////////////////////////////// + // put them all together and what do you get? + float lastMaxMotion = maxMotion; + maxMotion = 0; + motionRatio = 1.0; + for ( int i = 0; i < s.particles.size(); ++i ) { + Particle p = (Particle)s.particles.get( i ); + String freeDirection = p.freeDirection; + p.age += deltaT; + if ( p.isFree() ) { + // update position + Vector2D originalPosition = (Vector2D)originalPositions.get( i ); + Vector2D k1Velocity = (Vector2D)k1Velocities.get( i ); + Vector2D k2Velocity = (Vector2D)k2Velocities.get( i ); + Vector2D k3Velocity = (Vector2D)k3Velocities.get( i ); + Vector2D k4Velocity = (Vector2D)k4Velocities.get( i ); + + Vector2D dPosition = new Vector2D(); + if(freeDirection.indexOf("x")>=0) + dPosition.x = deltaT / 6.0f * ( k1Velocity.x + 2.0f * k2Velocity.x + 2.0f * k3Velocity.x + k4Velocity.x ); + if(freeDirection.indexOf("y")>=0) + dPosition.y = deltaT / 6.0f * ( k1Velocity.y + 2.0f * k2Velocity.y + 2.0f * k3Velocity.y + k4Velocity.y ); + //dPosition.z = deltaT / 6.0f * ( k1Velocity.z + 2.0f * k2Velocity.z + 2.0f * k3Velocity.z + k4Velocity.z ); + + float squared = dPosition.x*dPosition.x + dPosition.y*dPosition.y /*+ dPosition.z*dPosition.z*/; + float len = (float) Math.sqrt( squared ); + maxMotion = Math.max( maxMotion, len ); + if (maxMotion>0) motionRatio = lastMaxMotion/maxMotion - 1; //subtract 1 to make a positive value mean that + else motionRatio = 0; //things are moving faster + if ( motionRatio <= 0.001 ) { + //This is important. Only damp when the graph starts to move faster + //When there is noise, you damp roughly half the time. (Which is a lot) + //If things are slowing down, then you can let them do so on their own, + //without damping. + //If max motion<0.2, damp away + //If by the time the damper has ticked down to 0.9, maxMotion is still>1, damp away + //We never want the damper to be negative though +// if ((maxMotion<0.1 || (maxMotion>1 && damper<0.3)) && damper > 0.01) damper -= 0.01; + if ((maxMotion<0.2 || (maxMotion>1 && damper<0.7)) && damper > 0.01) damper -= 0.01; + //If we've slowed down significanly, damp more aggresively (then the line two below) + else if (maxMotion<0.4 && damper > 0.003) damper -= 0.003; + //If max motion is pretty high, and we just started damping, then only damp slightly + else if (damper>0.0001) damper -=0.0001; + } + if ( maxMotion<0.001 ) { + damper=0; + } + + dPosition.multiplyBy( damper ); + + if (len > MAX_DISTANCE) { + dPosition.multiplyBy( MAX_DISTANCE/len ); + } + + if(freeDirection.indexOf("x")>=0) + p.position.x = originalPosition.x + dPosition.x; + if(freeDirection.indexOf("y")>=0) + p.position.y = originalPosition.y + dPosition.y; + //p.position.z = originalPosition.z + dPosition.z; + + // update velocity + Vector2D originalVelocity = (Vector2D)originalVelocities.get( i ); + Vector2D k1Force = (Vector2D)k1Forces.get( i ); + Vector2D k2Force = (Vector2D)k2Forces.get( i ); + Vector2D k3Force = (Vector2D)k3Forces.get( i ); + Vector2D k4Force = (Vector2D)k4Forces.get( i ); + Vector2D dVelocity = new Vector2D(); + + if(freeDirection.indexOf("x")>=0) + dVelocity.x = deltaT / ( 6.0f * p.mass ) * ( k1Force.x + 2.0f * k2Force.x + 2.0f * k3Force.x + k4Force.x ); + if(freeDirection.indexOf("y")>=0) + dVelocity.y = deltaT / ( 6.0f * p.mass ) * ( k1Force.y + 2.0f * k2Force.y + 2.0f * k3Force.y + k4Force.y ); + //dVelocity.z = deltaT / ( 6.0f * p.mass ) * ( k1Force.z + 2.0f * k2Force.z + 2.0f * k3Force.z + k4Force.z ); + + squared = dVelocity.x*dVelocity.x + dVelocity.y*dVelocity.y /*+ dVelocity.z*dVelocity.z*/; + len = (float) Math.sqrt(squared); + if (len > MAX_VELOCITY) { + if(freeDirection.indexOf("x")>=0) + dVelocity.x *= MAX_VELOCITY/len; + if(freeDirection.indexOf("y")>=0) + dVelocity.y *= MAX_VELOCITY/len; + //dVelocity.z *= MAX_VELOCITY/len; + } + + if(freeDirection.indexOf("x")>=0) + p.velocity.x = originalVelocity.x + dVelocity.x; + if(freeDirection.indexOf("y")>=0) + p.velocity.y = originalVelocity.y + dVelocity.y; + //p.velocity.z = originalVelocity.z + dVelocity.z; + } + } + } +} + +public class Attraction implements Force { + Particle a; + Particle b; + float k; + boolean on; + float distanceMin; + float distanceMinSquared; + + public Attraction( Particle a, Particle b, float k, float distanceMin ) { + this.a = a; + this.b = b; + this.k = k; + on = true; + this.distanceMin = distanceMin; + this.distanceMinSquared = distanceMin*distanceMin; + } + + public void setA( Particle p ) { + a = p; + } + + public void setB( Particle p ) { + b = p; + } + + public final float getMinimumDistance() { + return distanceMin; + } + + public final void setMinimumDistance( float d ) { + distanceMin = d; + distanceMinSquared = d*d; + } + + public final void turnOff() { + on = false; + } + + public final void turnOn() { + on = true; + } + + public final void setStrength( float k ) { + this.k = k; + } + + public final Particle getOneEnd() { + return a; + } + + public final Particle getTheOtherEnd() { + return b; + } + + public void apply() { + if ( on && ( a.isFree() || b.isFree() ) ) { + float a2bX = a.position.x - b.position.x; + float a2bY = a.position.y - b.position.y; + float a2bDistanceSquared = a2bX*a2bX + a2bY*a2bY; + + if ( a2bDistanceSquared < distanceMinSquared ) { + a2bX = random(-distanceMin,distanceMin); + a2bY = random(-distanceMin,distanceMin); + } + + float force = k * a.mass * b.mass / a2bDistanceSquared; + + float length = (float)Math.sqrt( a2bDistanceSquared ); + + // make unit vector + a2bX /= length; + a2bY /= length; + + // multiply by force + a2bX *= force; + a2bY *= force; + + // apply + if (length < 600) { + if ( a.isFree() ) + a.force.add( -a2bX, -a2bY ); + if ( b.isFree() ) + b.force.add( a2bX, a2bY ); + } + } + } + + public final float getStrength() { + return k; + } + + public final boolean isOn() { + return on; + } + + public final boolean isOff() { + return !on; + } +} + +public class Particle { + public Vector2D position; + public Vector2D velocity; + public Vector2D force; + public float mass; + public float age; + public boolean dead; + public boolean fixed; + public String freeDirection; + + public Particle( float m ) { + position = new Vector2D(); + velocity = new Vector2D(); + force = new Vector2D(); + mass = m; + age = 0; + dead = false; + fixed = false; + freeDirection = "xy"; + } + + public final float distanceTo( Particle p ) { + return this.position.distanceTo( p.position ); + } + + public final void makeFixed() { + fixed = true; + velocity.clear(); + } + + public final boolean isFixed() { + return fixed; + } + + public final boolean isFree() { + return !fixed; + } + + public final void makeFree() { + fixed = false; + } + + public final Vector2D position() { + return position; + } + + public final Vector2D velocity() { + return velocity; + } + + public final float mass() { + return mass; + } + + public final void setMass( float m ) { + mass = m; + } + + public final Vector2D force() { + return force; + } + + public final float age() { + return age; + } + + public void reset() { + age = 0; + dead = false; + position.clear(); + velocity.clear(); + force.clear(); + mass = 1f; + } +} + +public class ParticleSystem { + public static final color RUNGE_KUTTA = 0; + public static final color EULER = 1; + public static final color MODIFIED_EULER = 2; + + public static final float DEFAULT_GRAVITY = 0; + public static final float DEFAULT_DRAG = 0.001f; + + ArrayList particles; + ArrayList springs; + ArrayList attractions; + ArrayList customForces = new ArrayList(); + + Integrator integrator; + + Vector2D gravity; + float drag; + + boolean hasDeadParticles = false; + + public final void setIntegrator( int integrator ) { + switch ( integrator ) { + case RUNGE_KUTTA: + this.integrator = new RungeKuttaIntegrator( this ); + break; + case EULER: + this.integrator = new EulerIntegrator( this ); + break; + } + } + + public final void setGravity( float x, float y/*, float z*/ ) { + gravity.set( x, y ); + } + + // default down gravity + public final void setGravity( float g ) { + gravity.set( 0, g ); + } + + public final void setDrag( float d ) { + drag = d; + } + + public final void tick() { + tick( 1 ); + } + + public final void tick( float t ) { + integrator.step( t ); + } + + public final Particle makeParticle( float mass, float x, float y/*, float z*/ ) { + Particle p = new Particle( mass ); + p.position.set( x, y ); + particles.add( p ); + return p; + } + + public final Particle makeParticle() { + return makeParticle( 1.0f, 0f, 0f ); + } + + public final Spring makeSpring( Particle a, Particle b, float ks, float d, float r ) { + Spring s = new Spring( a, b, ks, d, r ); + springs.add( s ); + return s; + } + + public final Attraction makeAttraction( Particle a, Particle b, float k, float minDistance ) { + Attraction m = new Attraction( a, b, k, minDistance ); + attractions.add( m ); + return m; + } + + public final void clear() { + particles.clear(); + springs.clear(); + attractions.clear(); + } + + public ParticleSystem( float g, float somedrag ) { + integrator = new RungeKuttaIntegrator( this ); + particles = new ArrayList(); + springs = new ArrayList(); + attractions = new ArrayList(); + gravity = new Vector2D( 0, g ); + drag = somedrag; + } + + public ParticleSystem( float gx, float gy, float gz, float somedrag ) { + integrator = new RungeKuttaIntegrator( this ); + particles = new ArrayList(); + springs = new ArrayList(); + attractions = new ArrayList(); + gravity = new Vector2D( gx, gy ); + drag = somedrag; + } + + public ParticleSystem() { + integrator = new RungeKuttaIntegrator( this ); + particles = new ArrayList(); + springs = new ArrayList(); + attractions = new ArrayList(); + gravity = new Vector2D( 0, ParticleSystem.DEFAULT_GRAVITY ); + drag = ParticleSystem.DEFAULT_DRAG; + } + + public final void applyForces() { + if ( !gravity.isZero() ) { + for ( int i = 0; i < particles.size(); ++i ) { + Particle p = (Particle)particles.get( i ); + p.force.add( gravity ); + } + } + + for ( int i = 0; i < particles.size(); ++i ) { + Particle p = (Particle)particles.get( i ); + p.force.add( p.velocity.x * -drag, p.velocity.y * -drag ); + } + + for ( int i = 0; i < springs.size(); i++ ) { + Spring f = (Spring)springs.get( i ); + f.apply(); + } + + for ( int i = 0; i < attractions.size(); i++ ) { + Attraction f = (Attraction)attractions.get( i ); + f.apply(); + } + + for ( int i = 0; i < customForces.size(); i++ ) { + Force f = (Force)customForces.get( i ); + f.apply(); + } + } + + public final void clearForces() { + Iterator i = particles.iterator(); + while ( i.hasNext () ) { + Particle p = (Particle)i.next(); + p.force.clear(); + } + } + + public final int numberOfParticles() { + return particles.size(); + } + + public final int numberOfSprings() { + return springs.size(); + } + + public final int numberOfAttractions() { + return attractions.size(); + } + + public final Particle getParticle( int i ) { + return (Particle)particles.get( i ); + } + + public final Spring getSpring( int i ) { + return (Spring)springs.get( i ); + } + + public final Attraction getAttraction( int i ) { + return (Attraction)attractions.get( i ); + } + + public final void addCustomForce( Force f ) { + customForces.add( f ); + } + + public final int numberOfCustomForces() { + return customForces.size(); + } + + public final Force getCustomForce( int i ) { + return (Force)customForces.get( i ); + } + + public final Force removeCustomForce( int i ) { + return (Force)customForces.remove( i ); + } + + public final void removeParticle( Particle p ) { + particles.remove( p ); + } + + public final Spring removeSpring( int i ) { + return (Spring)springs.remove( i ); + } + + public final Attraction removeAttraction( int i ) { + return (Attraction)attractions.remove( i ); + } + + public final void removeAttraction( Attraction s ) { + attractions.remove( s ); + } + + public final void removeSpring( Spring a ) { + springs.remove( a ); + } + + public final void removeCustomForce( Force f ) { + customForces.remove( f ); + } +} + +public class Spring implements Force { + float springConstant; + float damping; + float restLength; + Particle a, b; + boolean on; + + public Spring( Particle A, Particle B, float ks, float d, float r ) { + springConstant = ks; + damping = d; + restLength = r; + a = A; + b = B; + on = true; + } + + public final void turnOff() { + on = false; + } + + public final void turnOn() { + on = true; + } + + public final boolean isOn() { + return on; + } + + public final boolean isOff() { + return !on; + } + + public final Particle getOneEnd() { + return a; + } + + public final Particle getTheOtherEnd() { + return b; + } + + public final float currentLength() { + return a.position.distanceTo( b.position ); + } + + public final float restLength() { + return restLength; + } + + public final float strength() { + return springConstant; + } + + public final void setStrength( float ks ) { + springConstant = ks; + } + + public final float damping() { + return damping; + } + + public final void setDamping( float d ) { + damping = d; + } + + public final void setRestLength( float l ) { + restLength = l; + } + + public final void apply() { + if ( on && ( a.isFree() || b.isFree() ) ) { + float a2bX = a.position.x - b.position.x; + float a2bY = a.position.y - b.position.y; + + float a2bDistance = (float)Math.sqrt( a2bX*a2bX + a2bY*a2bY ); + + if ( a2bDistance == 0 ) { + a2bX = 0; + a2bY = 0; + //a2bZ = 0; + } + else { + a2bX /= a2bDistance; + a2bY /= a2bDistance; + } + + // spring force is proportional to how much it stretched + float springForce = -( a2bDistance - restLength ) * springConstant; + + // want velocity along line b/w a & b, damping force is proportional to this + float Va2bX = a.velocity.x - b.velocity.x; + float Va2bY = a.velocity.y - b.velocity.y; + + + float dampingForce = -damping * ( a2bX*Va2bX + a2bY*Va2bY ); + + // forceB is same as forceA in opposite direction + float r = springForce + dampingForce; + + a2bX *= r; + a2bY *= r; + + if (a2bDistance < MIN_DISTANCE) { + if ( a.isFree() ) + a.force.add( a2bX, a2bY ); + if ( b.isFree() ) + b.force.add( -a2bX, -a2bY ); + } + else { + if ( a.isFree() ) + a.force.add( a2bX/10, a2bY/10 ); + if ( b.isFree() ) + b.force.add( -a2bX/10, -a2bY/10 ); + } + + } + } + + public void setA( Particle p ) { + a = p; + } + + public void setB( Particle p ) { + b = p; + } +} + +public class Vector2D { + float x; + float y; + + public Vector2D( float X, float Y ) { + x = X; + y = Y; + } + + public Vector2D( ) { + x = 0; + y = 0; + } + + public Vector2D( Vector2D p ) { + x = p.x; + y = p.y; + } + + public final void set( float X, float Y ) { + x = X; + y = Y; + } + + public final void set( Vector2D p ) { + x = p.x; + y = p.y; + } + + public final void add( Vector2D p ) { + x += p.x; + y += p.y; + } + public final void subtract( Vector2D p ) { + x -= p.x; + y -= p.y; + } + + public final void add( float a, float b ) { + x += a; + y += b; + } + public final void subtract( float a, float b ) { + x -= a; + y -= b; + } + + public final Vector2D multiplyBy( float f ) { + x *= f; + y *= f; + return this; + } + + public final float distanceTo( Vector2D p ) { + return (float)Math.sqrt( distanceSquaredTo( p ) ); + } + + public final float distanceSquaredTo( Vector2D p ) { + float dx = x-p.x; + float dy = y-p.y; + return dx*dx + dy*dy; + } + + public final float distanceTo( float x, float y ) { + float dx = this.x - x; + float dy = this.y - y; + return (float)Math.sqrt( dx*dx + dy*dy ); + } + + public final float length() { + return (float)Math.sqrt( x*x + y*y ); + } + + public final float lengthSquared() { + return x*x + y*y; + } + + public final void clear() { + x = 0; + y = 0; + } + + public final String toString() { + return new String( "(" + x + ", " + y + ")" ); + } + + public boolean isZero() { + return x == 0 && y == 0; + } + + float dot( Vector2D p ) { + return x * p.x + y * p.y; + } + + float cross( Vector2D p ) { + float c = (x * p.y - y * p.x); + return (float) Math.sqrt( c * c ); + } + + float abs() { + return (float) Math.sqrt( x * x + y * y ); + } + + float distance( Vector2D a, Vector2D b) { + float EPS = 0.001f; + Vector2D b_a = new Vector2D( b.x - a.x, b.y - a.y ); + Vector2D p_a = new Vector2D( x - a.x, y - a.y ); + Vector2D a_b = new Vector2D( a.x - b.x, a.y - b.y ); + Vector2D p_b = new Vector2D( x - b.x, y - b.y ); + if ( b_a.dot(p_a) < EPS ) return p_a.abs(); + else if ( a_b.dot(p_b) < EPS ) return p_b.abs(); + else return ( b_a.cross(p_a) / b_a.abs() ); + } +} + +public class Vector3D { + float x; + float y; + float z; + + public Vector3D( float X, float Y, float Z ) { + x = X; + y = Y; + z = Z; + } + + public Vector3D() { + x = 0; + y = 0; + z = 0; + } + + public Vector3D( Vector3D p ) { + x = p.x; + y = p.y; + z = p.z; + } + + public final float z() { + return z; + } + + public final float y() { + return y; + } + + public final float x() { + return x; + } + + public final void setX( float X ) { + x = X; + } + + public final void setY( float Y ) { + y = Y; + } + + public final void setZ( float Z ) { + z = Z; + } + + public final void set( float X, float Y, float Z ) { + x = X; + y = Y; + z = Z; + } + + public final void set( Vector3D p ) { + x = p.x; + y = p.y; + z = p.z; + } + + public final void add( Vector3D p ) { + x += p.x; + y += p.y; + z += p.z; + } + public final void subtract( Vector3D p ) { + x -= p.x; + y -= p.y; + z -= p.z; + } + + public final void add( float a, float b, float c ) { + x += a; + y += b; + z += c; + } + public final void subtract( float a, float b, float c ) { + x -= a; + y -= b; + z -= c; + } + + public final Vector3D multiplyBy( float f ) { + x *= f; + y *= f; + z *= f; + return this; + } + + public final float distanceTo( Vector3D p ) { + return (float)Math.sqrt( distanceSquaredTo( p ) ); + } + + public final float distanceSquaredTo( Vector3D p ) { + float dx = x-p.x; + float dy = y-p.y; + float dz = z-p.z; + return dx*dx + dy*dy + dz*dz; + } + + public final float distanceTo( float x, float y, float z ) { + float dx = this.x - x; + float dy = this.y - y; + float dz = this.z - z; + return (float)Math.sqrt( dx*dx + dy*dy + dz*dz ); + } + + public final float dot( Vector3D p ) { + return x*p.x + y*p.y + z*p.z; + } + + public final float length() { + return (float)Math.sqrt( x*x + y*y + z*z ); + } + + public final float lengthSquared() { + return x*x + y*y + z*z; + } + + public final void clear() { + x = 0; + y = 0; + z = 0; + } + + public final String toString() { + return new String( "(" + x + ", " + y + ", " + z + ")" ); + } + + public final Vector3D cross( Vector3D p ) { + return new Vector3D( + this.y * p.z - this.z * p.y, + this.x * p.z - this.z * p.x, + this.x * p.y - this.y * p.x ); + } + + public boolean isZero() { + return x == 0 && y == 0 && z == 0; + } +} diff -r e05da377a27e -r 4baa7530912c src/hp/static/hp/tmgraph/preload.pde --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/hp/static/hp/tmgraph/preload.pde Wed Nov 14 17:26:06 2012 +0100 @@ -0,0 +1,1 @@ +/* @pjs preload="/blog/wp-content/uploads/2012/05/genbakunoko.jpg"; */ diff -r e05da377a27e -r 4baa7530912c src/hp/static/hp/tmgraph/tmgraph.pde --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/hp/static/hp/tmgraph/tmgraph.pde Wed Nov 14 17:26:06 2012 +0100 @@ -0,0 +1,370 @@ +String title = "17 June, 2012 ver.02"; +PFont font; + +String ln = "en";// "ja" "fr" +boolean personal = true; +boolean editmode = true; +boolean debug = false; +boolean nodetrace = false; +boolean edgetrace = false; +boolean eventtrace = false; +boolean attractiontrace = false; +boolean load = false; +boolean showusername = false; + +ParticleSystem physics; +Node selection, + selected, + previous_selection, + from_node, to_node, + dragnode; +Edge sel_edge, + selected_edge; +int edgeCount = 0; +int topicCount = 0; + +boolean touch = false; +boolean free = true; +boolean dragging = false; +boolean draggingnode = false; +boolean menu_active = false; +boolean apmenu_active = false; +boolean edgmenu_active = false; +boolean mouseMode = false; +boolean dowbleclick = false; +boolean touched = false; +boolean holding = false; +boolean dragmode = false; + +int menu = 0; +int edgmenu = 0; +int apmenu = 0; +int centerX, + centerY; +int touchX, + touchY; +int menuX, + menuY; +int scrnX, + scrnY; +int pressStartX, + pressStartY; +int pointX, + pointY; +int topicX, + topicY; + +float start = 0; +float elapsedTimeMillis = 0; +float elapsedTimeSec = 0.0; +float factor = 1.0; +float damper = 1.0; +float maxMotion = 0; +float motionRatio; +float start_dist, + currt_dist; +float scl; +float theta1, + phai, + theta2; +float fromX, + fromY, + toX, + toY, + cX, + cY; + +String both = "both"; +String msg = ""; +String str = ""; +String event= ""; +String func = ""; + +String unescapeSTR(String text) { + String str=text; + if (str == null || str.equals("")) return ""; + str = str.replaceAll("&","&"); + str = str.replaceAll(""","\""); + str = str.replaceAll("'","'"); + str = str.replaceAll(""","\""); + str = str.replaceAll("<","<"); + str = str.replaceAll(">",">"); + str = str.replaceAll("
","\n"); + return str; +} + +String trimSTR(String text) { + String str=text; + if (str == null || str.equals("")) return ""; + str = str.replaceAll("\n",""); + str = str.replaceAll("\f",""); + str = str.replaceAll(" ",""); + str = str.replaceAll(" ",""); + str = str.replaceAll("\r",""); + return str; +} + +void setDebugmode(){ + debug = true; +} + +//////// PROCESSING ////////////////////////////////////////////////////////// +int WORLD_SIZE_W, WORLD_SIZE_H; + +void setSize(int w, int h) { + if (javascript != null) { + WORLD_SIZE_W = w; + WORLD_SIZE_H = h; + size(w, h); + } +} + +void setup() { + WORLD_SIZE_W = 600; + WORLD_SIZE_H = 600; + size(WORLD_SIZE_W, WORLD_SIZE_H); + //size(600, 600); + + physics = new ParticleSystem( 0, DRAGFACTOR/* 0.1*/ ); + // Runge-Kutta, the default integrator is stable and snappy, + // but slows down quickly as you add particles. + // Try this to see how Euler is faster, but borderline unstable. + // physics.setIntegrator( ParticleSystem.EULER ); + // Now try this to see make it more damped, but stable. + physics.setDrag( DRAGFACTOR ); + physics.clear(); + + setNodeShapes(); + if (load) loadData(); + + frameRate(FRAME); + smooth(); + + selected = null; + selection = null; + menu_active = false; + apmenu_active = false; + mouseMode = false; + damper = 1.0f; + + if( debug || load || nodetrace || edgetrace || eventtrace || attractiontrace || editmode ) setMode(); + stopDoubleClickTimer(); +} + +void draw() { + physics.tick(TICK); + if (dragmode) + bgColor = MintCream; + else + bgColor = White; + background(bgColor); + smooth(); + + translate( WORLD_SIZE_W/2, WORLD_SIZE_H/2); + if (dragging == true) { + pushMatrix(); + translate((pointX - pressStartX) * factor, + (pointY - pressStartY) * factor); + } + + drawNetwork(); + + if (dragging == true) popMatrix(); + if (menu_active) showMenu(); + else if (apmenu_active) showApMenu(); + else if (edgmenu_active) showEdgMenu(); + translate( -WORLD_SIZE_W/2, -WORLD_SIZE_H/2); + debugTrace(); + checkHoldTimer(); +} + +void zoom(float value) { + factor = round(value*10)/10; +} + +void drawNetwork() { + noStroke(); + // draw attractions + if (attractiontrace) { + Iterator ita = physics.attractions.iterator(); + while (ita.hasNext ()) { + Attraction attraction = (Attraction) ita.next(); + if ( attraction.isOn() ) { + strokeWeight(1); + stroke(LightPink); + line(factor*attraction.getOneEnd().position.x, factor*attraction.getOneEnd().position.y, + factor*attraction.getTheOtherEnd().position.x, factor*attraction.getTheOtherEnd().position.y); + } + } + } + // draw edges + Iterator ite = edges.entrySet().iterator(); + while (ite.hasNext ()) { + Map.Entry ee = (Map.Entry)ite.next(); + String k = (String) ee.getKey(); + Edge edge = (Edge) ee.getValue(); + edge.show(); + } + if (sel_edge != null) sel_edge.highlight(); + // draw vertices + Iterator itv = nodes.entrySet().iterator(); + while (itv.hasNext ()) { + Map.Entry ev = (Map.Entry)itv.next(); + String k = (String) ev.getKey(); + Node node = (Node) ev.getValue(); + node.update(); + if(node != selection && node != selected) node.show(); + } + if ( selection != null) { + selection.highlight(); + highlite_vizgroup(); + } + if ( selected != null ) selected.highlight(); + if ( from_node != null ) from_node.highlight(); + if ( sel_edge != null ) sel_edge.highlight(); + markNode(); + markEdge(); +} + +void highlite_vizgroup() {//Displays selected group topics + if (vizgroup!=null){ + for (int i = 0; i < vizgroup.size(); i++) { + Node n = (Node) vizgroup.get(i); + n.highlight(); + } + } +} + +//////// DEBUG TRACE ///////////////////////////////////////////////////////// +void funcTrace(String f) { + func = f; + fill(Gray); + textSize(12); + textAlign(RIGHT, TOP); + text(f, WORLD_SIZE_W - 20, 10); +} + +void debugTrace() { + funcTrace(func); + fill(Gray); + textSize(12); + textAlign(LEFT, TOP); + str = "scale:" + factor; text(str, 10, 10); + str = (personal)?"personal":"team"; + str += " work"; + text(str, 70, 10); + + Iterator it = usercolors.keySet().iterator(); + int i=0,loc=10,h=10; + while (it.hasNext ()) { + String key = (String) it.next(); + UserColor usercolor = (UserColor) usercolors.get(key); + stroke(usercolor.c); + strokeWeight(3); + line (loc,WORLD_SIZE_H-h,loc+20,WORLD_SIZE_H-h); + text(usercolor.name,loc+25,WORLD_SIZE_H-h-10); + loc += textWidth(usercolor.name)+35; + if (loc > WORLD_SIZE_W - 100) { + loc=10; h -= 10; + } + } + + //str = "motion:" + toStr(mouse_motion); text(str, 10, 10); + if (debug) { + if (!isMouse) { + str = "touch menu active:" + menu_active; text(str, 10, 20); + str = "apmenu active:" + apmenu_active; text(str, 150, 20); + str = "menu:" + toStr(menu); text(str, 10, 30); + str = "apmenu:" + toStr(apmenu); text(str, 150, 30); + str = "tuoch x=" + touchX + " y=" + touchY; text(str, 10, 40); + str = "screen x=" + scrnX + " y=" + scrnY; text(str, 140, 40); + str = "point x=" + pointX + " y=" + pointY; text(str, 270, 40); + str = "screen x=" + scrnX + " y=" + scrnY; text(str, 400, 40); + str = "start x=" + pressStartX + " y=" + pressStartY; text(str, 530, 40); + str = (selection != null)? selection.name : ""; + str = "selection:\t" + str; text(str, 10, 50); + str = (selected != null)? selected.name : ""; + str = "selected:\t" + str; text(str, 10, 60); + str = event; text(str, 10, 70); + str = "dragging=" + dragging; text(str, 140, 70); + str = "dragging node=" + draggingnode; text(str, 270, 70); + str = "func=" + func; text(str, 400, 70); + str = "touch count=" + touch_count; text(str, 10, 80); + //str = "start time(ms)=" + start; text(str, 140, 80); + //str = "elapsed time=" + elapsedTimeSec; text(str, 270, 80); + //str = "holding=" + holding; text(str, 400, 80); + //str = "touched=" + touched; text(str, 530, 80); + } + else { + str = "menu active:" + menu_active; text(str, 10, 20); + str = "apmenu active:" + apmenu_active; text(str, 150, 20); + str = "menu:" + toStr(menu); text(str, 10, 30); + str = "apmenu:" + toStr(apmenu); text(str, 150, 30); + str = "mouse x=" + mouseX + " y=" + mouseY; text(str, 10, 40); + str = "point x=" + pointX + " y=" + pointY; text(str, 150, 40); + str = "screen x=" + scrnX + " y=" + scrnY; text(str, 290, 40); + str = "start x=" + pressStartX + " y=" + pressStartY;text(str, 430, 40); + str = (selection != null)? selection.name : ""; + str = "selection:\t" + str; text(str, 10, 50); + str = (from_node != null)? from_node.name : ""; + str = "from:\t" + str; text(str, 150, 50); + str = (selection != null)? selection.shape : ""; + str = "shape:\t" + str; text(str, 290, 50); + str = (selected != null)? selected.name : ""; + str = "selected:\t" + str; text(str, 10, 60); + str = (to_node != null)? to_node.name : ""; + str = "to:\t" + str; text(str, 150, 60); + str = event; text(str, 10, 70); + str = "mouse=" + mouseMode; text(str, 150, 70); + str = "dragging=" + dragging; text(str, 290, 70); + str = "func=" + func; text(str, 430, 70); + str = "start=" + start; text(str, 570, 70); + str = (sel_edge != null)? sel_edge.from.name : ""; + str = "edge from:\t" + str; text(str, 10, 80); + str = (sel_edge != null)? sel_edge.to.name : ""; + str = "to:\t" + str; text(str, 150, 80); + str = (sel_edge != null)? sel_edge.asc_id : ""; + str = "asc_id:\t" + str; text(str, 290, 80); + str = (sel_edge != null)? "" + sel_edge.dup : ""; + str = "dup:\t" + str; text(str, 430, 80); + str = (previous_selection != null)? "" + previous_selection.name : ""; + str = "previous_selection=" + str; text(str, 10, 90); + //str = "theta1=" + degrees(theta1); text(str, 10, 90); + //str = "phai=" + degrees(phai); text(str, 150, 90); + //str = "theta2=" + degrees(theta2); text(str, 290, 90); + } +} + +if (eventtrace) { + str = "mouse :" + toStr(mouse_event); text(str, 10, 110); + str = "touch :" + toStr(touch_event); text(str, 10, 120); + str = "motion:" + toStr(mouse_motion); text(str, 10, 130); + str = "action:" + toStr(mouse_action); text(str, 10, 140); + str = "time:" + millis()/1000F; text(str, 10, 150); + str = "Ct:" + touchedC; text(str, 10, 160); + str = "startC:" + startC; text(str, 10, 170); + str = "CTimer:" + elapsedTimeClick; text(str, 10, 180); + str = "Dt:" + touchedD; text(str,100, 160); + str = "startD:" + startD; text(str,100, 170); + str = "DTimer:" + elapsedTimeDoubleClick; text(str,100, 180); + str = "Ht:" + touchedH; text(str,180, 160); + str = "startH:" + startH; text(str,180, 170); + str = "HTimer:" + elapsedTimeHold; text(str,180, 180); + str = "pressed:" + mousePressed; text(str,120, 110); + str = "is down:" + is_down; text(str,120, 120); + str = "start__:" + start_dist; text(str, 10, 190); + str = "current:" + currt_dist; text(str, 10, 200); + str = "scale__:" + scl/100; text(str, 10, 210); + } +} +/* +void setParams(float frame, float spring_length, float spring_strength, float spring_damping, float spacer_strength, float drag, int mass) { + FRAME = frame; + SPRING_LENGTH = spring_length; + SPRING_STRENGTH = spring_strength; // 0.2; + SPRING_DAMPING = spring_damping; // 0.2; + SPACER_STRENGTH = spacer_strength;// 1000; + DRAGFACTOR = drag; //0.2 + //MASS = mass; +} +*/ diff -r e05da377a27e -r 4baa7530912c src/hp/templates/hp/partial/embed_player.html --- a/src/hp/templates/hp/partial/embed_player.html Wed Nov 14 16:35:12 2012 +0100 +++ b/src/hp/templates/hp/partial/embed_player.html Wed Nov 14 17:26:06 2012 +0100 @@ -2,15 +2,18 @@ {% load i18n %} {% load thumbnail %} {% load staticfiles %} -
-
+ +
-
{% endspaceless %} diff -r e05da377a27e -r 4baa7530912c src/hp/templates/hp/video_player.html --- a/src/hp/templates/hp/video_player.html Wed Nov 14 16:35:12 2012 +0100 +++ b/src/hp/templates/hp/video_player.html Wed Nov 14 17:26:06 2012 +0100 @@ -20,14 +20,11 @@

{% trans 'Watch' %} "{{content.title}}"

-
{% include "hp/partial/embed_player.html" %} -

{% trans 'Explore topics' %}

-

{% trans 'Related videos' %}