diff --git a/README.md b/README.md
index 6afd9b9a..1af6fd48 100644
--- a/README.md
+++ b/README.md
@@ -8,13 +8,17 @@ About
mil-sym-java is a well worn set of java libraries that have been used in US Army Mission Command software for years. In November 2013 Mission Command was given the approval to release and maintain these libraries as public open source.
[Developer's Guide Wiki](https://github.com/missioncommand/mil-sym-java/wiki/2525C-Renderer-Overview)
-[Google Group Discussion Forum](https://groups.google.com/forum/#!forum/mission-command-milstd-renderer)
+[JavaDocs](https://missioncommand.github.io/javadoc/2525C/java/index.html)
See new projects for 2525D+ rendering:
[Java](https://github.com/missioncommand/mil-sym-java)
[Android](https://github.com/missioncommand/mil-sym-android)
[TypeScript](https://github.com/missioncommand/mil-sym-ts)
+Other 2525C releases
+[JavaScript](https://github.com/missioncommand/mil-sym-ts/wiki/2525C-Renderer-Overview)
+[Android](https://github.com/missioncommand/mil-sym-android/wiki/2525C-Renderer-Overview)
+
MIL-STD-2525
-----------
The [MIL-STD-2525] standard defines how to visualize military symbology. This project provides support for the entire MIL-STD-2525B Change II plus USAS 13-14 and MIL-STD-2525C.
@@ -42,12 +46,6 @@ Updated to deploy on MavenCentral.
Search for mil-sym-renderer.
groupdID changed to io.github.missioncommand
-https://s01.oss.sonatype.org/#nexus-search;quick~mil-sym-renderer
-
-https://s01.oss.sonatype.org/#nexus-search;quick~mil-sym-service
-
-Also:
-
https://search.maven.org/search?q=a:mil-sym-renderer
https://search.maven.org/search?q=a:mil-sym-service
diff --git a/core/JavaLineArray/pom.xml b/core/JavaLineArray/pom.xml
index bc15da98..f3d6c29e 100644
--- a/core/JavaLineArray/pom.xml
+++ b/core/JavaLineArray/pom.xml
@@ -4,7 +4,7 @@
io.github.missioncommand
mil-sym-java
- 0.1.43
+ 0.1.45
../..
diff --git a/core/JavaLineArray/src/main/java/JavaTacticalRenderer/TGLight.java b/core/JavaLineArray/src/main/java/JavaTacticalRenderer/TGLight.java
index d40e468f..f422ed09 100644
--- a/core/JavaLineArray/src/main/java/JavaTacticalRenderer/TGLight.java
+++ b/core/JavaLineArray/src/main/java/JavaTacticalRenderer/TGLight.java
@@ -414,52 +414,55 @@ public void set_SymbolId(String value) {
}
//build the echelon symbol from the echelon
//regarless of symbolId.length
- if (echelon.equals("M")) //REGION
+ if(echelon != null)
{
- echelonSymbol = "XXXXXX";
- } else if (echelon.equals("L")) //FRONT
- {
- echelonSymbol = "XXXXX";
- } else if (echelon.equals("K")) //ARMY
- {
- echelonSymbol = "XXXX";
- } else if (echelon.equals("J")) //CORPS
- {
- echelonSymbol = "XXX";
- } else if (echelon.equals("I")) //DIVISION
- {
- echelonSymbol = "XX";
- } else if (echelon.equals("H")) //BRIGADE
- {
- echelonSymbol = "X";
- } else if (echelon.equals("G")) //REGIMENT
- {
- echelonSymbol = "III";
- } else if (echelon.equals("F")) //BATTALION
- {
- echelonSymbol = "II";
- } else if (echelon.equals("E")) //COMPANY
- {
- echelonSymbol = "I";
- } else if (echelon.equals("D")) //PLATOON
- {
- letter = (char) 9679;
- s = Character.toString(letter);
- echelonSymbol = s + s + s;
- } else if (echelon.equals("C")) //SECTION
- {
- letter = (char) 9679;
- s = Character.toString(letter);
- echelonSymbol = s + s;
- } else if (echelon.equals("B")) //SQUAD
- {
- letter = (char) 9679;
- s = Character.toString(letter);
- echelonSymbol = s;
- } else if (echelon.equals("A")) //GROUP
- {
- letter = (char) 216;
- echelonSymbol = Character.toString(letter);
+ if (echelon.equals("M")) //REGION
+ {
+ echelonSymbol = "XXXXXX";
+ } else if (echelon.equals("L")) //FRONT
+ {
+ echelonSymbol = "XXXXX";
+ } else if (echelon.equals("K")) //ARMY
+ {
+ echelonSymbol = "XXXX";
+ } else if (echelon.equals("J")) //CORPS
+ {
+ echelonSymbol = "XXX";
+ } else if (echelon.equals("I")) //DIVISION
+ {
+ echelonSymbol = "XX";
+ } else if (echelon.equals("H")) //BRIGADE
+ {
+ echelonSymbol = "X";
+ } else if (echelon.equals("G")) //REGIMENT
+ {
+ echelonSymbol = "III";
+ } else if (echelon.equals("F")) //BATTALION
+ {
+ echelonSymbol = "II";
+ } else if (echelon.equals("E")) //COMPANY
+ {
+ echelonSymbol = "I";
+ } else if (echelon.equals("D")) //PLATOON
+ {
+ letter = (char) 9679;
+ s = Character.toString(letter);
+ echelonSymbol = s + s + s;
+ } else if (echelon.equals("C")) //SECTION
+ {
+ letter = (char) 9679;
+ s = Character.toString(letter);
+ echelonSymbol = s + s;
+ } else if (echelon.equals("B")) //SQUAD
+ {
+ letter = (char) 9679;
+ s = Character.toString(letter);
+ echelonSymbol = s;
+ } else if (echelon.equals("A")) //GROUP
+ {
+ letter = (char) 216;
+ echelonSymbol = Character.toString(letter);
+ }
}
} catch (Exception exc) {
ErrorLogger.LogException(_className, "set_SymbolId",
diff --git a/core/JavaLineArray/src/main/java/JavaTacticalRenderer/clsMETOC.java b/core/JavaLineArray/src/main/java/JavaTacticalRenderer/clsMETOC.java
index 3c1f59e1..21af6cad 100644
--- a/core/JavaLineArray/src/main/java/JavaTacticalRenderer/clsMETOC.java
+++ b/core/JavaLineArray/src/main/java/JavaTacticalRenderer/clsMETOC.java
@@ -39,7 +39,7 @@ public static int IsWeather(String symbolID) {
try
{
//added section for revD
- if(symbolID.length()>15)
+ if(symbolID != null && symbolID.length()>15)
{
//test for hold,brdghd
//String setA=Modifier2.getSetA(symbolID);
diff --git a/core/JavaRenderer/pom.xml b/core/JavaRenderer/pom.xml
index 98d97a31..dfc8dbc6 100644
--- a/core/JavaRenderer/pom.xml
+++ b/core/JavaRenderer/pom.xml
@@ -4,7 +4,7 @@
io.github.missioncommand
mil-sym-java
- 0.1.43
+ 0.1.45
../..
diff --git a/core/JavaRendererServer/pom.xml b/core/JavaRendererServer/pom.xml
index 0bedd540..ce134c87 100644
--- a/core/JavaRendererServer/pom.xml
+++ b/core/JavaRendererServer/pom.xml
@@ -4,7 +4,7 @@
io.github.missioncommand
mil-sym-java
- 0.1.43
+ 0.1.45
../..
diff --git a/core/JavaRendererServer/src/main/java/RenderMultipoints/clsUtilityCPOF.java b/core/JavaRendererServer/src/main/java/RenderMultipoints/clsUtilityCPOF.java
index 0241876a..66dd6a4a 100644
--- a/core/JavaRendererServer/src/main/java/RenderMultipoints/clsUtilityCPOF.java
+++ b/core/JavaRendererServer/src/main/java/RenderMultipoints/clsUtilityCPOF.java
@@ -984,6 +984,7 @@ protected static TGLight GetCircularRangeFanFillTG(TGLight tg) {
try {
//instantiate a dummy tg which will be used to call GetSectorRangeFan
tg1 = new TGLight();
+ tg1.set_SymbolId("");
tg1.set_VisibleModifiers(true);
tg1.set_LineThickness(0);
tg1.set_FillColor(tg.get_FillColor());
diff --git a/core/JavaRendererUtils/pom.xml b/core/JavaRendererUtils/pom.xml
index fc6aab6b..c4b197ca 100644
--- a/core/JavaRendererUtils/pom.xml
+++ b/core/JavaRendererUtils/pom.xml
@@ -4,7 +4,7 @@
io.github.missioncommand
mil-sym-java
- 0.1.43
+ 0.1.45
../..
diff --git a/core/JavaRendererUtils/src/main/java/ArmyC2/C2SD/Utilities/MilStdSymbol.java b/core/JavaRendererUtils/src/main/java/ArmyC2/C2SD/Utilities/MilStdSymbol.java
index eadb1f58..9025cae9 100644
--- a/core/JavaRendererUtils/src/main/java/ArmyC2/C2SD/Utilities/MilStdSymbol.java
+++ b/core/JavaRendererUtils/src/main/java/ArmyC2/C2SD/Utilities/MilStdSymbol.java
@@ -1307,6 +1307,301 @@ public void set_WasClipped(boolean value) {
public boolean get_WasClipped() {
return _wasClipped;
}
+
+
+ /**
+ * Determines if the symbol has integral or modifier/amplifier text that would
+ * be impacted if the maps is zoomed in or out after initial draw.
+ * @return 0=not sensitive, 1=slightly little zoom in sensitive, 2=zoom in sensitive, 3=zoom in/out sensitive
+ */
+ public int isTextScaleSensitive()
+ {
+ ArrayList modifiers = this.getModifierShapes();
+ if(_Properties == null)
+ return 0;//no scale sensitive text
+ if (_Properties.isEmpty())
+ return 0;
+ else if(_symbolID.startsWith("G"))
+ {
+ String id = SymbolUtilities.getBasicSymbolID(_symbolID);
+ SymbolDef sd = SymbolDefTable.getInstance().getSymbolDef(id, this.getSymbologyStandard());
+ if(sd != null)
+ {
+ int dr = sd.getDrawCategory();
+ switch (dr)
+ {
+ case SymbolDef.DRAW_CATEGORY_ARROW:
+ if(_Properties.containsKey(ModifiersTG.W_DTG_1) ||
+ _Properties.containsKey(ModifiersTG.W1_DTG_2))
+ return 3;
+ else
+ return 0;
+
+ case SymbolDef.DRAW_CATEGORY_LINE://Linear Targets (2407##)
+ if(id.startsWith("G*F*LT"))
+ {
+ if(_Properties.containsKey(ModifiersTG.T1_UNIQUE_DESIGNATION_2))
+ return 3;
+ else if(_Properties.containsKey(ModifiersTG.T_UNIQUE_DESIGNATION_1))
+ return 2;
+ else
+ return 0;
+ }
+ break;
+ case SymbolDef.DRAW_CATEGORY_RECTANGULAR_PARAMETERED_AUTOSHAPE:
+ if(modifiers != null && modifiers.size() > 1)
+ return 3;
+ else
+ return 0;
+ case SymbolDef.DRAW_CATEGORY_CIRCULAR_PARAMETERED_AUTOSHAPE:
+ if(modifiers != null && modifiers.size() > 1)
+ return 3;
+ else
+ return 0;
+
+ default:
+ break;
+ }
+ }
+
+ switch (id)
+ {
+
+ //A Little Zoom in sensitive (1)
+ case "G*G*GLP---****X"://Phase line, only 5% sensitive
+ case "G*G*DLF---****X"://Forward Edge of Battle, only 5% sensitive
+ case "G*S*LCM---****X"://Moving Convoy
+ case "G*S*LCH---****X"://Halted Convoy
+ return 1;
+
+ //Zoom in sensitive (2)
+ case "G*G*GLL---****X"://Light Line
+ case "G*G*OLF---****X"://Final Coordination Line
+ case "G*G*OLL---****X"://Limit of Advance
+ case "G*G*OLT---****X"://Line of Departure
+ case "G*G*OLC---****X"://Line of Departure / Line of Contact
+ case "G*G*OLP---****X"://Probable Line of Deployment
+ case "G*G*SLB---****X"://Bridgehead Line
+ case "G*G*SLH---****X"://Holding Line
+ case "G*G*SLR---****X"://Release Line
+ case "G*G*SAN---****X"://Named Area of Interest Line (NAI)
+ case "G*S*LRM---****X"://Main Supply Route (MSR)
+ case "G*S*LRO---****X"://One Way Traffic
+ case "G*S*LRW---****X"://Two Way Traffic
+ case "G*S*LRT---****X"://Alternating Traffic
+ case "G*S*LRA---****X"://Alternate Supply Route (ASR)
+ return 2;
+ case "G*G*GLF---****X"://FLOT
+ case "G*G*GLC---****X"://LOC
+ if(SymbolUtilities.getAffiliation(_symbolID).equals("H"))
+ return 2;
+ else
+ return 1;
+
+ //Very Zoom in/out sensitive (multi-line text) (3)
+ //friendly and more than 1 text
+ //Hostile and more than 3 text assuming ENY is present
+ case "G*G*GLB---****X"://boundary line
+ if(_Properties.containsKey(ModifiersTG.T_UNIQUE_DESIGNATION_1) ||
+ _Properties.containsKey(ModifiersTG.T1_UNIQUE_DESIGNATION_2))
+ return 3;
+ else
+ return 0;
+
+
+ case "G*G*GAY---****X"://Limited Access Area if sector 1 modifier present
+ if(_Properties.containsKey(ModifiersTG.H_ADDITIONAL_INFO_1))
+ return 3;
+ else
+ return 0;
+
+
+ //Labels all contained in area but can drift away from each-other or overlap
+ case "G*G*GAG---****X": //Generic
+ case "G*G*AAH---****X": //High-Density Airspace Control Zone
+ case "G*G*AAR---****X": //Restricted Operations Zone (ROZ)
+ case "G*G*AAM---****X": //Missile Engagement Zone (MEZ)
+ case "G*G*AAML--****X": //Low (Altitude) Missile Engagement Zone (LOMEZ)
+ case "G*G*AAMH--****X": //High (Altitude) Missile Engagement Zone (HIMEZ)
+ case "G*G*AAF---****X": //Short Range Air Defense Engagement Zone (SHORADEZ)
+ case "G*G*AAW---****X": //Weapons Free Zone
+ case "G*F*ACAI--****X": //Airspace Coordination Area (ACA) - Irregular
+ case "G*F*ACFI--****X": //Free Fire Area (FFA) - Irregular
+ case "G*F*ACNI--****X": //No Fire Area (NFA) - Irregular
+ case "G*F*ACRI--****X": //Restricted Fire Area (RFA) - Irregular
+ case "G*F*ATS---****X": //Smoke
+ case "G*F*ACSI--****X"://Fire Support Area - Irregular
+ case "G*F*AZII--****X": //Artillery Target Intelligence Zone (ATI), - Irregular
+ case "G*F*AZXI--****X": //Call For Fire Zone (CFFZ) - Irregular
+ case "G*F*AZCI--****X": //Censor Zone, - Irregular
+ case "G*F*AZFI--****X": //Critical Friendly Zone (CFZ), - Irregular
+ case "G*F*ACDI--****X": //Dead Space Area (DA), - Irregular
+ case "G*F*ACEI--****X": //Sensor Zone, Irregular
+ case "G*F*ACBI--****X": //Target Build-up Area, Irregular
+ case "G*F*ACVI--****X": //Target Value Area, Irregular
+ case "G*F*ACZI--****X": //Zone of Responsibility, Irregular
+ //case "G*F*ACT---****X": //Terminally Guided Munition Footprint (TGMF)
+ case "G*F*AKBI--****X": //Blue Kill Box, Irregular
+ case "G*F*AKPI--****X": //Purple Kill Box, Irregular
+ case "G*M*OGF---****X": //Obstacle Free Zone
+ case "G*M*BCL---****X": //Lane
+ case "G*S*AD----****X": //Detainee Holding Area
+ case "G*S*AE----****X": //Enemy Prisoner of War Holding Area
+ case "G*S*AR----****X": //Forward Arming and Refueling Point (FARP)
+ case "G*S*AH----****X": //Refugee Holding Area
+ case "G*S*ASR---****X": //Regimental Support Area (RSA)
+ case "G*G*ALC---****X": //Air Corridor
+ case "G*G*ALM---****X": //MRR
+ case "G*G*ALS---****X": //SAAFR
+ case "G*G*ALU---****X": //UA
+ case "G*G*ALL---****X": //LLTR
+ if(modifiers != null && modifiers.size()>1)
+ return 3;
+ else
+ return 0;
+
+ case "G*F*LCF---****X"://Fire Support Coordination Line (FSCL)
+ case "G*F*LCC---****X"://Coordinated Fire Line (CFL)
+ case "G*F*LCN---****X"://No Fire Line
+ case "G*F*LCR---****X"://Restrictive Fire Line
+ if(_Properties.containsKey(ModifiersTG.W_DTG_1) ||
+ _Properties.containsKey(ModifiersTG.W1_DTG_2))
+ return 3;
+ else
+ return 2;
+
+ case "G*F*LCM---****X"://Munition Flight Path
+ case "G*T*L-----****X"://Delay
+ if(_Properties.containsKey(ModifiersTG.W_DTG_1) ||
+ _Properties.containsKey(ModifiersTG.W1_DTG_2))
+ return 2;
+ else
+ return 0;
+
+
+ default://No Scale Sensitive text
+ return 0;
+ }
+ }
+
+ return 0;
+ }
+
+ /**
+ * Checks if the symbol has features that make it scale aware and would require a refresh
+ * on zooming in or out.
+ * @return 0=No,1=arrowheads,2=decoratedLines,3=patternFills
+ */
+ public int isSymbolScaleSensitive()
+ {
+ //return SymbolUtilities.isScaleAware(this._symbolID);
+ String id = SymbolUtilities.getBasicSymbolID(_symbolID);
+
+ switch (id)
+ {
+ //ArrowHead or smaller detail
+ case "G*G*OAF---****X"://Attack By Fire
+ case "G*G*OAS---****X"://Support By Fire
+ case "G*G*GAS---****X"://Search Area/Reconnaissance Area
+ case "G*G*SLA---****X"://Ambush
+ case "G*G*OLKA--****X"://Airborne/Aviation
+ case "G*G*OLKGM-****X"://Direction of Main attack
+ case "G*G*OLKGS-****X"://Direction of Supporting attack
+ case "G*F*LT----****X"://Linear Target
+ case "G*F*LTS---****X"://Linear Smoke Target
+ case "G*F*LTF---****X"://Final Protective Fire
+ case "G*T*T-----****X"://Disrupt
+ case "G*M*OET---****X"://Turn
+ case "G*M*BDE---****X"://Obstacle Bypass Easy
+ case "G*M*BDD---****X"://Obstacle Bypass Difficult
+ case "G*M*BDI---****X"://Obstacle Bypass Impossible
+ case "G*M*BCB---****X"://Bridge or Gap?
+ case "G*M*BCA---****X"://Assault Crossing?
+ case "G*M*OS----****X"://Abatis?
+ case "G*M*BCL---****X"://?Lane?
+ case "G*M*BCF---****X"://Ferry
+ case "G*M*BCR---****X"://Raft Site
+ case "G*T*H-----****X"://Breach
+ case "G*T*Y-----****X"://Bypass
+ case "G*T*C-----****X"://Canalize
+ case "G*T*X-----****X"://Clear
+ case "G*T*L-----****X"://Delay
+ case "G*M*OED---****X"://Disrupt
+ case "G*T*A-----****X"://Follow and Assume
+ case "G*T*AS----****X"://Follow and Support
+ //case "G*T*O-----****X"://Occupy, details relative to size
+ //case "G*T*P-----****X"://Penetrate, details relative to size
+ //case "G*T*R-----****X"://Relief in Place (RIP), details relative to size
+ //case "G*T*M-----****X"://Retire/Retirement, details relative to size
+ case "G*T*S-----****X"://Secure, details relative to size
+ case "G*T*UC----****X"://Cover, details relative to size
+ case "G*T*UG----****X"://Guard, details relative to size
+ case "G*T*US----****X"://Screen, details relative to size
+ case "G*T*Z-----****X"://Seize, details relative to size
+ case "G*T*W-----****X"://Withdraw, details relative to size
+ case "G*T*WP----****X"://Withdraw under pressure, details relative to size
+ return 1;//arrowhead
+
+ //Decorated Lines
+ case "G*G*GLF---****X"://FLOT
+ case "G*G*GLC---****X"://Line of Contact
+ //case 140500://?Principal Direction of Fire?
+ case "G*G*GAF---****X"://Fortified Area
+ case "G*G*SAE---****X"://Encirclement
+ case "G*M*SP----****X"://Strong Point
+ case "G*G*DABP--****X"://Battle Position Prepared (P) but not Occupied
+ case "G*T*J-----****X"://Contain
+ case "G*T*Q-----****X"://Retain
+ case "G*M*OGB---****X"://Obstacle Belt
+ case "G*M*OGL---****X"://Obstacle Line
+ case "G*M*OGZ---****X"://Obstacle Zone
+ case "G*M*OGF---****X"://Obstacle Free Area
+ case "G*M*OGR---****X"://Obstacle Restricted Area
+ //case "G*MPOEF---****X"://Fix?
+ case "G*G*PY----****X"://Mined Area, Fenced
+ case "G*M*OHO---****X"://Overhead Wire
+ case "G*M*OADU--****X"://Ditch Under Construction
+ case "G*M*OADC--****X"://Ditch Completed
+ case "G*M*OAR---****X"://Ditch Reinforced
+ case "G*M*OAW---****X"://Antitank Wall
+ case "G*M*OWU---****X"://Wire Obstacles, Unspecified
+ case "G*M*OWS---****X"://Wire Obstacles, Single Fence
+ case "G*M*OWD---****X"://Wire Obstacles, Double Fence
+ case "G*M*OWA---****X"://Wire Obstacles, Double Apron Fence
+ case "G*M*OWL---****X"://Wire Obstacles, Low Wire Fence
+ case "G*M*OWH---****X"://Wire Obstacles, High Wire Fence
+ case "G*M*OWCS--****X"://Wire Obstacles, Single Concertina
+ case "G*M*OWCD--****X"://Wire Obstacles, Double Strand Concertina
+ case "G*M*OWCT--****X"://Wire Obstacles, Triple Strand Concertina
+ case "G*M*SL----****X"://Fortified Line
+ case "G*S*LCM---****X"://Moving Convoy
+ case "G*S*LCH---****X"://Halted Convoy
+ case "G*S*LRO---****X"://MSR One Way Traffic
+ case "G*S*LRW---****X"://MSR Two Way Traffic
+ case "G*S*LRT---****X"://MSR Alternating Traffic
+ case "G*T*F-----****X"://Fix
+ //case 341500://Isolate, most detail contained inside
+ //case 342600://Cordon and Knock, most detail contained inside
+ //case 342700://Cordon and Search, most detail contained inside
+ return 2;//decoration
+
+ //Areas with Pattern Fill
+ case "G*G*GAY---****X"://Limited Access Area
+ case "G*G*AAW---****X"://Weapons Free Zone
+ case "G*F*ACNI--****X"://NFA Irregular
+ case "G*F*ACNR--****X"://NFA Rectangular
+ case "G*F*ACNC--****X"://NFA Circular
+ case "G*M*NB----****X"://Bio Contaminated Area
+ case "G*M*NC----****X"://Chem Contaminated Area
+ case "G*M*NR----****X"://Rad Contaminated Area
+ if(!this.getUsePatternFill())
+ return 3;//pattern fill
+ else
+ return 0;
+ default:
+ return 0;
+ }
+ }
/**
* returns just the symbol as an ImageInfo object.
diff --git a/core/JavaRendererUtils/src/main/java/ArmyC2/C2SD/Utilities/RectUtilities.java b/core/JavaRendererUtils/src/main/java/ArmyC2/C2SD/Utilities/RectUtilities.java
new file mode 100644
index 00000000..5a63f89a
--- /dev/null
+++ b/core/JavaRendererUtils/src/main/java/ArmyC2/C2SD/Utilities/RectUtilities.java
@@ -0,0 +1,108 @@
+/*
+ * Copyright 2025 Michael.P.Spinelli.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package ArmyC2.C2SD.Utilities;
+
+import java.awt.Rectangle;
+import java.awt.geom.Rectangle2D;
+
+/**
+ *
+ */
+public class RectUtilities {
+
+ public static Rectangle makeRectangleFromRect(int x1, int y1, int x2, int y2) {
+ return new Rectangle(x1, y1, x2-x1, y2-y1);
+ }
+
+ public static Rectangle2D makeRectangle2DFromRect(double x1, double y1, double x2, double y2) {
+ return new Rectangle2D.Double(x1, y1, x2-x1, y2-y1);
+ }
+
+ public static Rectangle2D makeRectangle2DFromRect(float x1, float y1, float x2, float y2) {
+ return new Rectangle2D.Float(x1, y1, x2-x1, y2-y1);
+ }
+
+ /**
+ * Copies a Rectangle
+ * @param rect {@link Rectangle2D}
+ * @return {@link Rectangle2D}
+ */
+ public static Rectangle2D copyRect(Rectangle2D rect) {
+ return new Rectangle2D.Double((int)rect.getX(), (int)rect.getY(), (int)(rect.getWidth()+0.5), (int)(rect.getHeight()+0.5));
+ }
+
+ /**
+ * copies and rounds the points. x,y round down & width,height round up
+ * @param rect {@link Rectangle2D}
+ * @return {@link Rectangle2D}
+ */
+ public static Rectangle2D roundRect(Rectangle2D rect) {
+ double offsetX = rect.getX() - (int)(rect.getX());
+ double offsetY = rect.getY() - (int)(rect.getY());
+
+ return new Rectangle2D.Double((int)rect.getX(), (int)rect.getY(), (int)(Math.round(rect.getWidth()+offsetX+0.5)), (int)Math.round(rect.getHeight()+offsetY+0.5));
+ }
+
+ public static void grow(Rectangle2D rect, int size) {
+ rect.setRect(rect.getX() - size, rect.getY() - size, rect.getWidth() + (size*2), rect.getHeight() + (size*2));
+ //return new Rectangle2D.Double(rect.left - size, rect.top - size, rect.right + size, rect.bottom + size);
+ }
+
+
+ public static void shift(Rectangle2D rect, int x, int y) {
+ rect.setRect(rect.getX() + x, rect.getY() + y, rect.getWidth(), rect.getHeight());
+ }
+
+
+ public static void shiftBR(Rectangle2D rect, int x, int y) {
+ rect.setRect(rect.getX(), rect.getY(), rect.getWidth() + x, rect.getHeight() + y);
+ }
+
+ public static Rectangle toRectangle(Rectangle2D b) {
+ if (b == null) {
+ return null;
+ }/*from w ww . j a va 2s . c o m*/
+ if (b instanceof Rectangle) {
+ return (Rectangle) b;
+ } else {
+ return new Rectangle((int) b.getX(), (int) b.getY(),
+ (int) (b.getWidth()+0.5), (int) (b.getHeight()+0.5));
+ }
+ }
+
+ public static Rectangle toRectangle(double x, double y, double w, double h) {
+ return new Rectangle((int) x, (int) y,
+ (int)(w + 0.5), (int)(h + 0.5));
+ }
+
+ public static Rectangle2D toRectangle2D(double x, double y, double w, double h) {
+ return new Rectangle2D.Double(x, y,
+ w, h);
+ }
+
+ public static Rectangle2D toRectangle2D(Rectangle b) {
+ if (b == null) {
+ return null;
+ }/*from w ww . j a va 2s . c o m*/
+ else if (b instanceof Rectangle2D) {
+ return (Rectangle2D) b;
+ } else {
+ return new Rectangle2D.Double(b.getX(), b.getY(),
+ b.getWidth(), b.getHeight());
+ }
+ }
+
+}
diff --git a/core/JavaRendererUtils/src/main/java/ArmyC2/C2SD/Utilities/RendererSettings.java b/core/JavaRendererUtils/src/main/java/ArmyC2/C2SD/Utilities/RendererSettings.java
index a33b6248..fb9f5f4b 100644
--- a/core/JavaRendererUtils/src/main/java/ArmyC2/C2SD/Utilities/RendererSettings.java
+++ b/core/JavaRendererUtils/src/main/java/ArmyC2/C2SD/Utilities/RendererSettings.java
@@ -143,6 +143,8 @@ public class RendererSettings {
private boolean _TwoLabelOnly = true;
private double _overscanScale = 1.0;
+
+ private boolean _autoAdjustScale = true;
//acevedo - 12/8/17 - allow the setting of affiliation colors.
private Color _friendlyUnitFillColor = AffiliationColors.FriendlyUnitFillColor;
@@ -811,6 +813,19 @@ public void setOverscanScale(double overscanScale) {
public double getOverscanScale() {
return this._overscanScale;
}
+
+ /**
+ * Will attempt to adjust the scale if it doesn't seem to make sense with the passed in bbox.
+ * If you wish to have absolute control over the scale, set to false.
+ * @param autoAdjustScale default true
+ */
+ public void setAutoAdjustScale(boolean autoAdjustScale) {
+ this._autoAdjustScale = autoAdjustScale;
+ }
+
+ public boolean getAutoAdjustScale() {
+ return this._autoAdjustScale;
+ }
/**
* get the preferred fill affiliation color for units.
diff --git a/core/JavaRendererUtils/src/main/java/ArmyC2/C2SD/Utilities/ShapeInfo.java b/core/JavaRendererUtils/src/main/java/ArmyC2/C2SD/Utilities/ShapeInfo.java
index 17c3ce70..89fd13a7 100644
--- a/core/JavaRendererUtils/src/main/java/ArmyC2/C2SD/Utilities/ShapeInfo.java
+++ b/core/JavaRendererUtils/src/main/java/ArmyC2/C2SD/Utilities/ShapeInfo.java
@@ -400,6 +400,14 @@ public void setTexturePaint(TexturePaint value)
{
texturePaint=value;
}
+ public BufferedImage getPatternFillImage()
+ {
+ if(texturePaint != null && texturePaint.getImage() != null)
+ return texturePaint.getImage();
+ else
+ return null;
+ }
+
public int getFillStyle()
{
diff --git a/core/JavaRendererUtils/src/main/java/ArmyC2/C2SD/Utilities/SymbolDraw.java b/core/JavaRendererUtils/src/main/java/ArmyC2/C2SD/Utilities/SymbolDraw.java
index f3fdb64a..a836880f 100644
--- a/core/JavaRendererUtils/src/main/java/ArmyC2/C2SD/Utilities/SymbolDraw.java
+++ b/core/JavaRendererUtils/src/main/java/ArmyC2/C2SD/Utilities/SymbolDraw.java
@@ -435,7 +435,7 @@ public static ArrayList createTextOutlineQuick(ShapeInfo originalText
siOutline3.setLineColor(backgroundColor);
siOutline4.setLineColor(backgroundColor);
- Stroke tempStroke = new BasicStroke(1,BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND, 3);
+ BasicStroke tempStroke = new BasicStroke(1,BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND, 3);
siOutline1.setStroke(tempStroke);
siOutline2.setStroke(tempStroke);
siOutline3.setStroke(tempStroke);
@@ -490,7 +490,7 @@ else if(originalText.getGlyphVector() != null)
siOutline3.setLineColor(backgroundColor);
siOutline4.setLineColor(backgroundColor);
- Stroke tempStroke = new BasicStroke(1,BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND, 3);
+ BasicStroke tempStroke = new BasicStroke(1,BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND, 3);
siOutline1.setStroke(tempStroke);
siOutline2.setStroke(tempStroke);
siOutline3.setStroke(tempStroke);
@@ -534,7 +534,7 @@ else if(originalText.getShape() != null)
siOutline3.setLineColor(backgroundColor);
siOutline4.setLineColor(backgroundColor);
- Stroke tempStroke = new BasicStroke(1,BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND, 3);
+ BasicStroke tempStroke = new BasicStroke(1,BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND, 3);
siOutline1.setStroke(tempStroke);
siOutline2.setStroke(tempStroke);
siOutline3.setStroke(tempStroke);
@@ -680,7 +680,7 @@ public static ArrayList createSinglePointOutline(ShapeInfo symbolFram
siOutline7.setLineColor(backgroundColor);
siOutline8.setLineColor(backgroundColor);
- Stroke tempStroke = new BasicStroke(1,BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND, 3);
+ BasicStroke tempStroke = new BasicStroke(1,BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND, 3);
siOutline1.setStroke(tempStroke);
siOutline2.setStroke(tempStroke);
siOutline3.setStroke(tempStroke);
@@ -756,7 +756,7 @@ else if(symbolFrame.getGlyphVector() != null)
siOutline7.setLineColor(backgroundColor);
siOutline8.setLineColor(backgroundColor);
- Stroke tempStroke = new BasicStroke(1,BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND, 3);
+ BasicStroke tempStroke = new BasicStroke(1,BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND, 3);
siOutline1.setStroke(tempStroke);
siOutline2.setStroke(tempStroke);
siOutline3.setStroke(tempStroke);
@@ -818,7 +818,7 @@ else if(symbolFrame.getShape() != null)
siOutline7.setLineColor(backgroundColor);
siOutline8.setLineColor(backgroundColor);
- Stroke tempStroke = new BasicStroke(1,BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND, 3);
+ BasicStroke tempStroke = new BasicStroke(1,BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND, 3);
siOutline1.setStroke(tempStroke);
siOutline2.setStroke(tempStroke);
siOutline3.setStroke(tempStroke);
diff --git a/core/pom.xml b/core/pom.xml
index 9acbeaa0..c991dcfb 100644
--- a/core/pom.xml
+++ b/core/pom.xml
@@ -4,7 +4,7 @@
io.github.missioncommand
mil-sym-java
- 0.1.43
+ 0.1.45
..
diff --git a/pom.xml b/pom.xml
index 139785b1..088edd5c 100644
--- a/pom.xml
+++ b/pom.xml
@@ -3,7 +3,7 @@
io.github.missioncommand
mil-sym-java
- 0.1.43
+ 0.1.45
pom
mil-sym-java
diff --git a/renderer/RendererPluginInterface/pom.xml b/renderer/RendererPluginInterface/pom.xml
index a8f00a67..b3eafe27 100644
--- a/renderer/RendererPluginInterface/pom.xml
+++ b/renderer/RendererPluginInterface/pom.xml
@@ -4,7 +4,7 @@
io.github.missioncommand
mil-sym-java
- 0.1.43
+ 0.1.45
../..
diff --git a/renderer/mil-sym-renderer/pom.xml b/renderer/mil-sym-renderer/pom.xml
index 05581cd8..82f2190b 100644
--- a/renderer/mil-sym-renderer/pom.xml
+++ b/renderer/mil-sym-renderer/pom.xml
@@ -4,7 +4,7 @@
io.github.missioncommand
mil-sym-java
- 0.1.43
+ 0.1.45
../..
diff --git a/renderer/mil-sym-renderer/pomJava7.xml b/renderer/mil-sym-renderer/pomJava7.xml
index 16fddc35..9e634be3 100644
--- a/renderer/mil-sym-renderer/pomJava7.xml
+++ b/renderer/mil-sym-renderer/pomJava7.xml
@@ -7,7 +7,7 @@
sec.web.renderer
mil-sym-renderer
jar
- 0.1.43
+ 0.1.45
mil-sym-renderer
http://maven.apache.org
diff --git a/renderer/mil-sym-renderer/pomJava8.xml b/renderer/mil-sym-renderer/pomJava8.xml
index 52c75a08..8a309879 100644
--- a/renderer/mil-sym-renderer/pomJava8.xml
+++ b/renderer/mil-sym-renderer/pomJava8.xml
@@ -7,7 +7,7 @@
sec.web.renderer
mil-sym-renderer
jar
- 0.1.43
+ 0.1.45
mil-sym-renderer
http://maven.apache.org
diff --git a/renderer/mil-sym-renderer/src/main/java/sec/web/renderer/MultiPointHandler.java b/renderer/mil-sym-renderer/src/main/java/sec/web/renderer/MultiPointHandler.java
index 0e311df2..59fa59bd 100644
--- a/renderer/mil-sym-renderer/src/main/java/sec/web/renderer/MultiPointHandler.java
+++ b/renderer/mil-sym-renderer/src/main/java/sec/web/renderer/MultiPointHandler.java
@@ -140,7 +140,7 @@ public static void NormalizeGECoordsToGEExtents(double leftLongitude,
* @param pt2d
* @return
*/
- private static Point2D NormalizeCoordToGECoord(Point2D pt2d) {
+ protected static Point2D NormalizeCoordToGECoord(Point2D pt2d) {
Point2D ptGeo = null;
try {
double x = pt2d.getX(), y = pt2d.getY();
@@ -406,10 +406,25 @@ private static boolean crossesIDL(ArrayList geoCoords) {
* @param symbolID
* @return
*/
- public static Boolean ShouldClipSymbol(String symbolID) {
+ public static Boolean ShouldClipSymbol(String symbolID)
+ {
+ return ShouldClipSymbol(symbolID, false, false);
+ }
+
+ /**
+ * Checks if a symbol is one with decorated lines which puts a strain on
+ * google earth when rendering like FLOT. These complicated lines should be
+ * clipped when possible.
+ *
+ * @param symbolID
+ * @param useDashArray default true, some symbols don't need to be clipped if using dash array MilStdAttribute
+ * @param useFillPattern default true, some symbols don't need to be clipped if using fill pattern MilStdAttribute
+ * @return
+ */
+ public static Boolean ShouldClipSymbol(String symbolID, boolean useDashArray, boolean useFillPattern) {
String affiliation = SymbolUtilities.getStatus(symbolID);
- if (symbolID.substring(0, 1).equals("G") && affiliation.equals("A")) {
+ if (symbolID.substring(0, 1).equals("G") && affiliation.equals("A") && !useDashArray) {
//SymbolDef sd = SymbolDefTable.getInstance().getSymbolDef(symbolID);
//if(sd.getDrawCategory()==SymbolDef.DRAW_CATEGORY_LINE ||
// sd.getDrawCategory()==SymbolDef.DRAW_CATEGORY_POLYGON)
@@ -422,14 +437,14 @@ public static Boolean ShouldClipSymbol(String symbolID) {
return true;
}
+ boolean shouldClip = false;
String id = SymbolUtilities.getBasicSymbolID(symbolID);
- if (id.equals("G*T*F-----****X")
- || id.equals("G*F*LCC---****X") ||//CFL
+ if (
+ id.equals("G*F*LCC---****X") ||//CFL
id.equals("G*G*GLB---****X")
|| id.equals("G*G*GLF---****X")
|| id.equals("G*G*GLC---****X")
|| id.equals("G*G*GAF---****X")
- || id.equals("G*G*AAW---****X")
|| id.equals("G*G*DABP--****X")
|| id.equals("G*G*OLP---****X")
|| id.equals("G*G*PY----****X")
@@ -441,7 +456,6 @@ public static Boolean ShouldClipSymbol(String symbolID) {
|| id.equals("G*G*ALS---****X")
|| id.equals("G*G*SLB---****X")
|| id.equals("G*G*SLH---****X")
- || id.equals("G*G*GAY---****X")
|| id.equals("G*M*OFA---****X")
|| id.equals("G*M*OGB---****X")
|| id.equals("G*M*OGL---****X")
@@ -452,8 +466,7 @@ public static Boolean ShouldClipSymbol(String symbolID) {
|| id.equals("G*M*OADC--****X")
|| id.equals("G*M*OAR---****X")
|| id.equals("G*M*OAW---****X")
- || id.equals("G*M*OEF---****X") || //Obstacles Effect Fix
- id.equals("G*M*OMC---****X")
+ || id.equals("G*M*OEF---****X") //Obstacles Effect Fix
|| id.equals("G*M*OWU---****X")
|| id.equals("G*M*OWS---****X")
|| id.equals("G*M*OWD---****X")
@@ -469,15 +482,6 @@ public static Boolean ShouldClipSymbol(String symbolID) {
id.equals("G*M*BCE---****X") || //Ford Easy
id.equals("G*M*SL----****X")
|| id.equals("G*M*SP----****X")
- || id.equals("G*M*NR----****X")
- || id.equals("G*M*NB----****X")
- || id.equals("G*M*NC----****X")
- || id.equals("G*F*ACNI--****X")
- || id.equals("G*F*ACNR--****X")
- || id.equals("G*F*ACNC--****X")
- || id.equals("G*F*AKBC--****X")
- || id.equals("G*F*AKBI--****X")
- || id.equals("G*F*AKBR--****X")
|| id.equals("G*F*AKPC--****X")
|| id.equals("G*F*AKPI--****X")
|| id.equals("G*F*AKPR--****X")
@@ -492,17 +496,45 @@ public static Boolean ShouldClipSymbol(String symbolID) {
|| id.equals("G*S*LRW---****X")
|| id.equals("G*T*Q-----****X")
|| id.equals("G*T*E-----****X")
- || id.equals("G*T*F-----****X") || //Tasks Fix
- id.equals("G*T*K-----****X") || //counterattack.
- id.equals("G*T*KF----****X") || //counterattack by fire.
- id.equals("G*G*PA----****X") || //AoA for Feint
- id.equals("G*M*ORP---****X")
- || id.equals("G*M*ORS---****X")
- || id.equals("G*T*A-----****X")) {
- return true;
- } else {
- return false;
+ || id.equals("G*T*F-----****X") || //Tasks Fix
+ id.equals("G*G*PA----****X") //AoA for Feint
+ )
+ {
+ shouldClip = true;//decorated lines
+ }
+ else if(!useFillPattern)
+ {
+ if(id.equals("G*G*GAY---****X") //limited access area
+ || id.equals("G*G*AAW---****X")//weapons free zone
+ || id.equals("G*M*NB----****X")//bio area
+ || id.equals("G*M*NC----****X")//chem area
+ || id.equals("G*M*NR----****X")//radioactive area
+ || id.equals("G*F*AKBC--****X")//kill box blue circular
+ || id.equals("G*F*AKBI--****X")//kb irr
+ || id.equals("G*F*AKBR--****X")//kb rect
+ || id.equals("G*F*ACNI--****X")//NFA
+ || id.equals("G*F*ACNR--****X")//NFA rectnagular
+ || id.equals("G*F*ACNC--****X")//NFA circular
+ )
+ {
+ shouldClip = true;//not using fill pattern so clip to not draw more lines than we have to
+ }
+ }
+ else if (!useDashArray)
+ {
+ if(id.equals("G*M*OMC---****X") //mine cluster
+ || id.equals("G*T*K-----****X") //counterattack.
+ || id.equals("G*T*KF----****X") //counterattack by fire.
+ || id.equals("G*M*ORP---****X") //blown bridges planned
+ || id.equals("G*M*ORS---****X") //blown bridges explosive
+ || id.equals("G*T*A-----****X") //follow and assume
+ )
+ {
+ shouldClip = true;//not using dash array so clip to not draw more lines than we have to
+ }
}
+
+ return shouldClip;
}
/**
@@ -516,6 +548,8 @@ public static Boolean ShouldClipSymbol(String symbolID) {
*/
private static double getReasonableScale(String bbox, double origScale) {
double scale = origScale;
+ if(!RendererSettings.getInstance().getAutoAdjustScale())
+ return origScale;
try {
String[] bounds = bbox.split(",");
double left = Double.valueOf(bounds[0]).doubleValue();
@@ -826,13 +860,8 @@ public static String RenderSymbol(String id,
//if(normalize)
//NormalizeGECoordsToGEExtents(0,360,geoCoords2);
- //disable clipping unless it spans IDL
- if (ShouldClipSymbol(symbolCode) == false) {
- if (crossesIDL(geoCoords) == false) {
- rect = null;
- bboxCoords = null;
- }
- }
+
+
tgl.set_SymbolId(symbolCode);// "GFGPSLA---****X" AMBUSH symbol code
tgl.set_Pixels(null);
@@ -841,7 +870,14 @@ public static String RenderSymbol(String id,
MilStdSymbol mSymbol = new MilStdSymbol(symbolCode, null, geoCoords, null);
- mSymbol.setUseDashArray(false);
+ if(format == 3)//GEOSVG
+ {
+ mSymbol.setUseDashArray(true);
+ //mSymbol.setUsePatternFill(true);
+ }
+ else
+ mSymbol.setUseDashArray(false);
+
//set milstd symbology standard.
mSymbol.setSymbologyStandard(symStd);
@@ -850,6 +886,15 @@ public static String RenderSymbol(String id,
} else {
mSymbol.setFillColor(null);
}
+
+
+ //disable clipping unless it spans IDL
+ if (ShouldClipSymbol(symbolCode, mSymbol.getUseDashArray(), mSymbol.getUsePatternFill()) == false) {
+ if (crossesIDL(geoCoords) == false) {
+ rect = null;
+ bboxCoords = null;
+ }
+ }
//check for required points & parameters
String symbolIsValid = canRenderMultiPoint(mSymbol);
@@ -922,7 +967,7 @@ public static String RenderSymbol(String id,
textColor = Color.white;//textColor = "#FFFFFFFF";
}
- jsonContent = KMLize(id, name, description, symbolCode, shapes, modifiers, ipc, normalize, textColor, mSymbol.get_WasClipped());
+ jsonContent = KMLize(id, name, description, symbolCode, shapes, modifiers, ipc, normalize, textColor, mSymbol.get_WasClipped(),mSymbol.isTextScaleSensitive(),mSymbol.isSymbolScaleSensitive());
jsonOutput.append(jsonContent);
//if there's a symbol fill or line pattern, add to KML//////////
@@ -985,9 +1030,21 @@ public static String RenderSymbol(String id,
jsonOutput.append(symbolCode);
jsonOutput.append("\",\"wasClipped\":\"");
jsonOutput.append(String.valueOf(mSymbol.get_WasClipped()));
+ jsonOutput.append("\",\"textScaleSensitive\":\"");
+ jsonOutput.append(String.valueOf(mSymbol.isTextScaleSensitive()));
+ jsonOutput.append("\",\"symbolScaleSensitive\":\"");
+ jsonOutput.append(String.valueOf(mSymbol.isSymbolScaleSensitive()));
jsonOutput.append("\"}}");
}
+ else if(format == 3)//GEOSVG
+ {
+ String textColor = mSymbol.getTextColor() != null ? SymbolUtilities.colorToHexString(mSymbol.getTextColor(), false) : "";
+ String backgroundColor = mSymbol.getTextBackgroundColor() != null ? SymbolUtilities.colorToHexString(mSymbol.getTextBackgroundColor(), false) : "";
+ //returns an svg with a geoTL and geoBR value to use to place the canvas on the map
+ jsonContent = MultiPointHandlerSVG.GeoSVGize(id, name, description, symbolCode, shapes, modifiers, ipc, normalize, textColor, backgroundColor, mSymbol.get_WasClipped());
+ jsonOutput.append(jsonContent);
+ }
} catch (Exception exc) {
String st = JavaRendererUtilities.getStackTrace(exc);
@@ -1462,13 +1519,7 @@ public static MilStdSymbol RenderSymbolAsMilStdSymbol(String id,
//if(normalize)
//NormalizeGECoordsToGEExtents(0,360,geoCoords2);
- //disable clipping unless it spans IDL
- if (ShouldClipSymbol(symbolCode) == false) {
- if (crossesIDL(geoCoords) == false) {
- rect = null;
- bboxCoords = null;
- }
- }
+
tgl.set_SymbolId(symbolCode);// "GFGPSLA---****X" AMBUSH symbol code
tgl.set_Pixels(null);
@@ -1491,6 +1542,14 @@ public static MilStdSymbol RenderSymbolAsMilStdSymbol(String id,
Color fc = mSymbol.getFillColor();
fillColor = Integer.toHexString(fc.getRGB());
}
+
+ //disable clipping unless it spans IDL
+ if (ShouldClipSymbol(symbolCode,mSymbol.getUseDashArray(),mSymbol.getUsePatternFill()) == false) {
+ if (crossesIDL(geoCoords) == false) {
+ rect = null;
+ bboxCoords = null;
+ }
+ }
//get pixel values in case we need to do a fill.
if (mSymbol.getModifierMap().containsKey(SYMBOL_FILL_IDS)
@@ -1766,7 +1825,15 @@ public static String RenderSymbol2D(String id,
try {
MilStdSymbol mSymbol = new MilStdSymbol(symbolCode, null, geoCoords, null);
- mSymbol.setUseDashArray(false);
+
+ if(format == 3)//GEOSVG
+ {
+ mSymbol.setUseDashArray(true);
+ //mSymbol.setUsePatternFill(true);
+ }
+ else
+ mSymbol.setUseDashArray(false);
+
//set milstd symbology standard.
mSymbol.setSymbologyStandard(symStd);
@@ -1794,7 +1861,7 @@ public static String RenderSymbol2D(String id,
// {
// ((PointConversion)ipc).set_normalize(false);
// }
- if (ShouldClipSymbol(symbolCode) || crossesIDL(geoCoords)) {
+ if (ShouldClipSymbol(symbolCode,mSymbol.getUseDashArray(),mSymbol.getUsePatternFill()) || crossesIDL(geoCoords)) {
temp = ipc.GeoToPixels(new Point2D.Double(left, top));
leftX = (int) temp.getX();
topY = (int) temp.getY();
@@ -1857,7 +1924,7 @@ public static String RenderSymbol2D(String id,
{
textColor = Color.white;//textColor = "#FFFFFFFF";
}
- jsonContent = KMLize(id, name, description, symbolCode, shapes, modifiers, ipc, normalize, textColor, mSymbol.get_WasClipped());
+ jsonContent = KMLize(id, name, description, symbolCode, shapes, modifiers, ipc, normalize, textColor, mSymbol.get_WasClipped(),mSymbol.isTextScaleSensitive(),mSymbol.isSymbolScaleSensitive());
jsonOutput.append(jsonContent);
//if there's a symbol fill or line pattern, add to KML//////////
@@ -1894,9 +1961,21 @@ public static String RenderSymbol2D(String id,
jsonOutput.append(symbolCode);
jsonOutput.append("\",\"wasClipped\":\"");
jsonOutput.append(String.valueOf(mSymbol.get_WasClipped()));
+ jsonOutput.append("\",\"textScaleSensitive\":\"");
+ jsonOutput.append(String.valueOf(mSymbol.isTextScaleSensitive()));
+ jsonOutput.append("\",\"symbolScaleSensitive\":\"");
+ jsonOutput.append(String.valueOf(mSymbol.isSymbolScaleSensitive()));
jsonOutput.append("\"}}");
}
+ else if (format == 3)//GEOSVG
+ {
+ String textColor = mSymbol.getTextColor() != null ? SymbolUtilities.colorToHexString(mSymbol.getTextColor(), false) : "";
+ String backgroundColor = mSymbol.getTextBackgroundColor() != null ? SymbolUtilities.colorToHexString(mSymbol.getTextBackgroundColor(), false) : "";
+ //returns an svg with a geoTL and geoBR value to use to place the canvas on the map
+ jsonContent = MultiPointHandlerSVG.GeoSVGize(id, name, description, symbolCode, shapes, modifiers, ipc, normalize, textColor, backgroundColor, mSymbol.get_WasClipped());
+ jsonOutput.append(jsonContent);
+ }
} catch (Exception exc) {
jsonOutput = new StringBuilder();
@@ -2203,7 +2282,7 @@ public static String RenderSymbol2DX(String id,
if (mSymbol.getFillColor() != null) {
fillColor = Integer.toHexString(mSymbol.getFillColor().getRGB());//Integer.toHexString(shapeInfo.getFillColor().getRGB()
}
- jsonContent = KMLize(id, name, description, symbolCode, shapes, modifiers, ipc, normalize, mSymbol.getLineColor(), mSymbol.get_WasClipped());
+ jsonContent = KMLize(id, name, description, symbolCode, shapes, modifiers, ipc, normalize, mSymbol.getLineColor(), mSymbol.get_WasClipped(),mSymbol.isTextScaleSensitive(),mSymbol.isSymbolScaleSensitive());
jsonOutput.append(jsonContent);
}
@@ -3056,7 +3135,9 @@ private static String KMLize(String id, String name,
IPointConversion ipc,
boolean normalize,
Color textColor,
- boolean wasClipped) {
+ boolean wasClipped,
+ int textScaleSensitive,
+ int symbolScaleSensitive) {
StringBuilder kml = new StringBuilder();
@@ -3073,6 +3154,8 @@ private static String KMLize(String id, String name,
kml.append("");
kml.append("").append(symbolCode).append("");
kml.append("").append(wasClipped).append("");
+ kml.append("").append(textScaleSensitive).append("");
+ kml.append("").append(symbolScaleSensitive).append("");
kml.append("");
for (int i = 0; i < len; i++) {
diff --git a/renderer/mil-sym-renderer/src/main/java/sec/web/renderer/MultiPointHandlerSVG.java b/renderer/mil-sym-renderer/src/main/java/sec/web/renderer/MultiPointHandlerSVG.java
new file mode 100644
index 00000000..d05d1ed3
--- /dev/null
+++ b/renderer/mil-sym-renderer/src/main/java/sec/web/renderer/MultiPointHandlerSVG.java
@@ -0,0 +1,503 @@
+/*
+ *
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package sec.web.renderer;
+
+import ArmyC2.C2SD.Utilities.ErrorLogger;
+import ArmyC2.C2SD.Utilities.IPointConversion;
+import ArmyC2.C2SD.Utilities.RendererSettings;
+import ArmyC2.C2SD.Utilities.ShapeInfo;
+import ArmyC2.C2SD.Utilities.SymbolDraw;
+import ArmyC2.C2SD.Utilities.SymbolUtilities;
+import com.sun.org.apache.xerces.internal.impl.dv.util.Base64;
+import java.awt.BasicStroke;
+import java.awt.Color;
+import java.awt.Font;
+import java.awt.Rectangle;
+import java.awt.geom.Point2D;
+import java.awt.geom.Rectangle2D;
+import java.awt.image.BufferedImage;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.UncheckedIOException;
+import java.util.ArrayList;
+import javax.imageio.ImageIO;
+import sec.web.renderer.utilities.Path;
+import sec.web.renderer.utilities.SVGTextInfo;
+
+
+/**
+ *
+ */
+public class MultiPointHandlerSVG {
+ public static String GeoSVGize(String id, String name, String description, String symbolID, ArrayList shapes, ArrayList modifiers, IPointConversion ipc, boolean normalize, String textColor, String textBackgroundColor, boolean wasClipped) {
+ return GeoSVGize(id, name, description, symbolID, shapes, modifiers, ipc, normalize, textColor, textBackgroundColor, wasClipped, null);
+ }
+
+ /**
+ * Generates an SVG which can be draped on a map.
+ * Better with RenderSymbol2D
+ *
+ * @param id
+ * @param name
+ * @param description
+ * @param symbolID
+ * @param shapes {@link ShapeInfo[]}
+ * @param modifiers {@link ShapeInfo[]}
+ * @param ipc {@link IPointConversion}
+ * @param normalize
+ * @param textColor
+ * @param textBackgroundColor
+ * @param wasClipped
+ * @return
+ */
+ public static String GeoSVGize(String id, String name, String description, String symbolID, ArrayList shapes, ArrayList modifiers, IPointConversion ipc, boolean normalize, String textColor, String textBackgroundColor, boolean wasClipped, Rectangle bbox) {
+
+ int height = 10;
+
+ Rectangle tempBounds = null;
+ ArrayList paths = new ArrayList<>();
+ Rectangle pathBounds = null;
+ ArrayList labels = new ArrayList<>();
+ Rectangle labelBounds = null;
+ Rectangle unionBounds = null;
+ float lineWidth;
+ String fillTexture = null;
+ Point2D geoCoordTL = null;
+ Point2D geoCoordTR = null;
+ Point2D geoCoordBL = null;
+ Point2D geoCoordBR = null;
+ Point2D west = null;
+ Point2D north = null;
+ Point2D south = null;
+ Point2D east = null;
+ int len = shapes.size();
+
+ try {
+ Font fontInfo = RendererSettings.getInstance().getMPLabelFont();
+ height = fontInfo.getSize();
+
+
+ for (int i = 0; i < len; i++) {
+ tempBounds = new Rectangle();
+ String svg = MultiPointHandlerSVG.ShapesToGeoSVG(symbolID, shapes.get(i), tempBounds, ipc, normalize);
+ if (svg != null) {
+ BasicStroke bsTemp = (BasicStroke)shapes.get(i).getStroke();
+ lineWidth = bsTemp.getLineWidth();
+ tempBounds.grow(Math.round(lineWidth / 2), Math.round(lineWidth / 2));//adjust for line width so nothing gets clipped.
+ if (pathBounds == null)
+ pathBounds = (Rectangle) tempBounds.clone();
+ else
+ pathBounds = pathBounds.union(tempBounds);
+ paths.add(svg);
+
+
+ if (shapes.get(i).getPatternFillImage() != null && fillTexture == null)
+ fillTexture = getFillPattern(shapes.get(i));
+ }
+ }
+
+ ShapeInfo tempModifier;
+ int len2 = modifiers.size();
+ SVGTextInfo tiTemp = null;
+ for (int j = 0; j < len2; j++) {
+ tempModifier = modifiers.get(j);
+
+ if (tempModifier.getModifierString() != null && !tempModifier.getModifierString().isEmpty()) {
+ Point2D tempLocation = tempModifier.getModifierStringPosition();
+
+ int justify = tempModifier.getTextJustify();
+ String strJustify = "start";
+ if (justify == ShapeInfo.justify_left)
+ strJustify = "start";
+ else if (justify == ShapeInfo.justify_center)
+ strJustify = "middle";
+ else if (justify == ShapeInfo.justify_right)
+ strJustify = "end";
+
+ double degrees = tempModifier.getModifierStringAngle();
+ tiTemp = new SVGTextInfo(tempModifier.getModifierString(), tempLocation, fontInfo, strJustify, degrees);
+
+ Rectangle bounds = tiTemp.getTextBounds().getBounds();
+
+ //make sure labels are in the bbox, otherwise they can
+ //make the canvas grow out of control.
+ //if (tiTemp && bbox.containsRectangle(bounds))
+ //if(bbox !== null)
+ if (tiTemp != null) {
+ if ((bbox != null && bbox.intersects(bounds)) || bbox == null) {
+ labels.add(tiTemp);
+ if (bounds != null) {
+ if (labelBounds != null)
+ labelBounds = labelBounds.union(bounds);
+ else
+ labelBounds = bounds;
+ }
+ }
+ }
+ }
+ /* //Not implemented in 2525C renderer
+ else if (tempModifier.getModifierImage() != null)
+ {
+ BufferedImage imgModifier = tempModifier.getModifierImage();
+ Rectangle bounds = new Rectangle(0, 0, imgModifier.getWidth(), imgModifier.getHeight());
+
+ Point2D tempLocation = tempModifier.getModifierStringPosition();
+ tempLocation.setLocation(tempLocation.getX() - bounds.getWidth() / 2, tempLocation.getY() - bounds.getHeight() / 2);
+ int x = (int) tempLocation.getX();
+ int y = (int) tempLocation.getY();
+ bounds.setLocation(x, y);
+
+ double angle = tempModifier.getModifierStringAngle();
+ paths.add("");
+ if (angle != 0) {
+ Rectangle2D bounds2D = SVGTextInfo.getRotatedRectangleBounds(bounds, tempLocation, -angle, "middle");
+ bounds = bounds2D.getBounds();
+ }
+ if (bounds != null) {
+ if ((bbox != null && bbox.intersects(bounds)) || bbox == null) {
+ if (pathBounds != null)
+ pathBounds = pathBounds.union(bounds);
+ else
+ pathBounds = bounds;
+ }
+ }
+ }//*/
+ }
+ if (pathBounds != null) {
+ unionBounds = (Rectangle) pathBounds.clone();
+ }
+ if (labelBounds != null) {
+ if (unionBounds != null) {
+ unionBounds = unionBounds.union(labelBounds);
+ } else {
+ unionBounds = labelBounds;
+ }
+ }
+
+ //get geo bounds for canvas
+
+ if (unionBounds != null) {
+ Point2D coordTL = new Point2D.Double();
+ coordTL.setLocation(unionBounds.getX(), unionBounds.getY());
+ Point2D coordBR = new Point2D.Double();
+ coordBR.setLocation(unionBounds.getX() + unionBounds.getWidth(), unionBounds.getY() + unionBounds.getHeight());
+
+ Point2D coordTR = new Point2D.Double();
+ coordTR.setLocation(unionBounds.getX() + unionBounds.getWidth(), unionBounds.getY());
+ Point2D coordBL = new Point2D.Double();
+ coordBL.setLocation(unionBounds.getX(), unionBounds.getY() + unionBounds.getHeight());
+
+ south = new Point2D.Double(unionBounds.getX() + unionBounds.getWidth() / 2, unionBounds.getY() + unionBounds.getHeight());
+ north = new Point2D.Double(unionBounds.getX() + unionBounds.getWidth() / 2, unionBounds.getY());
+ east = new Point2D.Double(unionBounds.getX() + unionBounds.getWidth(), unionBounds.getY() + unionBounds.getHeight() / 2);
+ west = new Point2D.Double(unionBounds.getX(), unionBounds.getY() + unionBounds.getHeight() / 2);
+
+
+ geoCoordTL = ipc.PixelsToGeo(coordTL);
+ geoCoordBR = ipc.PixelsToGeo(coordBR);
+ geoCoordTR = ipc.PixelsToGeo(coordTR);
+ geoCoordBL = ipc.PixelsToGeo(coordBL);
+
+ north = ipc.PixelsToGeo(north);
+ south = ipc.PixelsToGeo(south);
+ east = ipc.PixelsToGeo(east);
+ west = ipc.PixelsToGeo(west);
+
+
+ if (normalize) {
+ geoCoordTL = MultiPointHandler.NormalizeCoordToGECoord(geoCoordTL);
+ geoCoordBR = MultiPointHandler.NormalizeCoordToGECoord(geoCoordBR);
+ geoCoordTR = MultiPointHandler.NormalizeCoordToGECoord(geoCoordTR);
+ geoCoordBL = MultiPointHandler.NormalizeCoordToGECoord(geoCoordBL);
+
+ north = MultiPointHandler.NormalizeCoordToGECoord(north);
+ south = MultiPointHandler.NormalizeCoordToGECoord(south);
+ east = MultiPointHandler.NormalizeCoordToGECoord(east);
+ west = MultiPointHandler.NormalizeCoordToGECoord(west);
+ }
+ } else//nothing to draw
+ {
+ geoCoordTL = new Point2D.Double(0, 0);
+ geoCoordBR = new Point2D.Double(0, 0);
+ geoCoordTR = new Point2D.Double(0, 0);
+ geoCoordBL = new Point2D.Double(0, 0);
+
+ north = new Point2D.Double(0, 0);
+ south = new Point2D.Double(0, 0);
+ east = new Point2D.Double(0, 0);
+ west = new Point2D.Double(0, 0);
+ }
+ } catch (Exception err) {
+ ErrorLogger.LogException("MultiPointHandler", "GeoSVGize", err);
+ }
+
+ if (paths != null && len > 0 && unionBounds != null) {
+ //create group with offset translation
+ //ctx.translate(bounds.getX() * -1, bounds.getY() * -1);
+ String group = "";
+
+ //loop through paths and labels and build SVG.
+ for (int i = 0; i < paths.size(); i++) {
+ group += paths.get(i);
+ }
+
+ ArrayList labelStrs = renderTextElement(labels, textColor, textBackgroundColor);
+ for (int j = 0; j < labelStrs.size(); j++) {
+ group += labelStrs.get(j);
+ }
+ //close
+ group += "";
+
+ //wrap in SVG
+ String geoSVG = "