/* * To change this template, choose Tools | Templates * and open the template in the editor. */ package armyc2.c2sd.JavaTacticalRenderer; import java.util.ArrayList; import armyc2.c2sd.JavaLineArray.ref; import armyc2.c2sd.JavaLineArray.POINT2; import armyc2.c2sd.JavaLineArray.TacticalLines; import armyc2.c2sd.JavaLineArray.CELineArray; import armyc2.c2sd.JavaLineArray.Shape2; import armyc2.c2sd.renderer.utilities.ErrorLogger; import armyc2.c2sd.renderer.utilities.RendererException; import armyc2.c2sd.JavaLineArray.Channels; import armyc2.c2sd.JavaLineArray.lineutility; /** * A class to process channel types. * * @author Michael Deutch */ public final class clsChannelUtility { private static final String _className = "clsChannelUtility"; /** * Gets partitions from the client points based on the segments generated by * GetSegments. Partitions are used handle double-backed segments. Each * partition is a continuous sequence of points for a channel. * * @param segments * @param partitions OUT the partitions * @return */ private static int GetPartitions(boolean[] segments, ArrayList<P1> partitions) { try { int j = 0; boolean nextSegment = false; //worst case is every segment is a separate partition //caller must deallocate partitions P1 p1 = new P1(); //first segment will always be true, //there are no bad one-segment channels if (segments[0] == false) { return 0; } if (partitions != null) { partitions.clear(); } else { return 0; } p1.start = 0; //only add the partitions after p1.end has been set int n = segments.length; //for (j = 0; j < segments.length - 1; j++) for (j = 0; j < n - 1; j++) { nextSegment = segments[j + 1]; if (nextSegment == false) { //the end of the current partition is the last good segment p1.end_Renamed = j; partitions.add(p1); //beginning of the next partition p1 = new P1(); p1.start = j + 1; } } p1.end_Renamed = j; partitions.add(p1); } catch (Exception exc) { //System.out.println(e.getMessage()); //clsUtility.WriteFile("error in clsChanneUtility.GetPartitions"); ErrorLogger.LogException(_className, "GetPartitions", new RendererException("Failed inside GetPartitions", exc)); } return partitions.size(); } /** * Draws a partition to the shapes array and stores the calculated channel * points * * @param fromSegment * @param toSegment * @param pixels * @param lineType * @param channelWidth * @param bolLastSegment * @param shapes * @param channelPoints * @param distanceToChannelPoint * @return */ private static int DrawGoodChannel2(int fromSegment, int toSegment, double[] pixels, int lineType, int channelWidth, boolean bolLastSegment, ArrayList<Shape2> shapes, ArrayList<POINT2> channelPoints, double distanceToChannelPoint, int rev) { int returnValue = 0; // Had to initialize to something try { int lineType2; double[] channelPixels = null; switch (lineType) { case TacticalLines.BELT1: lineType2 = TacticalLines.BELT1; //break; case TacticalLines.LC: case TacticalLines.LC_HOSTILE: case TacticalLines.LC2: case TacticalLines.UNSP: case TacticalLines.DFENCE: case TacticalLines.SFENCE: case TacticalLines.DOUBLEA: case TacticalLines.LWFENCE: case TacticalLines.HWFENCE: case TacticalLines.BBS_LINE: case TacticalLines.SINGLEC: case TacticalLines.SINGLEC2: case TacticalLines.DOUBLEC: case TacticalLines.DOUBLEC2: case TacticalLines.TRIPLE: case TacticalLines.TRIPLE2: lineType2 = lineType; break; case TacticalLines.AAFNT: if (fromSegment == 0) { lineType2 = TacticalLines.CHANNEL_FLARED; } else { lineType2 = TacticalLines.CHANNEL; } break; case TacticalLines.SPT: if (fromSegment == 0) { lineType2 = TacticalLines.CHANNEL_FLARED; } else { lineType2 = TacticalLines.CHANNEL; } break; case TacticalLines.MAIN: if (fromSegment == 0) { lineType2 = TacticalLines.CHANNEL_FLARED; } else { lineType2 = TacticalLines.CHANNEL; } break; case TacticalLines.CATK: lineType2 = TacticalLines.CHANNEL_DASHED; break; case TacticalLines.CATKBYFIRE: lineType2 = TacticalLines.CHANNEL_DASHED; break; default: lineType2 = TacticalLines.CHANNEL; break; } if (bolLastSegment == true) { if (fromSegment != 0) { switch (lineType) { case TacticalLines.AAFNT: lineType2 = TacticalLines.AAFNT_STRAIGHT; break; case TacticalLines.SPT: lineType2 = TacticalLines.SPT_STRAIGHT; break; case TacticalLines.MAIN: lineType2 = TacticalLines.MAIN_STRAIGHT; break; default: lineType2 = (int) lineType; break; } } else { lineType2 = (int) lineType; } } if (fromSegment < 0) { return returnValue; } if (toSegment < 0) { return returnValue; } if (toSegment < fromSegment) { return returnValue; } int j; int lineCount; int numPoints; int counter; double[] goodUpperPixels; double[] goodLowerPixels; numPoints = toSegment - fromSegment + 2; goodUpperPixels = new double[2 * numPoints]; goodLowerPixels = new double[2 * numPoints]; counter = 0; for (j = fromSegment; j < toSegment + 2; j++) { goodUpperPixels[counter] = pixels[2 * j]; goodUpperPixels[counter + 1] = pixels[2 * j + 1]; goodLowerPixels[counter] = pixels[2 * j]; goodLowerPixels[counter + 1] = pixels[2 * j + 1]; counter = counter + 2; } lineCount = CELineArray.CGetLineCountDouble(goodUpperPixels, numPoints, lineType2, channelWidth, rev); channelPixels = new double[3 * lineCount]; POINT2 pt = null; lineCount = CELineArray.CGetChannel2Double(goodUpperPixels, goodLowerPixels, channelPixels, numPoints, numPoints, lineType2, channelWidth / 2, (int) distanceToChannelPoint, shapes, rev); //if shapes is null then it is not a CPOF client if (shapes == null && channelPixels != null) { //do not clear channelPoints first because the function gets successive calls int n = channelPixels.length; //for (j = 0; j < channelPixels.length / 3; j++) for (j = 0; j < n / 3; j++) { pt = new POINT2(channelPixels[3 * j], channelPixels[3 * j + 1], (int) channelPixels[3 * j + 2]); if (j == channelPixels.length / 3 - 1) { pt.style = 5; } channelPoints.add(pt); } } if (lineCount > 0) { //DrawChannelPixels2(lineCount, channelPixels, (int)lineType); returnValue = channelPixels.length; } else { returnValue = 0; } //channelPixels[channelPixels.length - 1] = 5; if (lineCount > 0) { channelPixels[lineCount - 1] = 5; } //clean up goodUpperPixels = null; goodLowerPixels = null; } catch (Exception exc) { //clsUtility.WriteFile("error in clsChanneUtility.DrawGoodChannel2"); ErrorLogger.LogException(_className, "DrawGoodChannel2", new RendererException("Failed inside DrawGoodChannel2", exc)); } return returnValue; } /** * Draws the channel partitions to the shapes array * * @param pixels * @param partitions * @param linetype * @param channelWidth channel width in pixels * @param shapes * @param channelPoints * @param distanceToChannelPoint distance in pixels from the tip to the back * of the arrow */ private static void DrawSegments(double[] pixels, ArrayList<P1> partitions, int linetype, int channelWidth, ArrayList<Shape2> shapes, ArrayList<POINT2> channelPoints, double distanceToChannelPoint, int rev) { try { int j = 0; int n = 0; int t = partitions.size(); //for (j = 0; j < partitions.size() - 1; j++) for (j = 0; j < t - 1; j++) { n = DrawGoodChannel2(partitions.get(j).start, partitions.get(j).end_Renamed, pixels, linetype, channelWidth, false, shapes, channelPoints, distanceToChannelPoint, rev); } //draw the last partition using linetype n = DrawGoodChannel2(partitions.get(j).start, partitions.get(j).end_Renamed, pixels, linetype, channelWidth, true, shapes, channelPoints, distanceToChannelPoint, rev); } catch (Exception exc) { //clsUtility.WriteFile("error in clsChanneUtility.DrawSegments"); ErrorLogger.LogException(_className, "DrawSegments", new RendererException("Failed inside DrawSegments", exc)); } } /** * Handle symbol too small for line of contact * @param tg * @param pixels * @return */ private static ArrayList<POINT2> getLCPixels(TGLight tg,ArrayList<POINT2>pixels) { ArrayList<POINT2>pixels2=null; try { if(tg.get_LineType()!=TacticalLines.LC) return pixels; POINT2[] pts=tg.Pixels.toArray(new POINT2[pixels.size()]); POINT2 ul=new POINT2(),lr=new POINT2(); lineutility.CalcMBRPoints((POINT2[])pts, pts.length, ul, lr); if(lr.x-ul.x>=21) return pixels; else if (lr.y-ul.y>=21) return pixels; //at this point the mbr is too small for a meaningful LC symbol double x0=pts[0].x,y0=pts[0].y,x1=pts[1].x,y1=pts[1].y; if (x0<=x1) x1=x0+21; else x1=x0-21; y1=y0; POINT2 pt0=new POINT2(x0,y0),pt1=new POINT2(x1,y1); pixels2=new ArrayList(); pixels2.add(pt0); pixels2.add(pt1); } catch (Exception exc) { //clsUtility.WriteFile("error in clsChanneUtility.DrawSegments"); ErrorLogger.LogException(_className ,"getLCPixels", new RendererException("Failed inside getLCPixels", exc)); } return pixels2; } /** * The main interface to clsChannelUtility calls DrawChannel2 after stuffing * the points into an array of 2-tuples x,y * * @param pixels the client points * @param linetype the line type * @param tg the tactical graphic * @param shapes * @param channelPoints * @param rev Mil-Standard-2525 revision */ public static void DrawChannel(ArrayList<POINT2> pixels, int linetype, TGLight tg, ArrayList<Shape2> shapes, ArrayList<POINT2> channelPoints, int rev) { try { pixels=getLCPixels(tg,pixels); //we must do this because the rotary arrow tip now has to match the //anchor point, i.e. the rotary feature can no longer stick out past the anchor point //45 pixels shift here matches the 45 pixels shift for catkbyfire found in Channels.GetAXADDouble lineutility.adjustCATKBYFIREControlPoint(linetype, pixels, 45); if(tg.get_LineType()==TacticalLines.LC && tg.get_Affiliation().equalsIgnoreCase("H")) linetype=TacticalLines.LC_HOSTILE; int j = 0; double[] pixels2 = new double[pixels.size() * 2]; int n = pixels.size(); //for (j = 0; j < pixels.size(); j++) for (j = 0; j < n; j++) { pixels2[2 * j] = pixels.get(j).x; pixels2[2 * j + 1] = pixels.get(j).y; } DrawChannel2(pixels2, linetype, tg, shapes, channelPoints, rev); } catch (Exception exc) { //clsUtility.WriteFile("error in clsChanneUtility.DrawSegments"); ErrorLogger.LogException(_className, "DrawChannel", new RendererException("Failed inside DrawChannel", exc)); } } /** * utility for clsMETOC to handle double-backed segments * * @param tg the tactical graphic object */ public static ArrayList<P1> GetPartitions2(TGLight tg) { ArrayList partitions = null; try { double[] pixels = new double[tg.Pixels.size() * 2]; int n = tg.Pixels.size(); //for(int j=0;j<tg.Pixels.size();j++) for (int j = 0; j < n; j++) { pixels[2 * j] = tg.Pixels.get(j).x; pixels[2 * j + 1] = tg.Pixels.get(j).y; } boolean[] segments = new boolean[pixels.length / 2 - 1]; if (segments.length == 0) { return null; } double factor = 3; clsUtility.GetSegments(pixels, segments, factor); partitions = new ArrayList<P1>(); GetPartitions(segments, partitions); } catch (Exception exc) { ErrorLogger.LogException(_className, "GetPartitions2", new RendererException("Failed inside GetPartitions2", exc)); } return partitions; } /** * The main function for processing channel types. Gets segments, then gets * partitions from the segments and then draws the partitions. * * @param pixels the client points as an array of 2-tuples x,y * @param linetype the line type * @param tg the tactical graphic object * @param shapes * @param channelPoints */ private static void DrawChannel2(double[] pixels, int linetype, TGLight tg, ArrayList<Shape2> shapes, ArrayList<POINT2> channelPoints, int rev) { try { ref<double[]> distanceToChannelPoint = new ref(); boolean bolAnimation = false; //indicates if the colors are flipped from int j = 0; double[] pixels2 = null; int channelWidth = 0; ArrayList partitions = null; int n = pixels.length; int numPoints = 0; //LC and others do not call clsUtility.ChannelWidth, but the //value array still needs to be allocated or there is a //null pointer exception in DrawGoodChannel2 distanceToChannelPoint.value = new double[1]; distanceToChannelPoint.value[0] = 20; switch (linetype) { case TacticalLines.AAFNT: case TacticalLines.MAIN: case TacticalLines.CATK: case TacticalLines.CATKBYFIRE: case TacticalLines.AXAD: case TacticalLines.AIRAOA: case TacticalLines.AAAAA: case TacticalLines.SPT: clsUtility.ReorderPixels(pixels); //diagnostic shorten last segment by channelwidth/4 for AAFNT //so that the feint won't go past the 0th point if (linetype == TacticalLines.AAFNT) { channelWidth = clsUtility.ChannelWidth(pixels, distanceToChannelPoint) / 2; POINT2 pt0 = new POINT2(); POINT2 pt1 = new POINT2(); pt0.x = pixels[pixels.length - 4];//-2 pt0.y = pixels[pixels.length - 3];//-1 pt1.x = pixels[pixels.length - 6];//-4 pt1.y = pixels[pixels.length - 5];//-3 pt0 = lineutility.ExtendAlongLineDouble(pt0, pt1, channelWidth / 8); pixels[pixels.length - 4] = pt0.x; pixels[pixels.length - 3] = pt0.y; } //end section numPoints = pixels.length / 2; if (numPoints < 3) { return; } //moved this to be prior to stuffing pixels2 channelWidth = clsUtility.ChannelWidth(pixels, distanceToChannelPoint) / 2; //ValidateChannelPixels2(ref pixels, ref channelWidth, ref distanceToChannelPoint); numPoints = pixels.length / 2; pixels2 = new double[pixels.length - 2]; for (j = 0; j < numPoints; j++) { if (j < numPoints - 1) { pixels2[2 * j] = pixels[2 * j]; pixels2[2 * j + 1] = pixels[2 * j + 1]; } } break; case TacticalLines.LC: case TacticalLines.LC_HOSTILE: case TacticalLines.LC2: if (bolAnimation == true) { channelWidth = 32;// was 16; } else { channelWidth = 40;// was 20; } pixels2 = new double[pixels.length]; n = pixels.length; //for (j = 0; j < pixels.length; j++) for (j = 0; j < n; j++) { pixels2[j] = pixels[j]; } break; case TacticalLines.UNSP: case TacticalLines.DFENCE: case TacticalLines.SFENCE: case TacticalLines.DOUBLEA: case TacticalLines.LWFENCE: case TacticalLines.HWFENCE: channelWidth = 30; //was 20 1-10-13 if (Channels.getShiftLines()) { channelWidth = 60;//was 40 } pixels2 = new double[pixels.length]; n = pixels.length; //for (j = 0; j < pixels.length; j++) for (j = 0; j < n; j++) { pixels2[j] = pixels[j]; } break; case TacticalLines.BBS_LINE: channelWidth = 8 * tg.Pixels.get(0).style; //was 20 1-10-13 pixels2 = new double[pixels.length]; n = pixels.length; //for (j = 0; j < pixels.length; j++) for (j = 0; j < n; j++) { pixels2[j] = pixels[j]; } break; case TacticalLines.SINGLEC: //7-9-07 case TacticalLines.SINGLEC2: case TacticalLines.DOUBLEC: case TacticalLines.DOUBLEC2: case TacticalLines.TRIPLE: case TacticalLines.TRIPLE2: //diagnostic 9-27-11 //clsUtility.MovePixels(pixels, pixels.length / 2); channelWidth = 110; //was 80 pixels2 = new double[pixels.length]; n = pixels.length; //for (j = 0; j < pixels.length; j++) for (j = 0; j < n; j++) { pixels2[j] = pixels[j]; } break; default: break; } //we require new partitions because pixels are dirty boolean[] segments = new boolean[pixels2.length / 2 - 1]; if (segments.length == 0) { return; } double factor = 3; clsUtility.GetSegments(pixels2, segments, factor); partitions = new ArrayList(); GetPartitions(segments, partitions); DrawSegments(pixels2, partitions, linetype, channelWidth, shapes, channelPoints, distanceToChannelPoint.value[0], rev); } catch (Exception exc) { ErrorLogger.LogException(_className, "DrawChannel2", new RendererException("Failed inside DrawChannel2", exc)); } } }